Minor: reformat code in org.jetbrains.kotlin.codegen.optimization
This commit is contained in:
+7
-13
@@ -17,13 +17,7 @@
|
|||||||
package org.jetbrains.kotlin.codegen.optimization
|
package org.jetbrains.kotlin.codegen.optimization
|
||||||
|
|
||||||
import org.jetbrains.kotlin.builtins.PrimitiveType
|
import org.jetbrains.kotlin.builtins.PrimitiveType
|
||||||
import org.jetbrains.kotlin.codegen.optimization.common.ProperTrackedReferenceValue
|
import org.jetbrains.kotlin.codegen.optimization.common.*
|
||||||
import org.jetbrains.kotlin.codegen.optimization.common.ReferenceTrackingInterpreter
|
|
||||||
import org.jetbrains.kotlin.codegen.optimization.common.ReferenceValueDescriptor
|
|
||||||
import org.jetbrains.kotlin.codegen.optimization.common.TrackedReferenceValue
|
|
||||||
import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence
|
|
||||||
import org.jetbrains.kotlin.codegen.optimization.common.removeEmptyCatchBlocks
|
|
||||||
import org.jetbrains.kotlin.codegen.optimization.common.removeUnusedLocalVariables
|
|
||||||
import org.jetbrains.kotlin.codegen.optimization.fixStack.peek
|
import org.jetbrains.kotlin.codegen.optimization.fixStack.peek
|
||||||
import org.jetbrains.kotlin.codegen.optimization.fixStack.top
|
import org.jetbrains.kotlin.codegen.optimization.fixStack.top
|
||||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||||
@@ -195,8 +189,7 @@ class CapturedVarsOptimizationMethodTransformer : MethodTransformer() {
|
|||||||
|
|
||||||
if (descriptor.localVar == null) {
|
if (descriptor.localVar == null) {
|
||||||
descriptor.localVar = localVar
|
descriptor.localVar = localVar
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
descriptor.hazard = true
|
descriptor.hazard = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -210,8 +203,7 @@ class CapturedVarsOptimizationMethodTransformer : MethodTransformer() {
|
|||||||
refValue.localVarIndex = methodNode.maxLocals
|
refValue.localVarIndex = methodNode.maxLocals
|
||||||
methodNode.maxLocals += 2
|
methodNode.maxLocals += 2
|
||||||
localVar.index = refValue.localVarIndex
|
localVar.index = refValue.localVarIndex
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
refValue.localVarIndex = localVar.index
|
refValue.localVarIndex = localVar.index
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,7 +215,7 @@ class CapturedVarsOptimizationMethodTransformer : MethodTransformer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val cleanInstructions = findCleanInstructions(refValue, oldVarIndex, methodNode.instructions)
|
val cleanInstructions = findCleanInstructions(refValue, oldVarIndex, methodNode.instructions)
|
||||||
if (cleanInstructions.size > 1 ) {
|
if (cleanInstructions.size > 1) {
|
||||||
refValue.hazard = true
|
refValue.hazard = true
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -239,7 +231,9 @@ class CapturedVarsOptimizationMethodTransformer : MethodTransformer() {
|
|||||||
}.filter {
|
}.filter {
|
||||||
val operationIndex = instructions.indexOf(it)
|
val operationIndex = instructions.indexOf(it)
|
||||||
val localVariableNode = refValue.localVar!!
|
val localVariableNode = refValue.localVar!!
|
||||||
instructions.indexOf(localVariableNode.start) < operationIndex && operationIndex < instructions.indexOf(localVariableNode.end)
|
instructions.indexOf(localVariableNode.start) < operationIndex && operationIndex < instructions.indexOf(
|
||||||
|
localVariableNode.end
|
||||||
|
)
|
||||||
}.toList()
|
}.toList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-6
@@ -55,9 +55,9 @@ class ConstantConditionEliminationMethodTransformer : MethodTransformer() {
|
|||||||
val frame = frames[i] ?: continue
|
val frame = frames[i] ?: continue
|
||||||
val insn = insns[i] as? JumpInsnNode ?: continue
|
val insn = insns[i] as? JumpInsnNode ?: continue
|
||||||
when (insn.opcode) {
|
when (insn.opcode) {
|
||||||
in Opcodes.IFEQ .. Opcodes.IFLE ->
|
in Opcodes.IFEQ..Opcodes.IFLE ->
|
||||||
tryRewriteComparisonWithZero(insn, frame, actions)
|
tryRewriteComparisonWithZero(insn, frame, actions)
|
||||||
in Opcodes.IF_ICMPEQ .. Opcodes.IF_ICMPLE ->
|
in Opcodes.IF_ICMPEQ..Opcodes.IF_ICMPLE ->
|
||||||
tryRewriteBinaryComparison(insn, frame, actions)
|
tryRewriteBinaryComparison(insn, frame, actions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -93,8 +93,7 @@ class ConstantConditionEliminationMethodTransformer : MethodTransformer() {
|
|||||||
|
|
||||||
if (arg1 is IConstValue && arg2 is IConstValue) {
|
if (arg1 is IConstValue && arg2 is IConstValue) {
|
||||||
rewriteBinaryComparisonOfConsts(insn, arg1.value, arg2.value, actions)
|
rewriteBinaryComparisonOfConsts(insn, arg1.value, arg2.value, actions)
|
||||||
}
|
} else if (arg2 is IConstValue && arg2.value == 0) {
|
||||||
else if (arg2 is IConstValue && arg2.value == 0) {
|
|
||||||
rewriteBinaryComparisonWith0(insn, actions)
|
rewriteBinaryComparisonWith0(insn, actions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -155,7 +154,7 @@ class ConstantConditionEliminationMethodTransformer : MethodTransformer() {
|
|||||||
private val ICONST_CACHE = Array(7) { IConstValue(it - 1) }
|
private val ICONST_CACHE = Array(7) { IConstValue(it - 1) }
|
||||||
|
|
||||||
fun of(value: Int) =
|
fun of(value: Int) =
|
||||||
if (value in -1 .. 5)
|
if (value in -1..5)
|
||||||
ICONST_CACHE[value + 1]
|
ICONST_CACHE[value + 1]
|
||||||
else
|
else
|
||||||
IConstValue(value)
|
IConstValue(value)
|
||||||
@@ -165,7 +164,7 @@ class ConstantConditionEliminationMethodTransformer : MethodTransformer() {
|
|||||||
private class ConstantPropagationInterpreter : OptimizationBasicInterpreter() {
|
private class ConstantPropagationInterpreter : OptimizationBasicInterpreter() {
|
||||||
override fun newOperation(insn: AbstractInsnNode): BasicValue =
|
override fun newOperation(insn: AbstractInsnNode): BasicValue =
|
||||||
when (insn.opcode) {
|
when (insn.opcode) {
|
||||||
in Opcodes.ICONST_M1 .. Opcodes.ICONST_5 ->
|
in Opcodes.ICONST_M1..Opcodes.ICONST_5 ->
|
||||||
IConstValue.of(insn.opcode - Opcodes.ICONST_0)
|
IConstValue.of(insn.opcode - Opcodes.ICONST_0)
|
||||||
Opcodes.BIPUSH, Opcodes.SIPUSH ->
|
Opcodes.BIPUSH, Opcodes.SIPUSH ->
|
||||||
IConstValue.of(insn.cast<IntInsnNode>().operand)
|
IConstValue.of(insn.cast<IntInsnNode>().operand)
|
||||||
|
|||||||
-2
@@ -18,8 +18,6 @@ package org.jetbrains.kotlin.codegen.optimization
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.codegen.optimization.fixStack.FixStackMethodTransformer
|
import org.jetbrains.kotlin.codegen.optimization.fixStack.FixStackMethodTransformer
|
||||||
import org.jetbrains.kotlin.codegen.optimization.transformer.CompositeMethodTransformer
|
import org.jetbrains.kotlin.codegen.optimization.transformer.CompositeMethodTransformer
|
||||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
|
||||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
|
||||||
|
|
||||||
class FixStackWithLabelNormalizationMethodTransformer : CompositeMethodTransformer(
|
class FixStackWithLabelNormalizationMethodTransformer : CompositeMethodTransformer(
|
||||||
LabelNormalizationMethodTransformer(),
|
LabelNormalizationMethodTransformer(),
|
||||||
|
|||||||
+2
-4
@@ -49,13 +49,11 @@ class LabelNormalizationMethodTransformer : MethodTransformer() {
|
|||||||
newLabelNodes[thisNode.label] = prevNode
|
newLabelNodes[thisNode.label] = prevNode
|
||||||
removedAnyLabels = true
|
removedAnyLabels = true
|
||||||
thisNode = instructions.removeNodeGetNext(thisNode)
|
thisNode = instructions.removeNodeGetNext(thisNode)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
newLabelNodes[thisNode.label] = thisNode
|
newLabelNodes[thisNode.label] = thisNode
|
||||||
thisNode = thisNode.next
|
thisNode = thisNode.next
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
thisNode = thisNode.next
|
thisNode = thisNode.next
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,8 +24,7 @@ class MethodVerifier(private val checkPoint: String) : MethodTransformer() {
|
|||||||
override fun transform(internalClassName: String, methodNode: MethodNode) {
|
override fun transform(internalClassName: String, methodNode: MethodNode) {
|
||||||
try {
|
try {
|
||||||
analyze(internalClassName, methodNode, BasicVerifier())
|
analyze(internalClassName, methodNode, BasicVerifier())
|
||||||
}
|
} catch (e: Throwable) {
|
||||||
catch (e: Throwable) {
|
|
||||||
throw AssertionError("$checkPoint: incorrect bytecode", e)
|
throw AssertionError("$checkPoint: incorrect bytecode", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -22,7 +22,8 @@ import org.jetbrains.kotlin.codegen.optimization.fixStack.top
|
|||||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||||
import org.jetbrains.org.objectweb.asm.Type
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
import org.jetbrains.org.objectweb.asm.tree.*
|
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||||
|
import org.jetbrains.org.objectweb.asm.tree.TypeInsnNode
|
||||||
|
|
||||||
class RedundantCheckCastEliminationMethodTransformer : MethodTransformer() {
|
class RedundantCheckCastEliminationMethodTransformer : MethodTransformer() {
|
||||||
override fun transform(internalClassName: String, methodNode: MethodNode) {
|
override fun transform(internalClassName: String, methodNode: MethodNode) {
|
||||||
|
|||||||
+6
-6
@@ -16,13 +16,13 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.codegen.optimization
|
package org.jetbrains.kotlin.codegen.optimization
|
||||||
|
|
||||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
|
||||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
|
||||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
|
||||||
import org.jetbrains.org.objectweb.asm.tree.LabelNode
|
|
||||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
|
||||||
import org.jetbrains.org.objectweb.asm.tree.JumpInsnNode
|
|
||||||
import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful
|
import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful
|
||||||
|
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||||
|
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||||
|
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||||
|
import org.jetbrains.org.objectweb.asm.tree.JumpInsnNode
|
||||||
|
import org.jetbrains.org.objectweb.asm.tree.LabelNode
|
||||||
|
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||||
|
|
||||||
class RedundantGotoMethodTransformer : MethodTransformer() {
|
class RedundantGotoMethodTransformer : MethodTransformer() {
|
||||||
/**
|
/**
|
||||||
|
|||||||
+3
-5
@@ -46,8 +46,7 @@ class RedundantNopsCleanupMethodTransformer : MethodTransformer() {
|
|||||||
val toRemove = current
|
val toRemove = current
|
||||||
current = current.next
|
current = current.next
|
||||||
methodNode.instructions.remove(toRemove)
|
methodNode.instructions.remove(toRemove)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
current = current.next
|
current = current.next
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -84,7 +83,7 @@ class RedundantNopsCleanupMethodTransformer : MethodTransformer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for (i in 0 .. localVariableLabels.size - 2) {
|
for (i in 0..localVariableLabels.size - 2) {
|
||||||
val begin = localVariableLabels[i]
|
val begin = localVariableLabels[i]
|
||||||
val end = localVariableLabels[i + 1]
|
val end = localVariableLabels[i + 1]
|
||||||
if (InsnSequence(begin, end).any { it in requiredNops }) continue
|
if (InsnSequence(begin, end).any { it in requiredNops }) continue
|
||||||
@@ -109,8 +108,7 @@ internal fun getRequiredNopInRange(firstInclusive: AbstractInsnNode, lastExclusi
|
|||||||
while (current != null && current != lastExclusive) {
|
while (current != null && current != lastExclusive) {
|
||||||
if (current.isMeaningful && current.opcode != Opcodes.NOP) {
|
if (current.isMeaningful && current.opcode != Opcodes.NOP) {
|
||||||
return null
|
return null
|
||||||
}
|
} else if (current.opcode == Opcodes.NOP) {
|
||||||
else if (current.opcode == Opcodes.NOP) {
|
|
||||||
lastNop = current
|
lastNop = current
|
||||||
}
|
}
|
||||||
current = current.next
|
current = current.next
|
||||||
|
|||||||
+5
-1
@@ -36,7 +36,11 @@ import java.util.*
|
|||||||
open class BoxingInterpreter(private val insnList: InsnList) : OptimizationBasicInterpreter() {
|
open class BoxingInterpreter(private val insnList: InsnList) : OptimizationBasicInterpreter() {
|
||||||
private val boxingPlaces = HashMap<Int, BoxedBasicValue>()
|
private val boxingPlaces = HashMap<Int, BoxedBasicValue>()
|
||||||
|
|
||||||
protected open fun createNewBoxing(insn: AbstractInsnNode, type: Type, progressionIterator: ProgressionIteratorBasicValue?): BasicValue =
|
protected open fun createNewBoxing(
|
||||||
|
insn: AbstractInsnNode,
|
||||||
|
type: Type,
|
||||||
|
progressionIterator: ProgressionIteratorBasicValue?
|
||||||
|
): BasicValue =
|
||||||
boxingPlaces.getOrPut(insnList.indexOf(insn)) {
|
boxingPlaces.getOrPut(insnList.indexOf(insn)) {
|
||||||
val boxedBasicValue = CleanBoxedValue(type, insn, progressionIterator)
|
val boxedBasicValue = CleanBoxedValue(type, insn, progressionIterator)
|
||||||
onNewBoxedValue(boxedBasicValue)
|
onNewBoxedValue(boxedBasicValue)
|
||||||
|
|||||||
+11
-9
@@ -145,7 +145,12 @@ class PopBackwardPropagationTransformer : MethodTransformer() {
|
|||||||
return super.binaryOperation(insn, value1, value2)
|
return super.binaryOperation(insn, value1, value2)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun ternaryOperation(insn: AbstractInsnNode, value1: SourceValue, value2: SourceValue, value3: SourceValue): SourceValue {
|
override fun ternaryOperation(
|
||||||
|
insn: AbstractInsnNode,
|
||||||
|
value1: SourceValue,
|
||||||
|
value2: SourceValue,
|
||||||
|
value3: SourceValue
|
||||||
|
): SourceValue {
|
||||||
value1.insns.markAsDontTouch()
|
value1.insns.markAsDontTouch()
|
||||||
value2.insns.markAsDontTouch()
|
value2.insns.markAsDontTouch()
|
||||||
value3.insns.markAsDontTouch()
|
value3.insns.markAsDontTouch()
|
||||||
@@ -193,8 +198,7 @@ class PopBackwardPropagationTransformer : MethodTransformer() {
|
|||||||
if (sources.all { !isDontTouch(it) } && sources.any { isTransformableCheckcastOperand(it, resultType) }) {
|
if (sources.all { !isDontTouch(it) } && sources.any { isTransformableCheckcastOperand(it, resultType) }) {
|
||||||
transformations[insn] = replaceWithNopTransformation()
|
transformations[insn] = replaceWithNopTransformation()
|
||||||
sources.forEach { propagatePopBackwards(it, inputTop.size) }
|
sources.forEach { propagatePopBackwards(it, inputTop.size) }
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
transformations[insn] = insertPopAfterTransformation(poppedValueSize)
|
transformations[insn] = insertPopAfterTransformation(poppedValueSize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -214,8 +218,7 @@ class PopBackwardPropagationTransformer : MethodTransformer() {
|
|||||||
if (sources.all { !isDontTouch(it) }) {
|
if (sources.all { !isDontTouch(it) }) {
|
||||||
transformations[insn] = replaceWithNopTransformation()
|
transformations[insn] = replaceWithNopTransformation()
|
||||||
sources.forEach { propagatePopBackwards(it, inputTop.size) }
|
sources.forEach { propagatePopBackwards(it, inputTop.size) }
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
transformations[insn] = replaceWithPopTransformation(poppedValueSize)
|
transformations[insn] = replaceWithPopTransformation(poppedValueSize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -252,8 +255,7 @@ class PopBackwardPropagationTransformer : MethodTransformer() {
|
|||||||
while (node != null && node != end) {
|
while (node != null && node != end) {
|
||||||
if (node in removableNops && !keepNop) {
|
if (node in removableNops && !keepNop) {
|
||||||
node = insnList.removeNodeGetNext(node)
|
node = insnList.removeNodeGetNext(node)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if (node.isMeaningful) keepNop = false
|
if (node.isMeaningful) keepNop = false
|
||||||
node = node.next
|
node = node.next
|
||||||
}
|
}
|
||||||
@@ -300,7 +302,7 @@ class PopBackwardPropagationTransformer : MethodTransformer() {
|
|||||||
|
|
||||||
fun AbstractInsnNode.isPurePush() =
|
fun AbstractInsnNode.isPurePush() =
|
||||||
isLoadOperation() ||
|
isLoadOperation() ||
|
||||||
opcode in Opcodes.ACONST_NULL .. Opcodes.LDC + 2 ||
|
opcode in Opcodes.ACONST_NULL..Opcodes.LDC + 2 ||
|
||||||
isUnitInstance()
|
isUnitInstance()
|
||||||
|
|
||||||
fun AbstractInsnNode.isPop() =
|
fun AbstractInsnNode.isPop() =
|
||||||
@@ -311,4 +313,4 @@ fun AbstractInsnNode.isUnitInstance() =
|
|||||||
this is FieldInsnNode && owner == "kotlin/Unit" && name == "INSTANCE"
|
this is FieldInsnNode && owner == "kotlin/Unit" && name == "INSTANCE"
|
||||||
|
|
||||||
fun AbstractInsnNode.isPrimitiveTypeConversion() =
|
fun AbstractInsnNode.isPrimitiveTypeConversion() =
|
||||||
opcode in Opcodes.I2L .. Opcodes.I2S
|
opcode in Opcodes.I2L..Opcodes.I2S
|
||||||
+2
@@ -30,6 +30,7 @@ import org.jetbrains.org.objectweb.asm.Type;
|
|||||||
|
|
||||||
public class ProgressionIteratorBasicValue extends StrictBasicValue {
|
public class ProgressionIteratorBasicValue extends StrictBasicValue {
|
||||||
private final static ImmutableMap<String, Type> VALUES_TYPENAME_TO_TYPE;
|
private final static ImmutableMap<String, Type> VALUES_TYPENAME_TO_TYPE;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
ImmutableMap.Builder<String, Type> builder = ImmutableMap.builder();
|
ImmutableMap.Builder<String, Type> builder = ImmutableMap.builder();
|
||||||
for (PrimitiveType primitiveType : RangeCodegenUtilKt.getSupportedRangeTypes()) {
|
for (PrimitiveType primitiveType : RangeCodegenUtilKt.getSupportedRangeTypes()) {
|
||||||
@@ -39,6 +40,7 @@ public class ProgressionIteratorBasicValue extends StrictBasicValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static final ImmutableMap<PrimitiveType, ProgressionIteratorBasicValue> ITERATOR_VALUE_BY_ELEMENT_PRIMITIVE_TYPE;
|
private static final ImmutableMap<PrimitiveType, ProgressionIteratorBasicValue> ITERATOR_VALUE_BY_ELEMENT_PRIMITIVE_TYPE;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
ImmutableMap.Builder<PrimitiveType, ProgressionIteratorBasicValue> builder = ImmutableMap.builder();
|
ImmutableMap.Builder<PrimitiveType, ProgressionIteratorBasicValue> builder = ImmutableMap.builder();
|
||||||
for (PrimitiveType elementType : RangeCodegenUtilKt.getSupportedRangeTypes()) {
|
for (PrimitiveType elementType : RangeCodegenUtilKt.getSupportedRangeTypes()) {
|
||||||
|
|||||||
+1
-2
@@ -116,8 +116,7 @@ internal class RedundantBoxingInterpreter(insnList: InsnList) : BoxingInterprete
|
|||||||
|
|
||||||
if (!PERMITTED_OPERATIONS_OPCODES.contains(insnNode.opcode)) {
|
if (!PERMITTED_OPERATIONS_OPCODES.contains(insnNode.opcode)) {
|
||||||
markValueAsDirty(value)
|
markValueAsDirty(value)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
addAssociatedInsn(value, insnNode)
|
addAssociatedInsn(value, insnNode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-14
@@ -21,7 +21,7 @@ import org.jetbrains.kotlin.codegen.inline.insnOpcodeText
|
|||||||
import org.jetbrains.kotlin.codegen.inline.insnText
|
import org.jetbrains.kotlin.codegen.inline.insnText
|
||||||
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
|
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
|
||||||
import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue
|
import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue
|
||||||
import org.jetbrains.kotlin.codegen.optimization.common.*
|
import org.jetbrains.kotlin.codegen.optimization.common.remapLocalVariables
|
||||||
import org.jetbrains.kotlin.codegen.optimization.fixStack.peek
|
import org.jetbrains.kotlin.codegen.optimization.fixStack.peek
|
||||||
import org.jetbrains.kotlin.codegen.optimization.fixStack.top
|
import org.jetbrains.kotlin.codegen.optimization.fixStack.top
|
||||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||||
@@ -32,7 +32,6 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
|||||||
import org.jetbrains.org.objectweb.asm.tree.*
|
import org.jetbrains.org.objectweb.asm.tree.*
|
||||||
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
|
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 java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class RedundantBoxingMethodTransformer : MethodTransformer() {
|
class RedundantBoxingMethodTransformer : MethodTransformer() {
|
||||||
@@ -171,8 +170,7 @@ class RedundantBoxingMethodTransformer : MethodTransformer() {
|
|||||||
(insn as VarInsnNode).`var` == localVariableNode.index) {
|
(insn as VarInsnNode).`var` == localVariableNode.index) {
|
||||||
if (insn.getOpcode() == Opcodes.ASTORE) {
|
if (insn.getOpcode() == Opcodes.ASTORE) {
|
||||||
values.add(frame.top()!!)
|
values.add(frame.top()!!)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
values.add(frame.getLocal(insn.`var`))
|
values.add(frame.getLocal(insn.`var`))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -228,8 +226,7 @@ class RedundantBoxingMethodTransformer : MethodTransformer() {
|
|||||||
private fun adaptBoxingInstruction(node: MethodNode, value: BoxedValueDescriptor) {
|
private fun adaptBoxingInstruction(node: MethodNode, value: BoxedValueDescriptor) {
|
||||||
if (!value.isFromProgressionIterator()) {
|
if (!value.isFromProgressionIterator()) {
|
||||||
node.instructions.remove(value.boxingInsn)
|
node.instructions.remove(value.boxingInsn)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val iterator = value.progressionIterator ?: error("iterator should not be null because isFromProgressionIterator returns true")
|
val iterator = value.progressionIterator ?: error("iterator should not be null because isFromProgressionIterator returns true")
|
||||||
|
|
||||||
//add checkcast to kotlin/<T>Iterator before next() call
|
//add checkcast to kotlin/<T>Iterator before next() call
|
||||||
@@ -309,8 +306,7 @@ class RedundantBoxingMethodTransformer : MethodTransformer() {
|
|||||||
Opcodes.INVOKEINTERFACE -> {
|
Opcodes.INVOKEINTERFACE -> {
|
||||||
if (insn.isJavaLangComparableCompareTo()) {
|
if (insn.isJavaLangComparableCompareTo()) {
|
||||||
adaptJavaLangComparableCompareTo(node, insn, value)
|
adaptJavaLangComparableCompareTo(node, insn, value)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
throwCannotAdaptInstruction(insn)
|
throwCannotAdaptInstruction(insn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -339,8 +335,8 @@ class RedundantBoxingMethodTransformer : MethodTransformer() {
|
|||||||
adaptAreEqualIntrinsicForInt(node, insn)
|
adaptAreEqualIntrinsicForInt(node, insn)
|
||||||
Type.LONG ->
|
Type.LONG ->
|
||||||
adaptAreEqualIntrinsicForLong(node, insn)
|
adaptAreEqualIntrinsicForLong(node, insn)
|
||||||
Type.OBJECT ->
|
Type.OBJECT -> {
|
||||||
{}
|
}
|
||||||
else ->
|
else ->
|
||||||
throw AssertionError("Unexpected unboxed type kind: $unboxedType")
|
throw AssertionError("Unexpected unboxed type kind: $unboxedType")
|
||||||
}
|
}
|
||||||
@@ -353,8 +349,7 @@ class RedundantBoxingMethodTransformer : MethodTransformer() {
|
|||||||
fuseAreEqualWithBranch(node, insn, Opcodes.IF_ICMPNE, Opcodes.IF_ICMPEQ)
|
fuseAreEqualWithBranch(node, insn, Opcodes.IF_ICMPNE, Opcodes.IF_ICMPEQ)
|
||||||
remove(insn)
|
remove(insn)
|
||||||
remove(next)
|
remove(next)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
ifEqual1Else0(node, insn, Opcodes.IF_ICMPNE)
|
ifEqual1Else0(node, insn, Opcodes.IF_ICMPNE)
|
||||||
remove(insn)
|
remove(insn)
|
||||||
}
|
}
|
||||||
@@ -369,8 +364,7 @@ class RedundantBoxingMethodTransformer : MethodTransformer() {
|
|||||||
fuseAreEqualWithBranch(node, insn, Opcodes.IFNE, Opcodes.IFEQ)
|
fuseAreEqualWithBranch(node, insn, Opcodes.IFNE, Opcodes.IFEQ)
|
||||||
remove(insn)
|
remove(insn)
|
||||||
remove(next)
|
remove(next)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
ifEqual1Else0(node, insn, Opcodes.IFNE)
|
ifEqual1Else0(node, insn, Opcodes.IFNE)
|
||||||
remove(insn)
|
remove(insn)
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-2
@@ -84,8 +84,7 @@ class StackPeepholeOptimizationsTransformer : MethodTransformer() {
|
|||||||
it.set(insn, InsnNode(Opcodes.NOP))
|
it.set(insn, InsnNode(Opcodes.NOP))
|
||||||
it.remove(prevNonNop)
|
it.remove(prevNonNop)
|
||||||
}
|
}
|
||||||
}
|
} else if (i > 1) {
|
||||||
else if (i > 1) {
|
|
||||||
val prevNonNop2 = prevNonNop.findPreviousOrNull { it.opcode != Opcodes.NOP } ?: continue@forInsn
|
val prevNonNop2 = prevNonNop.findPreviousOrNull { it.opcode != Opcodes.NOP } ?: continue@forInsn
|
||||||
if (prevNonNop.isEliminatedByPop() && prevNonNop2.isEliminatedByPop()) {
|
if (prevNonNop.isEliminatedByPop() && prevNonNop2.isEliminatedByPop()) {
|
||||||
actions.add {
|
actions.add {
|
||||||
|
|||||||
+6
-8
@@ -116,8 +116,7 @@ open class MethodAnalyzer<V : Value>(
|
|||||||
|
|
||||||
if (insnType == AbstractInsnNode.LABEL || insnType == AbstractInsnNode.LINE || insnType == AbstractInsnNode.FRAME) {
|
if (insnType == AbstractInsnNode.LABEL || insnType == AbstractInsnNode.LINE || insnType == AbstractInsnNode.FRAME) {
|
||||||
visitNopInsn(f, insn)
|
visitNopInsn(f, insn)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
current.init(f).execute(insnNode, interpreter)
|
current.init(f).execute(insnNode, interpreter)
|
||||||
|
|
||||||
when {
|
when {
|
||||||
@@ -129,12 +128,13 @@ open class MethodAnalyzer<V : Value>(
|
|||||||
visitTableSwitchInsnNode(insnNode, current, insn)
|
visitTableSwitchInsnNode(insnNode, current, insn)
|
||||||
insnOpcode != Opcodes.ATHROW && (insnOpcode < Opcodes.IRETURN || insnOpcode > Opcodes.RETURN) ->
|
insnOpcode != Opcodes.ATHROW && (insnOpcode < Opcodes.IRETURN || insnOpcode > Opcodes.RETURN) ->
|
||||||
visitOpInsn(current, insn)
|
visitOpInsn(current, insn)
|
||||||
else -> {}
|
else -> {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handlers[insn]?.forEach { tcb ->
|
handlers[insn]?.forEach { tcb ->
|
||||||
val exnType = Type.getObjectType(tcb.type?:"java/lang/Throwable")
|
val exnType = Type.getObjectType(tcb.type ?: "java/lang/Throwable")
|
||||||
val jump = instructions.indexOf(tcb.handler)
|
val jump = instructions.indexOf(tcb.handler)
|
||||||
if (visitControlFlowExceptionEdge(insn, tcb)) {
|
if (visitControlFlowExceptionEdge(insn, tcb)) {
|
||||||
handler.init(f)
|
handler.init(f)
|
||||||
@@ -144,11 +144,9 @@ open class MethodAnalyzer<V : Value>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} catch (e: AnalyzerException) {
|
||||||
catch (e: AnalyzerException) {
|
|
||||||
throw AnalyzerException(e.node, "Error at instruction #$insn ${insnNode.insnText}: ${e.message}", e)
|
throw AnalyzerException(e.node, "Error at instruction #$insn ${insnNode.insnText}: ${e.message}", e)
|
||||||
}
|
} catch (e: Exception) {
|
||||||
catch (e: Exception) {
|
|
||||||
throw AnalyzerException(insnNode, "Error at instruction #$insn ${insnNode.insnText}: ${e.message}", e)
|
throw AnalyzerException(insnNode, "Error at instruction #$insn ${insnNode.insnText}: ${e.message}", e)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-3
@@ -40,7 +40,7 @@ abstract class ReferenceTrackingInterpreter : OptimizationBasicInterpreter() {
|
|||||||
super.merge(v, w)
|
super.merge(v, w)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun createTaintedValue(v: BasicValue, w: BasicValue) : TrackedReferenceValue =
|
protected fun createTaintedValue(v: BasicValue, w: BasicValue): TrackedReferenceValue =
|
||||||
TaintedTrackedReferenceValue(
|
TaintedTrackedReferenceValue(
|
||||||
getMergedValueType(v.type, w.type),
|
getMergedValueType(v.type, w.type),
|
||||||
mergeDescriptors(v, w).also {
|
mergeDescriptors(v, w).also {
|
||||||
@@ -74,8 +74,7 @@ abstract class ReferenceTrackingInterpreter : OptimizationBasicInterpreter() {
|
|||||||
if (value is TrackedReferenceValue) {
|
if (value is TrackedReferenceValue) {
|
||||||
checkRefValuesUsages(insn, listOf(value))
|
checkRefValuesUsages(insn, listOf(value))
|
||||||
value
|
value
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
super.copyOperation(insn, value)
|
super.copyOperation(insn, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -22,7 +22,7 @@ interface ReferenceValueDescriptor {
|
|||||||
fun onUseAsTainted()
|
fun onUseAsTainted()
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class TrackedReferenceValue(type: Type): StrictBasicValue(type) {
|
sealed class TrackedReferenceValue(type: Type) : StrictBasicValue(type) {
|
||||||
abstract val descriptors: Set<ReferenceValueDescriptor>
|
abstract val descriptors: Set<ReferenceValueDescriptor>
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,6 +62,7 @@ class TaintedTrackedReferenceValue(type: Type, override val descriptors: Set<Ref
|
|||||||
|
|
||||||
override fun hashCode(): Int =
|
override fun hashCode(): Int =
|
||||||
descriptors.hashCode()
|
descriptors.hashCode()
|
||||||
|
|
||||||
override fun toString(): String =
|
override fun toString(): String =
|
||||||
"!$descriptors"
|
"!$descriptors"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ import org.jetbrains.org.objectweb.asm.Opcodes.*
|
|||||||
import org.jetbrains.org.objectweb.asm.Type
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
import org.jetbrains.org.objectweb.asm.tree.*
|
import org.jetbrains.org.objectweb.asm.tree.*
|
||||||
|
|
||||||
val AbstractInsnNode.isMeaningful: Boolean get() =
|
val AbstractInsnNode.isMeaningful: Boolean
|
||||||
|
get() =
|
||||||
when (this.type) {
|
when (this.type) {
|
||||||
AbstractInsnNode.LABEL, AbstractInsnNode.LINE, AbstractInsnNode.FRAME -> false
|
AbstractInsnNode.LABEL, AbstractInsnNode.LINE, AbstractInsnNode.FRAME -> false
|
||||||
else -> true
|
else -> true
|
||||||
@@ -44,6 +45,7 @@ class InsnSequence(val from: AbstractInsnNode, val to: AbstractInsnNode?) : Sequ
|
|||||||
current = current!!.next
|
current = current!!.next
|
||||||
return result!!
|
return result!!
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hasNext() = current != to
|
override fun hasNext() = current != to
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -74,13 +76,15 @@ fun MethodNode.prepareForEmitting() {
|
|||||||
current = prev
|
current = prev
|
||||||
}
|
}
|
||||||
maxStack = -1
|
maxStack = -1
|
||||||
accept(MaxStackFrameSizeAndLocalsCalculator(
|
accept(
|
||||||
|
MaxStackFrameSizeAndLocalsCalculator(
|
||||||
Opcodes.ASM5, access, desc,
|
Opcodes.ASM5, access, desc,
|
||||||
object : MethodVisitor(Opcodes.ASM5) {
|
object : MethodVisitor(Opcodes.ASM5) {
|
||||||
override fun visitMaxs(maxStack: Int, maxLocals: Int) {
|
override fun visitMaxs(maxStack: Int, maxLocals: Int) {
|
||||||
this@prepareForEmitting.maxStack = maxStack
|
this@prepareForEmitting.maxStack = maxStack
|
||||||
}
|
}
|
||||||
}))
|
})
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun MethodNode.stripOptimizationMarkers() {
|
fun MethodNode.stripOptimizationMarkers() {
|
||||||
@@ -88,8 +92,7 @@ fun MethodNode.stripOptimizationMarkers() {
|
|||||||
while (insn != null) {
|
while (insn != null) {
|
||||||
if (isOptimizationMarker(insn)) {
|
if (isOptimizationMarker(insn)) {
|
||||||
insn = instructions.removeNodeGetNext(insn)
|
insn = instructions.removeNodeGetNext(insn)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
insn = insn.next
|
insn = insn.next
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -192,7 +195,8 @@ fun AbstractInsnNode.hasOpcode(): Boolean =
|
|||||||
// mv.visitLdcInsn(new Integer(cst));
|
// mv.visitLdcInsn(new Integer(cst));
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
val AbstractInsnNode.intConstant: Int? get() =
|
val AbstractInsnNode.intConstant: Int?
|
||||||
|
get() =
|
||||||
when (opcode) {
|
when (opcode) {
|
||||||
in ICONST_M1..ICONST_5 -> opcode - ICONST_0
|
in ICONST_M1..ICONST_5 -> opcode - ICONST_0
|
||||||
BIPUSH, SIPUSH -> (this as IntInsnNode).operand
|
BIPUSH, SIPUSH -> (this as IntInsnNode).operand
|
||||||
@@ -205,7 +209,8 @@ fun insnListOf(vararg insns: AbstractInsnNode) = InsnList().apply { insns.forEac
|
|||||||
fun AbstractInsnNode.isStoreOperation(): Boolean = opcode in Opcodes.ISTORE..Opcodes.ASTORE
|
fun AbstractInsnNode.isStoreOperation(): Boolean = opcode in Opcodes.ISTORE..Opcodes.ASTORE
|
||||||
fun AbstractInsnNode.isLoadOperation(): Boolean = opcode in Opcodes.ILOAD..Opcodes.ALOAD
|
fun AbstractInsnNode.isLoadOperation(): Boolean = opcode in Opcodes.ILOAD..Opcodes.ALOAD
|
||||||
|
|
||||||
val AbstractInsnNode?.debugText get() =
|
val AbstractInsnNode?.debugText
|
||||||
|
get() =
|
||||||
if (this == null) "<null>" else "${this::class.java.simpleName}: $insnText"
|
if (this == null) "<null>" else "${this::class.java.simpleName}: $insnText"
|
||||||
|
|
||||||
internal inline fun <reified T : AbstractInsnNode> AbstractInsnNode.isInsn(opcode: Int, condition: T.() -> Boolean): Boolean =
|
internal inline fun <reified T : AbstractInsnNode> AbstractInsnNode.isInsn(opcode: Int, condition: T.() -> Boolean): Boolean =
|
||||||
|
|||||||
+2
-2
@@ -51,6 +51,7 @@ class VariableLivenessFrame(val maxLocals: Int) : VarFrame<VariableLivenessFrame
|
|||||||
|
|
||||||
override fun hashCode() = bitSet.hashCode()
|
override fun hashCode() = bitSet.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun analyzeLiveness(node: MethodNode): List<VariableLivenessFrame> {
|
fun analyzeLiveness(node: MethodNode): List<VariableLivenessFrame> {
|
||||||
val typeAnnotatedFrames = MethodTransformer.analyze("fake", node, OptimizationBasicInterpreter())
|
val typeAnnotatedFrames = MethodTransformer.analyze("fake", node, OptimizationBasicInterpreter())
|
||||||
return analyze(node, object : BackwardAnalysisInterpreter<VariableLivenessFrame> {
|
return analyze(node, object : BackwardAnalysisInterpreter<VariableLivenessFrame> {
|
||||||
@@ -85,8 +86,7 @@ private fun useVar(
|
|||||||
|
|
||||||
if (insn is VarInsnNode && insn.isLoadOperation()) {
|
if (insn is VarInsnNode && insn.isLoadOperation()) {
|
||||||
frame.markAlive(insn.`var`)
|
frame.markAlive(insn.`var`)
|
||||||
}
|
} else if (insn is IincInsnNode) {
|
||||||
else if (insn is IincInsnNode) {
|
|
||||||
frame.markAlive(insn.`var`)
|
frame.markAlive(insn.`var`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-3
@@ -30,7 +30,7 @@ import java.util.*
|
|||||||
|
|
||||||
private class DecompiledTryDescriptor(val tryStartLabel: LabelNode) {
|
private class DecompiledTryDescriptor(val tryStartLabel: LabelNode) {
|
||||||
// Only used for assertions
|
// Only used for assertions
|
||||||
var defaultHandlerTcb : TryCatchBlockNode? = null
|
var defaultHandlerTcb: TryCatchBlockNode? = null
|
||||||
val handlerStartLabels = hashSetOf<LabelNode>()
|
val handlerStartLabels = hashSetOf<LabelNode>()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,8 +92,7 @@ private fun insertSaveRestoreStackMarkers(
|
|||||||
methodNode.instructions.insertBefore(nopNode, saveStackMarker)
|
methodNode.instructions.insertBefore(nopNode, saveStackMarker)
|
||||||
methodNode.instructions.insertBefore(nopNode, newTryStartLabel)
|
methodNode.instructions.insertBefore(nopNode, newTryStartLabel)
|
||||||
methodNode.instructions.insert(nopNode, restoreStackMarker)
|
methodNode.instructions.insert(nopNode, restoreStackMarker)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
saveStackMarker = saveStackMarkerByTryLabel[tryStartLabel]!!
|
saveStackMarker = saveStackMarkerByTryLabel[tryStartLabel]!!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
-10
@@ -24,7 +24,10 @@ import org.jetbrains.kotlin.codegen.optimization.common.MethodAnalyzer
|
|||||||
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
|
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.org.objectweb.asm.Opcodes
|
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||||
import org.jetbrains.org.objectweb.asm.tree.*
|
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||||
|
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.BasicValue
|
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
|
||||||
@@ -128,8 +131,7 @@ internal class FixStackAnalyzer(
|
|||||||
override fun push(value: BasicValue) {
|
override fun push(value: BasicValue) {
|
||||||
if (super.getStackSize() < maxStackSize) {
|
if (super.getStackSize() < maxStackSize) {
|
||||||
super.push(value)
|
super.push(value)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
extraStack.add(value)
|
extraStack.add(value)
|
||||||
maxExtraStackSize = Math.max(maxExtraStackSize, extraStack.size)
|
maxExtraStackSize = Math.max(maxExtraStackSize, extraStack.size)
|
||||||
}
|
}
|
||||||
@@ -142,8 +144,7 @@ internal class FixStackAnalyzer(
|
|||||||
override fun pop(): BasicValue {
|
override fun pop(): BasicValue {
|
||||||
return if (extraStack.isNotEmpty()) {
|
return if (extraStack.isNotEmpty()) {
|
||||||
extraStack.pop()
|
extraStack.pop()
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
super.pop()
|
super.pop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -151,8 +152,7 @@ internal class FixStackAnalyzer(
|
|||||||
override fun getStack(i: Int): BasicValue {
|
override fun getStack(i: Int): BasicValue {
|
||||||
return if (i < super.getMaxStackSize()) {
|
return if (i < super.getMaxStackSize()) {
|
||||||
super.getStack(i)
|
super.getStack(i)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
extraStack[i - maxStackSize]
|
extraStack[i - maxStackSize]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -176,8 +176,7 @@ internal class FixStackAnalyzer(
|
|||||||
val savedValues = spilledStacks[beforeInlineMarker]
|
val savedValues = spilledStacks[beforeInlineMarker]
|
||||||
pushAll(savedValues!!)
|
pushAll(savedValues!!)
|
||||||
push(returnValue)
|
push(returnValue)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val savedValues = spilledStacks[beforeInlineMarker]
|
val savedValues = spilledStacks[beforeInlineMarker]
|
||||||
pushAll(savedValues!!)
|
pushAll(savedValues!!)
|
||||||
}
|
}
|
||||||
@@ -197,5 +196,4 @@ internal class FixStackAnalyzer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-11
@@ -108,11 +108,9 @@ class FixStackMethodTransformer : MethodTransformer() {
|
|||||||
val actualStackContent = analyzer.getActualStack(gotoNode)
|
val actualStackContent = analyzer.getActualStack(gotoNode)
|
||||||
?: throw AssertionError("Jump at $gotoIndex should be alive")
|
?: throw AssertionError("Jump at $gotoIndex should be alive")
|
||||||
actions.add { replaceMarkerWithPops(methodNode, gotoNode.previous, expectedStackSize, actualStackContent) }
|
actions.add { replaceMarkerWithPops(methodNode, gotoNode.previous, expectedStackSize, actualStackContent) }
|
||||||
}
|
} else if (actualStackSize >= 0 && expectedStackSize < 0) {
|
||||||
else if (actualStackSize >= 0 && expectedStackSize < 0) {
|
|
||||||
throw AssertionError("Live jump $gotoIndex to dead label $labelIndex")
|
throw AssertionError("Live jump $gotoIndex to dead label $labelIndex")
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val marker = gotoNode.previous
|
val marker = gotoNode.previous
|
||||||
actions.add { methodNode.instructions.remove(marker) }
|
actions.add { methodNode.instructions.remove(marker) }
|
||||||
}
|
}
|
||||||
@@ -152,8 +150,7 @@ class FixStackMethodTransformer : MethodTransformer() {
|
|||||||
if (savedStackValues != null) {
|
if (savedStackValues != null) {
|
||||||
val savedStackDescriptor = localVariablesManager.allocateVariablesForSaveStackMarker(marker, savedStackValues)
|
val savedStackDescriptor = localVariablesManager.allocateVariablesForSaveStackMarker(marker, savedStackValues)
|
||||||
actions.add { saveStack(methodNode, marker, savedStackDescriptor) }
|
actions.add { saveStack(methodNode, marker, savedStackDescriptor) }
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// marker is dead code
|
// marker is dead code
|
||||||
localVariablesManager.allocateVariablesForSaveStackMarker(marker, emptyList())
|
localVariablesManager.allocateVariablesForSaveStackMarker(marker, emptyList())
|
||||||
actions.add { methodNode.instructions.remove(marker) }
|
actions.add { methodNode.instructions.remove(marker) }
|
||||||
@@ -186,7 +183,8 @@ class FixStackMethodTransformer : MethodTransformer() {
|
|||||||
val returnValue = stackContentAfterInline.last()
|
val returnValue = stackContentAfterInline.last()
|
||||||
val returnValueLocalVarIndex = localVariablesManager.createReturnValueVariable(returnValue)
|
val returnValueLocalVarIndex = localVariablesManager.createReturnValueVariable(returnValue)
|
||||||
actions.add {
|
actions.add {
|
||||||
restoreStackWithReturnValue(methodNode, inlineMarker, savedStackDescriptor,
|
restoreStackWithReturnValue(
|
||||||
|
methodNode, inlineMarker, savedStackDescriptor,
|
||||||
returnValue, returnValueLocalVarIndex
|
returnValue, returnValueLocalVarIndex
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -196,8 +194,7 @@ class FixStackMethodTransformer : MethodTransformer() {
|
|||||||
else ->
|
else ->
|
||||||
throw AssertionError("Inline method should not leave more than 1 value on stack")
|
throw AssertionError("Inline method should not leave more than 1 value on stack")
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// after inline marker is dead code
|
// after inline marker is dead code
|
||||||
actions.add { methodNode.instructions.remove(inlineMarker) }
|
actions.add { methodNode.instructions.remove(inlineMarker) }
|
||||||
}
|
}
|
||||||
@@ -215,8 +212,7 @@ class FixStackMethodTransformer : MethodTransformer() {
|
|||||||
if (savedStackValues != null) {
|
if (savedStackValues != null) {
|
||||||
val savedStackDescriptor = localVariablesManager.allocateVariablesForBeforeInlineMarker(inlineMarker, savedStackValues)
|
val savedStackDescriptor = localVariablesManager.allocateVariablesForBeforeInlineMarker(inlineMarker, savedStackValues)
|
||||||
actions.add { saveStack(methodNode, inlineMarker, savedStackDescriptor) }
|
actions.add { saveStack(methodNode, inlineMarker, savedStackDescriptor) }
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// before inline marker is dead code
|
// before inline marker is dead code
|
||||||
localVariablesManager.allocateVariablesForBeforeInlineMarker(inlineMarker, emptyList())
|
localVariablesManager.allocateVariablesForBeforeInlineMarker(inlineMarker, emptyList())
|
||||||
actions.add { methodNode.instructions.remove(inlineMarker) }
|
actions.add { methodNode.instructions.remove(inlineMarker) }
|
||||||
|
|||||||
+11
-4
@@ -43,7 +43,11 @@ internal class LocalVariablesManager(val context: FixStackContext, val methodNod
|
|||||||
return allocateNewHandle(numRestoreStackMarkers, saveStackMarker, savedStackValues)
|
return allocateNewHandle(numRestoreStackMarkers, saveStackMarker, savedStackValues)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun allocateNewHandle(numRestoreStackMarkers: Int, saveStackMarker: AbstractInsnNode, savedStackValues: List<BasicValue>): SavedStackDescriptor {
|
private fun allocateNewHandle(
|
||||||
|
numRestoreStackMarkers: Int,
|
||||||
|
saveStackMarker: AbstractInsnNode,
|
||||||
|
savedStackValues: List<BasicValue>
|
||||||
|
): SavedStackDescriptor {
|
||||||
if (savedStackValues.any { it.type == null }) {
|
if (savedStackValues.any { it.type == null }) {
|
||||||
throw AssertionError("Uninitialized value on stack at ${methodNode.instructions.indexOf(saveStackMarker)}")
|
throw AssertionError("Uninitialized value on stack at ${methodNode.instructions.indexOf(saveStackMarker)}")
|
||||||
}
|
}
|
||||||
@@ -62,8 +66,8 @@ internal class LocalVariablesManager(val context: FixStackContext, val methodNod
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getFirstUnusedLocalVariableIndex(): Int =
|
private fun getFirstUnusedLocalVariableIndex(): Int =
|
||||||
allocatedHandles.values.fold(initialMaxLocals) {
|
allocatedHandles.values.fold(initialMaxLocals) { index, handle ->
|
||||||
index, handle -> Math.max(index, handle.savedStackDescriptor.firstUnusedLocalVarIndex)
|
Math.max(index, handle.savedStackDescriptor.firstUnusedLocalVarIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun markRestoreStackMarkerEmitted(restoreStackMarker: AbstractInsnNode) {
|
fun markRestoreStackMarkerEmitted(restoreStackMarker: AbstractInsnNode) {
|
||||||
@@ -71,7 +75,10 @@ internal class LocalVariablesManager(val context: FixStackContext, val methodNod
|
|||||||
markEmitted(saveStackMarker!!)
|
markEmitted(saveStackMarker!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun allocateVariablesForBeforeInlineMarker(beforeInlineMarker: AbstractInsnNode, savedStackValues: List<BasicValue>): SavedStackDescriptor {
|
fun allocateVariablesForBeforeInlineMarker(
|
||||||
|
beforeInlineMarker: AbstractInsnNode,
|
||||||
|
savedStackValues: List<BasicValue>
|
||||||
|
): SavedStackDescriptor {
|
||||||
return allocateNewHandle(1, beforeInlineMarker, savedStackValues)
|
return allocateNewHandle(1, beforeInlineMarker, savedStackValues)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+15
-9
@@ -102,8 +102,10 @@ 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(location,
|
methodNode.instructions.insertBefore(
|
||||||
VarInsnNode(value.type.getOpcode(Opcodes.ILOAD), localVarIndex))
|
location,
|
||||||
|
VarInsnNode(value.type.getOpcode(Opcodes.ILOAD), localVarIndex)
|
||||||
|
)
|
||||||
localVarIndex += value.size
|
localVarIndex += value.size
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -112,27 +114,31 @@ 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(location,
|
methodNode.instructions.insertBefore(
|
||||||
VarInsnNode(value.type.getOpcode(Opcodes.ISTORE), localVarIndex))
|
location,
|
||||||
|
VarInsnNode(value.type.getOpcode(Opcodes.ISTORE), localVarIndex)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getPopInstruction(top: BasicValue) =
|
fun getPopInstruction(top: BasicValue) =
|
||||||
InsnNode(when (top.size) {
|
InsnNode(
|
||||||
|
when (top.size) {
|
||||||
1 -> Opcodes.POP
|
1 -> Opcodes.POP
|
||||||
2 -> Opcodes.POP2
|
2 -> Opcodes.POP2
|
||||||
else -> throw AssertionError("Unexpected value type size")
|
else -> throw AssertionError("Unexpected value type size")
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
fun removeAlwaysFalseIfeq(methodNode: MethodNode, node: AbstractInsnNode) {
|
fun removeAlwaysFalseIfeq(methodNode: MethodNode, node: AbstractInsnNode) {
|
||||||
with (methodNode.instructions) {
|
with(methodNode.instructions) {
|
||||||
remove(node.next)
|
remove(node.next)
|
||||||
remove(node)
|
remove(node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun replaceAlwaysTrueIfeqWithGoto(methodNode: MethodNode, node: AbstractInsnNode) {
|
fun replaceAlwaysTrueIfeqWithGoto(methodNode: MethodNode, node: AbstractInsnNode) {
|
||||||
with (methodNode.instructions) {
|
with(methodNode.instructions) {
|
||||||
val next = node.next as JumpInsnNode
|
val next = node.next as JumpInsnNode
|
||||||
insertBefore(node, JumpInsnNode(Opcodes.GOTO, next.label))
|
insertBefore(node, JumpInsnNode(Opcodes.GOTO, next.label))
|
||||||
remove(node)
|
remove(node)
|
||||||
@@ -141,7 +147,7 @@ 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<BasicValue>) {
|
||||||
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, getPopInstruction(stackValue))
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-11
@@ -37,7 +37,8 @@ import org.jetbrains.org.objectweb.asm.tree.*
|
|||||||
|
|
||||||
class RedundantNullCheckMethodTransformer : MethodTransformer() {
|
class RedundantNullCheckMethodTransformer : MethodTransformer() {
|
||||||
override fun transform(internalClassName: String, methodNode: MethodNode) {
|
override fun transform(internalClassName: String, methodNode: MethodNode) {
|
||||||
while (TransformerPass(internalClassName, methodNode).run()) {}
|
while (TransformerPass(internalClassName, methodNode).run()) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TransformerPass(val internalClassName: String, val methodNode: MethodNode) {
|
private class TransformerPass(val internalClassName: String, val methodNode: MethodNode) {
|
||||||
@@ -108,8 +109,7 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() {
|
|||||||
popReferenceValueBefore(insn)
|
popReferenceValueBefore(insn)
|
||||||
if (alwaysTrue) {
|
if (alwaysTrue) {
|
||||||
set(insn, JumpInsnNode(Opcodes.GOTO, insn.label))
|
set(insn, JumpInsnNode(Opcodes.GOTO, insn.label))
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
remove(insn)
|
remove(insn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,8 +120,7 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() {
|
|||||||
if (nullability == Nullability.NULL) {
|
if (nullability == Nullability.NULL) {
|
||||||
changes = true
|
changes = true
|
||||||
transformTrivialInstanceOf(insn, false)
|
transformTrivialInstanceOf(insn, false)
|
||||||
}
|
} else if (nullability == Nullability.NOT_NULL && value.type.internalName == insn.desc) {
|
||||||
else if (nullability == Nullability.NOT_NULL && value.type.internalName == insn.desc) {
|
|
||||||
changes = true
|
changes = true
|
||||||
transformTrivialInstanceOf(insn, true)
|
transformTrivialInstanceOf(insn, true)
|
||||||
}
|
}
|
||||||
@@ -160,8 +159,7 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() {
|
|||||||
val previous = insn.previous ?: continue@insnLoop
|
val previous = insn.previous ?: continue@insnLoop
|
||||||
if (previous.opcode == Opcodes.ALOAD) {
|
if (previous.opcode == Opcodes.ALOAD) {
|
||||||
addDependentCheck(insn, previous as VarInsnNode)
|
addDependentCheck(insn, previous as VarInsnNode)
|
||||||
}
|
} else if (previous.opcode == Opcodes.DUP) {
|
||||||
else if (previous.opcode == Opcodes.DUP) {
|
|
||||||
val previous2 = previous.previous ?: continue@insnLoop
|
val previous2 = previous.previous ?: continue@insnLoop
|
||||||
if (previous2.opcode == Opcodes.ALOAD) {
|
if (previous2.opcode == Opcodes.ALOAD) {
|
||||||
addDependentCheck(insn, previous2 as VarInsnNode)
|
addDependentCheck(insn, previous2 as VarInsnNode)
|
||||||
@@ -184,8 +182,7 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() {
|
|||||||
val insn1 = ldcInsn.previous ?: continue@insnLoop
|
val insn1 = ldcInsn.previous ?: continue@insnLoop
|
||||||
if (insn1.opcode == Opcodes.ALOAD) {
|
if (insn1.opcode == Opcodes.ALOAD) {
|
||||||
aLoadInsn = insn1 as VarInsnNode
|
aLoadInsn = insn1 as VarInsnNode
|
||||||
}
|
} else if (insn1.opcode == Opcodes.DUP) {
|
||||||
else if (insn1.opcode == Opcodes.DUP) {
|
|
||||||
val insn2 = insn1.previous ?: continue@insnLoop
|
val insn2 = insn1.previous ?: continue@insnLoop
|
||||||
if (insn2.opcode == Opcodes.ALOAD) {
|
if (insn2.opcode == Opcodes.ALOAD) {
|
||||||
aLoadInsn = insn2 as VarInsnNode
|
aLoadInsn = insn2 as VarInsnNode
|
||||||
@@ -318,8 +315,7 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() {
|
|||||||
methodNode.instructions.add(newLabel)
|
methodNode.instructions.add(newLabel)
|
||||||
next.label = newLabel
|
next.label = newLabel
|
||||||
insertAfterNotNull = newLabel
|
insertAfterNotNull = newLabel
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
originalLabel = null
|
originalLabel = null
|
||||||
insertAfterNotNull = next
|
insertAfterNotNull = next
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -37,6 +37,7 @@ object NullBasicValue : StrictBasicValue(AsmTypes.OBJECT_TYPE)
|
|||||||
|
|
||||||
enum class Nullability {
|
enum class Nullability {
|
||||||
NULL, NOT_NULL, NULLABLE;
|
NULL, NOT_NULL, NULLABLE;
|
||||||
|
|
||||||
fun isNull() = this == NULL
|
fun isNull() = this == NULL
|
||||||
fun isNotNull() = this == NOT_NULL
|
fun isNotNull() = this == NOT_NULL
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user