JVM FixStackValue & FixStackInterpreter
This commit is contained in:
committed by
teamcityserver
parent
8eb7e719d3
commit
3ecd612ce7
+23
-21
@@ -21,7 +21,6 @@ import org.jetbrains.kotlin.codegen.inline.isAfterInlineMarker
|
||||
import org.jetbrains.kotlin.codegen.inline.isBeforeInlineMarker
|
||||
import org.jetbrains.kotlin.codegen.inline.isMarkedReturn
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.FlexibleMethodAnalyzer
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
|
||||
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
@@ -30,7 +29,6 @@ import org.jetbrains.org.objectweb.asm.tree.JumpInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.LabelNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Interpreter
|
||||
import kotlin.math.max
|
||||
@@ -50,9 +48,14 @@ internal class FixStackAnalyzer(
|
||||
|
||||
val maxExtraStackSize: Int get() = analyzer.maxExtraStackSize
|
||||
|
||||
fun getStackToSpill(location: AbstractInsnNode) = analyzer.spilledStacks[location]
|
||||
fun getActualStack(location: AbstractInsnNode) = getFrame(location)?.getStackContent()
|
||||
fun getActualStackSize(location: AbstractInsnNode) = getFrame(location)?.stackSizeWithExtra ?: DEAD_CODE_STACK_SIZE
|
||||
fun getStackToSpill(location: AbstractInsnNode): List<FixStackValue>? =
|
||||
analyzer.spilledStacks[location]
|
||||
|
||||
fun getActualStack(location: AbstractInsnNode): List<FixStackValue>? =
|
||||
getFrame(location)?.getStackContent()
|
||||
|
||||
fun getActualStackSize(location: AbstractInsnNode): Int =
|
||||
getFrame(location)?.stackSizeWithExtra ?: DEAD_CODE_STACK_SIZE
|
||||
|
||||
fun getExpectedStackSize(location: AbstractInsnNode): Int {
|
||||
// We should look for expected stack size at loop entry point markers if available,
|
||||
@@ -90,9 +93,9 @@ internal class FixStackAnalyzer(
|
||||
private val analyzer = InternalAnalyzer(owner)
|
||||
|
||||
private inner class InternalAnalyzer(owner: String) :
|
||||
FlexibleMethodAnalyzer<BasicValue>(owner, method, OptimizationBasicInterpreter()) {
|
||||
FlexibleMethodAnalyzer<FixStackValue>(owner, method, FixStackInterpreter()) {
|
||||
|
||||
val spilledStacks = hashMapOf<AbstractInsnNode, List<BasicValue>>()
|
||||
val spilledStacks = hashMapOf<AbstractInsnNode, List<FixStackValue>>()
|
||||
var maxExtraStackSize = 0; private set
|
||||
|
||||
override fun visitControlFlowEdge(insn: Int, successor: Int): Boolean {
|
||||
@@ -101,15 +104,15 @@ internal class FixStackAnalyzer(
|
||||
return !(insnNode is JumpInsnNode && context.breakContinueGotoNodes.contains(insnNode))
|
||||
}
|
||||
|
||||
override fun newFrame(nLocals: Int, nStack: Int): Frame<BasicValue> =
|
||||
override fun newFrame(nLocals: Int, nStack: Int): Frame<FixStackValue> =
|
||||
FixStackFrame(nLocals, nStack)
|
||||
|
||||
private fun indexOf(node: AbstractInsnNode) = method.instructions.indexOf(node)
|
||||
|
||||
inner class FixStackFrame(nLocals: Int, nStack: Int) : Frame<BasicValue>(nLocals, nStack) {
|
||||
val extraStack = Stack<BasicValue>()
|
||||
inner class FixStackFrame(nLocals: Int, nStack: Int) : Frame<FixStackValue>(nLocals, nStack) {
|
||||
val extraStack = Stack<FixStackValue>()
|
||||
|
||||
override fun init(src: Frame<out BasicValue>): Frame<BasicValue> {
|
||||
override fun init(src: Frame<out FixStackValue>): Frame<FixStackValue> {
|
||||
extraStack.clear()
|
||||
extraStack.addAll((src as FixStackFrame).extraStack)
|
||||
return super.init(src)
|
||||
@@ -120,7 +123,7 @@ internal class FixStackAnalyzer(
|
||||
super.clearStack()
|
||||
}
|
||||
|
||||
override fun execute(insn: AbstractInsnNode, interpreter: Interpreter<BasicValue>) {
|
||||
override fun execute(insn: AbstractInsnNode, interpreter: Interpreter<FixStackValue>) {
|
||||
when {
|
||||
PseudoInsn.SAVE_STACK_BEFORE_TRY.isa(insn) ->
|
||||
executeSaveStackBeforeTry(insn)
|
||||
@@ -141,14 +144,14 @@ internal class FixStackAnalyzer(
|
||||
|
||||
val stackSizeWithExtra: Int get() = super.getStackSize() + extraStack.size
|
||||
|
||||
fun getStackContent(): List<BasicValue> {
|
||||
val savedStack = arrayListOf<BasicValue>()
|
||||
fun getStackContent(): List<FixStackValue> {
|
||||
val savedStack = ArrayList<FixStackValue>()
|
||||
IntRange(0, super.getStackSize() - 1).mapTo(savedStack) { super.getStack(it) }
|
||||
savedStack.addAll(extraStack)
|
||||
return savedStack
|
||||
}
|
||||
|
||||
override fun push(value: BasicValue) {
|
||||
override fun push(value: FixStackValue?) {
|
||||
if (super.getStackSize() < maxStackSize) {
|
||||
super.push(value)
|
||||
} else {
|
||||
@@ -157,19 +160,18 @@ internal class FixStackAnalyzer(
|
||||
}
|
||||
}
|
||||
|
||||
fun pushAll(values: Collection<BasicValue>) {
|
||||
fun pushAll(values: Collection<FixStackValue>) {
|
||||
values.forEach { push(it) }
|
||||
}
|
||||
|
||||
override fun pop(): BasicValue {
|
||||
return if (extraStack.isNotEmpty()) {
|
||||
override fun pop(): FixStackValue? =
|
||||
if (extraStack.isNotEmpty()) {
|
||||
extraStack.pop()
|
||||
} else {
|
||||
super.pop()
|
||||
}
|
||||
}
|
||||
|
||||
override fun setStack(i: Int, value: BasicValue) {
|
||||
override fun setStack(i: Int, value: FixStackValue) {
|
||||
if (i < super.getMaxStackSize()) {
|
||||
super.setStack(i, value)
|
||||
} else {
|
||||
@@ -177,7 +179,7 @@ internal class FixStackAnalyzer(
|
||||
}
|
||||
}
|
||||
|
||||
override fun merge(frame: Frame<out BasicValue>, interpreter: Interpreter<BasicValue>): Boolean {
|
||||
override fun merge(frame: Frame<out FixStackValue>, interpreter: Interpreter<FixStackValue>): Boolean {
|
||||
val other = frame as FixStackFrame
|
||||
if (stackSizeWithExtra != other.stackSizeWithExtra) {
|
||||
throw AnalyzerException(null, "Incompatible stack heights")
|
||||
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.optimization.fixStack
|
||||
|
||||
import org.jetbrains.kotlin.codegen.inline.insnOpcodeText
|
||||
import org.jetbrains.org.objectweb.asm.Handle
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.*
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Interpreter
|
||||
|
||||
open class FixStackInterpreter : Interpreter<FixStackValue>(API_VERSION) {
|
||||
|
||||
override fun newValue(type: Type?): FixStackValue? =
|
||||
type?.toFixStackValue()
|
||||
|
||||
override fun newOperation(insn: AbstractInsnNode): FixStackValue? =
|
||||
when (insn.opcode) {
|
||||
ACONST_NULL ->
|
||||
FixStackValue.OBJECT
|
||||
ICONST_M1, ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5 ->
|
||||
FixStackValue.INT
|
||||
LCONST_0, LCONST_1 ->
|
||||
FixStackValue.LONG
|
||||
FCONST_0, FCONST_1, FCONST_2 ->
|
||||
FixStackValue.FLOAT
|
||||
DCONST_0, DCONST_1 ->
|
||||
FixStackValue.DOUBLE
|
||||
BIPUSH, SIPUSH ->
|
||||
FixStackValue.INT
|
||||
LDC -> {
|
||||
val cst = (insn as LdcInsnNode).cst
|
||||
if (cst is Int) {
|
||||
FixStackValue.INT
|
||||
} else if (cst is Float) {
|
||||
FixStackValue.FLOAT
|
||||
} else if (cst is Long) {
|
||||
FixStackValue.LONG
|
||||
} else if (cst is Double) {
|
||||
FixStackValue.DOUBLE
|
||||
} else if (cst is String) {
|
||||
FixStackValue.OBJECT
|
||||
} else if (cst is Type) {
|
||||
val sort = cst.sort
|
||||
if (sort == Type.OBJECT || sort == Type.ARRAY || sort == Type.METHOD) {
|
||||
FixStackValue.OBJECT
|
||||
} else {
|
||||
throw IllegalArgumentException("Illegal LDC constant $cst")
|
||||
}
|
||||
} else if (cst is Handle) {
|
||||
FixStackValue.OBJECT
|
||||
} else {
|
||||
throw IllegalArgumentException("Illegal LDC constant $cst")
|
||||
}
|
||||
}
|
||||
GETSTATIC ->
|
||||
newValue(Type.getType((insn as FieldInsnNode).desc))
|
||||
NEW ->
|
||||
newValue(Type.getObjectType((insn as TypeInsnNode).desc))
|
||||
else ->
|
||||
throw IllegalArgumentException("Unexpected instruction: " + insn.insnOpcodeText)
|
||||
}
|
||||
|
||||
override fun copyOperation(insn: AbstractInsnNode, value: FixStackValue?): FixStackValue? =
|
||||
value
|
||||
|
||||
override fun binaryOperation(insn: AbstractInsnNode, value1: FixStackValue?, value2: FixStackValue?): FixStackValue? =
|
||||
when (insn.opcode) {
|
||||
IALOAD, BALOAD, CALOAD, SALOAD, IADD, ISUB, IMUL, IDIV, IREM, ISHL, ISHR, IUSHR, IAND, IOR, IXOR ->
|
||||
FixStackValue.INT
|
||||
FALOAD, FADD, FSUB, FMUL, FDIV, FREM ->
|
||||
FixStackValue.FLOAT
|
||||
LALOAD, LADD, LSUB, LMUL, LDIV, LREM, LSHL, LSHR, LUSHR, LAND, LOR, LXOR ->
|
||||
FixStackValue.LONG
|
||||
DALOAD, DADD, DSUB, DMUL, DDIV, DREM ->
|
||||
FixStackValue.DOUBLE
|
||||
AALOAD ->
|
||||
FixStackValue.OBJECT
|
||||
LCMP, FCMPL, FCMPG, DCMPL, DCMPG ->
|
||||
FixStackValue.INT
|
||||
IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE, PUTFIELD ->
|
||||
null
|
||||
else ->
|
||||
throw IllegalArgumentException("Unexpected instruction: " + insn.insnOpcodeText)
|
||||
}
|
||||
|
||||
override fun ternaryOperation(
|
||||
insn: AbstractInsnNode,
|
||||
value1: FixStackValue?,
|
||||
value2: FixStackValue?,
|
||||
value3: FixStackValue?
|
||||
): FixStackValue? =
|
||||
null
|
||||
|
||||
override fun naryOperation(insn: AbstractInsnNode, values: List<FixStackValue?>): FixStackValue? =
|
||||
when (insn.opcode) {
|
||||
MULTIANEWARRAY ->
|
||||
newValue(Type.getType((insn as MultiANewArrayInsnNode).desc))
|
||||
INVOKEDYNAMIC ->
|
||||
newValue(Type.getReturnType((insn as InvokeDynamicInsnNode).desc))
|
||||
else ->
|
||||
newValue(Type.getReturnType((insn as MethodInsnNode).desc))
|
||||
}
|
||||
|
||||
override fun returnOperation(insn: AbstractInsnNode?, value: FixStackValue?, expected: FixStackValue?) {
|
||||
}
|
||||
|
||||
override fun unaryOperation(insn: AbstractInsnNode, value: FixStackValue?): FixStackValue? =
|
||||
when (insn.opcode) {
|
||||
INEG, IINC, L2I, F2I, D2I, I2B, I2C, I2S ->
|
||||
FixStackValue.INT
|
||||
FNEG, I2F, L2F, D2F ->
|
||||
FixStackValue.FLOAT
|
||||
LNEG, I2L, F2L, D2L ->
|
||||
FixStackValue.LONG
|
||||
DNEG, I2D, L2D, F2D ->
|
||||
FixStackValue.DOUBLE
|
||||
IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, TABLESWITCH, LOOKUPSWITCH, IRETURN, LRETURN, FRETURN, DRETURN, ARETURN, PUTSTATIC ->
|
||||
null
|
||||
GETFIELD ->
|
||||
newValue(Type.getType((insn as FieldInsnNode).desc))
|
||||
NEWARRAY ->
|
||||
FixStackValue.OBJECT
|
||||
ANEWARRAY -> {
|
||||
FixStackValue.OBJECT
|
||||
}
|
||||
ARRAYLENGTH ->
|
||||
FixStackValue.INT
|
||||
ATHROW ->
|
||||
null
|
||||
CHECKCAST ->
|
||||
FixStackValue.OBJECT
|
||||
INSTANCEOF ->
|
||||
FixStackValue.INT
|
||||
MONITORENTER, MONITOREXIT, IFNULL, IFNONNULL ->
|
||||
null
|
||||
else ->
|
||||
throw IllegalArgumentException("Unexpected instruction: " + insn.insnOpcodeText)
|
||||
}
|
||||
|
||||
override fun merge(v: FixStackValue?, w: FixStackValue?): FixStackValue? =
|
||||
when {
|
||||
v == w -> v
|
||||
v == null -> w
|
||||
w == null -> v
|
||||
else -> throw AssertionError("Mismatching value kinds: $v != $w")
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.optimization.fixStack
|
||||
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Value
|
||||
|
||||
enum class FixStackValue(
|
||||
private val _size: Int,
|
||||
val loadOpcode: Int,
|
||||
val storeOpcode: Int,
|
||||
val popOpcode: Int
|
||||
) : Value {
|
||||
INT(1, Opcodes.ILOAD, Opcodes.ISTORE, Opcodes.POP),
|
||||
LONG(2, Opcodes.LLOAD, Opcodes.LSTORE, Opcodes.POP2),
|
||||
FLOAT(1, Opcodes.FLOAD, Opcodes.FSTORE, Opcodes.POP),
|
||||
DOUBLE(2, Opcodes.DLOAD, Opcodes.DSTORE, Opcodes.POP2),
|
||||
OBJECT(1, Opcodes.ALOAD, Opcodes.ASTORE, Opcodes.POP)
|
||||
;
|
||||
|
||||
override fun getSize(): Int = _size
|
||||
}
|
||||
|
||||
fun Type.toFixStackValue(): FixStackValue? =
|
||||
when (this.sort) {
|
||||
Type.VOID -> null
|
||||
Type.BOOLEAN, Type.BYTE, Type.CHAR, Type.SHORT, Type.INT -> FixStackValue.INT
|
||||
Type.LONG -> FixStackValue.LONG
|
||||
Type.FLOAT -> FixStackValue.FLOAT
|
||||
Type.DOUBLE -> FixStackValue.DOUBLE
|
||||
Type.OBJECT, Type.ARRAY, Type.METHOD -> FixStackValue.OBJECT
|
||||
else -> throw AssertionError("Unexpected type: $this")
|
||||
}
|
||||
+7
-9
@@ -18,7 +18,6 @@ package org.jetbrains.kotlin.codegen.optimization.fixStack
|
||||
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
|
||||
import kotlin.math.max
|
||||
|
||||
internal class LocalVariablesManager(val context: FixStackContext, val methodNode: MethodNode) {
|
||||
@@ -39,7 +38,10 @@ internal class LocalVariablesManager(val context: FixStackContext, val methodNod
|
||||
methodNode.maxLocals = max(methodNode.maxLocals, newValue)
|
||||
}
|
||||
|
||||
fun allocateVariablesForSaveStackMarker(saveStackMarker: AbstractInsnNode, savedStackValues: List<BasicValue>): SavedStackDescriptor {
|
||||
fun allocateVariablesForSaveStackMarker(
|
||||
saveStackMarker: AbstractInsnNode,
|
||||
savedStackValues: List<FixStackValue>
|
||||
): SavedStackDescriptor {
|
||||
val numRestoreStackMarkers = context.restoreStackMarkersForSaveMarker[saveStackMarker]!!.size
|
||||
return allocateNewHandle(numRestoreStackMarkers, saveStackMarker, savedStackValues)
|
||||
}
|
||||
@@ -47,12 +49,8 @@ internal class LocalVariablesManager(val context: FixStackContext, val methodNod
|
||||
private fun allocateNewHandle(
|
||||
numRestoreStackMarkers: Int,
|
||||
saveStackMarker: AbstractInsnNode,
|
||||
savedStackValues: List<BasicValue>
|
||||
savedStackValues: List<FixStackValue>
|
||||
): SavedStackDescriptor {
|
||||
if (savedStackValues.any { it.type == null }) {
|
||||
throw AssertionError("Uninitialized value on stack at ${methodNode.instructions.indexOf(saveStackMarker)}")
|
||||
}
|
||||
|
||||
val firstUnusedLocalVarIndex = getFirstUnusedLocalVariableIndex()
|
||||
val savedStackDescriptor = SavedStackDescriptor(savedStackValues, firstUnusedLocalVarIndex)
|
||||
updateMaxLocals(savedStackDescriptor.firstUnusedLocalVarIndex)
|
||||
@@ -78,7 +76,7 @@ internal class LocalVariablesManager(val context: FixStackContext, val methodNod
|
||||
|
||||
fun allocateVariablesForBeforeInlineMarker(
|
||||
beforeInlineMarker: AbstractInsnNode,
|
||||
savedStackValues: List<BasicValue>
|
||||
savedStackValues: List<FixStackValue>
|
||||
): SavedStackDescriptor {
|
||||
return allocateNewHandle(1, beforeInlineMarker, savedStackValues)
|
||||
}
|
||||
@@ -101,7 +99,7 @@ internal class LocalVariablesManager(val context: FixStackContext, val methodNod
|
||||
}
|
||||
}
|
||||
|
||||
fun createReturnValueVariable(returnValue: BasicValue): Int {
|
||||
fun createReturnValueVariable(returnValue: FixStackValue): Int {
|
||||
val returnValueIndex = getFirstUnusedLocalVariableIndex()
|
||||
updateMaxLocals(returnValueIndex + returnValue.size)
|
||||
return returnValueIndex
|
||||
|
||||
+9
-15
@@ -54,10 +54,10 @@ fun <V : Value> Frame<V>.peekWords(size1: Int, size2: Int): List<V>? {
|
||||
}
|
||||
|
||||
class SavedStackDescriptor(
|
||||
val savedValues: List<BasicValue>,
|
||||
val savedValues: List<FixStackValue>,
|
||||
val firstLocalVarIndex: Int
|
||||
) {
|
||||
private val savedValuesSize = savedValues.fold(0, { size, value -> size + value.size })
|
||||
private val savedValuesSize = savedValues.fold(0) { size, value -> size + value.size }
|
||||
val firstUnusedLocalVarIndex = firstLocalVarIndex + savedValuesSize
|
||||
|
||||
override fun toString(): String =
|
||||
@@ -88,13 +88,13 @@ fun restoreStackWithReturnValue(
|
||||
methodNode: MethodNode,
|
||||
nodeToReplace: AbstractInsnNode,
|
||||
savedStackDescriptor: SavedStackDescriptor,
|
||||
returnValue: BasicValue,
|
||||
returnValue: FixStackValue,
|
||||
returnValueLocalVarIndex: Int
|
||||
) {
|
||||
with(methodNode.instructions) {
|
||||
insertBefore(nodeToReplace, VarInsnNode(returnValue.type.getOpcode(Opcodes.ISTORE), returnValueLocalVarIndex))
|
||||
insertBefore(nodeToReplace, VarInsnNode(returnValue.storeOpcode, returnValueLocalVarIndex))
|
||||
generateLoadInstructions(methodNode, nodeToReplace, savedStackDescriptor)
|
||||
insertBefore(nodeToReplace, VarInsnNode(returnValue.type.getOpcode(Opcodes.ILOAD), returnValueLocalVarIndex))
|
||||
insertBefore(nodeToReplace, VarInsnNode(returnValue.loadOpcode, returnValueLocalVarIndex))
|
||||
remove(nodeToReplace)
|
||||
}
|
||||
}
|
||||
@@ -102,10 +102,7 @@ fun restoreStackWithReturnValue(
|
||||
fun generateLoadInstructions(methodNode: MethodNode, location: AbstractInsnNode, savedStackDescriptor: SavedStackDescriptor) {
|
||||
var localVarIndex = savedStackDescriptor.firstLocalVarIndex
|
||||
for (value in savedStackDescriptor.savedValues) {
|
||||
methodNode.instructions.insertBefore(
|
||||
location,
|
||||
VarInsnNode(value.type.getOpcode(Opcodes.ILOAD), localVarIndex)
|
||||
)
|
||||
methodNode.instructions.insertBefore(location, VarInsnNode(value.loadOpcode, localVarIndex))
|
||||
localVarIndex += value.size
|
||||
}
|
||||
}
|
||||
@@ -114,10 +111,7 @@ fun generateStoreInstructions(methodNode: MethodNode, location: AbstractInsnNode
|
||||
var localVarIndex = savedStackDescriptor.firstUnusedLocalVarIndex
|
||||
for (value in savedStackDescriptor.savedValues.asReversed()) {
|
||||
localVarIndex -= value.size
|
||||
methodNode.instructions.insertBefore(
|
||||
location,
|
||||
VarInsnNode(value.type.getOpcode(Opcodes.ISTORE), localVarIndex)
|
||||
)
|
||||
methodNode.instructions.insertBefore(location, VarInsnNode(value.storeOpcode, localVarIndex))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,10 +140,10 @@ fun replaceAlwaysTrueIfeqWithGoto(methodNode: MethodNode, node: AbstractInsnNode
|
||||
}
|
||||
}
|
||||
|
||||
fun replaceMarkerWithPops(methodNode: MethodNode, node: AbstractInsnNode, expectedStackSize: Int, stackContent: List<BasicValue>) {
|
||||
fun replaceMarkerWithPops(methodNode: MethodNode, node: AbstractInsnNode, expectedStackSize: Int, stackContent: List<FixStackValue>) {
|
||||
with(methodNode.instructions) {
|
||||
for (stackValue in stackContent.subList(expectedStackSize, stackContent.size)) {
|
||||
insert(node, getPopInstruction(stackValue))
|
||||
insert(node, InsnNode(stackValue.popOpcode))
|
||||
}
|
||||
remove(node)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user