Handle DUPnXm instructions in PopBackwardPropagationTransformer
This commit is contained in:
+74
-42
@@ -17,8 +17,10 @@
|
|||||||
package org.jetbrains.kotlin.codegen.optimization.boxing
|
package org.jetbrains.kotlin.codegen.optimization.boxing
|
||||||
|
|
||||||
import org.jetbrains.kotlin.codegen.optimization.OptimizationMethodVisitor
|
import org.jetbrains.kotlin.codegen.optimization.OptimizationMethodVisitor
|
||||||
|
import org.jetbrains.kotlin.codegen.optimization.common.debugText
|
||||||
import org.jetbrains.kotlin.codegen.optimization.common.isLoadOperation
|
import org.jetbrains.kotlin.codegen.optimization.common.isLoadOperation
|
||||||
import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful
|
import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful
|
||||||
|
import org.jetbrains.kotlin.codegen.optimization.fixStack.peekWords
|
||||||
import org.jetbrains.kotlin.codegen.optimization.fixStack.top
|
import org.jetbrains.kotlin.codegen.optimization.fixStack.top
|
||||||
import org.jetbrains.kotlin.codegen.optimization.removeNodeGetNext
|
import org.jetbrains.kotlin.codegen.optimization.removeNodeGetNext
|
||||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||||
@@ -33,17 +35,9 @@ import java.util.*
|
|||||||
class PopBackwardPropagationTransformer : MethodTransformer() {
|
class PopBackwardPropagationTransformer : MethodTransformer() {
|
||||||
override fun transform(internalClassName: String, methodNode: MethodNode) {
|
override fun transform(internalClassName: String, methodNode: MethodNode) {
|
||||||
if (!OptimizationMethodVisitor.canBeOptimizedUsingSourceInterpreter(methodNode)) return
|
if (!OptimizationMethodVisitor.canBeOptimizedUsingSourceInterpreter(methodNode)) return
|
||||||
if (methodNode.instructions.toArray().any { it.isUnsafeStackInsn() }) return
|
|
||||||
Transformer(methodNode).transform()
|
Transformer(methodNode).transform()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO better stack operations analysis
|
|
||||||
private fun AbstractInsnNode.isUnsafeStackInsn() =
|
|
||||||
opcode == Opcodes.DUP_X1 ||
|
|
||||||
opcode == Opcodes.DUP_X2 ||
|
|
||||||
opcode == Opcodes.DUP2_X1 ||
|
|
||||||
opcode == Opcodes.DUP2_X2
|
|
||||||
|
|
||||||
private class Transformer(val methodNode: MethodNode) {
|
private class Transformer(val methodNode: MethodNode) {
|
||||||
private interface Transformation {
|
private interface Transformation {
|
||||||
fun apply(insn: AbstractInsnNode)
|
fun apply(insn: AbstractInsnNode)
|
||||||
@@ -82,46 +76,84 @@ class PopBackwardPropagationTransformer : MethodTransformer() {
|
|||||||
postprocessNops()
|
postprocessNops()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun analyzeMethodBody(): Array<out Frame<SourceValue>?> =
|
private fun analyzeMethodBody(): Array<out Frame<SourceValue>?> {
|
||||||
Analyzer<SourceValue>(object : SourceInterpreter() {
|
val frames = Analyzer<SourceValue>(HazardsTrackingInterpreter()).analyze("fake", methodNode)
|
||||||
override fun naryOperation(insn: AbstractInsnNode, values: MutableList<out SourceValue>): SourceValue {
|
|
||||||
for (value in values) {
|
|
||||||
value.insns.markAsDontTouch()
|
|
||||||
}
|
|
||||||
return super.naryOperation(insn, values)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun copyOperation(insn: AbstractInsnNode, value: SourceValue): SourceValue {
|
postprocessDupNxM(frames)
|
||||||
value.insns.markAsDontTouch()
|
|
||||||
return super.copyOperation(insn, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun unaryOperation(insn: AbstractInsnNode, value: SourceValue): SourceValue {
|
return frames
|
||||||
if (insn.opcode != Opcodes.CHECKCAST && !insn.isPrimitiveTypeConversion()) {
|
}
|
||||||
value.insns.markAsDontTouch()
|
|
||||||
}
|
|
||||||
return super.unaryOperation(insn, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun binaryOperation(insn: AbstractInsnNode, value1: SourceValue, value2: SourceValue): SourceValue {
|
private fun postprocessDupNxM(frames: Array<out Frame<SourceValue>?>) {
|
||||||
value1.insns.markAsDontTouch()
|
val insns = methodNode.instructions.toArray()
|
||||||
value2.insns.markAsDontTouch()
|
for (i in frames.indices) {
|
||||||
return super.binaryOperation(insn, value1, value2)
|
val frame = frames[i] ?: continue
|
||||||
}
|
val insn = insns[i]
|
||||||
|
|
||||||
override fun ternaryOperation(insn: AbstractInsnNode, value1: SourceValue, value2: SourceValue, value3: SourceValue): SourceValue {
|
when (insn.opcode) {
|
||||||
value1.insns.markAsDontTouch()
|
Opcodes.DUP_X1 -> {
|
||||||
value2.insns.markAsDontTouch()
|
val top2 = frame.peekWords(1, 1) ?: throwIncorrectBytecode(insn, frame)
|
||||||
value3.insns.markAsDontTouch()
|
top2.forEach { it.insns.markAsDontTouch() }
|
||||||
return super.ternaryOperation(insn, value1, value2, value3)
|
|
||||||
}
|
}
|
||||||
|
Opcodes.DUP2_X1 -> {
|
||||||
|
val top3 = frame.peekWords(2, 1) ?: throwIncorrectBytecode(insn, frame)
|
||||||
|
top3.forEach { it.insns.markAsDontTouch() }
|
||||||
|
}
|
||||||
|
Opcodes.DUP_X2 -> {
|
||||||
|
val top3 = frame.peekWords(1, 2) ?: throwIncorrectBytecode(insn, frame)
|
||||||
|
top3.forEach { it.insns.markAsDontTouch() }
|
||||||
|
}
|
||||||
|
Opcodes.DUP2_X2 -> {
|
||||||
|
val top4 = frame.peekWords(2, 2) ?: throwIncorrectBytecode(insn, frame)
|
||||||
|
top4.forEach { it.insns.markAsDontTouch() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun Collection<AbstractInsnNode>.markAsDontTouch() {
|
private fun throwIncorrectBytecode(insn: AbstractInsnNode?, frame: Frame<SourceValue>): Nothing {
|
||||||
forEach {
|
throw AssertionError("Incorrect bytecode at ${methodNode.instructions.indexOf(insn)}: ${insn.debugText} $frame")
|
||||||
dontTouchInsnIndices[insnList.indexOf(it)] = true
|
}
|
||||||
}
|
|
||||||
}
|
private inner class HazardsTrackingInterpreter : SourceInterpreter() {
|
||||||
}).analyze("fake", methodNode)
|
override fun naryOperation(insn: AbstractInsnNode, values: MutableList<out SourceValue>): SourceValue {
|
||||||
|
for (value in values) {
|
||||||
|
value.insns.markAsDontTouch()
|
||||||
|
}
|
||||||
|
return super.naryOperation(insn, values)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun copyOperation(insn: AbstractInsnNode, value: SourceValue): SourceValue {
|
||||||
|
value.insns.markAsDontTouch()
|
||||||
|
return super.copyOperation(insn, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun unaryOperation(insn: AbstractInsnNode, value: SourceValue): SourceValue {
|
||||||
|
if (insn.opcode != Opcodes.CHECKCAST && !insn.isPrimitiveTypeConversion()) {
|
||||||
|
value.insns.markAsDontTouch()
|
||||||
|
}
|
||||||
|
return super.unaryOperation(insn, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun binaryOperation(insn: AbstractInsnNode, value1: SourceValue, value2: SourceValue): SourceValue {
|
||||||
|
value1.insns.markAsDontTouch()
|
||||||
|
value2.insns.markAsDontTouch()
|
||||||
|
return super.binaryOperation(insn, value1, value2)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun ternaryOperation(insn: AbstractInsnNode, value1: SourceValue, value2: SourceValue, value3: SourceValue): SourceValue {
|
||||||
|
value1.insns.markAsDontTouch()
|
||||||
|
value2.insns.markAsDontTouch()
|
||||||
|
value3.insns.markAsDontTouch()
|
||||||
|
return super.ternaryOperation(insn, value1, value2, value3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Collection<AbstractInsnNode>.markAsDontTouch() {
|
||||||
|
forEach {
|
||||||
|
dontTouchInsnIndices[insnList.indexOf(it)] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun computeTransformations() {
|
private fun computeTransformations() {
|
||||||
|
|||||||
+25
@@ -28,6 +28,31 @@ fun <V : Value> Frame<V>.top(): V? =
|
|||||||
fun <V : Value> Frame<V>.peek(offset: Int): V? =
|
fun <V : Value> Frame<V>.peek(offset: Int): V? =
|
||||||
if (stackSize > offset) getStack(stackSize - offset - 1) else null
|
if (stackSize > offset) getStack(stackSize - offset - 1) else null
|
||||||
|
|
||||||
|
private fun <V : Value> Frame<V>.peekWordsTo(dest: MutableList<V>, size: Int, offset0: Int = 0): Int {
|
||||||
|
var offset = offset0
|
||||||
|
var totalSize = 0
|
||||||
|
while (totalSize < size) {
|
||||||
|
val value = peek(offset++) ?: return -1
|
||||||
|
dest.add(value)
|
||||||
|
totalSize += value.size
|
||||||
|
}
|
||||||
|
if (totalSize > size) return -1
|
||||||
|
return offset
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <V : Value> Frame<V>.peekWords(size: Int): List<V>? {
|
||||||
|
val result = ArrayList<V>(size)
|
||||||
|
return if (peekWordsTo(result, size) < 0) null else result
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <V : Value> Frame<V>.peekWords(size1: Int, size2: Int): List<V>? {
|
||||||
|
val result = ArrayList<V>(size1 + size2)
|
||||||
|
val offset = peekWordsTo(result, size1)
|
||||||
|
if (offset < 0) return null
|
||||||
|
if (peekWordsTo(result, size2, offset) < 0) return null
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
class SavedStackDescriptor(
|
class SavedStackDescriptor(
|
||||||
val savedValues: List<BasicValue>,
|
val savedValues: List<BasicValue>,
|
||||||
val firstLocalVarIndex: Int
|
val firstLocalVarIndex: Int
|
||||||
|
|||||||
Reference in New Issue
Block a user