Make FunctionalArgumentInterpreter stateless
So, we can use fast basic interpreter.
This commit is contained in:
@@ -33,6 +33,7 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
import org.jetbrains.org.objectweb.asm.commons.LocalVariablesSorter
|
||||
import org.jetbrains.org.objectweb.asm.commons.MethodRemapper
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
|
||||
import org.jetbrains.org.objectweb.asm.util.Printer
|
||||
import java.util.*
|
||||
@@ -468,9 +469,11 @@ class MethodInliner(
|
||||
|
||||
val toDelete = SmartSet.create<AbstractInsnNode>()
|
||||
|
||||
val sources = analyzeMethodNodeWithInterpreter(processingNode, FunctionalArgumentInterpreter(this, toDelete))
|
||||
val sources = analyzeMethodNodeWithInterpreter(processingNode, FunctionalArgumentInterpreter(this))
|
||||
val instructions = processingNode.instructions
|
||||
|
||||
markObsoleteInstruction(instructions, toDelete, sources)
|
||||
|
||||
var awaitClassReification = false
|
||||
var currentFinallyDeep = 0
|
||||
|
||||
@@ -622,6 +625,41 @@ class MethodInliner(
|
||||
return processingNode
|
||||
}
|
||||
|
||||
private fun MethodInliner.markObsoleteInstruction(
|
||||
instructions: InsnList,
|
||||
toDelete: SmartSet<AbstractInsnNode>,
|
||||
sources: Array<out Frame<BasicValue>?>
|
||||
) {
|
||||
for (insn in instructions) {
|
||||
// Parameter checks are processed separately
|
||||
if (insn.isAloadBeforeCheckParameterIsNotNull()) continue
|
||||
val functionalArgument = getFunctionalArgumentIfExists(insn)
|
||||
if (functionalArgument is LambdaInfo) {
|
||||
toDelete.add(insn)
|
||||
} else {
|
||||
when (insn.opcode) {
|
||||
Opcodes.ASTORE -> {
|
||||
if (sources[instructions.indexOf(insn)]?.top().functionalArgument is LambdaInfo) {
|
||||
toDelete.add(insn)
|
||||
}
|
||||
}
|
||||
Opcodes.SWAP -> {
|
||||
if (sources[instructions.indexOf(insn)]?.peek(0).functionalArgument is LambdaInfo ||
|
||||
sources[instructions.indexOf(insn)]?.peek(1).functionalArgument is LambdaInfo
|
||||
) {
|
||||
toDelete.add(insn)
|
||||
}
|
||||
}
|
||||
Opcodes.ALOAD -> {
|
||||
if (sources[instructions.indexOf(insn)]?.getLocal((insn as VarInsnNode).`var`).functionalArgument is LambdaInfo) {
|
||||
toDelete.add(insn)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Replace ALOAD 0
|
||||
// with
|
||||
// ICONST fakeContinuationMarker
|
||||
|
||||
@@ -62,48 +62,32 @@ internal class FunctionalArgumentValue(
|
||||
val BasicValue?.functionalArgument
|
||||
get() = (this as? FunctionalArgumentValue)?.functionalArgument
|
||||
|
||||
internal class FunctionalArgumentInterpreter(
|
||||
private val inliner: MethodInliner, private val toDelete: MutableSet<AbstractInsnNode>
|
||||
) : BasicInterpreter(Opcodes.API_VERSION) {
|
||||
|
||||
internal class FunctionalArgumentInterpreter(private val inliner: MethodInliner) : BasicInterpreter(Opcodes.API_VERSION) {
|
||||
override fun unaryOperation(insn: AbstractInsnNode, value: BasicValue): BasicValue? =
|
||||
markInstructionIfNeeded(insn, super.unaryOperation(insn, value))
|
||||
wrapArgumentInValueIfNeeded(insn, super.unaryOperation(insn, value))
|
||||
|
||||
override fun copyOperation(insn: AbstractInsnNode, value: BasicValue?): BasicValue? {
|
||||
val basicValue = super.copyOperation(insn, value)
|
||||
// Parameter checks are processed separately
|
||||
if (insn.next?.opcode == Opcodes.LDC && insn.next?.next?.isCheckParameterIsNotNull() == true) {
|
||||
return basicValue
|
||||
}
|
||||
if (value.functionalArgument is LambdaInfo) {
|
||||
// SWAP and ASTORE
|
||||
toDelete.add(insn)
|
||||
return value
|
||||
}
|
||||
return markInstructionIfNeeded(insn, basicValue)
|
||||
}
|
||||
|
||||
private fun markInstructionIfNeeded(
|
||||
insn: AbstractInsnNode,
|
||||
basicValue: BasicValue?
|
||||
): BasicValue? {
|
||||
val functionalArgument = inliner.getFunctionalArgumentIfExists(insn)
|
||||
return if (functionalArgument != null) {
|
||||
if (functionalArgument is LambdaInfo) {
|
||||
toDelete.add(insn)
|
||||
}
|
||||
FunctionalArgumentValue(functionalArgument, basicValue)
|
||||
} else basicValue
|
||||
}
|
||||
override fun copyOperation(insn: AbstractInsnNode, value: BasicValue?): BasicValue? =
|
||||
wrapArgumentInValueIfNeeded(insn, super.copyOperation(insn, value))
|
||||
|
||||
override fun newOperation(insn: AbstractInsnNode): BasicValue? =
|
||||
markInstructionIfNeeded(insn, super.newOperation(insn))
|
||||
wrapArgumentInValueIfNeeded(insn, super.newOperation(insn))
|
||||
|
||||
private fun wrapArgumentInValueIfNeeded(
|
||||
insn: AbstractInsnNode,
|
||||
basicValue: BasicValue?
|
||||
): BasicValue? =
|
||||
inliner.getFunctionalArgumentIfExists(insn)
|
||||
?.let { FunctionalArgumentValue(it, basicValue) }
|
||||
?: basicValue
|
||||
|
||||
override fun merge(v: BasicValue?, w: BasicValue?): BasicValue? =
|
||||
if (v is FunctionalArgumentValue && w is FunctionalArgumentValue && v.functionalArgument == w.functionalArgument) v
|
||||
else super.merge(v, w)
|
||||
}
|
||||
|
||||
internal fun AbstractInsnNode.isAloadBeforeCheckParameterIsNotNull(): Boolean =
|
||||
opcode == Opcodes.ALOAD && next?.opcode == Opcodes.LDC && next?.next?.isCheckParameterIsNotNull() == true
|
||||
|
||||
// Interpreter, that analyzes only ALOAD_0s, which are used as continuation arguments
|
||||
|
||||
internal class Aload0BasicValue private constructor(val indices: Set<Int>) : BasicValue(AsmTypes.OBJECT_TYPE) {
|
||||
|
||||
Reference in New Issue
Block a user