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.isBeforeInlineMarker
|
||||||
import org.jetbrains.kotlin.codegen.inline.isMarkedReturn
|
import org.jetbrains.kotlin.codegen.inline.isMarkedReturn
|
||||||
import org.jetbrains.kotlin.codegen.optimization.common.FlexibleMethodAnalyzer
|
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.codegen.pseudoInsns.PseudoInsn
|
||||||
import org.jetbrains.kotlin.utils.SmartList
|
import org.jetbrains.kotlin.utils.SmartList
|
||||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
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.LabelNode
|
||||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
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.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.Frame
|
||||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Interpreter
|
import org.jetbrains.org.objectweb.asm.tree.analysis.Interpreter
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
@@ -50,9 +48,14 @@ internal class FixStackAnalyzer(
|
|||||||
|
|
||||||
val maxExtraStackSize: Int get() = analyzer.maxExtraStackSize
|
val maxExtraStackSize: Int get() = analyzer.maxExtraStackSize
|
||||||
|
|
||||||
fun getStackToSpill(location: AbstractInsnNode) = analyzer.spilledStacks[location]
|
fun getStackToSpill(location: AbstractInsnNode): List<FixStackValue>? =
|
||||||
fun getActualStack(location: AbstractInsnNode) = getFrame(location)?.getStackContent()
|
analyzer.spilledStacks[location]
|
||||||
fun getActualStackSize(location: AbstractInsnNode) = getFrame(location)?.stackSizeWithExtra ?: DEAD_CODE_STACK_SIZE
|
|
||||||
|
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 {
|
fun getExpectedStackSize(location: AbstractInsnNode): Int {
|
||||||
// We should look for expected stack size at loop entry point markers if available,
|
// 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 val analyzer = InternalAnalyzer(owner)
|
||||||
|
|
||||||
private inner class InternalAnalyzer(owner: String) :
|
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
|
var maxExtraStackSize = 0; private set
|
||||||
|
|
||||||
override fun visitControlFlowEdge(insn: Int, successor: Int): Boolean {
|
override fun visitControlFlowEdge(insn: Int, successor: Int): Boolean {
|
||||||
@@ -101,15 +104,15 @@ internal class FixStackAnalyzer(
|
|||||||
return !(insnNode is JumpInsnNode && context.breakContinueGotoNodes.contains(insnNode))
|
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)
|
FixStackFrame(nLocals, nStack)
|
||||||
|
|
||||||
private fun indexOf(node: AbstractInsnNode) = method.instructions.indexOf(node)
|
private fun indexOf(node: AbstractInsnNode) = method.instructions.indexOf(node)
|
||||||
|
|
||||||
inner class FixStackFrame(nLocals: Int, nStack: Int) : Frame<BasicValue>(nLocals, nStack) {
|
inner class FixStackFrame(nLocals: Int, nStack: Int) : Frame<FixStackValue>(nLocals, nStack) {
|
||||||
val extraStack = Stack<BasicValue>()
|
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.clear()
|
||||||
extraStack.addAll((src as FixStackFrame).extraStack)
|
extraStack.addAll((src as FixStackFrame).extraStack)
|
||||||
return super.init(src)
|
return super.init(src)
|
||||||
@@ -120,7 +123,7 @@ internal class FixStackAnalyzer(
|
|||||||
super.clearStack()
|
super.clearStack()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun execute(insn: AbstractInsnNode, interpreter: Interpreter<BasicValue>) {
|
override fun execute(insn: AbstractInsnNode, interpreter: Interpreter<FixStackValue>) {
|
||||||
when {
|
when {
|
||||||
PseudoInsn.SAVE_STACK_BEFORE_TRY.isa(insn) ->
|
PseudoInsn.SAVE_STACK_BEFORE_TRY.isa(insn) ->
|
||||||
executeSaveStackBeforeTry(insn)
|
executeSaveStackBeforeTry(insn)
|
||||||
@@ -141,14 +144,14 @@ internal class FixStackAnalyzer(
|
|||||||
|
|
||||||
val stackSizeWithExtra: Int get() = super.getStackSize() + extraStack.size
|
val stackSizeWithExtra: Int get() = super.getStackSize() + extraStack.size
|
||||||
|
|
||||||
fun getStackContent(): List<BasicValue> {
|
fun getStackContent(): List<FixStackValue> {
|
||||||
val savedStack = arrayListOf<BasicValue>()
|
val savedStack = ArrayList<FixStackValue>()
|
||||||
IntRange(0, super.getStackSize() - 1).mapTo(savedStack) { super.getStack(it) }
|
IntRange(0, super.getStackSize() - 1).mapTo(savedStack) { super.getStack(it) }
|
||||||
savedStack.addAll(extraStack)
|
savedStack.addAll(extraStack)
|
||||||
return savedStack
|
return savedStack
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun push(value: BasicValue) {
|
override fun push(value: FixStackValue?) {
|
||||||
if (super.getStackSize() < maxStackSize) {
|
if (super.getStackSize() < maxStackSize) {
|
||||||
super.push(value)
|
super.push(value)
|
||||||
} else {
|
} else {
|
||||||
@@ -157,19 +160,18 @@ internal class FixStackAnalyzer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun pushAll(values: Collection<BasicValue>) {
|
fun pushAll(values: Collection<FixStackValue>) {
|
||||||
values.forEach { push(it) }
|
values.forEach { push(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun pop(): BasicValue {
|
override fun pop(): FixStackValue? =
|
||||||
return if (extraStack.isNotEmpty()) {
|
if (extraStack.isNotEmpty()) {
|
||||||
extraStack.pop()
|
extraStack.pop()
|
||||||
} else {
|
} else {
|
||||||
super.pop()
|
super.pop()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun setStack(i: Int, value: BasicValue) {
|
override fun setStack(i: Int, value: FixStackValue) {
|
||||||
if (i < super.getMaxStackSize()) {
|
if (i < super.getMaxStackSize()) {
|
||||||
super.setStack(i, value)
|
super.setStack(i, value)
|
||||||
} else {
|
} 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
|
val other = frame as FixStackFrame
|
||||||
if (stackSizeWithExtra != other.stackSizeWithExtra) {
|
if (stackSizeWithExtra != other.stackSizeWithExtra) {
|
||||||
throw AnalyzerException(null, "Incompatible stack heights")
|
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.AbstractInsnNode
|
||||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||||
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
|
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
|
|
||||||
internal class LocalVariablesManager(val context: FixStackContext, val methodNode: MethodNode) {
|
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)
|
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
|
val numRestoreStackMarkers = context.restoreStackMarkersForSaveMarker[saveStackMarker]!!.size
|
||||||
return allocateNewHandle(numRestoreStackMarkers, saveStackMarker, savedStackValues)
|
return allocateNewHandle(numRestoreStackMarkers, saveStackMarker, savedStackValues)
|
||||||
}
|
}
|
||||||
@@ -47,12 +49,8 @@ internal class LocalVariablesManager(val context: FixStackContext, val methodNod
|
|||||||
private fun allocateNewHandle(
|
private fun allocateNewHandle(
|
||||||
numRestoreStackMarkers: Int,
|
numRestoreStackMarkers: Int,
|
||||||
saveStackMarker: AbstractInsnNode,
|
saveStackMarker: AbstractInsnNode,
|
||||||
savedStackValues: List<BasicValue>
|
savedStackValues: List<FixStackValue>
|
||||||
): SavedStackDescriptor {
|
): SavedStackDescriptor {
|
||||||
if (savedStackValues.any { it.type == null }) {
|
|
||||||
throw AssertionError("Uninitialized value on stack at ${methodNode.instructions.indexOf(saveStackMarker)}")
|
|
||||||
}
|
|
||||||
|
|
||||||
val firstUnusedLocalVarIndex = getFirstUnusedLocalVariableIndex()
|
val firstUnusedLocalVarIndex = getFirstUnusedLocalVariableIndex()
|
||||||
val savedStackDescriptor = SavedStackDescriptor(savedStackValues, firstUnusedLocalVarIndex)
|
val savedStackDescriptor = SavedStackDescriptor(savedStackValues, firstUnusedLocalVarIndex)
|
||||||
updateMaxLocals(savedStackDescriptor.firstUnusedLocalVarIndex)
|
updateMaxLocals(savedStackDescriptor.firstUnusedLocalVarIndex)
|
||||||
@@ -78,7 +76,7 @@ internal class LocalVariablesManager(val context: FixStackContext, val methodNod
|
|||||||
|
|
||||||
fun allocateVariablesForBeforeInlineMarker(
|
fun allocateVariablesForBeforeInlineMarker(
|
||||||
beforeInlineMarker: AbstractInsnNode,
|
beforeInlineMarker: AbstractInsnNode,
|
||||||
savedStackValues: List<BasicValue>
|
savedStackValues: List<FixStackValue>
|
||||||
): SavedStackDescriptor {
|
): SavedStackDescriptor {
|
||||||
return allocateNewHandle(1, beforeInlineMarker, savedStackValues)
|
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()
|
val returnValueIndex = getFirstUnusedLocalVariableIndex()
|
||||||
updateMaxLocals(returnValueIndex + returnValue.size)
|
updateMaxLocals(returnValueIndex + returnValue.size)
|
||||||
return returnValueIndex
|
return returnValueIndex
|
||||||
|
|||||||
+9
-15
@@ -54,10 +54,10 @@ fun <V : Value> Frame<V>.peekWords(size1: Int, size2: Int): List<V>? {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class SavedStackDescriptor(
|
class SavedStackDescriptor(
|
||||||
val savedValues: List<BasicValue>,
|
val savedValues: List<FixStackValue>,
|
||||||
val firstLocalVarIndex: Int
|
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
|
val firstUnusedLocalVarIndex = firstLocalVarIndex + savedValuesSize
|
||||||
|
|
||||||
override fun toString(): String =
|
override fun toString(): String =
|
||||||
@@ -88,13 +88,13 @@ fun restoreStackWithReturnValue(
|
|||||||
methodNode: MethodNode,
|
methodNode: MethodNode,
|
||||||
nodeToReplace: AbstractInsnNode,
|
nodeToReplace: AbstractInsnNode,
|
||||||
savedStackDescriptor: SavedStackDescriptor,
|
savedStackDescriptor: SavedStackDescriptor,
|
||||||
returnValue: BasicValue,
|
returnValue: FixStackValue,
|
||||||
returnValueLocalVarIndex: Int
|
returnValueLocalVarIndex: Int
|
||||||
) {
|
) {
|
||||||
with(methodNode.instructions) {
|
with(methodNode.instructions) {
|
||||||
insertBefore(nodeToReplace, VarInsnNode(returnValue.type.getOpcode(Opcodes.ISTORE), returnValueLocalVarIndex))
|
insertBefore(nodeToReplace, VarInsnNode(returnValue.storeOpcode, returnValueLocalVarIndex))
|
||||||
generateLoadInstructions(methodNode, nodeToReplace, savedStackDescriptor)
|
generateLoadInstructions(methodNode, nodeToReplace, savedStackDescriptor)
|
||||||
insertBefore(nodeToReplace, VarInsnNode(returnValue.type.getOpcode(Opcodes.ILOAD), returnValueLocalVarIndex))
|
insertBefore(nodeToReplace, VarInsnNode(returnValue.loadOpcode, returnValueLocalVarIndex))
|
||||||
remove(nodeToReplace)
|
remove(nodeToReplace)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -102,10 +102,7 @@ fun restoreStackWithReturnValue(
|
|||||||
fun generateLoadInstructions(methodNode: MethodNode, location: AbstractInsnNode, savedStackDescriptor: SavedStackDescriptor) {
|
fun generateLoadInstructions(methodNode: MethodNode, location: AbstractInsnNode, savedStackDescriptor: SavedStackDescriptor) {
|
||||||
var localVarIndex = savedStackDescriptor.firstLocalVarIndex
|
var localVarIndex = savedStackDescriptor.firstLocalVarIndex
|
||||||
for (value in savedStackDescriptor.savedValues) {
|
for (value in savedStackDescriptor.savedValues) {
|
||||||
methodNode.instructions.insertBefore(
|
methodNode.instructions.insertBefore(location, VarInsnNode(value.loadOpcode, localVarIndex))
|
||||||
location,
|
|
||||||
VarInsnNode(value.type.getOpcode(Opcodes.ILOAD), localVarIndex)
|
|
||||||
)
|
|
||||||
localVarIndex += value.size
|
localVarIndex += value.size
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -114,10 +111,7 @@ fun generateStoreInstructions(methodNode: MethodNode, location: AbstractInsnNode
|
|||||||
var localVarIndex = savedStackDescriptor.firstUnusedLocalVarIndex
|
var localVarIndex = savedStackDescriptor.firstUnusedLocalVarIndex
|
||||||
for (value in savedStackDescriptor.savedValues.asReversed()) {
|
for (value in savedStackDescriptor.savedValues.asReversed()) {
|
||||||
localVarIndex -= value.size
|
localVarIndex -= value.size
|
||||||
methodNode.instructions.insertBefore(
|
methodNode.instructions.insertBefore(location, VarInsnNode(value.storeOpcode, localVarIndex))
|
||||||
location,
|
|
||||||
VarInsnNode(value.type.getOpcode(Opcodes.ISTORE), 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) {
|
with(methodNode.instructions) {
|
||||||
for (stackValue in stackContent.subList(expectedStackSize, stackContent.size)) {
|
for (stackValue in stackContent.subList(expectedStackSize, stackContent.size)) {
|
||||||
insert(node, getPopInstruction(stackValue))
|
insert(node, InsnNode(stackValue.popOpcode))
|
||||||
}
|
}
|
||||||
remove(node)
|
remove(node)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user