in src/main/java/org/apache/bcel/verifier/structurals/OperandStack.java [132:166]
public void merge(final OperandStack s) {
try {
if (slotsUsed() != s.slotsUsed() || size() != s.size()) {
throw new StructuralCodeConstraintException("Cannot merge stacks of different size:\nOperandStack A:\n" + this + "\nOperandStack B:\n" + s);
}
for (int i = 0; i < size(); i++) {
// If the object _was_ initialized and we're supposed to merge
// in some uninitialized object, we reject the code (see vmspec2, 4.9.4, last paragraph).
if (!(stack.get(i) instanceof UninitializedObjectType) && s.stack.get(i) instanceof UninitializedObjectType) {
throw new StructuralCodeConstraintException("Backwards branch with an uninitialized object on the stack detected.");
}
// Even harder, we're not initialized but are supposed to broaden
// the known object type
if (!stack.get(i).equals(s.stack.get(i)) && stack.get(i) instanceof UninitializedObjectType
&& !(s.stack.get(i) instanceof UninitializedObjectType)) {
throw new StructuralCodeConstraintException("Backwards branch with an uninitialized object on the stack detected.");
}
// on the other hand...
if (stack.get(i) instanceof UninitializedObjectType && !(s.stack.get(i) instanceof UninitializedObjectType)) { // that has been initialized by
// now
stack.set(i, ((UninitializedObjectType) stack.get(i)).getInitialized()); // note that.
}
if (!stack.get(i).equals(s.stack.get(i))) {
if (!(stack.get(i) instanceof ReferenceType) || !(s.stack.get(i) instanceof ReferenceType)) {
throw new StructuralCodeConstraintException("Cannot merge stacks of different types:\nStack A:\n" + this + "\nStack B:\n" + s);
}
stack.set(i, ((ReferenceType) stack.get(i)).getFirstCommonSuperclass((ReferenceType) s.stack.get(i)));
}
}
} catch (final ClassNotFoundException e) {
// FIXME: maybe not the best way to handle this
throw new AssertionViolatedException("Missing class: " + e, e);
}
}