Make FunctionalArgumentInterpreter stateless

So, we can use fast basic interpreter.
This commit is contained in:
Ilmir Usmanov
2022-03-03 00:25:16 +01:00
committed by teamcity
parent eb42a01926
commit f89588011e
2 changed files with 55 additions and 33 deletions
@@ -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) {