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