JVM skip methods without NEW insns in UninitializedStoresProcessor
This commit is contained in:
committed by
teamcityserver
parent
eff7c375ce
commit
6c734289be
+21
-23
@@ -73,8 +73,8 @@ import kotlin.math.max
|
|||||||
* - restore constructor arguments
|
* - restore constructor arguments
|
||||||
*/
|
*/
|
||||||
class UninitializedStoresProcessor(
|
class UninitializedStoresProcessor(
|
||||||
private val methodNode: MethodNode,
|
private val methodNode: MethodNode,
|
||||||
private val shouldPreserveClassInitialization: Boolean
|
private val shouldPreserveClassInitialization: Boolean
|
||||||
) {
|
) {
|
||||||
// <init> method is "special", because it will invoke <init> from this class or from a base class for #0
|
// <init> method is "special", because it will invoke <init> from this class or from a base class for #0
|
||||||
//
|
//
|
||||||
@@ -87,10 +87,10 @@ class UninitializedStoresProcessor(
|
|||||||
fun run() {
|
fun run() {
|
||||||
val interpreter = UninitializedNewValueMarkerInterpreter(methodNode.instructions)
|
val interpreter = UninitializedNewValueMarkerInterpreter(methodNode.instructions)
|
||||||
|
|
||||||
val frames = CustomFramesMethodAnalyzer(
|
if (methodNode.instructions.toArray().none { it.opcode == Opcodes.NEW })
|
||||||
"fake", methodNode, interpreter,
|
return
|
||||||
this::UninitializedNewValueFrame
|
|
||||||
).analyze()
|
val frames = CustomFramesMethodAnalyzer("fake", methodNode, interpreter, this::UninitializedNewValueFrame).analyze()
|
||||||
|
|
||||||
interpreter.analyzePopInstructions(frames)
|
interpreter.analyzePopInstructions(frames)
|
||||||
|
|
||||||
@@ -115,12 +115,12 @@ class UninitializedStoresProcessor(
|
|||||||
// POP
|
// POP
|
||||||
val typeNameForClass = newInsn.desc.replace('/', '.')
|
val typeNameForClass = newInsn.desc.replace('/', '.')
|
||||||
insertBefore(newInsn, LdcInsnNode(typeNameForClass))
|
insertBefore(newInsn, LdcInsnNode(typeNameForClass))
|
||||||
insertBefore(newInsn, MethodInsnNode(
|
insertBefore(
|
||||||
Opcodes.INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;", false
|
newInsn,
|
||||||
))
|
MethodInsnNode(Opcodes.INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;", false)
|
||||||
|
)
|
||||||
set(newInsn, InsnNode(Opcodes.POP))
|
set(newInsn, InsnNode(Opcodes.POP))
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
remove(newInsn)
|
remove(newInsn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -138,10 +138,7 @@ class UninitializedStoresProcessor(
|
|||||||
}
|
}
|
||||||
methodNode.maxLocals = max(methodNode.maxLocals, nextVarIndex)
|
methodNode.maxLocals = max(methodNode.maxLocals, nextVarIndex)
|
||||||
|
|
||||||
methodNode.instructions.insertBefore(insn, insnListOf(
|
methodNode.instructions.insertBefore(insn, insnListOf(TypeInsnNode(Opcodes.NEW, newInsn.desc), InsnNode(Opcodes.DUP)))
|
||||||
TypeInsnNode(Opcodes.NEW, newInsn.desc),
|
|
||||||
InsnNode(Opcodes.DUP)
|
|
||||||
))
|
|
||||||
|
|
||||||
for (type in storedTypes.reversed()) {
|
for (type in storedTypes.reversed()) {
|
||||||
nextVarIndex -= type.size
|
nextVarIndex -= type.size
|
||||||
@@ -174,11 +171,11 @@ class UninitializedStoresProcessor(
|
|||||||
|
|
||||||
assert(insn.opcode == Opcodes.INVOKESPECIAL) { "Expected opcode Opcodes.INVOKESPECIAL for <init>, but ${insn.opcode} found" }
|
assert(insn.opcode == Opcodes.INVOKESPECIAL) { "Expected opcode Opcodes.INVOKESPECIAL for <init>, but ${insn.opcode} found" }
|
||||||
val paramsCountIncludingReceiver = Type.getArgumentTypes((insn as MethodInsnNode).desc).size + 1
|
val paramsCountIncludingReceiver = Type.getArgumentTypes((insn as MethodInsnNode).desc).size + 1
|
||||||
val newValue = peek(paramsCountIncludingReceiver) as? UninitializedNewValue ?:
|
val newValue = peek(paramsCountIncludingReceiver) as? UninitializedNewValue
|
||||||
if (isInSpecialMethod)
|
?: if (isInSpecialMethod)
|
||||||
return null
|
return null
|
||||||
else
|
else
|
||||||
error("Expected value generated with NEW")
|
error("Expected value generated with NEW")
|
||||||
|
|
||||||
assert(peek(paramsCountIncludingReceiver - 1) is UninitializedNewValue) {
|
assert(peek(paramsCountIncludingReceiver - 1) is UninitializedNewValue) {
|
||||||
"Next value after NEW should be one generated by DUP"
|
"Next value after NEW should be one generated by DUP"
|
||||||
@@ -188,8 +185,8 @@ class UninitializedStoresProcessor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class UninitializedNewValue(
|
private class UninitializedNewValue(
|
||||||
val newInsn: TypeInsnNode,
|
val newInsn: TypeInsnNode,
|
||||||
val internalName: String
|
val internalName: String
|
||||||
) : StrictBasicValue(Type.getObjectType(internalName)) {
|
) : StrictBasicValue(Type.getObjectType(internalName)) {
|
||||||
override fun toString() = "UninitializedNewValue(internalName='$internalName')"
|
override fun toString() = "UninitializedNewValue(internalName='$internalName')"
|
||||||
}
|
}
|
||||||
@@ -236,7 +233,8 @@ class UninitializedStoresProcessor(
|
|||||||
|
|
||||||
private fun checkUninitializedObjectCopy(newInsn: TypeInsnNode, usageInsn: AbstractInsnNode) {
|
private fun checkUninitializedObjectCopy(newInsn: TypeInsnNode, usageInsn: AbstractInsnNode) {
|
||||||
when (usageInsn.opcode) {
|
when (usageInsn.opcode) {
|
||||||
Opcodes.DUP, Opcodes.ASTORE, Opcodes.ALOAD -> {}
|
Opcodes.DUP, Opcodes.ASTORE, Opcodes.ALOAD -> {
|
||||||
|
}
|
||||||
else -> error("Unexpected copy instruction for ${newInsn.debugText}: ${usageInsn.debugText}")
|
else -> error("Unexpected copy instruction for ${newInsn.debugText}: ${usageInsn.debugText}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user