Minor. Reformat code
This commit is contained in:
+106
-113
@@ -29,10 +29,10 @@ import org.jetbrains.org.objectweb.asm.tree.*
|
||||
import java.util.*
|
||||
|
||||
class AnonymousObjectTransformer(
|
||||
transformationInfo: AnonymousObjectTransformationInfo,
|
||||
private val inliningContext: InliningContext,
|
||||
private val isSameModule: Boolean,
|
||||
private val continuationClassName: String?
|
||||
transformationInfo: AnonymousObjectTransformationInfo,
|
||||
private val inliningContext: InliningContext,
|
||||
private val isSameModule: Boolean,
|
||||
private val continuationClassName: String?
|
||||
) : ObjectTransformer<AnonymousObjectTransformationInfo>(transformationInfo, inliningContext.state) {
|
||||
|
||||
private val oldObjectType = Type.getObjectType(transformationInfo.oldClassName)
|
||||
@@ -75,7 +75,7 @@ class AnonymousObjectTransformer(
|
||||
}
|
||||
|
||||
override fun visitMethod(
|
||||
access: Int, name: String, desc: String, signature: String?, exceptions: Array<String>?
|
||||
access: Int, name: String, desc: String, signature: String?, exceptions: Array<String>?
|
||||
): MethodVisitor {
|
||||
val node = MethodNode(access, name, desc, signature, exceptions)
|
||||
if (name == "<init>") {
|
||||
@@ -83,8 +83,7 @@ class AnonymousObjectTransformer(
|
||||
throw RuntimeException("Lambda, SAM or anonymous object should have only one constructor")
|
||||
}
|
||||
constructor = node
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
methodsToTransform.add(node)
|
||||
}
|
||||
return node
|
||||
@@ -94,8 +93,7 @@ class AnonymousObjectTransformer(
|
||||
addUniqueField(name)
|
||||
return if (isCapturedFieldName(name)) {
|
||||
null
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
classBuilder.newField(JvmDeclarationOrigin.NO_ORIGIN, access, name, desc, signature, value)
|
||||
}
|
||||
}
|
||||
@@ -111,16 +109,14 @@ class AnonymousObjectTransformer(
|
||||
if (!inliningContext.isInliningLambda) {
|
||||
sourceMapper = if (debugInfo != null && !debugInfo!!.isEmpty()) {
|
||||
SourceMapper.createFromSmap(SMAPParser.parse(debugInfo!!))
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
//seems we can't do any clever mapping cause we don't know any about original class name
|
||||
IdenticalSourceMapper
|
||||
}
|
||||
if (sourceInfo != null && !GENERATE_SMAP) {
|
||||
classBuilder.visitSource(sourceInfo!!, debugInfo)
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (sourceInfo != null) {
|
||||
classBuilder.visitSource(sourceInfo!!, debugInfo)
|
||||
}
|
||||
@@ -130,7 +126,7 @@ class AnonymousObjectTransformer(
|
||||
val allCapturedParamBuilder = ParametersBuilder.newBuilder()
|
||||
val constructorParamBuilder = ParametersBuilder.newBuilder()
|
||||
val additionalFakeParams = extractParametersMappingAndPatchConstructor(
|
||||
constructor!!, allCapturedParamBuilder, constructorParamBuilder,transformationInfo, parentRemapper
|
||||
constructor!!, allCapturedParamBuilder, constructorParamBuilder, transformationInfo, parentRemapper
|
||||
)
|
||||
|
||||
val deferringMethods = ArrayList<DeferredMethodVisitor>()
|
||||
@@ -172,8 +168,7 @@ class AnonymousObjectTransformer(
|
||||
SourceMapper.flushToClassBuilder(sourceMapper, classBuilder)
|
||||
|
||||
val visitor = classBuilder.visitor
|
||||
innerClassNodes.forEach {
|
||||
node ->
|
||||
innerClassNodes.forEach { node ->
|
||||
visitor.visitInnerClass(node.name, node.outerName, node.innerName, node.access)
|
||||
}
|
||||
|
||||
@@ -194,7 +189,7 @@ class AnonymousObjectTransformer(
|
||||
}
|
||||
|
||||
private fun writeTransformedMetadata(header: KotlinClassHeader, classBuilder: ClassBuilder) {
|
||||
writeKotlinMetadata(classBuilder, state, header.kind, header.extraInt) action@ { av ->
|
||||
writeKotlinMetadata(classBuilder, state, header.kind, header.extraInt) action@{ av ->
|
||||
val (newProto, newStringTable) = transformMetadata(header) ?: run {
|
||||
val data = header.data
|
||||
val strings = header.strings
|
||||
@@ -238,11 +233,11 @@ class AnonymousObjectTransformer(
|
||||
}
|
||||
|
||||
private fun inlineMethodAndUpdateGlobalResult(
|
||||
parentRemapper: FieldRemapper,
|
||||
deferringVisitor: MethodVisitor,
|
||||
next: MethodNode,
|
||||
allCapturedParamBuilder: ParametersBuilder,
|
||||
isConstructor: Boolean
|
||||
parentRemapper: FieldRemapper,
|
||||
deferringVisitor: MethodVisitor,
|
||||
next: MethodNode,
|
||||
allCapturedParamBuilder: ParametersBuilder,
|
||||
isConstructor: Boolean
|
||||
): InlineResult {
|
||||
val funResult = inlineMethod(parentRemapper, deferringVisitor, next, allCapturedParamBuilder, isConstructor)
|
||||
transformationResult.merge(funResult)
|
||||
@@ -251,33 +246,34 @@ class AnonymousObjectTransformer(
|
||||
}
|
||||
|
||||
private fun inlineMethod(
|
||||
parentRemapper: FieldRemapper,
|
||||
deferringVisitor: MethodVisitor,
|
||||
sourceNode: MethodNode,
|
||||
capturedBuilder: ParametersBuilder,
|
||||
isConstructor: Boolean
|
||||
parentRemapper: FieldRemapper,
|
||||
deferringVisitor: MethodVisitor,
|
||||
sourceNode: MethodNode,
|
||||
capturedBuilder: ParametersBuilder,
|
||||
isConstructor: Boolean
|
||||
): InlineResult {
|
||||
val typeParametersToReify = inliningContext.root.inlineMethodReifier.reifyInstructions(sourceNode)
|
||||
val parameters = if (isConstructor) capturedBuilder.buildParameters() else getMethodParametersWithCaptured(capturedBuilder, sourceNode)
|
||||
val parameters =
|
||||
if (isConstructor) capturedBuilder.buildParameters() else getMethodParametersWithCaptured(capturedBuilder, sourceNode)
|
||||
|
||||
val remapper = RegeneratedLambdaFieldRemapper(
|
||||
oldObjectType.internalName, transformationInfo.newClassName, parameters,
|
||||
transformationInfo.capturedLambdasToInline, parentRemapper, isConstructor
|
||||
oldObjectType.internalName, transformationInfo.newClassName, parameters,
|
||||
transformationInfo.capturedLambdasToInline, parentRemapper, isConstructor
|
||||
)
|
||||
|
||||
val inliner = MethodInliner(
|
||||
sourceNode,
|
||||
parameters,
|
||||
inliningContext.subInline(transformationInfo.nameGenerator),
|
||||
remapper,
|
||||
isSameModule,
|
||||
"Transformer for " + transformationInfo.oldClassName,
|
||||
sourceMapper,
|
||||
InlineCallSiteInfo(
|
||||
transformationInfo.oldClassName,
|
||||
sourceNode.name,
|
||||
if (isConstructor) transformationInfo.newConstructorDescriptor else sourceNode.desc
|
||||
), null
|
||||
sourceNode,
|
||||
parameters,
|
||||
inliningContext.subInline(transformationInfo.nameGenerator),
|
||||
remapper,
|
||||
isSameModule,
|
||||
"Transformer for " + transformationInfo.oldClassName,
|
||||
sourceMapper,
|
||||
InlineCallSiteInfo(
|
||||
transformationInfo.oldClassName,
|
||||
sourceNode.name,
|
||||
if (isConstructor) transformationInfo.newConstructorDescriptor else sourceNode.desc
|
||||
), null
|
||||
)
|
||||
|
||||
val result = inliner.doInline(deferringVisitor, LocalVarRemapper(parameters, 0), false, LabelOwner.NOT_APPLICABLE)
|
||||
@@ -287,11 +283,11 @@ class AnonymousObjectTransformer(
|
||||
}
|
||||
|
||||
private fun generateConstructorAndFields(
|
||||
classBuilder: ClassBuilder,
|
||||
allCapturedBuilder: ParametersBuilder,
|
||||
constructorInlineBuilder: ParametersBuilder,
|
||||
parentRemapper: FieldRemapper,
|
||||
constructorAdditionalFakeParams: List<CapturedParamInfo>
|
||||
classBuilder: ClassBuilder,
|
||||
allCapturedBuilder: ParametersBuilder,
|
||||
constructorInlineBuilder: ParametersBuilder,
|
||||
parentRemapper: FieldRemapper,
|
||||
constructorAdditionalFakeParams: List<CapturedParamInfo>
|
||||
) {
|
||||
val descTypes = ArrayList<Type>()
|
||||
|
||||
@@ -319,7 +315,7 @@ class AnonymousObjectTransformer(
|
||||
//TODO for inline method make public class
|
||||
transformationInfo.newConstructorDescriptor = constructorDescriptor
|
||||
val constructorVisitor = classBuilder.newMethod(
|
||||
NO_ORIGIN, constructor!!.access, "<init>", constructorDescriptor, null, ArrayUtil.EMPTY_STRING_ARRAY
|
||||
NO_ORIGIN, constructor!!.access, "<init>", constructorDescriptor, null, ArrayUtil.EMPTY_STRING_ARRAY
|
||||
)
|
||||
|
||||
val newBodyStartLabel = Label()
|
||||
@@ -345,11 +341,11 @@ class AnonymousObjectTransformer(
|
||||
if (fake.lambda != null) {
|
||||
//set remap value to skip this fake (captured with lambda already skipped)
|
||||
val composed = StackValue.field(
|
||||
fake.getType(),
|
||||
oldObjectType,
|
||||
fake.newFieldName,
|
||||
false,
|
||||
StackValue.LOCAL_0
|
||||
fake.getType(),
|
||||
oldObjectType,
|
||||
fake.newFieldName,
|
||||
false,
|
||||
StackValue.LOCAL_0
|
||||
)
|
||||
fake.remapValue = composed
|
||||
}
|
||||
@@ -363,19 +359,19 @@ class AnonymousObjectTransformer(
|
||||
val oldStartLabel = (first as? LabelNode)?.label
|
||||
intermediateMethodNode.accept(object : MethodBodyVisitor(capturedFieldInitializer) {
|
||||
override fun visitLocalVariable(
|
||||
name: String, desc: String, signature: String?, start: Label, end: Label, index: Int
|
||||
name: String, desc: String, signature: String?, start: Label, end: Label, index: Int
|
||||
) {
|
||||
super.visitLocalVariable(
|
||||
name, desc, signature,
|
||||
//patch for jack&jill
|
||||
if (oldStartLabel === start) newBodyStartLabel else start,
|
||||
end, index
|
||||
name, desc, signature,
|
||||
//patch for jack&jill
|
||||
if (oldStartLabel === start) newBodyStartLabel else start,
|
||||
end, index
|
||||
)
|
||||
}
|
||||
})
|
||||
constructorVisitor.visitEnd()
|
||||
AsmUtil.genClosureFields(
|
||||
toNameTypePair(filterSkipped(newFieldsWithSkipped)), classBuilder
|
||||
toNameTypePair(filterSkipped(newFieldsWithSkipped)), classBuilder
|
||||
)
|
||||
}
|
||||
|
||||
@@ -393,24 +389,24 @@ class AnonymousObjectTransformer(
|
||||
|
||||
private fun newMethod(builder: ClassBuilder, original: MethodNode): DeferredMethodVisitor {
|
||||
return DeferredMethodVisitor(
|
||||
MethodNode(
|
||||
original.access, original.name, original.desc, original.signature,
|
||||
ArrayUtil.toStringArray(original.exceptions)
|
||||
)
|
||||
MethodNode(
|
||||
original.access, original.name, original.desc, original.signature,
|
||||
ArrayUtil.toStringArray(original.exceptions)
|
||||
)
|
||||
) {
|
||||
builder.newMethod(
|
||||
NO_ORIGIN, original.access, original.name, original.desc, original.signature,
|
||||
ArrayUtil.toStringArray(original.exceptions)
|
||||
NO_ORIGIN, original.access, original.name, original.desc, original.signature,
|
||||
ArrayUtil.toStringArray(original.exceptions)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun extractParametersMappingAndPatchConstructor(
|
||||
constructor: MethodNode,
|
||||
capturedParamBuilder: ParametersBuilder,
|
||||
constructorParamBuilder: ParametersBuilder,
|
||||
transformationInfo: AnonymousObjectTransformationInfo,
|
||||
parentFieldRemapper: FieldRemapper
|
||||
constructor: MethodNode,
|
||||
capturedParamBuilder: ParametersBuilder,
|
||||
constructorParamBuilder: ParametersBuilder,
|
||||
transformationInfo: AnonymousObjectTransformationInfo,
|
||||
parentFieldRemapper: FieldRemapper
|
||||
): List<CapturedParamInfo> {
|
||||
val capturedLambdas = LinkedHashSet<LambdaInfo>() //captured var of inlined parameter
|
||||
val constructorAdditionalFakeParams = ArrayList<CapturedParamInfo>()
|
||||
@@ -420,31 +416,30 @@ class AnonymousObjectTransformer(
|
||||
//load captured parameters and patch instruction list
|
||||
// NB: there is also could be object fields
|
||||
val toDelete = arrayListOf<AbstractInsnNode>()
|
||||
constructor.findCapturedFieldAssignmentInstructions().
|
||||
forEach { fieldNode ->
|
||||
val fieldName = fieldNode.name
|
||||
val parameterAload = fieldNode.previous as VarInsnNode
|
||||
val varIndex = parameterAload.`var`
|
||||
val lambdaInfo = indexToLambda[varIndex]
|
||||
val newFieldName = if (isThis0(fieldName) && shouldRenameThis0(parentFieldRemapper, indexToLambda.values))
|
||||
getNewFieldName(fieldName, true)
|
||||
else
|
||||
fieldName
|
||||
val info = capturedParamBuilder.addCapturedParam(
|
||||
Type.getObjectType(transformationInfo.oldClassName), fieldName, newFieldName,
|
||||
Type.getType(fieldNode.desc), lambdaInfo != null, null
|
||||
)
|
||||
if (lambdaInfo != null) {
|
||||
info.lambda = lambdaInfo
|
||||
capturedLambdas.add(lambdaInfo)
|
||||
}
|
||||
constructorAdditionalFakeParams.add(info)
|
||||
capturedParams.add(varIndex)
|
||||
constructor.findCapturedFieldAssignmentInstructions().forEach { fieldNode ->
|
||||
val fieldName = fieldNode.name
|
||||
val parameterAload = fieldNode.previous as VarInsnNode
|
||||
val varIndex = parameterAload.`var`
|
||||
val lambdaInfo = indexToLambda[varIndex]
|
||||
val newFieldName = if (isThis0(fieldName) && shouldRenameThis0(parentFieldRemapper, indexToLambda.values))
|
||||
getNewFieldName(fieldName, true)
|
||||
else
|
||||
fieldName
|
||||
val info = capturedParamBuilder.addCapturedParam(
|
||||
Type.getObjectType(transformationInfo.oldClassName), fieldName, newFieldName,
|
||||
Type.getType(fieldNode.desc), lambdaInfo != null, null
|
||||
)
|
||||
if (lambdaInfo != null) {
|
||||
info.lambda = lambdaInfo
|
||||
capturedLambdas.add(lambdaInfo)
|
||||
}
|
||||
constructorAdditionalFakeParams.add(info)
|
||||
capturedParams.add(varIndex)
|
||||
|
||||
toDelete.add(parameterAload.previous)
|
||||
toDelete.add(parameterAload)
|
||||
toDelete.add(fieldNode)
|
||||
}
|
||||
toDelete.add(parameterAload.previous)
|
||||
toDelete.add(parameterAload)
|
||||
toDelete.add(fieldNode)
|
||||
}
|
||||
constructor.remove(toDelete)
|
||||
|
||||
constructorParamBuilder.addThis(oldObjectType, false)
|
||||
@@ -456,8 +451,7 @@ class AnonymousObjectTransformer(
|
||||
parameterInfo.lambda = info
|
||||
if (capturedParams.contains(parameterInfo.index)) {
|
||||
parameterInfo.isCaptured = true
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
//otherwise it's super constructor parameter
|
||||
}
|
||||
}
|
||||
@@ -466,7 +460,8 @@ class AnonymousObjectTransformer(
|
||||
//TODO: some of such parameters could be skipped - we should perform additional analysis
|
||||
val capturedLambdasToInline = HashMap<String, LambdaInfo>() //captured var of inlined parameter
|
||||
val allRecapturedParameters = ArrayList<CapturedParamDesc>()
|
||||
val addCapturedNotAddOuter = parentFieldRemapper.isRoot || parentFieldRemapper is InlinedLambdaRemapper && parentFieldRemapper.parent!!.isRoot
|
||||
val addCapturedNotAddOuter =
|
||||
parentFieldRemapper.isRoot || parentFieldRemapper is InlinedLambdaRemapper && parentFieldRemapper.parent!!.isRoot
|
||||
val alreadyAdded = HashMap<String, CapturedParamInfo>()
|
||||
for (info in capturedLambdas) {
|
||||
if (addCapturedNotAddOuter) {
|
||||
@@ -475,16 +470,16 @@ class AnonymousObjectTransformer(
|
||||
val alreadyAddedParam = alreadyAdded[key]
|
||||
|
||||
val recapturedParamInfo = capturedParamBuilder.addCapturedParam(
|
||||
desc,
|
||||
alreadyAddedParam?.newFieldName ?: getNewFieldName(desc.fieldName, false),
|
||||
alreadyAddedParam != null
|
||||
desc,
|
||||
alreadyAddedParam?.newFieldName ?: getNewFieldName(desc.fieldName, false),
|
||||
alreadyAddedParam != null
|
||||
)
|
||||
val composed = StackValue.field(
|
||||
desc.type,
|
||||
oldObjectType, /*TODO owner type*/
|
||||
recapturedParamInfo.newFieldName,
|
||||
false,
|
||||
StackValue.LOCAL_0
|
||||
desc.type,
|
||||
oldObjectType, /*TODO owner type*/
|
||||
recapturedParamInfo.newFieldName,
|
||||
false,
|
||||
StackValue.LOCAL_0
|
||||
)
|
||||
recapturedParamInfo.remapValue = composed
|
||||
allRecapturedParameters.add(desc)
|
||||
@@ -501,8 +496,8 @@ class AnonymousObjectTransformer(
|
||||
|
||||
if (parentFieldRemapper is InlinedLambdaRemapper && !capturedLambdas.isEmpty() && !addCapturedNotAddOuter) {
|
||||
//lambda with non InlinedLambdaRemapper already have outer
|
||||
val parent = parentFieldRemapper.parent as? RegeneratedLambdaFieldRemapper ?:
|
||||
throw AssertionError("Expecting RegeneratedLambdaFieldRemapper, but ${parentFieldRemapper.parent}")
|
||||
val parent = parentFieldRemapper.parent as? RegeneratedLambdaFieldRemapper
|
||||
?: throw AssertionError("Expecting RegeneratedLambdaFieldRemapper, but ${parentFieldRemapper.parent}")
|
||||
val ownerType = Type.getObjectType(parent.originalLambdaInternalName)
|
||||
val desc = CapturedParamDesc(ownerType, AsmUtil.THIS, ownerType)
|
||||
val recapturedParamInfo = capturedParamBuilder.addCapturedParam(desc, AsmUtil.CAPTURED_THIS_FIELD/*outer lambda/object*/, false)
|
||||
@@ -521,17 +516,15 @@ class AnonymousObjectTransformer(
|
||||
|
||||
private fun shouldRenameThis0(parentFieldRemapper: FieldRemapper, values: Collection<LambdaInfo>): Boolean {
|
||||
return if (isFirstDeclSiteLambdaFieldRemapper(parentFieldRemapper)) {
|
||||
values.any { it.capturedVars.any { isThis0(it.fieldName) }}
|
||||
}
|
||||
else false
|
||||
values.any { it.capturedVars.any { isThis0(it.fieldName) } }
|
||||
} else false
|
||||
}
|
||||
|
||||
private fun getNewFieldName(oldName: String, originalField: Boolean): String {
|
||||
if (AsmUtil.CAPTURED_THIS_FIELD == oldName) {
|
||||
return if (!originalField) {
|
||||
oldName
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
//rename original 'this$0' in declaration site lambda (inside inline function) to use this$0 only for outer lambda/object access on call site
|
||||
addUniqueField(oldName + INLINE_FUN_THIS_0_SUFFIX)
|
||||
}
|
||||
@@ -548,5 +541,5 @@ class AnonymousObjectTransformer(
|
||||
}
|
||||
|
||||
private fun isFirstDeclSiteLambdaFieldRemapper(parentRemapper: FieldRemapper): Boolean =
|
||||
parentRemapper !is RegeneratedLambdaFieldRemapper && parentRemapper !is InlinedLambdaRemapper
|
||||
parentRemapper !is RegeneratedLambdaFieldRemapper && parentRemapper !is InlinedLambdaRemapper
|
||||
}
|
||||
|
||||
+7
-7
@@ -133,8 +133,7 @@ class IntervalMetaInfo<T : SplittableInterval<T>>(private val processor: Coverin
|
||||
val split = interval.split(by, keepStart)
|
||||
if (!keepStart) {
|
||||
remapStartLabel(split.newPart.startLabel, split.patchedPart)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
remapEndLabel(split.newPart.endLabel, split.patchedPart)
|
||||
}
|
||||
addNewInterval(split.newPart)
|
||||
@@ -149,7 +148,7 @@ class IntervalMetaInfo<T : SplittableInterval<T>>(private val processor: Coverin
|
||||
}
|
||||
|
||||
private fun getInterval(curIns: LabelNode, isOpen: Boolean) =
|
||||
if (isOpen) intervalStarts.get(curIns) else intervalEnds.get(curIns)
|
||||
if (isOpen) intervalStarts.get(curIns) else intervalEnds.get(curIns)
|
||||
}
|
||||
|
||||
fun TryCatchBlockNode.isMeaningless() = SimpleInterval(start, end).isMeaningless()
|
||||
@@ -191,15 +190,16 @@ class LocalVarNodeWrapper(val node: LocalVariableNode) : Interval, SplittableInt
|
||||
val oldEnd = endLabel
|
||||
node.end = splitBy.startLabel
|
||||
Pair(splitBy.endLabel, oldEnd)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
val oldStart = startLabel
|
||||
node.start = splitBy.endLabel
|
||||
Pair(oldStart, splitBy.startLabel)
|
||||
}
|
||||
|
||||
return SplitPair(this, LocalVarNodeWrapper(
|
||||
return SplitPair(
|
||||
this, LocalVarNodeWrapper(
|
||||
LocalVariableNode(node.name, node.desc, node.signature, newPartInterval.first, newPartInterval.second, node.index)
|
||||
))
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@ import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
|
||||
class DeferredMethodVisitor(
|
||||
val intermediate: MethodNode,
|
||||
private val resultNode: () -> MethodVisitor
|
||||
val intermediate: MethodNode,
|
||||
private val resultNode: () -> MethodVisitor
|
||||
) : MethodVisitor(Opcodes.API_VERSION, intermediate) {
|
||||
|
||||
override fun visitEnd() {
|
||||
|
||||
+6
-4
@@ -21,16 +21,18 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
||||
|
||||
internal class FictitiousArrayConstructor(arrayClass: ClassDescriptor) : SimpleFunctionDescriptorImpl(
|
||||
arrayClass.containingDeclaration, null, Annotations.EMPTY, arrayClass.name, CallableMemberDescriptor.Kind.SYNTHESIZED,
|
||||
SourceElement.NO_SOURCE
|
||||
arrayClass.containingDeclaration, null, Annotations.EMPTY, arrayClass.name, CallableMemberDescriptor.Kind.SYNTHESIZED,
|
||||
SourceElement.NO_SOURCE
|
||||
) {
|
||||
companion object Factory {
|
||||
@JvmStatic
|
||||
fun create(arrayConstructor: ConstructorDescriptor): FictitiousArrayConstructor {
|
||||
val arrayClass = arrayConstructor.constructedClass
|
||||
return FictitiousArrayConstructor(arrayClass).apply {
|
||||
this.initialize(null, null, arrayConstructor.typeParameters, arrayConstructor.valueParameters, arrayClass.defaultType,
|
||||
Modality.FINAL, Visibilities.PUBLIC)
|
||||
this.initialize(
|
||||
null, null, arrayConstructor.typeParameters, arrayConstructor.valueParameters, arrayClass.defaultType,
|
||||
Modality.FINAL, Visibilities.PUBLIC
|
||||
)
|
||||
this.isInline = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,9 +24,9 @@ import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
|
||||
open class FieldRemapper(
|
||||
val originalLambdaInternalName: String?,
|
||||
@JvmField val parent: FieldRemapper?,
|
||||
protected val parameters: Parameters
|
||||
val originalLambdaInternalName: String?,
|
||||
@JvmField val parent: FieldRemapper?,
|
||||
protected val parameters: Parameters
|
||||
) {
|
||||
val isRoot = parent == null
|
||||
|
||||
@@ -34,15 +34,15 @@ open class FieldRemapper(
|
||||
|
||||
protected open fun canProcess(fieldOwner: String, fieldName: String, isFolding: Boolean): Boolean {
|
||||
return fieldOwner == originalLambdaInternalName &&
|
||||
//don't process general field of anonymous objects
|
||||
isCapturedFieldName(fieldName)
|
||||
//don't process general field of anonymous objects
|
||||
isCapturedFieldName(fieldName)
|
||||
}
|
||||
|
||||
fun foldFieldAccessChainIfNeeded(capturedFieldAccess: List<AbstractInsnNode>, node: MethodNode): AbstractInsnNode? =
|
||||
if (capturedFieldAccess.size == 1)
|
||||
null //single aload
|
||||
else
|
||||
foldFieldAccessChainIfNeeded(capturedFieldAccess, 1, node)
|
||||
if (capturedFieldAccess.size == 1)
|
||||
null //single aload
|
||||
else
|
||||
foldFieldAccessChainIfNeeded(capturedFieldAccess, 1, node)
|
||||
|
||||
/**constructors could access outer not through
|
||||
* ALOAD 0 //this
|
||||
@@ -51,13 +51,13 @@ open class FieldRemapper(
|
||||
* but directly through constructor parameter
|
||||
* ALOAD X //outer
|
||||
* GETFIELD this$0 //outer of outer
|
||||
*/
|
||||
*/
|
||||
open fun shouldProcessNonAload0FieldAccessChains(): Boolean = false
|
||||
|
||||
private fun foldFieldAccessChainIfNeeded(
|
||||
capturedFieldAccess: List<AbstractInsnNode>,
|
||||
currentInstruction: Int,
|
||||
node: MethodNode
|
||||
capturedFieldAccess: List<AbstractInsnNode>,
|
||||
currentInstruction: Int,
|
||||
node: MethodNode
|
||||
): AbstractInsnNode? {
|
||||
if (currentInstruction < capturedFieldAccess.lastIndex) {
|
||||
//try to fold longest chain first
|
||||
@@ -94,10 +94,10 @@ open class FieldRemapper(
|
||||
get() = originalLambdaInternalName!!
|
||||
|
||||
open fun getFieldForInline(node: FieldInsnNode, prefix: StackValue?): StackValue? =
|
||||
MethodInliner.findCapturedField(node, this).remapValue
|
||||
MethodInliner.findCapturedField(node, this).remapValue
|
||||
|
||||
companion object {
|
||||
fun foldName(fieldName: String) =
|
||||
CAPTURED_FIELD_FOLD_PREFIX + fieldName
|
||||
CAPTURED_FIELD_FOLD_PREFIX + fieldName
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,8 +33,7 @@ inline fun <K, V> SLRUMap<K, V>.getOrPut(key: K, defaultValue: () -> V): V {
|
||||
val answer = defaultValue()
|
||||
put(key, answer)
|
||||
answer
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
value
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,10 +224,10 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
||||
val originalSuspendLambdaDescriptor =
|
||||
parentContext.originalSuspendLambdaDescriptor ?: error("No original lambda descriptor found")
|
||||
codegen.genCoroutineInstanceForSuspendLambda(originalSuspendLambdaDescriptor)
|
||||
?: error("No stack value for coroutine instance of lambda found")
|
||||
?: error("No stack value for coroutine instance of lambda found")
|
||||
} else
|
||||
codegen.getContinuationParameterFromEnclosingSuspendFunctionDescriptor(codegen.context.functionDescriptor)
|
||||
?: error("No stack value for continuation parameter of suspend function")
|
||||
?: error("No stack value for continuation parameter of suspend function")
|
||||
}
|
||||
|
||||
protected fun inlineCall(nodeAndSmap: SMAPAndMethodNode, callDefault: Boolean): InlineResult {
|
||||
@@ -514,10 +514,10 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
||||
|
||||
val resultInCache = state.inlineCache.methodNodeById.getOrPut(methodId) {
|
||||
val result = doCreateMethodNodeFromCompiled(directMember, state, asmMethod)
|
||||
?: if (functionDescriptor.isSuspend)
|
||||
doCreateMethodNodeFromCompiled(directMember, state, jvmSignature.asmMethod)
|
||||
else
|
||||
null
|
||||
?: if (functionDescriptor.isSuspend)
|
||||
doCreateMethodNodeFromCompiled(directMember, state, jvmSignature.asmMethod)
|
||||
else
|
||||
null
|
||||
result ?: throw IllegalStateException("Couldn't obtain compiled function body for $functionDescriptor")
|
||||
}
|
||||
|
||||
@@ -567,7 +567,7 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
||||
|
||||
val bytes = state.inlineCache.classBytes.getOrPut(containerId) {
|
||||
findVirtualFile(state, containerId)?.contentsToByteArray()
|
||||
?: throw IllegalStateException("Couldn't find declaration file for " + containerId)
|
||||
?: throw IllegalStateException("Couldn't find declaration file for " + containerId)
|
||||
}
|
||||
|
||||
val methodNode =
|
||||
|
||||
@@ -21,29 +21,29 @@ import org.jetbrains.kotlin.codegen.StackValue
|
||||
import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode
|
||||
|
||||
class InlinedLambdaRemapper(
|
||||
originalLambdaInternalName: String,
|
||||
parent: FieldRemapper,
|
||||
methodParams: Parameters,
|
||||
private val isDefaultBoundCallableReference: Boolean
|
||||
originalLambdaInternalName: String,
|
||||
parent: FieldRemapper,
|
||||
methodParams: Parameters,
|
||||
private val isDefaultBoundCallableReference: Boolean
|
||||
) : FieldRemapper(originalLambdaInternalName, parent, methodParams) {
|
||||
|
||||
public override fun canProcess(fieldOwner: String, fieldName: String, isFolding: Boolean) =
|
||||
isFolding && (isMyBoundReceiverForDefaultLambda(fieldOwner, fieldName) || super.canProcess(fieldOwner, fieldName, true))
|
||||
isFolding && (isMyBoundReceiverForDefaultLambda(fieldOwner, fieldName) || super.canProcess(fieldOwner, fieldName, true))
|
||||
|
||||
private fun isMyBoundReceiverForDefaultLambda(fieldOwner: String, fieldName: String) =
|
||||
isDefaultBoundCallableReference && fieldName == AsmUtil.BOUND_REFERENCE_RECEIVER && fieldOwner == originalLambdaInternalName
|
||||
isDefaultBoundCallableReference && fieldName == AsmUtil.BOUND_REFERENCE_RECEIVER && fieldOwner == originalLambdaInternalName
|
||||
|
||||
override fun getFieldNameForFolding(insnNode: FieldInsnNode): String =
|
||||
if (isMyBoundReceiverForDefaultLambda(insnNode.owner, insnNode.name)) AsmUtil.RECEIVER_PARAMETER_NAME else insnNode.name
|
||||
if (isMyBoundReceiverForDefaultLambda(insnNode.owner, insnNode.name)) AsmUtil.RECEIVER_PARAMETER_NAME else insnNode.name
|
||||
|
||||
override fun findField(fieldInsnNode: FieldInsnNode, captured: Collection<CapturedParamInfo>) =
|
||||
parent!!.findField(fieldInsnNode, captured)
|
||||
parent!!.findField(fieldInsnNode, captured)
|
||||
|
||||
override val isInsideInliningLambda: Boolean = true
|
||||
|
||||
override fun getFieldForInline(node: FieldInsnNode, prefix: StackValue?) =
|
||||
if (parent!!.isRoot)
|
||||
super.getFieldForInline(node, prefix)
|
||||
else
|
||||
parent.getFieldForInline(node, prefix)
|
||||
if (parent!!.isRoot)
|
||||
super.getFieldForInline(node, prefix)
|
||||
else
|
||||
parent.getFieldForInline(node, prefix)
|
||||
}
|
||||
|
||||
@@ -9,39 +9,39 @@ import org.jetbrains.kotlin.codegen.ClassBuilder
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
|
||||
class RootInliningContext(
|
||||
expressionMap: Map<Int, LambdaInfo>,
|
||||
state: GenerationState,
|
||||
nameGenerator: NameGenerator,
|
||||
val sourceCompilerForInline: SourceCompilerForInline,
|
||||
override val callSiteInfo: InlineCallSiteInfo,
|
||||
val inlineMethodReifier: ReifiedTypeInliner,
|
||||
typeParameterMappings: TypeParameterMappings
|
||||
expressionMap: Map<Int, LambdaInfo>,
|
||||
state: GenerationState,
|
||||
nameGenerator: NameGenerator,
|
||||
val sourceCompilerForInline: SourceCompilerForInline,
|
||||
override val callSiteInfo: InlineCallSiteInfo,
|
||||
val inlineMethodReifier: ReifiedTypeInliner,
|
||||
typeParameterMappings: TypeParameterMappings
|
||||
) : InliningContext(
|
||||
null, expressionMap, state, nameGenerator, TypeRemapper.createRoot(typeParameterMappings), null, false
|
||||
null, expressionMap, state, nameGenerator, TypeRemapper.createRoot(typeParameterMappings), null, false
|
||||
)
|
||||
|
||||
class RegeneratedClassContext(
|
||||
parent: InliningContext,
|
||||
expressionMap: Map<Int, LambdaInfo>,
|
||||
state: GenerationState,
|
||||
nameGenerator: NameGenerator,
|
||||
typeRemapper: TypeRemapper,
|
||||
lambdaInfo: LambdaInfo?,
|
||||
override val callSiteInfo: InlineCallSiteInfo
|
||||
parent: InliningContext,
|
||||
expressionMap: Map<Int, LambdaInfo>,
|
||||
state: GenerationState,
|
||||
nameGenerator: NameGenerator,
|
||||
typeRemapper: TypeRemapper,
|
||||
lambdaInfo: LambdaInfo?,
|
||||
override val callSiteInfo: InlineCallSiteInfo
|
||||
) : InliningContext(
|
||||
parent, expressionMap, state, nameGenerator, typeRemapper, lambdaInfo, true
|
||||
parent, expressionMap, state, nameGenerator, typeRemapper, lambdaInfo, true
|
||||
) {
|
||||
val continuationBuilders: MutableMap<String, ClassBuilder> = hashMapOf()
|
||||
}
|
||||
|
||||
open class InliningContext(
|
||||
val parent: InliningContext?,
|
||||
val expressionMap: Map<Int, LambdaInfo>,
|
||||
val state: GenerationState,
|
||||
val nameGenerator: NameGenerator,
|
||||
val typeRemapper: TypeRemapper,
|
||||
val lambdaInfo: LambdaInfo?,
|
||||
val classRegeneration: Boolean
|
||||
val parent: InliningContext?,
|
||||
val expressionMap: Map<Int, LambdaInfo>,
|
||||
val state: GenerationState,
|
||||
val nameGenerator: NameGenerator,
|
||||
val typeRemapper: TypeRemapper,
|
||||
val lambdaInfo: LambdaInfo?,
|
||||
val classRegeneration: Boolean
|
||||
) {
|
||||
|
||||
val isInliningLambda = lambdaInfo != null
|
||||
@@ -57,45 +57,45 @@ open class InliningContext(
|
||||
|
||||
fun findAnonymousObjectTransformationInfo(internalName: String, searchInParent: Boolean = true): AnonymousObjectTransformationInfo? =
|
||||
internalNameToAnonymousObjectTransformationInfo[internalName]
|
||||
?: if (searchInParent) parent?.findAnonymousObjectTransformationInfo(internalName, searchInParent) else null
|
||||
?: if (searchInParent) parent?.findAnonymousObjectTransformationInfo(internalName, searchInParent) else null
|
||||
|
||||
fun recordIfNotPresent(internalName: String, info: AnonymousObjectTransformationInfo) {
|
||||
internalNameToAnonymousObjectTransformationInfo.putIfAbsent(internalName, info)
|
||||
}
|
||||
|
||||
fun subInlineLambda(lambdaInfo: LambdaInfo): InliningContext =
|
||||
subInline(
|
||||
nameGenerator.subGenerator("lambda"),
|
||||
//mark lambda inlined
|
||||
hashMapOf(lambdaInfo.lambdaClassType.internalName to null),
|
||||
lambdaInfo
|
||||
)
|
||||
subInline(
|
||||
nameGenerator.subGenerator("lambda"),
|
||||
//mark lambda inlined
|
||||
hashMapOf(lambdaInfo.lambdaClassType.internalName to null),
|
||||
lambdaInfo
|
||||
)
|
||||
|
||||
fun subInlineWithClassRegeneration(
|
||||
generator: NameGenerator,
|
||||
newTypeMappings: MutableMap<String, String?>,
|
||||
callSiteInfo: InlineCallSiteInfo
|
||||
generator: NameGenerator,
|
||||
newTypeMappings: MutableMap<String, String?>,
|
||||
callSiteInfo: InlineCallSiteInfo
|
||||
): InliningContext = RegeneratedClassContext(
|
||||
this, expressionMap, state, generator, TypeRemapper.createFrom(typeRemapper, newTypeMappings),
|
||||
lambdaInfo, callSiteInfo
|
||||
this, expressionMap, state, generator, TypeRemapper.createFrom(typeRemapper, newTypeMappings),
|
||||
lambdaInfo, callSiteInfo
|
||||
)
|
||||
|
||||
@JvmOverloads
|
||||
fun subInline(
|
||||
generator: NameGenerator,
|
||||
additionalTypeMappings: Map<String, String?> = emptyMap(),
|
||||
lambdaInfo: LambdaInfo? = this.lambdaInfo
|
||||
generator: NameGenerator,
|
||||
additionalTypeMappings: Map<String, String?> = emptyMap(),
|
||||
lambdaInfo: LambdaInfo? = this.lambdaInfo
|
||||
): InliningContext {
|
||||
val isInliningLambda = lambdaInfo != null
|
||||
return InliningContext(
|
||||
this, expressionMap, state, generator,
|
||||
TypeRemapper.createFrom(
|
||||
typeRemapper,
|
||||
additionalTypeMappings,
|
||||
//root inline lambda
|
||||
isInliningLambda && !this.isInliningLambda
|
||||
),
|
||||
lambdaInfo, classRegeneration
|
||||
this, expressionMap, state, generator,
|
||||
TypeRemapper.createFrom(
|
||||
typeRemapper,
|
||||
additionalTypeMappings,
|
||||
//root inline lambda
|
||||
isInliningLambda && !this.isInliningLambda
|
||||
),
|
||||
lambdaInfo, classRegeneration
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+23
-13
@@ -55,7 +55,6 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor {
|
||||
public boolean isEmpty() {
|
||||
if (!(startIns instanceof LabelNode)) {
|
||||
return false;
|
||||
|
||||
}
|
||||
AbstractInsnNode end = endInsExclusive;
|
||||
while (end != startIns && end instanceof LabelNode) {
|
||||
@@ -78,7 +77,8 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor {
|
||||
}
|
||||
|
||||
if (hasFinallyBlocks(inlineFunTryBlockInfo)) {
|
||||
new InternalFinallyBlockInliner(inlineFun, inlineFunTryBlockInfo, localVars, finallyParamOffset).processInlineFunFinallyBlocks();
|
||||
new InternalFinallyBlockInliner(inlineFun, inlineFunTryBlockInfo, localVars, finallyParamOffset)
|
||||
.processInlineFunFinallyBlocks();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,10 +88,12 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor {
|
||||
|
||||
//lambdaTryCatchBlockNodes is number of TryCatchBlockNodes that was inlined with lambdas into function
|
||||
//due to code generation specific they placed before function TryCatchBlockNodes
|
||||
private InternalFinallyBlockInliner(@NotNull MethodNode inlineFun,
|
||||
private InternalFinallyBlockInliner(
|
||||
@NotNull MethodNode inlineFun,
|
||||
@NotNull List<TryCatchBlockNodeInfo> inlineFunTryBlockInfo,
|
||||
@NotNull List<LocalVarNodeWrapper> localVariableInfo,
|
||||
int finallyParamOffset) {
|
||||
int finallyParamOffset
|
||||
) {
|
||||
super(finallyParamOffset);
|
||||
this.inlineFun = inlineFun;
|
||||
for (TryCatchBlockNodeInfo block : inlineFunTryBlockInfo) {
|
||||
@@ -166,7 +168,8 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor {
|
||||
List<TryCatchBlockNodeInfo> clusterBlocks = clusterToFindFinally.getBlocks();
|
||||
TryCatchBlockNodeInfo nodeWithDefaultHandlerIfExists = clusterBlocks.get(clusterBlocks.size() - 1);
|
||||
|
||||
FinallyBlockInfo finallyInfo = findFinallyBlockBody(nodeWithDefaultHandlerIfExists, getTryBlocksMetaInfo().getAllIntervals());
|
||||
FinallyBlockInfo finallyInfo =
|
||||
findFinallyBlockBody(nodeWithDefaultHandlerIfExists, getTryBlocksMetaInfo().getAllIntervals());
|
||||
if (finallyInfo == null) continue;
|
||||
|
||||
if (nodeWithDefaultHandlerIfExists.getOnlyCopyNotProcess()) {
|
||||
@@ -253,7 +256,8 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor {
|
||||
if (isFinallyMarker(currentIns.getNext())) {
|
||||
Integer constant = getConstant(currentIns);
|
||||
finallyBlockCopy.visitLdcInsn(constant + depthShift);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
currentIns.accept(finallyBlockCopy); //VISIT
|
||||
}
|
||||
}
|
||||
@@ -286,7 +290,9 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor {
|
||||
@NotNull
|
||||
private static Set<LabelNode> rememberOriginalLabelNodes(@NotNull FinallyBlockInfo finallyInfo) {
|
||||
Set<LabelNode> labelsInsideFinally = new HashSet<>();
|
||||
for (AbstractInsnNode currentIns = finallyInfo.startIns; currentIns != finallyInfo.endInsExclusive; currentIns = currentIns.getNext()) {
|
||||
for (AbstractInsnNode currentIns = finallyInfo.startIns;
|
||||
currentIns != finallyInfo.endInsExclusive;
|
||||
currentIns = currentIns.getNext()) {
|
||||
if (currentIns instanceof LabelNode) {
|
||||
labelsInsideFinally.add((LabelNode) currentIns);
|
||||
}
|
||||
@@ -326,7 +332,8 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor {
|
||||
tryCatchBlockNode.type);
|
||||
|
||||
|
||||
assert inlineFun.instructions.indexOf(additionalTryCatchBlock.start) <= inlineFun.instructions.indexOf(additionalTryCatchBlock.end);
|
||||
assert inlineFun.instructions.indexOf(additionalTryCatchBlock.start) <=
|
||||
inlineFun.instructions.indexOf(additionalTryCatchBlock.end);
|
||||
|
||||
tryBlocksMetaInfo.addNewInterval(new TryCatchBlockNodeInfo(additionalTryCatchBlock, true));
|
||||
}
|
||||
@@ -350,7 +357,10 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor {
|
||||
TryCatchBlockNodeInfo startNode = startBlockPositions.next().getNodeInfo();
|
||||
TryCatchBlockNodeInfo endNode = endBlockPosition.getNodeInfo();
|
||||
|
||||
assert Objects.equal(startNode.getType(), endNode.getType()) : "Different handler types : " + startNode.getType() + " " + endNode.getType();
|
||||
assert Objects.equal(startNode.getType(), endNode.getType()) : "Different handler types : " +
|
||||
startNode.getType() +
|
||||
" " +
|
||||
endNode.getType();
|
||||
|
||||
getTryBlocksMetaInfo()
|
||||
.split(endNode, new SimpleInterval((LabelNode) endNode.getNode().end.getLabel().info,
|
||||
@@ -427,9 +437,10 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor {
|
||||
}
|
||||
|
||||
if (afterStartBlock) {
|
||||
if (block.getNode().type == null && (firstLabelInChain(tryCatchBlock.getNode().start) == firstLabelInChain(block.getNode().start) &&
|
||||
firstLabelInChain(tryCatchBlock.getNode().end) == firstLabelInChain(block.getNode().end)
|
||||
|| defaultHandler == firstLabelInChain(block.getNode().handler))) {
|
||||
if (block.getNode().type == null &&
|
||||
(firstLabelInChain(tryCatchBlock.getNode().start) == firstLabelInChain(block.getNode().start) &&
|
||||
firstLabelInChain(tryCatchBlock.getNode().end) == firstLabelInChain(block.getNode().end)
|
||||
|| defaultHandler == firstLabelInChain(block.getNode().handler))) {
|
||||
sameDefaultHandler.add(block); //first is tryCatchBlock if no catch clauses
|
||||
if (defaultHandler == null) {
|
||||
defaultHandler = firstLabelInChain(block.getNode().handler);
|
||||
@@ -545,5 +556,4 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor {
|
||||
String text = getNodeText(inlineFun);
|
||||
System.out.println(text);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ abstract class LambdaInfo(@JvmField val isCrossInline: Boolean) : LabelOwner {
|
||||
|
||||
for (info in capturedVars) {
|
||||
val field = remapper.findField(FieldInsnNode(0, info.containingLambdaName, info.fieldName, ""))
|
||||
?: error("Captured field not found: " + info.containingLambdaName + "." + info.fieldName)
|
||||
?: error("Captured field not found: " + info.containingLambdaName + "." + info.fieldName)
|
||||
builder.addCapturedParam(field, info.fieldName)
|
||||
}
|
||||
|
||||
@@ -124,13 +124,13 @@ class DefaultLambda(
|
||||
}, ClassReader.SKIP_CODE or ClassReader.SKIP_FRAMES or ClassReader.SKIP_DEBUG)
|
||||
|
||||
invokeMethodDescriptor =
|
||||
parameterDescriptor.type.memberScope
|
||||
.getContributedFunctions(OperatorNameConventions.INVOKE, NoLookupLocation.FROM_BACKEND)
|
||||
.single()
|
||||
.let {
|
||||
//property reference generates erased 'get' method
|
||||
if (isPropertyReference) it.original else it
|
||||
}
|
||||
parameterDescriptor.type.memberScope
|
||||
.getContributedFunctions(OperatorNameConventions.INVOKE, NoLookupLocation.FROM_BACKEND)
|
||||
.single()
|
||||
.let {
|
||||
//property reference generates erased 'get' method
|
||||
if (isPropertyReference) it.original else it
|
||||
}
|
||||
|
||||
val descriptor = Type.getMethodDescriptor(Type.VOID_TYPE, *capturedArgs)
|
||||
val constructor = getMethodNode(
|
||||
@@ -145,15 +145,15 @@ class DefaultLambda(
|
||||
}
|
||||
|
||||
capturedVars =
|
||||
if (isFunctionReference || isPropertyReference)
|
||||
constructor?.desc?.let { Type.getArgumentTypes(it) }?.singleOrNull()?.let {
|
||||
originalBoundReceiverType = it
|
||||
listOf(capturedParamDesc(AsmUtil.RECEIVER_PARAMETER_NAME, it.boxReceiverForBoundReference()))
|
||||
} ?: emptyList()
|
||||
else
|
||||
constructor?.findCapturedFieldAssignmentInstructions()?.map { fieldNode ->
|
||||
capturedParamDesc(fieldNode.name, Type.getType(fieldNode.desc))
|
||||
}?.toList() ?: emptyList()
|
||||
if (isFunctionReference || isPropertyReference)
|
||||
constructor?.desc?.let { Type.getArgumentTypes(it) }?.singleOrNull()?.let {
|
||||
originalBoundReceiverType = it
|
||||
listOf(capturedParamDesc(AsmUtil.RECEIVER_PARAMETER_NAME, it.boxReceiverForBoundReference()))
|
||||
} ?: emptyList()
|
||||
else
|
||||
constructor?.findCapturedFieldAssignmentInstructions()?.map { fieldNode ->
|
||||
capturedParamDesc(fieldNode.name, Type.getType(fieldNode.desc))
|
||||
}?.toList() ?: emptyList()
|
||||
|
||||
isBoundCallableReference = (isFunctionReference || isPropertyReference) && capturedVars.isNotEmpty()
|
||||
|
||||
@@ -234,7 +234,7 @@ class PsiExpressionLambda(
|
||||
if (function == null && expression is KtCallableReferenceExpression) {
|
||||
val variableDescriptor =
|
||||
bindingContext.get(BindingContext.VARIABLE, functionWithBodyOrCallableReference) as? VariableDescriptorWithAccessors
|
||||
?: throw AssertionError("""Reference expression not resolved to variable descriptor with accessors: ${expression.getText()}""")
|
||||
?: throw AssertionError("""Reference expression not resolved to variable descriptor with accessors: ${expression.getText()}""")
|
||||
classDescriptor = CodegenBinding.anonymousClassForCallable(bindingContext, variableDescriptor)
|
||||
lambdaClassType = typeMapper.mapClass(classDescriptor)
|
||||
val getFunction = PropertyReferenceCodegen.findGetFunction(variableDescriptor)
|
||||
|
||||
@@ -28,7 +28,7 @@ import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
// before/after suspension point marks, so we detect those functions here and insert the corresponding marks
|
||||
|
||||
fun insertLegacySuspendInlineMarks(node: MethodNode) {
|
||||
with (node.instructions) {
|
||||
with(node.instructions) {
|
||||
// look for return instruction before the end and insert "afterSuspendMarker" there
|
||||
insertBefore(findLastReturn(last) ?: return, produceSuspendMarker(false).instructions)
|
||||
// insert "beforeSuspendMarker" at the beginning
|
||||
|
||||
@@ -36,8 +36,7 @@ class LocalVarRemapper(private val params: Parameters, private val additionalShi
|
||||
if (!info.isSkippedOrRemapped) {
|
||||
remapValues[shift] = StackValue.local(realSize, AsmTypes.OBJECT_TYPE)
|
||||
realSize += info.getType().size
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
remapValues[shift] = if (info.isRemapped) info.remapValue else null
|
||||
if (CapturedParamInfo.isSynthetic(info)) {
|
||||
realSize += info.getType().size
|
||||
@@ -59,12 +58,10 @@ class LocalVarRemapper(private val params: Parameters, private val additionalShi
|
||||
}
|
||||
if (info.isRemapped) {
|
||||
return RemapInfo(info, remapped, REMAPPED)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
remappedIndex = (remapped as StackValue.Local).index
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
//captured params are not used directly in this inlined method, they are used in closure
|
||||
//except captured ones for default lambdas, they are generated in default body
|
||||
remappedIndex = actualParamsSize - params.argsSizeOnStack + index
|
||||
@@ -115,8 +112,7 @@ class LocalVarRemapper(private val params: Parameters, private val additionalShi
|
||||
if (remapInfo.parameterInfo != null && !isStore) {
|
||||
StackValue.coerce(value.type, remapInfo.parameterInfo.type, mv)
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
assert(remapInfo.parameterInfo != null) { "Non local value should have parameter info" }
|
||||
value!!.put(remapInfo.parameterInfo!!.type, mv)
|
||||
}
|
||||
@@ -129,8 +125,8 @@ class LocalVarRemapper(private val params: Parameters, private val additionalShi
|
||||
}
|
||||
|
||||
class RemapInfo(
|
||||
@JvmField val parameterInfo: ParameterInfo?,
|
||||
@JvmField val value: StackValue? = null,
|
||||
@JvmField val status: RemapStatus = FAIL
|
||||
@JvmField val parameterInfo: ParameterInfo?,
|
||||
@JvmField val value: StackValue? = null,
|
||||
@JvmField val status: RemapStatus = FAIL
|
||||
)
|
||||
}
|
||||
|
||||
@@ -86,5 +86,4 @@ public class MaxLocalsCalculator extends MethodVisitor {
|
||||
maxLocals = nextFreeSlotNumber;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-1
@@ -61,6 +61,7 @@ import java.util.*;
|
||||
*/
|
||||
public class MaxStackFrameSizeAndLocalsCalculator extends MaxLocalsCalculator {
|
||||
private static final int[] FRAME_SIZE_CHANGE_BY_OPCODE;
|
||||
|
||||
static {
|
||||
// copy-pasted from org.jetbrains.org.objectweb.asm.Frame
|
||||
int i;
|
||||
@@ -375,7 +376,7 @@ public class MaxStackFrameSizeAndLocalsCalculator extends MaxLocalsCalculator {
|
||||
@NotNull Label handler, String type
|
||||
) {
|
||||
ExceptionHandler exceptionHandler = new ExceptionHandler(
|
||||
getLabelWrapper(start), getLabelWrapper(end), getLabelWrapper(handler)
|
||||
getLabelWrapper(start), getLabelWrapper(end), getLabelWrapper(handler)
|
||||
);
|
||||
|
||||
exceptionHandlers.add(exceptionHandler);
|
||||
@@ -418,6 +419,7 @@ public class MaxStackFrameSizeAndLocalsCalculator extends MaxLocalsCalculator {
|
||||
|
||||
private int outputStackMax = 0;
|
||||
private int inputStackSize = 0;
|
||||
|
||||
public LabelWrapper(Label label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
@@ -45,16 +45,16 @@ import org.jetbrains.org.objectweb.asm.util.Printer
|
||||
import java.util.*
|
||||
|
||||
class MethodInliner(
|
||||
private val node: MethodNode,
|
||||
private val parameters: Parameters,
|
||||
private val inliningContext: InliningContext,
|
||||
private val nodeRemapper: FieldRemapper,
|
||||
private val isSameModule: Boolean,
|
||||
private val errorPrefix: String,
|
||||
private val sourceMapper: SourceMapper,
|
||||
private val inlineCallSiteInfo: InlineCallSiteInfo,
|
||||
private val inlineOnlySmapSkipper: InlineOnlySmapSkipper?, //non null only for root
|
||||
private val shouldPreprocessApiVersionCalls: Boolean = false
|
||||
private val node: MethodNode,
|
||||
private val parameters: Parameters,
|
||||
private val inliningContext: InliningContext,
|
||||
private val nodeRemapper: FieldRemapper,
|
||||
private val isSameModule: Boolean,
|
||||
private val errorPrefix: String,
|
||||
private val sourceMapper: SourceMapper,
|
||||
private val inlineCallSiteInfo: InlineCallSiteInfo,
|
||||
private val inlineOnlySmapSkipper: InlineOnlySmapSkipper?, //non null only for root
|
||||
private val shouldPreprocessApiVersionCalls: Boolean = false
|
||||
) {
|
||||
private val typeMapper = inliningContext.state.typeMapper
|
||||
private val languageVersionSettings = inliningContext.state.languageVersionSettings
|
||||
@@ -67,10 +67,10 @@ class MethodInliner(
|
||||
private var lambdasFinallyBlocks: Int = 0
|
||||
|
||||
fun doInline(
|
||||
adapter: MethodVisitor,
|
||||
remapper: LocalVarRemapper,
|
||||
remapReturn: Boolean,
|
||||
labelOwner: LabelOwner
|
||||
adapter: MethodVisitor,
|
||||
remapper: LocalVarRemapper,
|
||||
remapReturn: Boolean,
|
||||
labelOwner: LabelOwner
|
||||
): InlineResult {
|
||||
return doInline(adapter, remapper, remapReturn, labelOwner, 0)
|
||||
}
|
||||
@@ -83,11 +83,11 @@ class MethodInliner(
|
||||
}
|
||||
|
||||
private fun doInline(
|
||||
adapter: MethodVisitor,
|
||||
remapper: LocalVarRemapper,
|
||||
remapReturn: Boolean,
|
||||
labelOwner: LabelOwner,
|
||||
finallyDeepShift: Int
|
||||
adapter: MethodVisitor,
|
||||
remapper: LocalVarRemapper,
|
||||
remapReturn: Boolean,
|
||||
labelOwner: LabelOwner,
|
||||
finallyDeepShift: Int
|
||||
): InlineResult {
|
||||
//analyze body
|
||||
var transformedNode = markPlacesForInlineAndRemoveInlinable(node, labelOwner, finallyDeepShift)
|
||||
@@ -120,8 +120,7 @@ class MethodInliner(
|
||||
visitor
|
||||
} else MethodBodyVisitor(visitor)
|
||||
)
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
} catch (e: Throwable) {
|
||||
throw wrapException(e, transformedNode, "couldn't inline method call")
|
||||
}
|
||||
|
||||
@@ -130,7 +129,7 @@ class MethodInliner(
|
||||
if (inliningContext.isRoot) {
|
||||
val remapValue = remapper.remap(parameters.argsSizeOnStack + 1).value
|
||||
InternalFinallyBlockInliner.processInlineFunFinallyBlocks(
|
||||
resultNode, lambdasFinallyBlocks, (remapValue as StackValue.Local).index
|
||||
resultNode, lambdasFinallyBlocks, (remapValue as StackValue.Local).index
|
||||
)
|
||||
}
|
||||
|
||||
@@ -176,9 +175,9 @@ class MethodInliner(
|
||||
remapper.addMapping(oldClassName, newClassName)
|
||||
|
||||
val childInliningContext = inliningContext.subInlineWithClassRegeneration(
|
||||
inliningContext.nameGenerator,
|
||||
currentTypeMapping,
|
||||
inlineCallSiteInfo
|
||||
inliningContext.nameGenerator,
|
||||
currentTypeMapping,
|
||||
inlineCallSiteInfo
|
||||
)
|
||||
val transformer = transformationInfo!!.createTransformer(
|
||||
childInliningContext,
|
||||
@@ -203,8 +202,7 @@ class MethodInliner(
|
||||
ReifiedTypeInliner.putNeedClassReificationMarker(mv)
|
||||
result.reifiedTypeParametersUsages.mergeAll(transformResult.reifiedTypeParametersUsages)
|
||||
}
|
||||
}
|
||||
else if (!transformationInfo!!.wasAlreadyRegenerated) {
|
||||
} else if (!transformationInfo!!.wasAlreadyRegenerated) {
|
||||
result.addNotChangedClass(oldClassName)
|
||||
}
|
||||
}
|
||||
@@ -278,27 +276,26 @@ class MethodInliner(
|
||||
val lambdaParameters = info.addAllParameters(nodeRemapper)
|
||||
|
||||
val newCapturedRemapper = InlinedLambdaRemapper(
|
||||
info.lambdaClassType.internalName, nodeRemapper, lambdaParameters,
|
||||
info is DefaultLambda && info.isBoundCallableReference
|
||||
info.lambdaClassType.internalName, nodeRemapper, lambdaParameters,
|
||||
info is DefaultLambda && info.isBoundCallableReference
|
||||
)
|
||||
|
||||
setLambdaInlining(true)
|
||||
val lambdaSMAP = info.node.classSMAP
|
||||
|
||||
val childSourceMapper =
|
||||
if (inliningContext.classRegeneration && !inliningContext.isInliningLambda)
|
||||
NestedSourceMapper(sourceMapper, lambdaSMAP.intervals, lambdaSMAP.sourceInfo)
|
||||
else if (info is DefaultLambda) {
|
||||
NestedSourceMapper(sourceMapper.parent!!, lambdaSMAP.intervals, lambdaSMAP.sourceInfo)
|
||||
}
|
||||
else InlineLambdaSourceMapper(sourceMapper.parent!!, info.node)
|
||||
if (inliningContext.classRegeneration && !inliningContext.isInliningLambda)
|
||||
NestedSourceMapper(sourceMapper, lambdaSMAP.intervals, lambdaSMAP.sourceInfo)
|
||||
else if (info is DefaultLambda) {
|
||||
NestedSourceMapper(sourceMapper.parent!!, lambdaSMAP.intervals, lambdaSMAP.sourceInfo)
|
||||
} else InlineLambdaSourceMapper(sourceMapper.parent!!, info.node)
|
||||
|
||||
val inliner = MethodInliner(
|
||||
info.node.node, lambdaParameters, inliningContext.subInlineLambda(info),
|
||||
newCapturedRemapper,
|
||||
if (info is DefaultLambda) isSameModule else true /*cause all nested objects in same module as lambda*/,
|
||||
"Lambda inlining " + info.lambdaClassType.internalName,
|
||||
childSourceMapper, inlineCallSiteInfo, null
|
||||
info.node.node, lambdaParameters, inliningContext.subInlineLambda(info),
|
||||
newCapturedRemapper,
|
||||
if (info is DefaultLambda) isSameModule else true /*cause all nested objects in same module as lambda*/,
|
||||
"Lambda inlining " + info.lambdaClassType.internalName,
|
||||
childSourceMapper, inlineCallSiteInfo, null
|
||||
)
|
||||
|
||||
val varRemapper = LocalVarRemapper(lambdaParameters, valueParamShift)
|
||||
@@ -315,8 +312,7 @@ class MethodInliner(
|
||||
addInlineMarker(this, false)
|
||||
childSourceMapper.endMapping()
|
||||
inlineOnlySmapSkipper?.markCallSiteLineNumber(remappingMethodAdapter)
|
||||
}
|
||||
else if (isAnonymousConstructorCall(owner, name)) { //TODO add method
|
||||
} else if (isAnonymousConstructorCall(owner, name)) { //TODO add method
|
||||
//TODO add proper message
|
||||
assert(transformationInfo is AnonymousObjectTransformationInfo) {
|
||||
"<init> call doesn't correspond to object transformation info for '$owner.$name': $transformationInfo"
|
||||
@@ -366,16 +362,14 @@ class MethodInliner(
|
||||
}
|
||||
|
||||
transformationInfo = null
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
super.visitMethodInsn(opcode, owner, name, desc, itf)
|
||||
}
|
||||
}
|
||||
else if ((!inliningContext.isInliningLambda || isDefaultLambdaWithReification(inliningContext.lambdaInfo!!)) &&
|
||||
ReifiedTypeInliner.isNeedClassReificationMarker(MethodInsnNode(opcode, owner, name, desc, false))) {
|
||||
} else if ((!inliningContext.isInliningLambda || isDefaultLambdaWithReification(inliningContext.lambdaInfo!!)) &&
|
||||
ReifiedTypeInliner.isNeedClassReificationMarker(MethodInsnNode(opcode, owner, name, desc, false))
|
||||
) {
|
||||
//we shouldn't process here content of inlining lambda it should be reified at external level except default lambdas
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
super.visitMethodInsn(opcode, owner, name, desc, itf)
|
||||
}
|
||||
}
|
||||
@@ -399,7 +393,7 @@ class MethodInliner(
|
||||
}
|
||||
|
||||
private fun isDefaultLambdaWithReification(lambdaInfo: LambdaInfo) =
|
||||
lambdaInfo is DefaultLambda && lambdaInfo.needReification
|
||||
lambdaInfo is DefaultLambda && lambdaInfo.needReification
|
||||
|
||||
private fun prepareNode(node: MethodNode, finallyDeepShift: Int): MethodNode {
|
||||
node.instructions.resetLabels()
|
||||
@@ -457,24 +451,25 @@ class MethodInliner(
|
||||
if (DEFAULT_LAMBDA_FAKE_CALL == owner) {
|
||||
val index = name.substringAfter(DEFAULT_LAMBDA_FAKE_CALL).toInt()
|
||||
val lambda = getLambdaIfExists(index) as DefaultLambda
|
||||
lambda.parameterOffsetsInDefault.zip(lambda.capturedVars).asReversed().forEach {
|
||||
(_, captured) ->
|
||||
lambda.parameterOffsetsInDefault.zip(lambda.capturedVars).asReversed().forEach { (_, captured) ->
|
||||
val originalBoundReceiverType = lambda.originalBoundReceiverType
|
||||
if (lambda.isBoundCallableReference && AsmUtil.isPrimitive(originalBoundReceiverType)) {
|
||||
StackValue.onStack(originalBoundReceiverType!!).put(captured.type, InstructionAdapter(this))
|
||||
}
|
||||
super.visitFieldInsn(
|
||||
Opcodes.PUTSTATIC, captured.containingLambdaName, CAPTURED_FIELD_FOLD_PREFIX + captured.fieldName, captured.type.descriptor
|
||||
Opcodes.PUTSTATIC,
|
||||
captured.containingLambdaName,
|
||||
CAPTURED_FIELD_FOLD_PREFIX + captured.fieldName,
|
||||
captured.type.descriptor
|
||||
)
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
super.visitMethodInsn(opcode, owner, name, desc, itf)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitLocalVariable(
|
||||
name: String, desc: String, signature: String?, start: Label, end: Label, index: Int
|
||||
name: String, desc: String, signature: String?, start: Label, end: Label, index: Int
|
||||
) {
|
||||
if (isInliningLambda || GENERATE_DEBUG_INFO) {
|
||||
val varSuffix = if (inliningContext.isRoot && !isFakeLocalVariableForInline(name)) INLINE_FUN_VAR_SUFFIX else ""
|
||||
@@ -493,7 +488,7 @@ class MethodInliner(
|
||||
}
|
||||
|
||||
private fun markPlacesForInlineAndRemoveInlinable(
|
||||
node: MethodNode, labelOwner: LabelOwner, finallyDeepShift: Int
|
||||
node: MethodNode, labelOwner: LabelOwner, finallyDeepShift: Int
|
||||
): MethodNode {
|
||||
val processingNode = prepareNode(node, finallyDeepShift)
|
||||
|
||||
@@ -532,23 +527,21 @@ class MethodInliner(
|
||||
val sourceValue = frame.getStack(firstParameterIndex)
|
||||
val lambdaInfo = getLambdaIfExistsAndMarkInstructions(sourceValue, true, instructions, sources, toDelete)
|
||||
invokeCalls.add(InvokeCall(lambdaInfo, currentFinallyDeep))
|
||||
}
|
||||
else if (isSamWrapperConstructorCall(owner, name)) {
|
||||
} else if (isSamWrapperConstructorCall(owner, name)) {
|
||||
recordTransformation(SamWrapperTransformationInfo(owner, inliningContext, isAlreadyRegenerated(owner)))
|
||||
}
|
||||
else if (isAnonymousConstructorCall(owner, name)) {
|
||||
} else if (isAnonymousConstructorCall(owner, name)) {
|
||||
val lambdaMapping = HashMap<Int, LambdaInfo>()
|
||||
|
||||
var offset = 0
|
||||
var capturesAnonymousObjectThatMustBeRegenerated = false
|
||||
for (i in 0 until paramCount) {
|
||||
val sourceValue = frame.getStack(firstParameterIndex + i)
|
||||
val lambdaInfo = getLambdaIfExistsAndMarkInstructions(sourceValue, false, instructions, sources, toDelete
|
||||
val lambdaInfo = getLambdaIfExistsAndMarkInstructions(
|
||||
sourceValue, false, instructions, sources, toDelete
|
||||
)
|
||||
if (lambdaInfo != null) {
|
||||
lambdaMapping.put(offset, lambdaInfo)
|
||||
}
|
||||
else if (i < argTypes.size && isAnonymousClassThatMustBeRegenerated(argTypes[i])) {
|
||||
} else if (i < argTypes.size && isAnonymousClassThatMustBeRegenerated(argTypes[i])) {
|
||||
capturesAnonymousObjectThatMustBeRegenerated = true
|
||||
}
|
||||
|
||||
@@ -556,13 +549,12 @@ class MethodInliner(
|
||||
}
|
||||
|
||||
recordTransformation(
|
||||
buildConstructorInvocation(
|
||||
owner, cur.desc, lambdaMapping, awaitClassReification, capturesAnonymousObjectThatMustBeRegenerated
|
||||
)
|
||||
buildConstructorInvocation(
|
||||
owner, cur.desc, lambdaMapping, awaitClassReification, capturesAnonymousObjectThatMustBeRegenerated
|
||||
)
|
||||
)
|
||||
awaitClassReification = false
|
||||
}
|
||||
else if (inliningContext.isInliningLambda && ReifiedTypeInliner.isOperationReifiedMarker(cur)) {
|
||||
} else if (inliningContext.isInliningLambda && ReifiedTypeInliner.isOperationReifiedMarker(cur)) {
|
||||
val reificationArgument = cur.reificationArgument
|
||||
val parameterName = reificationArgument!!.parameterName
|
||||
result.reifiedTypeParametersUsages.addUsedReifiedParameter(parameterName)
|
||||
@@ -574,23 +566,28 @@ class MethodInliner(
|
||||
val className = fieldInsnNode!!.owner
|
||||
if (isAnonymousSingletonLoad(className, fieldInsnNode.name)) {
|
||||
recordTransformation(
|
||||
AnonymousObjectTransformationInfo(
|
||||
className, awaitClassReification, isAlreadyRegenerated(className), true,
|
||||
inliningContext.nameGenerator
|
||||
)
|
||||
AnonymousObjectTransformationInfo(
|
||||
className, awaitClassReification, isAlreadyRegenerated(className), true,
|
||||
inliningContext.nameGenerator
|
||||
)
|
||||
)
|
||||
awaitClassReification = false
|
||||
}
|
||||
else if (isWhenMappingAccess(className, fieldInsnNode.name)) {
|
||||
} else if (isWhenMappingAccess(className, fieldInsnNode.name)) {
|
||||
recordTransformation(
|
||||
WhenMappingTransformationInfo(
|
||||
className, inliningContext.nameGenerator, isAlreadyRegenerated(className), fieldInsnNode
|
||||
)
|
||||
WhenMappingTransformationInfo(
|
||||
className, inliningContext.nameGenerator, isAlreadyRegenerated(className), fieldInsnNode
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
cur.opcode == Opcodes.POP -> getLambdaIfExistsAndMarkInstructions(frame.top()!!, true, instructions, sources, toDelete)?.let {
|
||||
cur.opcode == Opcodes.POP -> getLambdaIfExistsAndMarkInstructions(
|
||||
frame.top()!!,
|
||||
true,
|
||||
instructions,
|
||||
sources,
|
||||
toDelete
|
||||
)?.let {
|
||||
toDelete.add(cur)
|
||||
}
|
||||
|
||||
@@ -605,9 +602,11 @@ class MethodInliner(
|
||||
val fieldInsn = cur as FieldInsnNode
|
||||
if (isCapturedFieldName(fieldInsn.name) &&
|
||||
nodeRemapper is InlinedLambdaRemapper &&
|
||||
nodeRemapper.originalLambdaInternalName == fieldInsn.owner) {
|
||||
nodeRemapper.originalLambdaInternalName == fieldInsn.owner
|
||||
) {
|
||||
val stackTransformations = mutableSetOf<AbstractInsnNode>()
|
||||
val lambdaInfo = getLambdaIfExistsAndMarkInstructions(frame.peek(1)!!, false, instructions, sources, stackTransformations)
|
||||
val lambdaInfo =
|
||||
getLambdaIfExistsAndMarkInstructions(frame.peek(1)!!, false, instructions, sources, stackTransformations)
|
||||
if (lambdaInfo != null && stackTransformations.all { it is VarInsnNode }) {
|
||||
assert(lambdaInfo.lambdaClassType.internalName == nodeRemapper.originalLambdaInternalName) {
|
||||
"Wrong bytecode template for contract template: ${lambdaInfo.lambdaClassType.internalName} != ${nodeRemapper.originalLambdaInternalName}"
|
||||
@@ -619,16 +618,14 @@ class MethodInliner(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
//given frame is <tt>null</tt> if and only if the corresponding instruction cannot be reached (dead code).
|
||||
//clean dead code otherwise there is problems in unreachable finally block, don't touch label it cause try/catch/finally problems
|
||||
if (cur.type == AbstractInsnNode.LABEL) {
|
||||
//NB: Cause we generate exception table for default handler using gaps (see ExpressionCodegen.visitTryExpression)
|
||||
//it may occurs that interval for default handler starts before catch start label, so this label seems as dead,
|
||||
//but as result all this labels will be merged into one (see KT-5863)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
toDelete.add(cur)
|
||||
}
|
||||
}
|
||||
@@ -758,8 +755,7 @@ class MethodInliner(
|
||||
private fun preprocessNodeBeforeInline(node: MethodNode, labelOwner: LabelOwner) {
|
||||
try {
|
||||
FixStackWithLabelNormalizationMethodTransformer().transform("fake", node)
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
} catch (e: Throwable) {
|
||||
throw wrapException(e, node, "couldn't inline method call")
|
||||
}
|
||||
|
||||
@@ -800,21 +796,21 @@ class MethodInliner(
|
||||
}
|
||||
|
||||
private fun buildConstructorInvocation(
|
||||
anonymousType: String,
|
||||
desc: String,
|
||||
lambdaMapping: Map<Int, LambdaInfo>,
|
||||
needReification: Boolean,
|
||||
capturesAnonymousObjectThatMustBeRegenerated: Boolean
|
||||
anonymousType: String,
|
||||
desc: String,
|
||||
lambdaMapping: Map<Int, LambdaInfo>,
|
||||
needReification: Boolean,
|
||||
capturesAnonymousObjectThatMustBeRegenerated: Boolean
|
||||
): AnonymousObjectTransformationInfo {
|
||||
|
||||
val info = AnonymousObjectTransformationInfo(
|
||||
anonymousType, needReification, lambdaMapping,
|
||||
inliningContext.classRegeneration,
|
||||
isAlreadyRegenerated(anonymousType),
|
||||
desc,
|
||||
false,
|
||||
inliningContext.nameGenerator,
|
||||
capturesAnonymousObjectThatMustBeRegenerated
|
||||
anonymousType, needReification, lambdaMapping,
|
||||
inliningContext.classRegeneration,
|
||||
isAlreadyRegenerated(anonymousType),
|
||||
desc,
|
||||
false,
|
||||
inliningContext.nameGenerator,
|
||||
capturesAnonymousObjectThatMustBeRegenerated
|
||||
)
|
||||
|
||||
val memoizeAnonymousObject = inliningContext.findAnonymousObjectTransformationInfo(anonymousType)
|
||||
@@ -911,17 +907,16 @@ class MethodInliner(
|
||||
private fun wrapException(originalException: Throwable, node: MethodNode, errorSuffix: String): RuntimeException {
|
||||
return if (originalException is InlineException) {
|
||||
InlineException("$errorPrefix: $errorSuffix", originalException)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
InlineException("$errorPrefix: $errorSuffix\nCause: ${node.nodeText}", originalException)
|
||||
}
|
||||
}
|
||||
|
||||
private class LocalReturnsNormalizer {
|
||||
private class LocalReturn(
|
||||
private val returnInsn: AbstractInsnNode,
|
||||
private val insertBeforeInsn: AbstractInsnNode,
|
||||
private val frame: Frame<SourceValue>
|
||||
private val returnInsn: AbstractInsnNode,
|
||||
private val insertBeforeInsn: AbstractInsnNode,
|
||||
private val frame: Frame<SourceValue>
|
||||
) {
|
||||
|
||||
fun transform(insnList: InsnList, returnVariableIndex: Int) {
|
||||
@@ -958,9 +953,9 @@ class MethodInliner(
|
||||
private var returnOpcode = -1
|
||||
|
||||
internal fun addLocalReturnToTransform(
|
||||
returnInsn: AbstractInsnNode,
|
||||
insertBeforeInsn: AbstractInsnNode,
|
||||
sourceValueFrame: Frame<SourceValue>
|
||||
returnInsn: AbstractInsnNode,
|
||||
insertBeforeInsn: AbstractInsnNode,
|
||||
sourceValueFrame: Frame<SourceValue>
|
||||
) {
|
||||
assert(isReturnOpcode(returnInsn.opcode)) { "return instruction expected" }
|
||||
assert(returnOpcode < 0 || returnOpcode == returnInsn.opcode) { "Return op should be " + Printer.OPCODES[returnOpcode] + ", got " + Printer.OPCODES[returnInsn.opcode] }
|
||||
@@ -971,8 +966,7 @@ class MethodInliner(
|
||||
if (returnInsn.opcode != Opcodes.RETURN) {
|
||||
returnVariableSize = if (returnInsn.opcode == Opcodes.LRETURN || returnInsn.opcode == Opcodes.DRETURN) {
|
||||
2
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
1
|
||||
}
|
||||
}
|
||||
@@ -993,9 +987,9 @@ class MethodInliner(
|
||||
|
||||
//Place to insert finally blocks from try blocks that wraps inline fun call
|
||||
class PointForExternalFinallyBlocks(
|
||||
@JvmField val beforeIns: AbstractInsnNode,
|
||||
@JvmField val returnType: Type,
|
||||
@JvmField val finallyIntervalEnd: LabelNode
|
||||
@JvmField val beforeIns: AbstractInsnNode,
|
||||
@JvmField val returnType: Type,
|
||||
@JvmField val finallyIntervalEnd: LabelNode
|
||||
)
|
||||
|
||||
companion object {
|
||||
@@ -1007,7 +1001,7 @@ class MethodInliner(
|
||||
}
|
||||
val fin = FieldInsnNode(node.opcode, node.owner, node.name.substring(3), node.desc)
|
||||
return fieldRemapper.findField(fin) ?: throw IllegalStateException(
|
||||
"Couldn't find captured field ${node.owner}.${node.name} in ${fieldRemapper.originalLambdaInternalName}"
|
||||
"Couldn't find captured field ${node.owner}.${node.name} in ${fieldRemapper.originalLambdaInternalName}"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1028,8 +1022,7 @@ class MethodInliner(
|
||||
|
||||
try {
|
||||
return analyzer.analyze("fake", node)
|
||||
}
|
||||
catch (e: AnalyzerException) {
|
||||
} catch (e: AnalyzerException) {
|
||||
throw RuntimeException(e)
|
||||
}
|
||||
|
||||
@@ -1041,8 +1034,7 @@ class MethodInliner(
|
||||
// INTRINSICS_CLASS_NAME.checkParameterIsNotNull(...)
|
||||
private fun removeClosureAssertions(node: MethodNode) {
|
||||
val toDelete = arrayListOf<AbstractInsnNode>()
|
||||
InsnSequence(node.instructions).filterIsInstance<MethodInsnNode>().forEach {
|
||||
methodInsnNode ->
|
||||
InsnSequence(node.instructions).filterIsInstance<MethodInsnNode>().forEach { methodInsnNode ->
|
||||
if (methodInsnNode.name == "checkParameterIsNotNull" && methodInsnNode.owner == IntrinsicMethods.INTRINSICS_CLASS_NAME) {
|
||||
val prev = methodInsnNode.previous
|
||||
assert(Opcodes.LDC == prev?.opcode) { "'checkParameterIsNotNull' should go after LDC but $prev" }
|
||||
@@ -1077,8 +1069,7 @@ class MethodInliner(
|
||||
|
||||
private fun getCapturedFieldAccessChain(aload0: VarInsnNode): List<AbstractInsnNode> {
|
||||
val lambdaAccessChain = mutableListOf<AbstractInsnNode>(aload0).apply {
|
||||
addAll(InsnSequence(aload0.next, null).filter { it.isMeaningful }.takeWhile {
|
||||
insnNode ->
|
||||
addAll(InsnSequence(aload0.next, null).filter { it.isMeaningful }.takeWhile { insnNode ->
|
||||
insnNode is FieldInsnNode && "this$0" == insnNode.name
|
||||
}.toList())
|
||||
}
|
||||
@@ -1086,7 +1077,8 @@ class MethodInliner(
|
||||
return lambdaAccessChain.apply {
|
||||
last().getNextMeaningful().takeIf { insn -> insn is FieldInsnNode }?.also {
|
||||
//captured field access
|
||||
insn -> add(insn)
|
||||
insn ->
|
||||
add(insn)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1134,7 +1126,7 @@ class MethodInliner(
|
||||
//process local and global returns (local substituted with goto end-label global kept unchanged)
|
||||
@JvmStatic
|
||||
fun processReturns(
|
||||
node: MethodNode, labelOwner: LabelOwner, remapReturn: Boolean, endLabel: Label?
|
||||
node: MethodNode, labelOwner: LabelOwner, remapReturn: Boolean, endLabel: Label?
|
||||
): List<PointForExternalFinallyBlocks> {
|
||||
if (!remapReturn) {
|
||||
return emptyList()
|
||||
@@ -1170,9 +1162,11 @@ class MethodInliner(
|
||||
//generate finally block before nonLocalReturn flag/return/goto
|
||||
val label = LabelNode()
|
||||
instructions.insert(insnNode, label)
|
||||
result.add(PointForExternalFinallyBlocks(
|
||||
result.add(
|
||||
PointForExternalFinallyBlocks(
|
||||
getInstructionToInsertFinallyBefore(insnNode, isLocalReturn), getReturnType(insnNode.opcode), label
|
||||
))
|
||||
)
|
||||
)
|
||||
}
|
||||
insnNode = insnNode.next
|
||||
}
|
||||
|
||||
@@ -27,11 +27,11 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.SourceValue
|
||||
|
||||
fun MethodInliner.getLambdaIfExistsAndMarkInstructions(
|
||||
sourceValue: SourceValue,
|
||||
processSwap: Boolean,
|
||||
insnList: InsnList,
|
||||
frames: Array<Frame<SourceValue>?>,
|
||||
toDelete: MutableSet<AbstractInsnNode>
|
||||
sourceValue: SourceValue,
|
||||
processSwap: Boolean,
|
||||
insnList: InsnList,
|
||||
frames: Array<Frame<SourceValue>?>,
|
||||
toDelete: MutableSet<AbstractInsnNode>
|
||||
): LambdaInfo? {
|
||||
val toDeleteInner = SmartSet.create<AbstractInsnNode>()
|
||||
|
||||
@@ -48,11 +48,11 @@ fun MethodInliner.getLambdaIfExistsAndMarkInstructions(
|
||||
private fun SourceValue.singleOrNullInsn() = insns.singleOrNull()
|
||||
|
||||
private fun MethodInliner.getLambdaIfExistsAndMarkInstructions(
|
||||
insnNode: AbstractInsnNode?,
|
||||
processSwap: Boolean,
|
||||
insnList: InsnList,
|
||||
frames: Array<Frame<SourceValue>?>,
|
||||
toDelete: MutableSet<AbstractInsnNode>
|
||||
insnNode: AbstractInsnNode?,
|
||||
processSwap: Boolean,
|
||||
insnList: InsnList,
|
||||
frames: Array<Frame<SourceValue>?>,
|
||||
toDelete: MutableSet<AbstractInsnNode>
|
||||
): LambdaInfo? {
|
||||
if (insnNode == null) return null
|
||||
|
||||
@@ -76,8 +76,7 @@ private fun MethodInliner.getLambdaIfExistsAndMarkInstructions(
|
||||
return it
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (processSwap && insnNode.opcode == Opcodes.SWAP) {
|
||||
} else if (processSwap && insnNode.opcode == Opcodes.SWAP) {
|
||||
val swapFrame = frames[insnList.indexOf(insnNode)] ?: return null
|
||||
val dispatchReceiver = swapFrame.top()!!
|
||||
getLambdaIfExistsAndMarkInstructions(dispatchReceiver, false, insnList, frames, toDelete)?.let {
|
||||
@@ -100,9 +99,9 @@ fun parameterOffsets(isStatic: Boolean, valueParameters: List<JvmMethodParameter
|
||||
}
|
||||
|
||||
fun MethodNode.remove(instructions: Sequence<AbstractInsnNode>) =
|
||||
instructions.forEach {
|
||||
this@remove.instructions.remove(it)
|
||||
}
|
||||
instructions.forEach {
|
||||
this@remove.instructions.remove(it)
|
||||
}
|
||||
|
||||
fun MethodNode.remove(instructions: Collection<AbstractInsnNode>) {
|
||||
instructions.forEach {
|
||||
@@ -111,19 +110,18 @@ fun MethodNode.remove(instructions: Collection<AbstractInsnNode>) {
|
||||
}
|
||||
|
||||
fun MethodNode.findCapturedFieldAssignmentInstructions(): Sequence<FieldInsnNode> {
|
||||
return InsnSequence(instructions).filterIsInstance<FieldInsnNode>().
|
||||
filter { fieldNode ->
|
||||
//filter captured field assignment
|
||||
// aload 0
|
||||
// aload x
|
||||
// PUTFIELD $fieldName
|
||||
return InsnSequence(instructions).filterIsInstance<FieldInsnNode>().filter { fieldNode ->
|
||||
//filter captured field assignment
|
||||
// aload 0
|
||||
// aload x
|
||||
// PUTFIELD $fieldName
|
||||
|
||||
val prevPrev = fieldNode.previous?.previous as? VarInsnNode
|
||||
val prevPrev = fieldNode.previous?.previous as? VarInsnNode
|
||||
|
||||
fieldNode.opcode == Opcodes.PUTFIELD &&
|
||||
fieldNode.opcode == Opcodes.PUTFIELD &&
|
||||
isCapturedFieldName(fieldNode.name) &&
|
||||
fieldNode.previous is VarInsnNode && prevPrev != null && prevPrev.`var` == 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun AbstractInsnNode.getNextMeaningful(): AbstractInsnNode? {
|
||||
|
||||
@@ -28,10 +28,12 @@ class ParametersBuilder private constructor() {
|
||||
}
|
||||
|
||||
fun addNextValueParameter(type: Type, skipped: Boolean, remapValue: StackValue?, parameterIndex: Int): ParameterInfo {
|
||||
return addParameter(ParameterInfo(
|
||||
return addParameter(
|
||||
ParameterInfo(
|
||||
type, skipped, nextParameterOffset, remapValue,
|
||||
if (parameterIndex == -1) nextValueParameterIndex else parameterIndex + valueParamFirstIndex
|
||||
))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun addCapturedParam(original: CapturedParamInfo, newFieldName: String): CapturedParamInfo {
|
||||
@@ -49,15 +51,15 @@ class ParametersBuilder private constructor() {
|
||||
}
|
||||
|
||||
fun addCapturedParam(
|
||||
containingLambdaType: Type,
|
||||
fieldName: String,
|
||||
newFieldName: String,
|
||||
type: Type,
|
||||
skipped: Boolean,
|
||||
original: ParameterInfo?
|
||||
containingLambdaType: Type,
|
||||
fieldName: String,
|
||||
newFieldName: String,
|
||||
type: Type,
|
||||
skipped: Boolean,
|
||||
original: ParameterInfo?
|
||||
): CapturedParamInfo {
|
||||
val info = CapturedParamInfo(
|
||||
CapturedParamDesc(containingLambdaType, fieldName, type), newFieldName, skipped, nextParameterOffset, original?.index ?: -1
|
||||
CapturedParamDesc(containingLambdaType, fieldName, type), newFieldName, skipped, nextParameterOffset, original?.index ?: -1
|
||||
)
|
||||
if (original != null) {
|
||||
info.lambda = original.lambda
|
||||
@@ -65,7 +67,7 @@ class ParametersBuilder private constructor() {
|
||||
return addParameter(info)
|
||||
}
|
||||
|
||||
private fun <T: ParameterInfo> addParameter(info: T): T {
|
||||
private fun <T : ParameterInfo> addParameter(info: T): T {
|
||||
params.add(info)
|
||||
nextParameterOffset += info.getType().size
|
||||
if (info !is CapturedParamInfo) {
|
||||
@@ -94,8 +96,7 @@ class ParametersBuilder private constructor() {
|
||||
return Parameters(params.map { param ->
|
||||
if (param is CapturedParamInfo) {
|
||||
param.cloneWithNewDeclarationIndex(nextDeclarationIndex++)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
param
|
||||
}
|
||||
})
|
||||
|
||||
@@ -20,5 +20,6 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||
|
||||
class PropertyReferenceInfo(
|
||||
val target: VariableDescriptor,
|
||||
val getFunction: FunctionDescriptor)
|
||||
val target: VariableDescriptor,
|
||||
val getFunction: FunctionDescriptor
|
||||
)
|
||||
+22
-21
@@ -24,19 +24,19 @@ import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode
|
||||
|
||||
class RegeneratedLambdaFieldRemapper(
|
||||
originalLambdaInternalName: String,
|
||||
override val newLambdaInternalName: String,
|
||||
parameters: Parameters,
|
||||
val recapturedLambdas: Map<String, LambdaInfo>,
|
||||
remapper: FieldRemapper,
|
||||
private val isConstructor: Boolean
|
||||
originalLambdaInternalName: String,
|
||||
override val newLambdaInternalName: String,
|
||||
parameters: Parameters,
|
||||
val recapturedLambdas: Map<String, LambdaInfo>,
|
||||
remapper: FieldRemapper,
|
||||
private val isConstructor: Boolean
|
||||
) : FieldRemapper(originalLambdaInternalName, remapper, parameters) {
|
||||
|
||||
public override fun canProcess(fieldOwner: String, fieldName: String, isFolding: Boolean) =
|
||||
super.canProcess(fieldOwner, fieldName, isFolding) || isRecapturedLambdaType(fieldOwner, isFolding)
|
||||
super.canProcess(fieldOwner, fieldName, isFolding) || isRecapturedLambdaType(fieldOwner, isFolding)
|
||||
|
||||
private fun isRecapturedLambdaType(owner: String, isFolding: Boolean) =
|
||||
recapturedLambdas.containsKey(owner) && (isFolding || parent !is InlinedLambdaRemapper)
|
||||
recapturedLambdas.containsKey(owner) && (isFolding || parent !is InlinedLambdaRemapper)
|
||||
|
||||
override fun findField(fieldInsnNode: FieldInsnNode, captured: Collection<CapturedParamInfo>): CapturedParamInfo? {
|
||||
val searchInParent = !canProcess(fieldInsnNode.owner, fieldInsnNode.name, false)
|
||||
@@ -65,22 +65,23 @@ class RegeneratedLambdaFieldRemapper(
|
||||
val fin = FieldInsnNode(node.opcode, node.owner, fieldName.substringAfter(CAPTURED_FIELD_FOLD_PREFIX), node.desc)
|
||||
var fromParent = false
|
||||
val field = findFieldInSuper(fin) ?:
|
||||
//search in parent
|
||||
findFieldInSuper(FieldInsnNode(
|
||||
Opcodes.GETSTATIC, originalLambdaInternalName, AsmUtil.CAPTURED_THIS_FIELD,
|
||||
Type.getObjectType(parent!!.originalLambdaInternalName!!).descriptor
|
||||
))?.also { fromParent = true } ?:
|
||||
throw AssertionError("Couldn't find captured this $originalLambdaInternalName for $fieldName")
|
||||
//search in parent
|
||||
findFieldInSuper(
|
||||
FieldInsnNode(
|
||||
Opcodes.GETSTATIC, originalLambdaInternalName, AsmUtil.CAPTURED_THIS_FIELD,
|
||||
Type.getObjectType(parent!!.originalLambdaInternalName!!).descriptor
|
||||
)
|
||||
)?.also { fromParent = true } ?: throw AssertionError("Couldn't find captured this $originalLambdaInternalName for $fieldName")
|
||||
|
||||
|
||||
val result = StackValue.field(
|
||||
if (field.isSkipped)
|
||||
Type.getObjectType(parent!!.parent!!.newLambdaInternalName)
|
||||
else
|
||||
field.getType(),
|
||||
Type.getObjectType(newLambdaInternalName), /*TODO owner type*/
|
||||
field.newFieldName, false,
|
||||
prefix ?: StackValue.LOCAL_0
|
||||
if (field.isSkipped)
|
||||
Type.getObjectType(parent!!.parent!!.newLambdaInternalName)
|
||||
else
|
||||
field.getType(),
|
||||
Type.getObjectType(newLambdaInternalName), /*TODO owner type*/
|
||||
field.newFieldName, false,
|
||||
prefix ?: StackValue.LOCAL_0
|
||||
)
|
||||
|
||||
return if (fromParent) parent!!.getFieldForInline(node, result) else result
|
||||
|
||||
@@ -32,18 +32,21 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
|
||||
class ReificationArgument(
|
||||
val parameterName: String, val nullable: Boolean, private val arrayDepth: Int
|
||||
val parameterName: String, val nullable: Boolean, private val arrayDepth: Int
|
||||
) {
|
||||
fun asString() = "[".repeat(arrayDepth) + parameterName + (if (nullable) "?" else "")
|
||||
fun combine(replacement: ReificationArgument) =
|
||||
ReificationArgument(
|
||||
replacement.parameterName,
|
||||
this.nullable || (replacement.nullable && this.arrayDepth == 0),
|
||||
this.arrayDepth + replacement.arrayDepth
|
||||
)
|
||||
ReificationArgument(
|
||||
replacement.parameterName,
|
||||
this.nullable || (replacement.nullable && this.arrayDepth == 0),
|
||||
this.arrayDepth + replacement.arrayDepth
|
||||
)
|
||||
|
||||
fun reify(replacementAsmType: Type, kotlinType: KotlinType) =
|
||||
Pair(Type.getType("[".repeat(arrayDepth) + replacementAsmType), TypeUtils.makeNullableIfNeeded(kotlinType.arrayOf(arrayDepth), nullable))
|
||||
Pair(
|
||||
Type.getType("[".repeat(arrayDepth) + replacementAsmType),
|
||||
TypeUtils.makeNullableIfNeeded(kotlinType.arrayOf(arrayDepth), nullable)
|
||||
)
|
||||
|
||||
private fun KotlinType.arrayOf(arrayDepth: Int): KotlinType {
|
||||
val builtins = this.builtIns
|
||||
@@ -69,7 +72,7 @@ class ReifiedTypeInliner(private val parametersMapping: TypeParameterMappings?,
|
||||
const val NEED_CLASS_REIFICATION_MARKER_METHOD_NAME = "needClassReification"
|
||||
|
||||
fun isOperationReifiedMarker(insn: AbstractInsnNode) =
|
||||
isReifiedMarker(insn) { it == REIFIED_OPERATION_MARKER_METHOD_NAME }
|
||||
isReifiedMarker(insn) { it == REIFIED_OPERATION_MARKER_METHOD_NAME }
|
||||
|
||||
private fun isReifiedMarker(insn: AbstractInsnNode, namePredicate: (String) -> Boolean): Boolean {
|
||||
if (insn.opcode != Opcodes.INVOKESTATIC || insn !is MethodInsnNode) return false
|
||||
@@ -78,14 +81,14 @@ class ReifiedTypeInliner(private val parametersMapping: TypeParameterMappings?,
|
||||
|
||||
@JvmStatic
|
||||
fun isNeedClassReificationMarker(insn: AbstractInsnNode): Boolean =
|
||||
isReifiedMarker(insn) { s -> s == NEED_CLASS_REIFICATION_MARKER_METHOD_NAME }
|
||||
isReifiedMarker(insn) { s -> s == NEED_CLASS_REIFICATION_MARKER_METHOD_NAME }
|
||||
|
||||
@JvmStatic
|
||||
fun putNeedClassReificationMarker(v: MethodVisitor) {
|
||||
v.visitMethodInsn(
|
||||
Opcodes.INVOKESTATIC,
|
||||
IntrinsicMethods.INTRINSICS_CLASS_NAME, NEED_CLASS_REIFICATION_MARKER_METHOD_NAME,
|
||||
Type.getMethodDescriptor(Type.VOID_TYPE), false
|
||||
Opcodes.INVOKESTATIC,
|
||||
IntrinsicMethods.INTRINSICS_CLASS_NAME, NEED_CLASS_REIFICATION_MARKER_METHOD_NAME,
|
||||
Type.getMethodDescriptor(Type.VOID_TYPE), false
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -134,21 +137,21 @@ class ReifiedTypeInliner(private val parametersMapping: TypeParameterMappings?,
|
||||
val (asmType, kotlinType) = reificationArgument.reify(mapping.asmType, mapping.type)
|
||||
|
||||
if (when (operationKind) {
|
||||
OperationKind.NEW_ARRAY -> processNewArray(insn, asmType)
|
||||
OperationKind.AS -> processAs(insn, instructions, kotlinType, asmType, safe = false)
|
||||
OperationKind.SAFE_AS -> processAs(insn, instructions, kotlinType, asmType, safe = true)
|
||||
OperationKind.IS -> processIs(insn, instructions, kotlinType, asmType)
|
||||
OperationKind.JAVA_CLASS -> processJavaClass(insn, asmType)
|
||||
OperationKind.ENUM_REIFIED -> processSpecialEnumFunction(insn, instructions, asmType)
|
||||
}) {
|
||||
OperationKind.NEW_ARRAY -> processNewArray(insn, asmType)
|
||||
OperationKind.AS -> processAs(insn, instructions, kotlinType, asmType, safe = false)
|
||||
OperationKind.SAFE_AS -> processAs(insn, instructions, kotlinType, asmType, safe = true)
|
||||
OperationKind.IS -> processIs(insn, instructions, kotlinType, asmType)
|
||||
OperationKind.JAVA_CLASS -> processJavaClass(insn, asmType)
|
||||
OperationKind.ENUM_REIFIED -> processSpecialEnumFunction(insn, instructions, asmType)
|
||||
}
|
||||
) {
|
||||
instructions.remove(insn.previous.previous!!) // PUSH operation ID
|
||||
instructions.remove(insn.previous!!) // PUSH type parameter
|
||||
instructions.remove(insn) // INVOKESTATIC marker method
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
val newReificationArgument = reificationArgument.combine(mapping.reificationArgument!!)
|
||||
instructions.set(insn.previous!!, LdcInsnNode(newReificationArgument.asString()))
|
||||
return mapping.reificationArgument.parameterName
|
||||
@@ -156,14 +159,14 @@ class ReifiedTypeInliner(private val parametersMapping: TypeParameterMappings?,
|
||||
}
|
||||
|
||||
private fun processNewArray(insn: MethodInsnNode, parameter: Type) =
|
||||
processNextTypeInsn(insn, parameter, Opcodes.ANEWARRAY)
|
||||
processNextTypeInsn(insn, parameter, Opcodes.ANEWARRAY)
|
||||
|
||||
private fun processAs(
|
||||
insn: MethodInsnNode,
|
||||
instructions: InsnList,
|
||||
kotlinType: KotlinType,
|
||||
asmType: Type,
|
||||
safe: Boolean
|
||||
insn: MethodInsnNode,
|
||||
instructions: InsnList,
|
||||
kotlinType: KotlinType,
|
||||
asmType: Type,
|
||||
safe: Boolean
|
||||
) = rewriteNextTypeInsn(insn, Opcodes.CHECKCAST) { stubCheckcast: AbstractInsnNode ->
|
||||
if (stubCheckcast !is TypeInsnNode) return false
|
||||
|
||||
@@ -180,10 +183,10 @@ class ReifiedTypeInliner(private val parametersMapping: TypeParameterMappings?,
|
||||
}
|
||||
|
||||
private fun processIs(
|
||||
insn: MethodInsnNode,
|
||||
instructions: InsnList,
|
||||
kotlinType: KotlinType,
|
||||
asmType: Type
|
||||
insn: MethodInsnNode,
|
||||
instructions: InsnList,
|
||||
kotlinType: KotlinType,
|
||||
asmType: Type
|
||||
) = rewriteNextTypeInsn(insn, Opcodes.INSTANCEOF) { stubInstanceOf: AbstractInsnNode ->
|
||||
if (stubInstanceOf !is TypeInsnNode) return false
|
||||
|
||||
@@ -199,9 +202,9 @@ class ReifiedTypeInliner(private val parametersMapping: TypeParameterMappings?,
|
||||
}
|
||||
|
||||
inline private fun rewriteNextTypeInsn(
|
||||
marker: MethodInsnNode,
|
||||
expectedNextOpcode: Int,
|
||||
rewrite: (AbstractInsnNode) -> Boolean
|
||||
marker: MethodInsnNode,
|
||||
expectedNextOpcode: Int,
|
||||
rewrite: (AbstractInsnNode) -> Boolean
|
||||
): Boolean {
|
||||
val next = marker.next ?: return false
|
||||
if (next.opcode != expectedNextOpcode) return false
|
||||
@@ -232,8 +235,7 @@ class ReifiedTypeInliner(private val parametersMapping: TypeParameterMappings?,
|
||||
next3.desc = getSpecialEnumFunDescriptor(parameter, true)
|
||||
return true
|
||||
}
|
||||
}
|
||||
else if (next1.opcode == Opcodes.ICONST_0 && next2.opcode == Opcodes.ANEWARRAY) {
|
||||
} else if (next1.opcode == Opcodes.ICONST_0 && next2.opcode == Opcodes.ANEWARRAY) {
|
||||
instructions.remove(next1)
|
||||
instructions.remove(next2)
|
||||
val desc = getSpecialEnumFunDescriptor(parameter, false)
|
||||
@@ -261,23 +263,29 @@ val MethodInsnNode.reificationArgument: ReificationArgument?
|
||||
return ReificationArgument(parameterName, nullable, arrayDepth)
|
||||
}
|
||||
|
||||
val MethodInsnNode.operationKind: ReifiedTypeInliner.OperationKind? get() =
|
||||
previous?.previous?.intConstant?.let {
|
||||
ReifiedTypeInliner.OperationKind.values().getOrNull(it)
|
||||
}
|
||||
val MethodInsnNode.operationKind: ReifiedTypeInliner.OperationKind?
|
||||
get() =
|
||||
previous?.previous?.intConstant?.let {
|
||||
ReifiedTypeInliner.OperationKind.values().getOrNull(it)
|
||||
}
|
||||
|
||||
class TypeParameterMappings() {
|
||||
private val mappingsByName = hashMapOf<String, TypeParameterMapping>()
|
||||
|
||||
fun addParameterMappingToType(name: String, type: KotlinType, asmType: Type, signature: String, isReified: Boolean) {
|
||||
mappingsByName[name] = TypeParameterMapping(
|
||||
name, type, asmType, reificationArgument = null, signature = signature, isReified = isReified
|
||||
name, type, asmType, reificationArgument = null, signature = signature, isReified = isReified
|
||||
)
|
||||
}
|
||||
|
||||
fun addParameterMappingForFurtherReification(name: String, type: KotlinType, reificationArgument: ReificationArgument, isReified: Boolean) {
|
||||
fun addParameterMappingForFurtherReification(
|
||||
name: String,
|
||||
type: KotlinType,
|
||||
reificationArgument: ReificationArgument,
|
||||
isReified: Boolean
|
||||
) {
|
||||
mappingsByName[name] = TypeParameterMapping(
|
||||
name, type, asmType = null, reificationArgument = reificationArgument, signature = null, isReified = isReified
|
||||
name, type, asmType = null, reificationArgument = reificationArgument, signature = null, isReified = isReified
|
||||
)
|
||||
}
|
||||
|
||||
@@ -285,18 +293,18 @@ class TypeParameterMappings() {
|
||||
|
||||
fun hasReifiedParameters() = mappingsByName.values.any { it.isReified }
|
||||
|
||||
internal inline fun forEach(l: (TypeParameterMapping) -> Unit) {
|
||||
internal inline fun forEach(l: (TypeParameterMapping) -> Unit) {
|
||||
mappingsByName.values.forEach(l)
|
||||
}
|
||||
}
|
||||
|
||||
class TypeParameterMapping(
|
||||
val name: String,
|
||||
val type: KotlinType,
|
||||
val asmType: Type?,
|
||||
val reificationArgument: ReificationArgument?,
|
||||
val signature: String?,
|
||||
val isReified: Boolean
|
||||
val name: String,
|
||||
val type: KotlinType,
|
||||
val asmType: Type?,
|
||||
val reificationArgument: ReificationArgument?,
|
||||
val signature: String?,
|
||||
val isReified: Boolean
|
||||
)
|
||||
|
||||
class ReifiedTypeParametersUsages {
|
||||
|
||||
@@ -54,7 +54,8 @@ public class RemappingClassBuilder extends DelegatingClassBuilder {
|
||||
@NotNull String superName,
|
||||
@NotNull String[] interfaces
|
||||
) {
|
||||
super.defineClass(origin, version, access, remapper.mapType(name), remapper.mapSignature(signature, false), remapper.mapType(superName), remapper.mapTypes(interfaces));
|
||||
super.defineClass(origin, version, access, remapper.mapType(name), remapper.mapSignature(signature, false),
|
||||
remapper.mapType(superName), remapper.mapTypes(interfaces));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -109,7 +109,7 @@ open class NestedSourceMapper(
|
||||
} else {
|
||||
val rangeForMapping =
|
||||
(if (lastVisitedRange?.contains(lineNumber) == true) lastVisitedRange!! else findMappingIfExists(lineNumber))
|
||||
?: error("Can't find range to map line $lineNumber in ${sourceInfo.source}: ${sourceInfo.pathOrCleanFQN}")
|
||||
?: error("Can't find range to map line $lineNumber in ${sourceInfo.source}: ${sourceInfo.pathOrCleanFQN}")
|
||||
val sourceLineNumber = rangeForMapping.mapDestToSource(lineNumber)
|
||||
val newLineNumber = parent.mapLineNumber(sourceLineNumber, rangeForMapping.parent!!.name, rangeForMapping.parent!!.path)
|
||||
if (newLineNumber > 0) {
|
||||
|
||||
@@ -30,8 +30,7 @@ class SMAPAndMethodNode(val node: MethodNode, val classSMAP: SMAP) {
|
||||
|
||||
private fun createLineNumberSequence(node: MethodNode, classSMAP: SMAP): Sequence<RangeMapping> {
|
||||
return InsnSequence(node.instructions.first, null).filterIsInstance<LineNumberNode>().map { lineNumber ->
|
||||
val index = classSMAP.intervals.binarySearch(RangeMapping(lineNumber.line, lineNumber.line, 1), Comparator {
|
||||
value, key ->
|
||||
val index = classSMAP.intervals.binarySearch(RangeMapping(lineNumber.line, lineNumber.line, 1), Comparator { value, key ->
|
||||
if (key.dest in value) 0 else RangeMapping.Comparator.compare(value, key)
|
||||
})
|
||||
if (index < 0) {
|
||||
|
||||
@@ -25,15 +25,15 @@ object SMAPParser {
|
||||
}
|
||||
|
||||
val mapping =
|
||||
if (source == null || source.isEmpty() || methodStartLine > methodEndLine)
|
||||
FileMapping.SKIP
|
||||
else
|
||||
FileMapping(source, path).apply {
|
||||
if (methodStartLine <= methodEndLine) {
|
||||
//one to one
|
||||
addRangeMapping(RangeMapping(methodStartLine, methodStartLine, methodEndLine - methodStartLine + 1))
|
||||
}
|
||||
if (source == null || source.isEmpty() || methodStartLine > methodEndLine)
|
||||
FileMapping.SKIP
|
||||
else
|
||||
FileMapping(source, path).apply {
|
||||
if (methodStartLine <= methodEndLine) {
|
||||
//one to one
|
||||
addRangeMapping(RangeMapping(methodStartLine, methodStartLine, methodEndLine - methodStartLine + 1))
|
||||
}
|
||||
}
|
||||
|
||||
return SMAP(listOf(mapping))
|
||||
}
|
||||
|
||||
@@ -20,19 +20,23 @@ import org.jetbrains.org.objectweb.asm.ClassReader
|
||||
import org.jetbrains.org.objectweb.asm.ClassVisitor
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
|
||||
class SamWrapperTransformationInfo(override val oldClassName: String, private val inliningContext: InliningContext, private val alreadyRegenerated: Boolean): TransformationInfo {
|
||||
class SamWrapperTransformationInfo(
|
||||
override val oldClassName: String,
|
||||
private val inliningContext: InliningContext,
|
||||
private val alreadyRegenerated: Boolean
|
||||
) : TransformationInfo {
|
||||
override val nameGenerator: NameGenerator
|
||||
get() = object: NameGenerator("stub") {
|
||||
get() = object : NameGenerator("stub") {
|
||||
override fun getGeneratorClass(): String {
|
||||
error ("Shouldn't be called on $oldClassName transformation")
|
||||
error("Shouldn't be called on $oldClassName transformation")
|
||||
}
|
||||
|
||||
override fun subGenerator(inliningMethod: String?): NameGenerator {
|
||||
error ("Shouldn't be called on $oldClassName transformation")
|
||||
error("Shouldn't be called on $oldClassName transformation")
|
||||
}
|
||||
|
||||
override fun subGenerator(lambdaNoWhen: Boolean, nameSuffix: String?): NameGenerator {
|
||||
error ("Shouldn't be called on $oldClassName transformation")
|
||||
error("Shouldn't be called on $oldClassName transformation")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,11 +49,11 @@ class SamWrapperTransformationInfo(override val oldClassName: String, private va
|
||||
override fun canRemoveAfterTransformation() = false
|
||||
|
||||
override fun createTransformer(inliningContext: InliningContext, sameModule: Boolean, continuationClassName: String?) =
|
||||
SamWrapperTransformer(this, inliningContext)
|
||||
SamWrapperTransformer(this, inliningContext)
|
||||
}
|
||||
|
||||
class SamWrapperTransformer(transformationInfo: SamWrapperTransformationInfo, private val inliningContext: InliningContext) :
|
||||
ObjectTransformer<SamWrapperTransformationInfo>(transformationInfo, inliningContext.state) {
|
||||
ObjectTransformer<SamWrapperTransformationInfo>(transformationInfo, inliningContext.state) {
|
||||
|
||||
override fun doTransform(parentRemapper: FieldRemapper): InlineResult {
|
||||
val classReader = createClassReader()
|
||||
|
||||
@@ -38,10 +38,10 @@ interface TransformationInfo {
|
||||
}
|
||||
|
||||
class WhenMappingTransformationInfo(
|
||||
override val oldClassName: String,
|
||||
parentNameGenerator: NameGenerator,
|
||||
private val alreadyRegenerated: Boolean,
|
||||
val fieldNode: FieldInsnNode
|
||||
override val oldClassName: String,
|
||||
parentNameGenerator: NameGenerator,
|
||||
private val alreadyRegenerated: Boolean,
|
||||
val fieldNode: FieldInsnNode
|
||||
) : TransformationInfo {
|
||||
|
||||
override val nameGenerator by lazy {
|
||||
@@ -52,8 +52,12 @@ class WhenMappingTransformationInfo(
|
||||
|
||||
override fun canRemoveAfterTransformation(): Boolean = true
|
||||
|
||||
override fun createTransformer(inliningContext: InliningContext, sameModule: Boolean, continuationClassName: String?): ObjectTransformer<*> =
|
||||
WhenMappingTransformer(this, inliningContext)
|
||||
override fun createTransformer(
|
||||
inliningContext: InliningContext,
|
||||
sameModule: Boolean,
|
||||
continuationClassName: String?
|
||||
): ObjectTransformer<*> =
|
||||
WhenMappingTransformer(this, inliningContext)
|
||||
|
||||
companion object {
|
||||
const val TRANSFORMED_WHEN_MAPPING_MARKER = "\$wm$"
|
||||
@@ -61,15 +65,15 @@ class WhenMappingTransformationInfo(
|
||||
}
|
||||
|
||||
class AnonymousObjectTransformationInfo internal constructor(
|
||||
override val oldClassName: String,
|
||||
private val needReification: Boolean,
|
||||
val lambdasToInline: Map<Int, LambdaInfo>,
|
||||
private val capturedOuterRegenerated: Boolean,
|
||||
private val alreadyRegenerated: Boolean,
|
||||
val constructorDesc: String?,
|
||||
private val isStaticOrigin: Boolean,
|
||||
parentNameGenerator: NameGenerator,
|
||||
private val capturesAnonymousObjectThatMustBeRegenerated: Boolean = false
|
||||
override val oldClassName: String,
|
||||
private val needReification: Boolean,
|
||||
val lambdasToInline: Map<Int, LambdaInfo>,
|
||||
private val capturedOuterRegenerated: Boolean,
|
||||
private val alreadyRegenerated: Boolean,
|
||||
val constructorDesc: String?,
|
||||
private val isStaticOrigin: Boolean,
|
||||
parentNameGenerator: NameGenerator,
|
||||
private val capturesAnonymousObjectThatMustBeRegenerated: Boolean = false
|
||||
) : TransformationInfo {
|
||||
|
||||
override val nameGenerator by lazy {
|
||||
@@ -86,16 +90,16 @@ class AnonymousObjectTransformationInfo internal constructor(
|
||||
get() = alreadyRegenerated
|
||||
|
||||
constructor(
|
||||
ownerInternalName: String,
|
||||
needReification: Boolean,
|
||||
alreadyRegenerated: Boolean,
|
||||
isStaticOrigin: Boolean,
|
||||
nameGenerator: NameGenerator
|
||||
ownerInternalName: String,
|
||||
needReification: Boolean,
|
||||
alreadyRegenerated: Boolean,
|
||||
isStaticOrigin: Boolean,
|
||||
nameGenerator: NameGenerator
|
||||
) : this(ownerInternalName, needReification, hashMapOf(), false, alreadyRegenerated, null, isStaticOrigin, nameGenerator)
|
||||
|
||||
override fun shouldRegenerate(sameModule: Boolean): Boolean =
|
||||
!alreadyRegenerated &&
|
||||
(!lambdasToInline.isEmpty() || !sameModule || capturedOuterRegenerated || needReification || capturesAnonymousObjectThatMustBeRegenerated)
|
||||
!alreadyRegenerated &&
|
||||
(!lambdasToInline.isEmpty() || !sameModule || capturedOuterRegenerated || needReification || capturesAnonymousObjectThatMustBeRegenerated)
|
||||
|
||||
override fun canRemoveAfterTransformation(): Boolean {
|
||||
// Note: It is unsafe to remove anonymous class that is referenced by GETSTATIC within lambda
|
||||
|
||||
@@ -38,7 +38,7 @@ interface Interval {
|
||||
fun isEmpty(): Boolean = startLabel == endLabel
|
||||
|
||||
fun verify(processor: CoveringTryCatchNodeProcessor) {
|
||||
assert (processor.instructionIndex(startLabel) <= processor.instructionIndex(endLabel)) {
|
||||
assert(processor.instructionIndex(startLabel) <= processor.instructionIndex(endLabel)) {
|
||||
"Try block body starts after body end: ${processor.instructionIndex(startLabel)} > ${processor.instructionIndex(endLabel)}"
|
||||
}
|
||||
}
|
||||
@@ -54,8 +54,8 @@ interface IntervalWithHandler : Interval {
|
||||
}
|
||||
|
||||
class TryCatchBlockNodeInfo(
|
||||
val node: TryCatchBlockNode,
|
||||
val onlyCopyNotProcess: Boolean
|
||||
val node: TryCatchBlockNode,
|
||||
val onlyCopyNotProcess: Boolean
|
||||
) : IntervalWithHandler, SplittableInterval<TryCatchBlockNodeInfo> {
|
||||
override val startLabel: LabelNode
|
||||
get() = node.start
|
||||
@@ -71,15 +71,14 @@ class TryCatchBlockNodeInfo(
|
||||
val oldEnd = endLabel
|
||||
node.end = splitBy.startLabel
|
||||
Pair(splitBy.endLabel, oldEnd)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
val oldStart = startLabel
|
||||
node.start = splitBy.endLabel
|
||||
Pair(oldStart, splitBy.startLabel)
|
||||
}
|
||||
return SplitPair(
|
||||
this,
|
||||
TryCatchBlockNodeInfo(TryCatchBlockNode(newPartInterval.first, newPartInterval.second, handler, type), onlyCopyNotProcess)
|
||||
this,
|
||||
TryCatchBlockNodeInfo(TryCatchBlockNode(newPartInterval.first, newPartInterval.second, handler, type), onlyCopyNotProcess)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -88,8 +87,8 @@ val TryCatchBlockNodeInfo.bodyInstuctions
|
||||
get() = InsnSequence(startLabel, endLabel)
|
||||
|
||||
class TryCatchBlockNodePosition(
|
||||
val nodeInfo: TryCatchBlockNodeInfo,
|
||||
var position: TryCatchPosition
|
||||
val nodeInfo: TryCatchBlockNodeInfo,
|
||||
var position: TryCatchPosition
|
||||
) : IntervalWithHandler by nodeInfo
|
||||
|
||||
class TryBlockCluster<T : IntervalWithHandler>(val blocks: MutableList<T>) {
|
||||
|
||||
@@ -22,9 +22,9 @@ class TypeParameter(val oldName: String, val newName: String?, val isReified: Bo
|
||||
|
||||
//typeMapping data could be changed outside through method processing
|
||||
class TypeRemapper private constructor(
|
||||
private val typeMapping: MutableMap<String, String?>,
|
||||
val parent: TypeRemapper? = null,
|
||||
private val isRootInlineLambda: Boolean = false
|
||||
private val typeMapping: MutableMap<String, String?>,
|
||||
val parent: TypeRemapper? = null,
|
||||
private val isRootInlineLambda: Boolean = false
|
||||
) {
|
||||
private val additionalMappings = hashMapOf<String, String>()
|
||||
private val typeParametersMapping = hashMapOf<String, TypeParameter>()
|
||||
@@ -54,7 +54,7 @@ class TypeRemapper private constructor(
|
||||
|
||||
fun registerTypeParameter(mapping: TypeParameterMapping) {
|
||||
typeParametersMapping[mapping.name] = TypeParameter(
|
||||
mapping.name, mapping.reificationArgument?.parameterName, mapping.isReified, mapping.signature
|
||||
mapping.name, mapping.reificationArgument?.parameterName, mapping.isReified, mapping.signature
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -32,21 +32,24 @@ import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
|
||||
private data class Condition(
|
||||
val mask: Int, val constant: Int,
|
||||
val maskInstruction: VarInsnNode,
|
||||
val jumpInstruction: JumpInsnNode,
|
||||
val varInsNode: VarInsnNode?
|
||||
val mask: Int, val constant: Int,
|
||||
val maskInstruction: VarInsnNode,
|
||||
val jumpInstruction: JumpInsnNode,
|
||||
val varInsNode: VarInsnNode?
|
||||
) {
|
||||
val expandNotDelete = mask and constant != 0
|
||||
val varIndex = varInsNode?.`var` ?: 0
|
||||
}
|
||||
|
||||
fun extractDefaultLambdaOffsetAndDescriptor(jvmSignature: JvmMethodSignature, functionDescriptor: FunctionDescriptor): Map<Int, ValueParameterDescriptor> {
|
||||
fun extractDefaultLambdaOffsetAndDescriptor(
|
||||
jvmSignature: JvmMethodSignature,
|
||||
functionDescriptor: FunctionDescriptor
|
||||
): Map<Int, ValueParameterDescriptor> {
|
||||
val valueParameters = jvmSignature.valueParameters
|
||||
val containingDeclaration = functionDescriptor.containingDeclaration
|
||||
val kind =
|
||||
if (DescriptorUtils.isInterface(containingDeclaration)) OwnerKind.DEFAULT_IMPLS
|
||||
else OwnerKind.getMemberOwnerKind(containingDeclaration)
|
||||
if (DescriptorUtils.isInterface(containingDeclaration)) OwnerKind.DEFAULT_IMPLS
|
||||
else OwnerKind.getMemberOwnerKind(containingDeclaration)
|
||||
val parameterOffsets = parameterOffsets(AsmUtil.isStaticMethod(kind, functionDescriptor), valueParameters)
|
||||
val valueParameterOffset = valueParameters.takeWhile { it.kind != JvmMethodParameterKind.VALUE }.size
|
||||
|
||||
@@ -59,11 +62,11 @@ fun extractDefaultLambdaOffsetAndDescriptor(jvmSignature: JvmMethodSignature, fu
|
||||
|
||||
|
||||
fun expandMaskConditionsAndUpdateVariableNodes(
|
||||
node: MethodNode,
|
||||
maskStartIndex: Int,
|
||||
masks: List<Int>,
|
||||
methodHandlerIndex: Int,
|
||||
defaultLambdas: Map<Int, ValueParameterDescriptor>
|
||||
node: MethodNode,
|
||||
maskStartIndex: Int,
|
||||
masks: List<Int>,
|
||||
methodHandlerIndex: Int,
|
||||
defaultLambdas: Map<Int, ValueParameterDescriptor>
|
||||
): List<DefaultLambda> {
|
||||
fun isMaskIndex(varIndex: Int): Boolean {
|
||||
return maskStartIndex <= varIndex && varIndex < maskStartIndex + masks.size
|
||||
@@ -74,8 +77,7 @@ fun expandMaskConditionsAndUpdateVariableNodes(
|
||||
if (isMaskIndex(it.`var`)) {
|
||||
/*if slot for default mask is updated than we occurred in actual function body*/
|
||||
return@takeWhile it.opcode == Opcodes.ILOAD
|
||||
}
|
||||
else if (methodHandlerIndex == it.`var`) {
|
||||
} else if (methodHandlerIndex == it.`var`) {
|
||||
return@takeWhile it.opcode == Opcodes.ALOAD
|
||||
}
|
||||
}
|
||||
@@ -85,24 +87,24 @@ fun expandMaskConditionsAndUpdateVariableNodes(
|
||||
val conditions = maskProcessingHeader.filterIsInstance<VarInsnNode>().mapNotNull {
|
||||
if (isMaskIndex(it.`var`) &&
|
||||
it.next?.next?.opcode == Opcodes.IAND &&
|
||||
it.next.next.next?.opcode == Opcodes.IFEQ) {
|
||||
it.next.next.next?.opcode == Opcodes.IFEQ
|
||||
) {
|
||||
val jumpInstruction = it.next?.next?.next as JumpInsnNode
|
||||
Condition(
|
||||
masks[it.`var` - maskStartIndex],
|
||||
getConstant(it.next),
|
||||
it,
|
||||
jumpInstruction,
|
||||
jumpInstruction.label.previous as VarInsnNode
|
||||
masks[it.`var` - maskStartIndex],
|
||||
getConstant(it.next),
|
||||
it,
|
||||
jumpInstruction,
|
||||
jumpInstruction.label.previous as VarInsnNode
|
||||
)
|
||||
}
|
||||
else if (methodHandlerIndex == it.`var` &&
|
||||
it.next?.opcode == Opcodes.IFNULL &&
|
||||
it.next.next?.opcode == Opcodes.NEW) {
|
||||
} else if (methodHandlerIndex == it.`var` &&
|
||||
it.next?.opcode == Opcodes.IFNULL &&
|
||||
it.next.next?.opcode == Opcodes.NEW
|
||||
) {
|
||||
//Always delete method handle for now
|
||||
//This logic should be updated when method handles would be supported
|
||||
Condition(0, 0, it, it.next as JumpInsnNode, null)
|
||||
}
|
||||
else null
|
||||
} else null
|
||||
}.toList()
|
||||
|
||||
val toDelete = linkedSetOf<AbstractInsnNode>()
|
||||
@@ -136,10 +138,10 @@ fun expandMaskConditionsAndUpdateVariableNodes(
|
||||
|
||||
|
||||
private fun extractDefaultLambdasInfo(
|
||||
conditions: List<Condition>,
|
||||
defaultLambdas: Map<Int, ValueParameterDescriptor>,
|
||||
toDelete: MutableCollection<AbstractInsnNode>,
|
||||
toInsert: MutableList<Pair<AbstractInsnNode, AbstractInsnNode>>
|
||||
conditions: List<Condition>,
|
||||
defaultLambdas: Map<Int, ValueParameterDescriptor>,
|
||||
toDelete: MutableCollection<AbstractInsnNode>,
|
||||
toInsert: MutableList<Pair<AbstractInsnNode, AbstractInsnNode>>
|
||||
): List<DefaultLambda> {
|
||||
val defaultLambdaConditions = conditions.filter { it.expandNotDelete && defaultLambdas.contains(it.varIndex) }
|
||||
return defaultLambdaConditions.map {
|
||||
@@ -166,14 +168,16 @@ private fun extractDefaultLambdasInfo(
|
||||
addAll(InsnSequence(instanceInstuction, varAssignmentInstruction.next).toList())
|
||||
}
|
||||
|
||||
val needReification = instanceCreation.previous.takeIf { isNeedClassReificationMarker(it) }?.let { toDelete.add(it) } != null
|
||||
val needReification =
|
||||
instanceCreation.previous.takeIf { isNeedClassReificationMarker(it) }?.let { toDelete.add(it) } != null
|
||||
Triple(Type.getObjectType(instanceInstuction.owner), Type.getArgumentTypes(instanceInstuction.desc), needReification)
|
||||
}
|
||||
|
||||
is FieldInsnNode -> {
|
||||
toDelete.addAll(InsnSequence(instanceInstuction, varAssignmentInstruction.next).toList())
|
||||
|
||||
val needReification = instanceInstuction.previous.takeIf { isNeedClassReificationMarker(it) }?.let { toDelete.add(it) } != null
|
||||
val needReification =
|
||||
instanceInstuction.previous.takeIf { isNeedClassReificationMarker(it) }?.let { toDelete.add(it) } != null
|
||||
|
||||
Triple(Type.getObjectType(instanceInstuction.owner), emptyArray<Type>(), needReification)
|
||||
}
|
||||
@@ -190,10 +194,10 @@ private fun extractDefaultLambdasInfo(
|
||||
//at inlining it would be substituted with parameters store
|
||||
private fun defaultLambdaFakeCallStub(args: Array<Type>, lambdaOffset: Int): MethodInsnNode {
|
||||
return MethodInsnNode(
|
||||
Opcodes.INVOKESTATIC,
|
||||
DEFAULT_LAMBDA_FAKE_CALL,
|
||||
DEFAULT_LAMBDA_FAKE_CALL + lambdaOffset,
|
||||
Type.getMethodDescriptor(Type.VOID_TYPE, *args),
|
||||
false
|
||||
Opcodes.INVOKESTATIC,
|
||||
DEFAULT_LAMBDA_FAKE_CALL,
|
||||
DEFAULT_LAMBDA_FAKE_CALL + lambdaOffset,
|
||||
Type.getMethodDescriptor(Type.VOID_TYPE, *args),
|
||||
false
|
||||
)
|
||||
}
|
||||
@@ -469,8 +469,10 @@ internal fun isAfterSuspendMarker(insn: AbstractInsnNode) = isSuspendMarker(insn
|
||||
internal fun isReturnsUnitMarker(insn: AbstractInsnNode) = isSuspendMarker(insn, INLINE_MARKER_RETURNS_UNIT)
|
||||
internal fun isFakeContinuationMarker(insn: AbstractInsnNode) =
|
||||
insn.previous != null && isSuspendMarker(insn.previous, INLINE_MARKER_FAKE_CONTINUATION) && insn.opcode == Opcodes.ACONST_NULL
|
||||
|
||||
internal fun isBeforeFakeContinuationConstructorCallMarker(insn: AbstractInsnNode) =
|
||||
isSuspendMarker(insn, INLINE_MARKER_BEFORE_FAKE_CONTINUATION_CONSTRUCTOR_CALL)
|
||||
|
||||
internal fun isAfterFakeContinuationConstructorCallMarker(insn: AbstractInsnNode) =
|
||||
isSuspendMarker(insn, INLINE_MARKER_AFTER_FAKE_CONTINUATION_CONSTRUCTOR_CALL)
|
||||
|
||||
@@ -599,7 +601,7 @@ fun FunctionDescriptor.getClassFilePath(typeMapper: KotlinTypeMapper, cache: Inc
|
||||
return when (source) {
|
||||
is KotlinJvmBinaryPackageSourceElement -> {
|
||||
val directMember = JvmCodegenUtil.getDirectMember(this) as? DeserializedCallableMemberDescriptor
|
||||
?: throw AssertionError("Expected DeserializedCallableMemberDescriptor, got: $this")
|
||||
?: throw AssertionError("Expected DeserializedCallableMemberDescriptor, got: $this")
|
||||
val kotlinClass =
|
||||
source.getContainingBinaryClass(directMember) ?: throw AssertionError("Descriptor $this is not found, in: $source")
|
||||
if (kotlinClass !is VirtualFileKotlinClass) {
|
||||
|
||||
Reference in New Issue
Block a user