@@ -149,54 +149,33 @@ final class NullnessInterpreter(knownNonNullInvocation: MethodInsnNode => Boolea
149
149
}
150
150
151
151
class NullnessFrame (nLocals : Int , nStack : Int ) extends AliasingFrame [NullnessValue ](nLocals, nStack) {
152
- /**
153
- * Hack to support branch-dependent values after a null check (if (x == null) ... else ...).
154
- * Short pseudo-code of the analyzer:
155
- *
156
- * analyze()
157
- * while (numInstructionsToProcess > 0) {
158
- * currentFrame = oldFrame.clone().execute(insnNode, interpreter)
159
- * if (insnNode instanceof JumpInsnNode) {
160
- * merge(insnIndex + 1, currentFrame, subroutine)
161
- * merge(jumpInsnIndex, currentFrame, subroutine)
162
- *
163
- * merge(int insnIndex, Frame frame)
164
- * oldFrame = frames[insnIndex]
165
- * if (oldFrame == null) frames[insnIndex] = newFrame(frame)
166
- * else oldFrame.merge(frame, interpreter)
167
- *
168
- * The `currentFrame` is a temporary frame with the status after executing the instruction.
169
- * It is then either passed to `frame.merge` or to `new Frame` as parameter.
170
- *
171
- * Both of these methods are overwritten in NullnessFrame to invoke `postBranch()`. On the first
172
- * invocation it sets the state of `currentFrame` for the first branch, then for the second branch.
173
- * So `currentFrame` can have a different state for each branch.
174
- */
175
- private var postBranch : () => Unit = null
176
-
177
- override def init (src : Frame [_ <: NullnessValue ]): Frame [NullnessValue ] = {
178
- postBranch = null
179
- super .init(src)
180
- }
152
+ private [this ] var ifNullAliases : AliasSet = null
181
153
182
154
// Auxiliary constructor required for implementing `NullnessAnalyzer.newFrame`
183
155
def this (src : Frame [_ <: NullnessValue ]) {
184
156
this (src.getLocals, src.getMaxStackSize)
185
- val s = src.asInstanceOf [NullnessFrame ]
186
- if (s.postBranch != null ) s.postBranch()
187
157
init(src)
188
158
}
189
159
190
- override def merge (other : Frame [_ <: NullnessValue ], interpreter : Interpreter [NullnessValue ]): Boolean = {
191
- val o = other.asInstanceOf [NullnessFrame ]
192
- if (o.postBranch != null ) o.postBranch()
193
- super .merge(other, interpreter)
160
+ private def setNullness (s : AliasSet , v : NullnessValue ) = {
161
+ val it = s.iterator
162
+ while (it.hasNext)
163
+ this .setValue(it.next(), v)
164
+ }
165
+
166
+ override def initJumpTarget (opcode : Int , target : LabelNode ): Unit = {
167
+ // when `target` is defined, we're in the case where the branch condition is true
168
+ val conditionTrue = target != null
169
+ if (opcode == Opcodes .IFNULL )
170
+ setNullness(ifNullAliases, if (conditionTrue) NullValue else NotNullValue )
171
+ else if (opcode == Opcodes .IFNONNULL )
172
+ setNullness(ifNullAliases, if (conditionTrue) NotNullValue else NullValue )
194
173
}
195
174
196
175
override def execute (insn : AbstractInsnNode , interpreter : Interpreter [NullnessValue ]): Unit = {
197
176
import Opcodes ._
198
177
199
- val ifNullAliases : AliasSet = insn.getOpcode match {
178
+ ifNullAliases = insn.getOpcode match {
200
179
case IFNULL | IFNONNULL => aliasesOf(this .stackTop)
201
180
case _ => null
202
181
}
@@ -264,24 +243,8 @@ class NullnessFrame(nLocals: Int, nStack: Int) extends AliasingFrame[NullnessVal
264
243
265
244
super .execute(insn, interpreter)
266
245
267
- def setNullness (s : AliasSet , v : NullnessValue ) = {
268
- val it = s.iterator
269
- while (it.hasNext)
270
- this .setValue(it.next(), v)
271
- }
272
-
273
- if (ifNullAliases != null ) {
274
- val v = if (insn.getOpcode == IFNULL ) NotNullValue else NullValue
275
- postBranch = () => {
276
- setNullness(ifNullAliases, v)
277
- postBranch = () => {
278
- setNullness(ifNullAliases, v.invert)
279
- postBranch = null
280
- }
281
- }
282
- }
283
-
284
- if (nullCheckedAliases != null ) setNullness(nullCheckedAliases, NotNullValue )
246
+ if (nullCheckedAliases != null )
247
+ setNullness(nullCheckedAliases, NotNullValue )
285
248
}
286
249
}
287
250
0 commit comments