Minor. Reformat code

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