View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   https://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.bcel.verifier.structurals;
20  
21  import org.apache.bcel.Const;
22  import org.apache.bcel.Repository;
23  import org.apache.bcel.classfile.Constant;
24  import org.apache.bcel.classfile.ConstantClass;
25  import org.apache.bcel.classfile.ConstantDouble;
26  import org.apache.bcel.classfile.ConstantDynamic;
27  import org.apache.bcel.classfile.ConstantFieldref;
28  import org.apache.bcel.classfile.ConstantFloat;
29  import org.apache.bcel.classfile.ConstantInteger;
30  import org.apache.bcel.classfile.ConstantLong;
31  import org.apache.bcel.classfile.ConstantString;
32  import org.apache.bcel.classfile.Field;
33  import org.apache.bcel.classfile.JavaClass;
34  import org.apache.bcel.verifier.VerificationResult;
35  import org.apache.bcel.verifier.Verifier;
36  import org.apache.bcel.verifier.VerifierFactory;
37  import org.apache.bcel.verifier.exc.AssertionViolatedException;
38  import org.apache.bcel.verifier.exc.StructuralCodeConstraintException;
39  
40  //CHECKSTYLE:OFF (there are lots of references!)
41  import org.apache.bcel.generic.*;
42  //CHECKSTYLE:ON
43  
44  /**
45   * A Visitor class testing for valid preconditions of JVM instructions. The instance of this class will throw a
46   * StructuralCodeConstraintException instance if an instruction is visitXXX()ed which has preconditions that are not
47   * satisfied. TODO: Currently, the JVM's behavior concerning monitors (MONITORENTER, MONITOREXIT) is not modeled in
48   * JustIce.
49   *
50   * @see StructuralCodeConstraintException
51   */
52  public class InstConstraintVisitor extends EmptyVisitor {
53  
54      private static final ObjectType GENERIC_ARRAY = ObjectType.getInstance(GenericArray.class.getName());
55  
56      /**
57       * The Execution Frame we're working on.
58       *
59       * @see #setFrame(Frame f)
60       * @see #locals()
61       * @see #stack()
62       */
63      private Frame frame;
64  
65      /**
66       * The ConstantPoolGen we're working on.
67       *
68       * @see #setConstantPoolGen(ConstantPoolGen cpg)
69       */
70      private ConstantPoolGen cpg;
71  
72      /**
73       * The MethodGen we're working on.
74       *
75       * @see #setMethodGen(MethodGen mg)
76       */
77      private MethodGen mg;
78  
79      /**
80       * The constructor. Constructs a new instance of this class.
81       */
82      public InstConstraintVisitor() {
83      }
84  
85      /**
86       * Assures arrayref is of ArrayType or NULL; returns true if and only if arrayref is non-NULL.
87       *
88       * @throws StructuralCodeConstraintException if the above constraint is violated.
89       */
90      private boolean arrayrefOfArrayType(final Instruction o, final Type arrayref) {
91          if (!(arrayref instanceof ArrayType || arrayref.equals(Type.NULL))) {
92              constraintViolated(o, "The 'arrayref' does not refer to an array but is of type " + arrayref + ".");
93          }
94          return arrayref instanceof ArrayType;
95      }
96  
97      /**
98       * This method is called by the visitXXX() to notify the acceptor of this InstConstraintVisitor that a constraint
99       * violation has occurred. This is done by throwing an instance of a StructuralCodeConstraintException.
100      *
101      * @throws StructuralCodeConstraintException always.
102      */
103     private void constraintViolated(final Instruction violator, final String description) {
104         final String fqClassName = violator.getClass().getName();
105         throw new StructuralCodeConstraintException(
106             "Instruction " + fqClassName.substring(fqClassName.lastIndexOf('.') + 1) + " constraint violated: " + description);
107     }
108 
109     private ObjectType getObjectType(final FieldInstruction o) {
110         final ReferenceType rt = o.getReferenceType(cpg);
111         if (rt instanceof ObjectType) {
112             return (ObjectType) rt;
113         }
114         constraintViolated(o, "expecting ObjectType but got " + rt);
115         return null;
116     }
117 
118     /**
119      * Assures index is of type INT.
120      *
121      * @throws StructuralCodeConstraintException if the above constraint is not satisfied.
122      */
123     private void indexOfInt(final Instruction o, final Type index) {
124         if (!index.equals(Type.INT)) {
125             constraintViolated(o, "The 'index' is not of type int but of type " + index + ".");
126         }
127     }
128 
129     /**
130      * The LocalVariables we're working on.
131      *
132      * @see #setFrame(Frame f)
133      */
134     private LocalVariables locals() {
135         return frame.getLocals();
136     }
137 
138     /**
139      * Assures the ReferenceType r is initialized (or Type.NULL). Formally, this means (!(r instanceof
140      * UninitializedObjectType)), because there are no uninitialized array types.
141      *
142      * @throws StructuralCodeConstraintException if the above constraint is not satisfied.
143      */
144     private void referenceTypeIsInitialized(final Instruction o, final ReferenceType r) {
145         if (r instanceof UninitializedObjectType) {
146             constraintViolated(o, "Working on an uninitialized object '" + r + "'.");
147         }
148     }
149 
150     /**
151      * Sets the ConstantPoolGen instance needed for constraint checking prior to execution.
152      *
153      * @param cpg the constant pool generator.
154      */
155     public void setConstantPoolGen(final ConstantPoolGen cpg) { // TODO could be package-protected?
156         this.cpg = cpg;
157     }
158 
159     /**
160      * This returns the single instance of the InstConstraintVisitor class. To operate correctly, other values must have
161      * been set before actually using the instance. Use this method for performance reasons.
162      *
163      * @param f the frame to set.
164      * @see #setConstantPoolGen(ConstantPoolGen cpg)
165      * @see #setMethodGen(MethodGen mg)
166      */
167     public void setFrame(final Frame f) { // TODO could be package-protected?
168         this.frame = f;
169         // if (singleInstance.mg == null || singleInstance.cpg == null)
170         // throw new AssertionViolatedException("Forgot to set important values first.");
171     }
172 
173     /**
174      * Sets the MethodGen instance needed for constraint checking prior to execution.
175      *
176      * @param mg the method generator.
177      */
178     public void setMethodGen(final MethodGen mg) {
179         this.mg = mg;
180     }
181 
182     /**
183      * The OperandStack we're working on.
184      *
185      * @see #setFrame(Frame f)
186      */
187     private OperandStack stack() {
188         return frame.getStack();
189     }
190 
191     /** Assures value is of type INT. */
192     private void valueOfInt(final Instruction o, final Type value) {
193         if (!value.equals(Type.INT)) {
194             constraintViolated(o, "The 'value' is not of type int but of type " + value + ".");
195         }
196     }
197 
198     /*
199      * "generic"visitXXXX methods where XXXX is an interface therefore, we don't know the order of visiting; but we know these methods are called before the
200      * visitYYYY methods below
201      */
202 
203     /**
204      * Ensures the specific preconditions of the said instruction.
205      */
206     @Override
207     public void visitAALOAD(final AALOAD o) {
208         final Type arrayref = stack().peek(1);
209         final Type index = stack().peek(0);
210 
211         indexOfInt(o, index);
212         if (arrayrefOfArrayType(o, arrayref) && !(((ArrayType) arrayref).getElementType() instanceof ReferenceType)) {
213             constraintViolated(o, "The 'arrayref' does not refer to an array with elements of a ReferenceType but to an array of "
214                 + ((ArrayType) arrayref).getElementType() + ".");
215         }
216         // referenceTypeIsInitialized(o, (ReferenceType) (((ArrayType) arrayref).getElementType()));
217     }
218 
219     /**
220      * Ensures the specific preconditions of the said instruction.
221      */
222     @Override
223     public void visitAASTORE(final AASTORE o) {
224         final Type arrayref = stack().peek(2);
225         final Type index = stack().peek(1);
226         final Type value = stack().peek(0);
227 
228         indexOfInt(o, index);
229         if (!(value instanceof ReferenceType)) {
230             constraintViolated(o, "The 'value' is not of a ReferenceType but of type " + value + ".");
231         }
232         // } else {
233             // referenceTypeIsInitialized(o, (ReferenceType) value);
234         // }
235         //
236         // Don't bother further with "referenceTypeIsInitialized()", there are no arrays
237         // of an uninitialized object type.
238         if (arrayrefOfArrayType(o, arrayref) && !(((ArrayType) arrayref).getElementType() instanceof ReferenceType)) {
239             constraintViolated(o, "The 'arrayref' does not refer to an array with elements of a ReferenceType but to an array of "
240                 + ((ArrayType) arrayref).getElementType() + ".");
241         }
242         // No check for array element assignment compatibility. This is done at runtime.
243     }
244 
245     /**
246      * Ensures the specific preconditions of the said instruction.
247      */
248     @Override
249     public void visitACONST_NULL(final ACONST_NULL o) {
250         // Nothing needs to be done here.
251     }
252 
253     /**
254      * Ensures the specific preconditions of the said instruction.
255      */
256     @Override
257     public void visitALOAD(final ALOAD o) {
258         // visitLoadInstruction(LoadInstruction) is called before.
259 
260         // Nothing else needs to be done here.
261     }
262 
263     /**
264      * Ensures the specific preconditions of the said instruction.
265      */
266     @Override
267     public void visitANEWARRAY(final ANEWARRAY o) {
268         if (!stack().peek().equals(Type.INT)) {
269             constraintViolated(o, "The 'count' at the stack top is not of type '" + Type.INT + "' but of type '" + stack().peek() + "'.");
270             // The runtime constant pool item at that index must be a symbolic reference to a class,
271             // array, or interface type. See Pass 3a.
272         }
273     }
274 
275     /**
276      * Ensures the specific preconditions of the said instruction.
277      */
278     @Override
279     public void visitARETURN(final ARETURN o) {
280         if (!(stack().peek() instanceof ReferenceType)) {
281             constraintViolated(o, "The 'objectref' at the stack top is not of a ReferenceType but of type '" + stack().peek() + "'.");
282         }
283         final ReferenceType objectref = (ReferenceType) stack().peek();
284         referenceTypeIsInitialized(o, objectref);
285 
286         // The check below should already done via visitReturnInstruction(ReturnInstruction), see there.
287         // It cannot be done using Staerk-et-al's "set of object types" instead of a
288         // "wider cast object type", anyway.
289         // if (! objectref.isAssignmentCompatibleWith(mg.getReturnType() )) {
290         // constraintViolated(o, "The 'objectref' type "+objectref+
291         // " at the stack top is not assignment compatible with the return type '"+mg.getReturnType()+"' of the method.");
292         // }
293     }
294 
295     /**
296      * Ensures the specific preconditions of the said instruction.
297      */
298     @Override
299     public void visitARRAYLENGTH(final ARRAYLENGTH o) {
300         final Type arrayref = stack().peek(0);
301         arrayrefOfArrayType(o, arrayref);
302     }
303 
304     /**
305      * Ensures the specific preconditions of the said instruction.
306      */
307     @Override
308     public void visitASTORE(final ASTORE o) {
309         if (!(stack().peek() instanceof ReferenceType || stack().peek() instanceof ReturnaddressType)) {
310             constraintViolated(o, "The 'objectref' is not of a ReferenceType or of ReturnaddressType but of " + stack().peek() + ".");
311         }
312         // if (stack().peek() instanceof ReferenceType) {
313         // referenceTypeIsInitialized(o, (ReferenceType) (stack().peek()) );
314         // }
315     }
316 
317     /**
318      * Ensures the specific preconditions of the said instruction.
319      */
320     @Override
321     public void visitATHROW(final ATHROW o) {
322         try {
323             // It's stated that 'objectref' must be of a ReferenceType --- but since Throwable is
324             // not derived from an ArrayType, it follows that 'objectref' must be of an ObjectType or Type.NULL.
325             if (!(stack().peek() instanceof ObjectType || stack().peek().equals(Type.NULL))) {
326                 constraintViolated(o, "The 'objectref' is not of an (initialized) ObjectType but of type " + stack().peek() + ".");
327             }
328 
329             // NULL is a subclass of every class, so to speak.
330             if (stack().peek().equals(Type.NULL)) {
331                 return;
332             }
333 
334             final ObjectType exc = (ObjectType) stack().peek();
335             final ObjectType throwable = (ObjectType) Type.getType("Ljava/lang/Throwable;");
336             if (!exc.subclassOf(throwable) && !exc.equals(throwable)) {
337                 constraintViolated(o, "The 'objectref' is not of class Throwable or of a subclass of Throwable, but of '" + stack().peek() + "'.");
338             }
339         } catch (final ClassNotFoundException e) {
340             // FIXME: maybe not the best way to handle this
341             throw new AssertionViolatedException("Missing class: " + e, e);
342         }
343     }
344 
345     /**
346      * Ensures the specific preconditions of the said instruction.
347      */
348     @Override
349     public void visitBALOAD(final BALOAD o) {
350         final Type arrayref = stack().peek(1);
351         final Type index = stack().peek(0);
352         indexOfInt(o, index);
353         if (arrayrefOfArrayType(o, arrayref)
354             && !(((ArrayType) arrayref).getElementType().equals(Type.BOOLEAN) || ((ArrayType) arrayref).getElementType().equals(Type.BYTE))) {
355             constraintViolated(o, "The 'arrayref' does not refer to an array with elements of a Type.BYTE or Type.BOOLEAN but to an array of '"
356                 + ((ArrayType) arrayref).getElementType() + "'.");
357         }
358     }
359 
360     /**
361      * Ensures the specific preconditions of the said instruction.
362      */
363     @Override
364     public void visitBASTORE(final BASTORE o) {
365         final Type arrayref = stack().peek(2);
366         final Type index = stack().peek(1);
367         final Type value = stack().peek(0);
368 
369         indexOfInt(o, index);
370         valueOfInt(o, value);
371         if (arrayrefOfArrayType(o, arrayref)
372             && !(((ArrayType) arrayref).getElementType().equals(Type.BOOLEAN) || ((ArrayType) arrayref).getElementType().equals(Type.BYTE))) {
373             constraintViolated(o, "The 'arrayref' does not refer to an array with elements of a Type.BYTE or Type.BOOLEAN but to an array of '"
374                 + ((ArrayType) arrayref).getElementType() + "'.");
375         }
376     }
377 
378     /*
379     /* "special"visitXXXX methods for one type of instruction each.
380      */
381 
382     /**
383      * Ensures the specific preconditions of the said instruction.
384      */
385     @Override
386     public void visitBIPUSH(final BIPUSH o) {
387         // Nothing to do...
388     }
389 
390     /**
391      * Ensures the specific preconditions of the said instruction.
392      */
393     @Override
394     public void visitBREAKPOINT(final BREAKPOINT o) {
395         throw new AssertionViolatedException("In this JustIce verification pass there should not occur an illegal instruction such as BREAKPOINT.");
396     }
397 
398     /**
399      * Ensures the specific preconditions of the said instruction.
400      */
401     @Override
402     public void visitCALOAD(final CALOAD o) {
403         final Type arrayref = stack().peek(1);
404         final Type index = stack().peek(0);
405 
406         indexOfInt(o, index);
407         arrayrefOfArrayType(o, arrayref);
408     }
409 
410     /**
411      * Ensures the specific preconditions of the said instruction.
412      */
413     @Override
414     public void visitCASTORE(final CASTORE o) {
415         final Type arrayref = stack().peek(2);
416         final Type index = stack().peek(1);
417         final Type value = stack().peek(0);
418 
419         indexOfInt(o, index);
420         valueOfInt(o, value);
421         if (arrayrefOfArrayType(o, arrayref) && !((ArrayType) arrayref).getElementType().equals(Type.CHAR)) {
422             constraintViolated(o, "The 'arrayref' does not refer to an array with elements of type char but to an array of type "
423                 + ((ArrayType) arrayref).getElementType() + ".");
424         }
425     }
426 
427     /**
428      * Ensures the specific preconditions of the said instruction.
429      */
430     @Override
431     public void visitCHECKCAST(final CHECKCAST o) {
432         // The objectref must be of type reference.
433         final Type objectref = stack().peek(0);
434         if (!(objectref instanceof ReferenceType)) {
435             constraintViolated(o, "The 'objectref' is not of a ReferenceType but of type " + objectref + ".");
436         }
437         // else{
438         // referenceTypeIsInitialized(o, (ReferenceType) objectref);
439         // }
440         // The unsigned indexbyte1 and indexbyte2 are used to construct an index into the runtime constant pool of the
441         // current class (�3.6), where the value of the index is (indexbyte1 << 8) | indexbyte2. The runtime constant
442         // pool item at the index must be a symbolic reference to a class, array, or interface type.
443         final Constant c = cpg.getConstant(o.getIndex());
444         if (!(c instanceof ConstantClass)) {
445             constraintViolated(o, "The Constant at 'index' is not a ConstantClass, but '" + c + "'.");
446         }
447     }
448 
449     /*
450      * "generic" visitYYYY methods where YYYY is a superclass.
451      * therefore, we know the order of visiting; we know
452      * these methods are called after the visitXXXX methods above.
453      */
454 
455     /**
456      * Ensures the general preconditions of a CPInstruction instance.
457      */
458     @Override
459     public void visitCPInstruction(final CPInstruction o) {
460         final int idx = o.getIndex();
461         if (idx < 0 || idx >= cpg.getSize()) {
462             throw new AssertionViolatedException("Huh?! Constant pool index of instruction '" + o + "' illegal? Pass 3a should have checked this!");
463         }
464     }
465 
466     /**
467      * Ensures the specific preconditions of the said instruction.
468      */
469     @Override
470     public void visitD2F(final D2F o) {
471         if (stack().peek() != Type.DOUBLE) {
472             constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'.");
473         }
474     }
475 
476     /**
477      * Ensures the specific preconditions of the said instruction.
478      */
479     @Override
480     public void visitD2I(final D2I o) {
481         if (stack().peek() != Type.DOUBLE) {
482             constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'.");
483         }
484     }
485 
486     /**
487      * Ensures the specific preconditions of the said instruction.
488      */
489     @Override
490     public void visitD2L(final D2L o) {
491         if (stack().peek() != Type.DOUBLE) {
492             constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'.");
493         }
494     }
495 
496     /**
497      * Ensures the specific preconditions of the said instruction.
498      */
499     @Override
500     public void visitDADD(final DADD o) {
501         if (stack().peek() != Type.DOUBLE) {
502             constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'.");
503         }
504         if (stack().peek(1) != Type.DOUBLE) {
505             constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '" + stack().peek(1) + "'.");
506         }
507     }
508 
509     /**
510      * Ensures the specific preconditions of the said instruction.
511      */
512     @Override
513     public void visitDALOAD(final DALOAD o) {
514         indexOfInt(o, stack().peek());
515         if (stack().peek(1) == Type.NULL) {
516             return;
517         }
518         if (!(stack().peek(1) instanceof ArrayType)) {
519             constraintViolated(o, "Stack next-to-top must be of type double[] but is '" + stack().peek(1) + "'.");
520         }
521         final Type t = ((ArrayType) stack().peek(1)).getBasicType();
522         if (t != Type.DOUBLE) {
523             constraintViolated(o, "Stack next-to-top must be of type double[] but is '" + stack().peek(1) + "'.");
524         }
525     }
526 
527     /**
528      * Ensures the specific preconditions of the said instruction.
529      */
530     @Override
531     public void visitDASTORE(final DASTORE o) {
532         if (stack().peek() != Type.DOUBLE) {
533             constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'.");
534         }
535         indexOfInt(o, stack().peek(1));
536         if (stack().peek(2) == Type.NULL) {
537             return;
538         }
539         if (!(stack().peek(2) instanceof ArrayType)) {
540             constraintViolated(o, "Stack next-to-next-to-top must be of type double[] but is '" + stack().peek(2) + "'.");
541         }
542         final Type t = ((ArrayType) stack().peek(2)).getBasicType();
543         if (t != Type.DOUBLE) {
544             constraintViolated(o, "Stack next-to-next-to-top must be of type double[] but is '" + stack().peek(2) + "'.");
545         }
546     }
547 
548     /**
549      * Ensures the specific preconditions of the said instruction.
550      */
551     @Override
552     public void visitDCMPG(final DCMPG o) {
553         if (stack().peek() != Type.DOUBLE) {
554             constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'.");
555         }
556         if (stack().peek(1) != Type.DOUBLE) {
557             constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '" + stack().peek(1) + "'.");
558         }
559     }
560 
561     /**
562      * Ensures the specific preconditions of the said instruction.
563      */
564     @Override
565     public void visitDCMPL(final DCMPL o) {
566         if (stack().peek() != Type.DOUBLE) {
567             constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'.");
568         }
569         if (stack().peek(1) != Type.DOUBLE) {
570             constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '" + stack().peek(1) + "'.");
571         }
572     }
573 
574     /**
575      * Ensures the specific preconditions of the said instruction.
576      */
577     @Override
578     public void visitDCONST(final DCONST o) {
579         // There's nothing to be done here.
580     }
581 
582     /**
583      * Ensures the specific preconditions of the said instruction.
584      */
585     @Override
586     public void visitDDIV(final DDIV o) {
587         if (stack().peek() != Type.DOUBLE) {
588             constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'.");
589         }
590         if (stack().peek(1) != Type.DOUBLE) {
591             constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '" + stack().peek(1) + "'.");
592         }
593     }
594 
595     /**
596      * Ensures the specific preconditions of the said instruction.
597      */
598     @Override
599     public void visitDLOAD(final DLOAD o) {
600         // visitLoadInstruction(LoadInstruction) is called before.
601 
602         // Nothing else needs to be done here.
603     }
604 
605     /**
606      * Ensures the specific preconditions of the said instruction.
607      */
608     @Override
609     public void visitDMUL(final DMUL o) {
610         if (stack().peek() != Type.DOUBLE) {
611             constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'.");
612         }
613         if (stack().peek(1) != Type.DOUBLE) {
614             constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '" + stack().peek(1) + "'.");
615         }
616     }
617 
618     /**
619      * Ensures the specific preconditions of the said instruction.
620      */
621     @Override
622     public void visitDNEG(final DNEG o) {
623         if (stack().peek() != Type.DOUBLE) {
624             constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'.");
625         }
626     }
627 
628     /**
629      * Ensures the specific preconditions of the said instruction.
630      */
631     @Override
632     public void visitDREM(final DREM o) {
633         if (stack().peek() != Type.DOUBLE) {
634             constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'.");
635         }
636         if (stack().peek(1) != Type.DOUBLE) {
637             constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '" + stack().peek(1) + "'.");
638         }
639     }
640 
641     /**
642      * Ensures the specific preconditions of the said instruction.
643      */
644     @Override
645     public void visitDRETURN(final DRETURN o) {
646         if (stack().peek() != Type.DOUBLE) {
647             constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'.");
648         }
649     }
650 
651     /**
652      * Ensures the specific preconditions of the said instruction.
653      */
654     @Override
655     public void visitDSTORE(final DSTORE o) {
656         // visitStoreInstruction(StoreInstruction) is called before.
657 
658         // Nothing else needs to be done here.
659     }
660 
661     /**
662      * Ensures the specific preconditions of the said instruction.
663      */
664     @Override
665     public void visitDSUB(final DSUB o) {
666         if (stack().peek() != Type.DOUBLE) {
667             constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'.");
668         }
669         if (stack().peek(1) != Type.DOUBLE) {
670             constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '" + stack().peek(1) + "'.");
671         }
672     }
673 
674     /**
675      * Ensures the specific preconditions of the said instruction.
676      */
677     @Override
678     public void visitDUP(final DUP o) {
679         if (stack().peek().getSize() != 1) {
680             constraintViolated(o,
681                 "Won't DUP type on stack top '" + stack().peek() + "' because it must occupy exactly one slot, not '" + stack().peek().getSize() + "'.");
682         }
683     }
684 
685     /**
686      * Ensures the specific preconditions of the said instruction.
687      */
688     @Override
689     public void visitDUP_X1(final DUP_X1 o) {
690         if (stack().peek().getSize() != 1) {
691             constraintViolated(o, "Type on stack top '" + stack().peek() + "' should occupy exactly one slot, not '" + stack().peek().getSize() + "'.");
692         }
693         if (stack().peek(1).getSize() != 1) {
694             constraintViolated(o,
695                 "Type on stack next-to-top '" + stack().peek(1) + "' should occupy exactly one slot, not '" + stack().peek(1).getSize() + "'.");
696         }
697     }
698 
699     /**
700      * Ensures the specific preconditions of the said instruction.
701      */
702     @Override
703     public void visitDUP_X2(final DUP_X2 o) {
704         if (stack().peek().getSize() != 1) {
705             constraintViolated(o, "Stack top type must be of size 1, but is '" + stack().peek() + "' of size '" + stack().peek().getSize() + "'.");
706         }
707         if (stack().peek(1).getSize() == 2) {
708             return; // Form 2, okay.
709         }
710         // stack().peek(1).getSize == 1.
711         if (stack().peek(2).getSize() != 1) {
712             constraintViolated(o, "If stack top's size is 1 and stack next-to-top's size is 1, stack next-to-next-to-top's size must also be 1, but is: '"
713                 + stack().peek(2) + "' of size '" + stack().peek(2).getSize() + "'.");
714         }
715     }
716 
717     /**
718      * Ensures the specific preconditions of the said instruction.
719      */
720     @Override
721     public void visitDUP2(final DUP2 o) {
722         if (stack().peek().getSize() == 2) {
723             return; // Form 2, okay.
724         }
725         // stack().peek().getSize() == 1.
726         if (stack().peek(1).getSize() != 1) {
727             constraintViolated(o, "If stack top's size is 1, then stack next-to-top's size must also be 1. But it is '" + stack().peek(1) + "' of size '"
728                 + stack().peek(1).getSize() + "'.");
729         }
730     }
731 
732     /**
733      * Ensures the specific preconditions of the said instruction.
734      */
735     @Override
736     public void visitDUP2_X1(final DUP2_X1 o) {
737         if (stack().peek().getSize() == 2) {
738             if (stack().peek(1).getSize() != 1) {
739                 constraintViolated(o, "If stack top's size is 2, then stack next-to-top's size must be 1. But it is '" + stack().peek(1) + "' of size '"
740                     + stack().peek(1).getSize() + "'.");
741             }
742         } else { // stack top is of size 1
743             if (stack().peek(1).getSize() != 1) {
744                 constraintViolated(o, "If stack top's size is 1, then stack next-to-top's size must also be 1. But it is '" + stack().peek(1) + "' of size '"
745                     + stack().peek(1).getSize() + "'.");
746             }
747             if (stack().peek(2).getSize() != 1) {
748                 constraintViolated(o, "If stack top's size is 1, then stack next-to-next-to-top's size must also be 1. But it is '" + stack().peek(2)
749                     + "' of size '" + stack().peek(2).getSize() + "'.");
750             }
751         }
752     }
753 
754     /**
755      * Ensures the specific preconditions of the said instruction.
756      */
757     @Override
758     public void visitDUP2_X2(final DUP2_X2 o) {
759 
760         if (stack().peek(0).getSize() == 2) {
761             // stack top size is 2, next-to-top's size is 1
762             if (stack().peek(1).getSize() == 2 || stack().peek(2).getSize() == 1) {
763                 return; // Form 2
764             }
765             constraintViolated(o, "If stack top's size is 2 and stack-next-to-top's size is 1,"
766                 + " then stack next-to-next-to-top's size must also be 1. But it is '" + stack().peek(2) + "' of size '" + stack().peek(2).getSize() + "'.");
767         } else if (stack().peek(1).getSize() == 1 && (stack().peek(2).getSize() == 2 || stack().peek(3).getSize() == 1)) {
768             return; // Form 1
769         }
770         constraintViolated(o, "The operand sizes on the stack do not match any of the four forms of usage of this instruction.");
771     }
772 
773     /**
774      * Ensures the specific preconditions of the said instruction.
775      */
776     @Override
777     public void visitF2D(final F2D o) {
778         if (stack().peek() != Type.FLOAT) {
779             constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'.");
780         }
781     }
782 
783     /**
784      * Ensures the specific preconditions of the said instruction.
785      */
786     @Override
787     public void visitF2I(final F2I o) {
788         if (stack().peek() != Type.FLOAT) {
789             constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'.");
790         }
791     }
792 
793     /**
794      * Ensures the specific preconditions of the said instruction.
795      */
796     @Override
797     public void visitF2L(final F2L o) {
798         if (stack().peek() != Type.FLOAT) {
799             constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'.");
800         }
801     }
802 
803     /**
804      * Ensures the specific preconditions of the said instruction.
805      */
806     @Override
807     public void visitFADD(final FADD o) {
808         if (stack().peek() != Type.FLOAT) {
809             constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'.");
810         }
811         if (stack().peek(1) != Type.FLOAT) {
812             constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '" + stack().peek(1) + "'.");
813         }
814     }
815 
816     /**
817      * Ensures the specific preconditions of the said instruction.
818      */
819     @Override
820     public void visitFALOAD(final FALOAD o) {
821         indexOfInt(o, stack().peek());
822         if (stack().peek(1) == Type.NULL) {
823             return;
824         }
825         if (!(stack().peek(1) instanceof ArrayType)) {
826             constraintViolated(o, "Stack next-to-top must be of type float[] but is '" + stack().peek(1) + "'.");
827         }
828         final Type t = ((ArrayType) stack().peek(1)).getBasicType();
829         if (t != Type.FLOAT) {
830             constraintViolated(o, "Stack next-to-top must be of type float[] but is '" + stack().peek(1) + "'.");
831         }
832     }
833 
834     /**
835      * Ensures the specific preconditions of the said instruction.
836      */
837     @Override
838     public void visitFASTORE(final FASTORE o) {
839         if (stack().peek() != Type.FLOAT) {
840             constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'.");
841         }
842         indexOfInt(o, stack().peek(1));
843         if (stack().peek(2) == Type.NULL) {
844             return;
845         }
846         if (!(stack().peek(2) instanceof ArrayType)) {
847             constraintViolated(o, "Stack next-to-next-to-top must be of type float[] but is '" + stack().peek(2) + "'.");
848         }
849         final Type t = ((ArrayType) stack().peek(2)).getBasicType();
850         if (t != Type.FLOAT) {
851             constraintViolated(o, "Stack next-to-next-to-top must be of type float[] but is '" + stack().peek(2) + "'.");
852         }
853     }
854 
855     /**
856      * Ensures the specific preconditions of the said instruction.
857      */
858     @Override
859     public void visitFCMPG(final FCMPG o) {
860         if (stack().peek() != Type.FLOAT) {
861             constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'.");
862         }
863         if (stack().peek(1) != Type.FLOAT) {
864             constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '" + stack().peek(1) + "'.");
865         }
866     }
867 
868     /**
869      * Ensures the specific preconditions of the said instruction.
870      */
871     @Override
872     public void visitFCMPL(final FCMPL o) {
873         if (stack().peek() != Type.FLOAT) {
874             constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'.");
875         }
876         if (stack().peek(1) != Type.FLOAT) {
877             constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '" + stack().peek(1) + "'.");
878         }
879     }
880 
881     /**
882      * Ensures the specific preconditions of the said instruction.
883      */
884     @Override
885     public void visitFCONST(final FCONST o) {
886         // nothing to do here.
887     }
888 
889     /**
890      * Ensures the specific preconditions of the said instruction.
891      */
892     @Override
893     public void visitFDIV(final FDIV o) {
894         if (stack().peek() != Type.FLOAT) {
895             constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'.");
896         }
897         if (stack().peek(1) != Type.FLOAT) {
898             constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '" + stack().peek(1) + "'.");
899         }
900     }
901 
902     /**
903      * Ensures the general preconditions of a FieldInstruction instance.
904      */
905     @Override
906     public void visitFieldInstruction(final FieldInstruction o) {
907         // visitLoadClass(o) has been called before: Every FieldOrMethod
908         // implements LoadClass.
909         // visitCPInstruction(o) has been called before.
910         // A FieldInstruction may be: GETFIELD, GETSTATIC, PUTFIELD, PUTSTATIC
911         final Constant c = cpg.getConstant(o.getIndex());
912         if (!(c instanceof ConstantFieldref)) {
913             constraintViolated(o, "Index '" + o.getIndex() + "' should refer to a CONSTANT_Fieldref_info structure, but refers to '" + c + "'.");
914         }
915         // the o.getClassType(cpg) type has passed pass 2; see visitLoadClass(o).
916         final Type t = o.getType(cpg);
917         if (t instanceof ObjectType) {
918             final String name = ((ObjectType) t).getClassName();
919             final Verifier v = VerifierFactory.getVerifier(name);
920             final VerificationResult vr = v.doPass2();
921             if (vr.getStatus() != VerificationResult.VERIFIED_OK) {
922                 constraintViolated(o, "Class '" + name + "' is referenced, but cannot be loaded and resolved: '" + vr + "'.");
923             }
924         }
925     }
926 
927     private Field visitFieldInstructionInternals(final FieldInstruction o) throws ClassNotFoundException {
928         final String fieldName = o.getFieldName(cpg);
929         final JavaClass jc = Repository.lookupClass(getObjectType(o).getClassName());
930         final Field f = jc.findField(fieldName, o.getType(cpg));
931         if (f == null) {
932             throw new AssertionViolatedException("Field '" + fieldName + "' not found in " + jc.getClassName());
933         }
934         final Type value = stack().peek();
935         final Type t = Type.getType(f.getSignature());
936         Type shouldBe = t;
937         if (shouldBe == Type.BOOLEAN || shouldBe == Type.BYTE || shouldBe == Type.CHAR || shouldBe == Type.SHORT) {
938             shouldBe = Type.INT;
939         }
940         if (t instanceof ReferenceType) {
941             if (value instanceof ReferenceType) {
942                 final ReferenceType rValue = (ReferenceType) value;
943                 referenceTypeIsInitialized(o, rValue);
944                 // TODO: This can possibly only be checked using Staerk-et-al's "set-of-object types", not
945                 // using "wider cast object types" created during verification.
946                 // Comment it out if you encounter problems. See also the analogon at visitPUTFIELD|visitPUTSTATIC.
947                 if (!rValue.isAssignmentCompatibleWith(shouldBe)) {
948                     constraintViolated(o, "The stack top type '" + value + "' is not assignment compatible with '" + shouldBe + "'.");
949                 }
950             } else {
951                 constraintViolated(o, "The stack top type '" + value + "' is not of a reference type as expected.");
952             }
953         } else if (shouldBe != value) {
954             constraintViolated(o, "The stack top type '" + value + "' is not of type '" + shouldBe + "' as expected.");
955         }
956         return f;
957     }
958 
959     /**
960      * Ensures the specific preconditions of the said instruction.
961      */
962     @Override
963     public void visitFLOAD(final FLOAD o) {
964         // visitLoadInstruction(LoadInstruction) is called before.
965 
966         // Nothing else needs to be done here.
967     }
968 
969     /**
970      * Ensures the specific preconditions of the said instruction.
971      */
972     @Override
973     public void visitFMUL(final FMUL o) {
974         if (stack().peek() != Type.FLOAT) {
975             constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'.");
976         }
977         if (stack().peek(1) != Type.FLOAT) {
978             constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '" + stack().peek(1) + "'.");
979         }
980     }
981 
982     /**
983      * Ensures the specific preconditions of the said instruction.
984      */
985     @Override
986     public void visitFNEG(final FNEG o) {
987         if (stack().peek() != Type.FLOAT) {
988             constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'.");
989         }
990     }
991 
992     /**
993      * Ensures the specific preconditions of the said instruction.
994      */
995     @Override
996     public void visitFREM(final FREM o) {
997         if (stack().peek() != Type.FLOAT) {
998             constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'.");
999         }
1000         if (stack().peek(1) != Type.FLOAT) {
1001             constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '" + stack().peek(1) + "'.");
1002         }
1003     }
1004 
1005     /**
1006      * Ensures the specific preconditions of the said instruction.
1007      */
1008     @Override
1009     public void visitFRETURN(final FRETURN o) {
1010         if (stack().peek() != Type.FLOAT) {
1011             constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'.");
1012         }
1013     }
1014 
1015     /**
1016      * Ensures the specific preconditions of the said instruction.
1017      */
1018     @Override
1019     public void visitFSTORE(final FSTORE o) {
1020         // visitStoreInstruction(StoreInstruction) is called before.
1021 
1022         // Nothing else needs to be done here.
1023     }
1024 
1025     /**
1026      * Ensures the specific preconditions of the said instruction.
1027      */
1028     @Override
1029     public void visitFSUB(final FSUB o) {
1030         if (stack().peek() != Type.FLOAT) {
1031             constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'.");
1032         }
1033         if (stack().peek(1) != Type.FLOAT) {
1034             constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '" + stack().peek(1) + "'.");
1035         }
1036     }
1037 
1038     /**
1039      * Ensures the specific preconditions of the said instruction.
1040      */
1041     @Override
1042     public void visitGETFIELD(final GETFIELD o) {
1043         try {
1044             final Type objectref = stack().peek();
1045             if (!(objectref instanceof ObjectType || objectref == Type.NULL)) {
1046                 constraintViolated(o, "Stack top should be an object reference that's not an array reference, but is '" + objectref + "'.");
1047             }
1048 
1049             final String fieldName = o.getFieldName(cpg);
1050 
1051             final JavaClass jc = Repository.lookupClass(getObjectType(o).getClassName());
1052             final Field f = jc.findField(fieldName, o.getType(cpg));
1053             if (f == null) {
1054                 throw new AssertionViolatedException("Field '" + fieldName + "' not found in " + jc.getClassName());
1055             }
1056 
1057             if (f.isProtected()) {
1058                 final ObjectType classtype = getObjectType(o);
1059                 final ObjectType curr = ObjectType.getInstance(mg.getClassName());
1060 
1061                 if (classtype.equals(curr) || curr.subclassOf(classtype)) {
1062                     final Type t = stack().peek();
1063                     if (t == Type.NULL) {
1064                         return;
1065                     }
1066                     if (!(t instanceof ObjectType)) {
1067                         constraintViolated(o, "The 'objectref' must refer to an object that's not an array. Found instead: '" + t + "'.");
1068                     }
1069                     // final ObjectType objreftype = (ObjectType) t;
1070                     // if (!(objreftype.equals(curr) || objreftype.subclassOf(curr))) {
1071                         // TODO: One day move to Staerk-et-al's "Set of object types" instead of "wider" object types
1072                         // created during the verification.
1073                         // "Wider" object types don't allow us to check for things like that below.
1074                         // constraintViolated(o, "The referenced field has the ACC_PROTECTED modifier, "+
1075                         // "and it's a member of the current class or a superclass of the current class."+
1076                         // " However, the referenced object type '"+stack().peek()+
1077                         // "' is not the current class or a subclass of the current class.");
1078                     //}
1079                 }
1080             }
1081 
1082             // TODO: Could go into Pass 3a.
1083             if (f.isStatic()) {
1084                 constraintViolated(o, "Referenced field '" + f + "' is static which it shouldn't be.");
1085             }
1086 
1087         } catch (final ClassNotFoundException e) {
1088             // FIXME: maybe not the best way to handle this
1089             throw new AssertionViolatedException("Missing class: " + e, e);
1090         }
1091     }
1092 
1093     /**
1094      * Ensures the specific preconditions of the said instruction.
1095      */
1096     @Override
1097     public void visitGETSTATIC(final GETSTATIC o) {
1098         // Field must be static: see Pass 3a.
1099     }
1100 
1101     /**
1102      * Ensures the specific preconditions of the said instruction.
1103      */
1104     @Override
1105     public void visitGOTO(final GOTO o) {
1106         // nothing to do here.
1107     }
1108 
1109     /**
1110      * Ensures the specific preconditions of the said instruction.
1111      */
1112     @Override
1113     public void visitGOTO_W(final GOTO_W o) {
1114         // nothing to do here.
1115     }
1116 
1117     /**
1118      * Ensures the specific preconditions of the said instruction.
1119      */
1120     @Override
1121     public void visitI2B(final I2B o) {
1122         if (stack().peek() != Type.INT) {
1123             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
1124         }
1125     }
1126 
1127     /**
1128      * Ensures the specific preconditions of the said instruction.
1129      */
1130     @Override
1131     public void visitI2C(final I2C o) {
1132         if (stack().peek() != Type.INT) {
1133             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
1134         }
1135     }
1136 
1137     /**
1138      * Ensures the specific preconditions of the said instruction.
1139      */
1140     @Override
1141     public void visitI2D(final I2D o) {
1142         if (stack().peek() != Type.INT) {
1143             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
1144         }
1145     }
1146 
1147     /**
1148      * Ensures the specific preconditions of the said instruction.
1149      */
1150     @Override
1151     public void visitI2F(final I2F o) {
1152         if (stack().peek() != Type.INT) {
1153             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
1154         }
1155     }
1156 
1157     /**
1158      * Ensures the specific preconditions of the said instruction.
1159      */
1160     @Override
1161     public void visitI2L(final I2L o) {
1162         if (stack().peek() != Type.INT) {
1163             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
1164         }
1165     }
1166 
1167     /**
1168      * Ensures the specific preconditions of the said instruction.
1169      */
1170     @Override
1171     public void visitI2S(final I2S o) {
1172         if (stack().peek() != Type.INT) {
1173             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
1174         }
1175     }
1176 
1177     /**
1178      * Ensures the specific preconditions of the said instruction.
1179      */
1180     @Override
1181     public void visitIADD(final IADD o) {
1182         if (stack().peek() != Type.INT) {
1183             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
1184         }
1185         if (stack().peek(1) != Type.INT) {
1186             constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'.");
1187         }
1188     }
1189 
1190     /**
1191      * Ensures the specific preconditions of the said instruction.
1192      */
1193     @Override
1194     public void visitIALOAD(final IALOAD o) {
1195         indexOfInt(o, stack().peek());
1196         if (stack().peek(1) == Type.NULL) {
1197             return;
1198         }
1199         if (!(stack().peek(1) instanceof ArrayType)) {
1200             constraintViolated(o, "Stack next-to-top must be of type int[] but is '" + stack().peek(1) + "'.");
1201         }
1202         final Type t = ((ArrayType) stack().peek(1)).getBasicType();
1203         if (t != Type.INT) {
1204             constraintViolated(o, "Stack next-to-top must be of type int[] but is '" + stack().peek(1) + "'.");
1205         }
1206     }
1207 
1208     /**
1209      * Ensures the specific preconditions of the said instruction.
1210      */
1211     @Override
1212     public void visitIAND(final IAND o) {
1213         if (stack().peek() != Type.INT) {
1214             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
1215         }
1216         if (stack().peek(1) != Type.INT) {
1217             constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'.");
1218         }
1219     }
1220 
1221     /**
1222      * Ensures the specific preconditions of the said instruction.
1223      */
1224     @Override
1225     public void visitIASTORE(final IASTORE o) {
1226         if (stack().peek() != Type.INT) {
1227             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
1228         }
1229         indexOfInt(o, stack().peek(1));
1230         if (stack().peek(2) == Type.NULL) {
1231             return;
1232         }
1233         if (!(stack().peek(2) instanceof ArrayType)) {
1234             constraintViolated(o, "Stack next-to-next-to-top must be of type int[] but is '" + stack().peek(2) + "'.");
1235         }
1236         final Type t = ((ArrayType) stack().peek(2)).getBasicType();
1237         if (t != Type.INT) {
1238             constraintViolated(o, "Stack next-to-next-to-top must be of type int[] but is '" + stack().peek(2) + "'.");
1239         }
1240     }
1241 
1242     /**
1243      * Ensures the specific preconditions of the said instruction.
1244      */
1245     @Override
1246     public void visitICONST(final ICONST o) {
1247         // nothing to do here.
1248     }
1249 
1250     /**
1251      * Ensures the specific preconditions of the said instruction.
1252      */
1253     @Override
1254     public void visitIDIV(final IDIV o) {
1255         if (stack().peek() != Type.INT) {
1256             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
1257         }
1258         if (stack().peek(1) != Type.INT) {
1259             constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'.");
1260         }
1261     }
1262 
1263     /**
1264      * Ensures the specific preconditions of the said instruction.
1265      */
1266     @Override
1267     public void visitIF_ACMPEQ(final IF_ACMPEQ o) {
1268         if (!(stack().peek() instanceof ReferenceType)) {
1269             constraintViolated(o, "The value at the stack top is not of a ReferenceType, but of type '" + stack().peek() + "'.");
1270         }
1271         // referenceTypeIsInitialized(o, (ReferenceType) (stack().peek()) );
1272 
1273         if (!(stack().peek(1) instanceof ReferenceType)) {
1274             constraintViolated(o, "The value at the stack next-to-top is not of a ReferenceType, but of type '" + stack().peek(1) + "'.");
1275         }
1276         // referenceTypeIsInitialized(o, (ReferenceType) (stack().peek(1)) );
1277 
1278     }
1279 
1280     /**
1281      * Ensures the specific preconditions of the said instruction.
1282      */
1283     @Override
1284     public void visitIF_ACMPNE(final IF_ACMPNE o) {
1285         if (!(stack().peek() instanceof ReferenceType)) {
1286             constraintViolated(o, "The value at the stack top is not of a ReferenceType, but of type '" + stack().peek() + "'.");
1287             // referenceTypeIsInitialized(o, (ReferenceType) (stack().peek()) );
1288         }
1289         if (!(stack().peek(1) instanceof ReferenceType)) {
1290             constraintViolated(o, "The value at the stack next-to-top is not of a ReferenceType, but of type '" + stack().peek(1) + "'.");
1291             // referenceTypeIsInitialized(o, (ReferenceType) (stack().peek(1)) );
1292         }
1293     }
1294 
1295     /**
1296      * Ensures the specific preconditions of the said instruction.
1297      */
1298     @Override
1299     public void visitIF_ICMPEQ(final IF_ICMPEQ o) {
1300         if (stack().peek() != Type.INT) {
1301             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
1302         }
1303         if (stack().peek(1) != Type.INT) {
1304             constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'.");
1305         }
1306     }
1307 
1308     /**
1309      * Ensures the specific preconditions of the said instruction.
1310      */
1311     @Override
1312     public void visitIF_ICMPGE(final IF_ICMPGE o) {
1313         if (stack().peek() != Type.INT) {
1314             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
1315         }
1316         if (stack().peek(1) != Type.INT) {
1317             constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'.");
1318         }
1319     }
1320 
1321     /**
1322      * Ensures the specific preconditions of the said instruction.
1323      */
1324     @Override
1325     public void visitIF_ICMPGT(final IF_ICMPGT o) {
1326         if (stack().peek() != Type.INT) {
1327             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
1328         }
1329         if (stack().peek(1) != Type.INT) {
1330             constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'.");
1331         }
1332     }
1333 
1334     /**
1335      * Ensures the specific preconditions of the said instruction.
1336      */
1337     @Override
1338     public void visitIF_ICMPLE(final IF_ICMPLE o) {
1339         if (stack().peek() != Type.INT) {
1340             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
1341         }
1342         if (stack().peek(1) != Type.INT) {
1343             constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'.");
1344         }
1345     }
1346 
1347     /**
1348      * Ensures the specific preconditions of the said instruction.
1349      */
1350     @Override
1351     public void visitIF_ICMPLT(final IF_ICMPLT o) {
1352         if (stack().peek() != Type.INT) {
1353             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
1354         }
1355         if (stack().peek(1) != Type.INT) {
1356             constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'.");
1357         }
1358     }
1359 
1360     /**
1361      * Ensures the specific preconditions of the said instruction.
1362      */
1363     @Override
1364     public void visitIF_ICMPNE(final IF_ICMPNE o) {
1365         if (stack().peek() != Type.INT) {
1366             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
1367         }
1368         if (stack().peek(1) != Type.INT) {
1369             constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'.");
1370         }
1371     }
1372 
1373     /**
1374      * Ensures the specific preconditions of the said instruction.
1375      */
1376     @Override
1377     public void visitIFEQ(final IFEQ o) {
1378         if (stack().peek() != Type.INT) {
1379             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
1380         }
1381     }
1382 
1383     /**
1384      * Ensures the specific preconditions of the said instruction.
1385      */
1386     @Override
1387     public void visitIFGE(final IFGE o) {
1388         if (stack().peek() != Type.INT) {
1389             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
1390         }
1391     }
1392 
1393     /**
1394      * Ensures the specific preconditions of the said instruction.
1395      */
1396     @Override
1397     public void visitIFGT(final IFGT o) {
1398         if (stack().peek() != Type.INT) {
1399             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
1400         }
1401     }
1402 
1403     /**
1404      * Ensures the specific preconditions of the said instruction.
1405      */
1406     @Override
1407     public void visitIFLE(final IFLE o) {
1408         if (stack().peek() != Type.INT) {
1409             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
1410         }
1411     }
1412 
1413     /**
1414      * Ensures the specific preconditions of the said instruction.
1415      */
1416     @Override
1417     public void visitIFLT(final IFLT o) {
1418         if (stack().peek() != Type.INT) {
1419             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
1420         }
1421     }
1422 
1423     /**
1424      * Ensures the specific preconditions of the said instruction.
1425      */
1426     @Override
1427     public void visitIFNE(final IFNE o) {
1428         if (stack().peek() != Type.INT) {
1429             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
1430         }
1431     }
1432 
1433     /**
1434      * Ensures the specific preconditions of the said instruction.
1435      */
1436     @Override
1437     public void visitIFNONNULL(final IFNONNULL o) {
1438         if (!(stack().peek() instanceof ReferenceType)) {
1439             constraintViolated(o, "The value at the stack top is not of a ReferenceType, but of type '" + stack().peek() + "'.");
1440         }
1441         referenceTypeIsInitialized(o, (ReferenceType) stack().peek());
1442     }
1443 
1444     /**
1445      * Ensures the specific preconditions of the said instruction.
1446      */
1447     @Override
1448     public void visitIFNULL(final IFNULL o) {
1449         if (!(stack().peek() instanceof ReferenceType)) {
1450             constraintViolated(o, "The value at the stack top is not of a ReferenceType, but of type '" + stack().peek() + "'.");
1451         }
1452         referenceTypeIsInitialized(o, (ReferenceType) stack().peek());
1453     }
1454 
1455     /**
1456      * Ensures the specific preconditions of the said instruction.
1457      */
1458     @Override
1459     public void visitIINC(final IINC o) {
1460         // Mhhh. In BCEL, at this time "IINC" is not a LocalVariableInstruction.
1461         if (locals().maxLocals() <= (o.getType(cpg).getSize() == 1 ? o.getIndex() : o.getIndex() + 1)) {
1462             constraintViolated(o, "The 'index' is not a valid index into the local variable array.");
1463         }
1464 
1465         indexOfInt(o, locals().get(o.getIndex()));
1466     }
1467 
1468     /**
1469      * Ensures the specific preconditions of the said instruction.
1470      */
1471     @Override
1472     public void visitILOAD(final ILOAD o) {
1473         // All done by visitLocalVariableInstruction(), visitLoadInstruction()
1474     }
1475 
1476     /**
1477      * Ensures the specific preconditions of the said instruction.
1478      */
1479     @Override
1480     public void visitIMPDEP1(final IMPDEP1 o) {
1481         throw new AssertionViolatedException("In this JustIce verification pass there should not occur an illegal instruction such as IMPDEP1.");
1482     }
1483 
1484     /**
1485      * Ensures the specific preconditions of the said instruction.
1486      */
1487     @Override
1488     public void visitIMPDEP2(final IMPDEP2 o) {
1489         throw new AssertionViolatedException("In this JustIce verification pass there should not occur an illegal instruction such as IMPDEP2.");
1490     }
1491 
1492     /**
1493      * Ensures the specific preconditions of the said instruction.
1494      */
1495     @Override
1496     public void visitIMUL(final IMUL o) {
1497         if (stack().peek() != Type.INT) {
1498             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
1499         }
1500         if (stack().peek(1) != Type.INT) {
1501             constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'.");
1502         }
1503     }
1504 
1505     /**
1506      * Ensures the specific preconditions of the said instruction.
1507      */
1508     @Override
1509     public void visitINEG(final INEG o) {
1510         if (stack().peek() != Type.INT) {
1511             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
1512         }
1513     }
1514 
1515     /**
1516      * Ensures the specific preconditions of the said instruction.
1517      */
1518     @Override
1519     public void visitINSTANCEOF(final INSTANCEOF o) {
1520         // The objectref must be of type reference.
1521         final Type objectref = stack().peek(0);
1522         if (!(objectref instanceof ReferenceType)) {
1523             constraintViolated(o, "The 'objectref' is not of a ReferenceType but of type " + objectref + ".");
1524         }
1525         // else{
1526         // referenceTypeIsInitialized(o, (ReferenceType) objectref);
1527         // }
1528         // The unsigned indexbyte1 and indexbyte2 are used to construct an index into the runtime constant pool of the
1529         // current class (�3.6), where the value of the index is (indexbyte1 << 8) | indexbyte2. The runtime constant
1530         // pool item at the index must be a symbolic reference to a class, array, or interface type.
1531         final Constant c = cpg.getConstant(o.getIndex());
1532         if (!(c instanceof ConstantClass)) {
1533             constraintViolated(o, "The Constant at 'index' is not a ConstantClass, but '" + c + "'.");
1534         }
1535     }
1536 
1537     /**
1538      * Ensures the specific preconditions of the said instruction.
1539      *
1540      * @since 6.0
1541      */
1542     @Override
1543     public void visitINVOKEDYNAMIC(final INVOKEDYNAMIC o) {
1544         throw new UnsupportedOperationException("INVOKEDYNAMIC instruction is not supported at this time");
1545     }
1546 
1547     /**
1548      * Ensures the general preconditions of an InvokeInstruction instance.
1549      */
1550     @Override
1551     public void visitInvokeInstruction(final InvokeInstruction o) {
1552         // visitLoadClass(o) has been called before: Every FieldOrMethod
1553         // implements LoadClass.
1554         // visitCPInstruction(o) has been called before.
1555         // TODO
1556     }
1557 
1558     /**
1559      * Ensures the specific preconditions of the said instruction.
1560      */
1561     @Override
1562     public void visitINVOKEINTERFACE(final INVOKEINTERFACE o) {
1563         // Method is not native, otherwise pass 3 would not happen.
1564 
1565         final int count = o.getCount();
1566         if (count == 0) {
1567             constraintViolated(o, "The 'count' argument must not be 0.");
1568         }
1569         // It is a ConstantInterfaceMethodref, Pass 3a made it sure.
1570         // TODO: Do we want to do anything with it?
1571         // ConstantInterfaceMethodref cimr = (ConstantInterfaceMethodref) (cpg.getConstant(o.getIndex()));
1572 
1573         // the o.getClassType(cpg) type has passed pass 2; see visitLoadClass(o).
1574 
1575         final Type t = o.getType(cpg);
1576         if (t instanceof ObjectType) {
1577             final String name = ((ObjectType) t).getClassName();
1578             final Verifier v = VerifierFactory.getVerifier(name);
1579             final VerificationResult vr = v.doPass2();
1580             if (vr.getStatus() != VerificationResult.VERIFIED_OK) {
1581                 constraintViolated(o, "Class '" + name + "' is referenced, but cannot be loaded and resolved: '" + vr + "'.");
1582             }
1583         }
1584 
1585         final Type[] argTypes = o.getArgumentTypes(cpg);
1586         final int argCount = argTypes.length;
1587 
1588         for (int i = argCount - 1; i >= 0; i--) {
1589             final Type fromStack = stack().peek(argCount - 1 - i); // 0 to argCount - 1
1590             Type fromDesc = argTypes[i];
1591             if (fromDesc == Type.BOOLEAN || fromDesc == Type.BYTE || fromDesc == Type.CHAR || fromDesc == Type.SHORT) {
1592                 fromDesc = Type.INT;
1593             }
1594             if (!fromStack.equals(fromDesc)) {
1595                 if (fromStack instanceof ReferenceType && fromDesc instanceof ReferenceType) {
1596                     final ReferenceType rFromStack = (ReferenceType) fromStack;
1597                     // ReferenceType rFromDesc = (ReferenceType) fromDesc;
1598                     // TODO: This can only be checked when using Staerk-et-al's "set of object types"
1599                     // instead of a "wider cast object type" created during verification.
1600                     // if ( ! rFromStack.isAssignmentCompatibleWith(rFromDesc) ) {
1601                     // constraintViolated(o, "Expecting a '"+fromDesc+"' but found a '"+fromStack+
1602                     // "' on the stack (which is not assignment compatible).");
1603                     // }
1604                     referenceTypeIsInitialized(o, rFromStack);
1605                 } else {
1606                     constraintViolated(o, "Expecting a '" + fromDesc + "' but found a '" + fromStack + "' on the stack.");
1607                 }
1608             }
1609         }
1610 
1611         Type objRef = stack().peek(argCount);
1612         if (objRef == Type.NULL) {
1613             return;
1614         }
1615         if (!(objRef instanceof ReferenceType)) {
1616             constraintViolated(o, "Expecting a reference type as 'objectref' on the stack, not a '" + objRef + "'.");
1617         }
1618         referenceTypeIsInitialized(o, (ReferenceType) objRef);
1619         if (!(objRef instanceof ObjectType)) {
1620             if (!(objRef instanceof ArrayType)) { // could be a ReturnaddressType
1621                 constraintViolated(o, "Expecting an ObjectType as 'objectref' on the stack, not a '" + objRef + "'.");
1622             } else {
1623                 objRef = GENERIC_ARRAY;
1624             }
1625         }
1626 
1627         // String objRefClassName = ((ObjectType) objRef).getClassName();
1628         // String theInterface = o.getClassName(cpg);
1629         // TODO: This can only be checked if we're using Staerk-et-al's "set of object types"
1630         // instead of "wider cast object types" generated during verification.
1631         // if ( ! Repository.implementationOf(objRefClassName, theInterface) ) {
1632         // constraintViolated(o, "The 'objRef' item '" + objRef + "' does not implement '" + theInterface + "' as expected.");
1633         // }
1634 
1635         int countedCount = 1; // 1 for the objectref
1636         for (int i = 0; i < argCount; i++) {
1637             countedCount += argTypes[i].getSize();
1638         }
1639         if (count != countedCount) {
1640             constraintViolated(o, "The 'count' argument should probably read '" + countedCount + "' but is '" + count + "'.");
1641         }
1642     }
1643 
1644     private int visitInvokeInternals(final InvokeInstruction o) throws ClassNotFoundException {
1645         final Type t = o.getType(cpg);
1646         if (t instanceof ObjectType) {
1647             final String name = ((ObjectType) t).getClassName();
1648             final Verifier v = VerifierFactory.getVerifier(name);
1649             final VerificationResult vr = v.doPass2();
1650             if (vr.getStatus() != VerificationResult.VERIFIED_OK) {
1651                 constraintViolated(o, "Class '" + name + "' is referenced, but cannot be loaded and resolved: '" + vr + "'.");
1652             }
1653         }
1654 
1655         final Type[] argtypes = o.getArgumentTypes(cpg);
1656         final int nargs = argtypes.length;
1657 
1658         for (int i = nargs - 1; i >= 0; i--) {
1659             final Type fromStack = stack().peek(nargs - 1 - i); // 0 to nargs-1
1660             Type fromDesc = argtypes[i];
1661             if (fromDesc == Type.BOOLEAN || fromDesc == Type.BYTE || fromDesc == Type.CHAR || fromDesc == Type.SHORT) {
1662                 fromDesc = Type.INT;
1663             }
1664             if (!fromStack.equals(fromDesc)) {
1665                 if (fromStack instanceof ReferenceType && fromDesc instanceof ReferenceType) {
1666                     final ReferenceType rFromStack = (ReferenceType) fromStack;
1667                     final ReferenceType rFromDesc = (ReferenceType) fromDesc;
1668                     // TODO: This can possibly only be checked when using Staerk-et-al's "set of object types" instead
1669                     // of a single "wider cast object type" created during verification.
1670                     if (!rFromStack.isAssignmentCompatibleWith(rFromDesc)) {
1671                         constraintViolated(o,
1672                             "Expecting a '" + fromDesc + "' but found a '" + fromStack + "' on the stack (which is not assignment compatible).");
1673                     }
1674                     referenceTypeIsInitialized(o, rFromStack);
1675                 } else {
1676                     constraintViolated(o, "Expecting a '" + fromDesc + "' but found a '" + fromStack + "' on the stack.");
1677                 }
1678             }
1679         }
1680         return nargs;
1681     }
1682 
1683     /**
1684      * Ensures the specific preconditions of the said instruction.
1685      */
1686     @Override
1687     public void visitINVOKESPECIAL(final INVOKESPECIAL o) {
1688         try {
1689             // Don't init an object twice.
1690             if (o.getMethodName(cpg).equals(Const.CONSTRUCTOR_NAME) && !(stack().peek(o.getArgumentTypes(cpg).length) instanceof UninitializedObjectType)) {
1691                 constraintViolated(o,
1692                     "Possibly initializing object twice."
1693                         + " A valid instruction sequence must not have an uninitialized object on the operand stack or in a local variable"
1694                         + " during a backwards branch, or in a local variable in code protected by an exception handler."
1695                         + " Please see The Java Virtual Machine Specification, Second Edition, 4.9.4 (pages 147 and 148) for details.");
1696             }
1697 
1698             // the o.getClassType(cpg) type has passed pass 2; see visitLoadClass(o).
1699 
1700             final int nargs = visitInvokeInternals(o);
1701             Type objref = stack().peek(nargs);
1702             if (objref == Type.NULL) {
1703                 return;
1704             }
1705             if (!(objref instanceof ReferenceType)) {
1706                 constraintViolated(o, "Expecting a reference type as 'objectref' on the stack, not a '" + objref + "'.");
1707             }
1708             String objRefClassName = null;
1709             if (!o.getMethodName(cpg).equals(Const.CONSTRUCTOR_NAME)) {
1710                 referenceTypeIsInitialized(o, (ReferenceType) objref);
1711                 if (!(objref instanceof ObjectType)) {
1712                     if (!(objref instanceof ArrayType)) { // could be a ReturnaddressType
1713                         constraintViolated(o, "Expecting an ObjectType as 'objectref' on the stack, not a '" + objref + "'.");
1714                     } else {
1715                         objref = GENERIC_ARRAY;
1716                     }
1717                 }
1718 
1719                 objRefClassName = ((ObjectType) objref).getClassName();
1720             } else {
1721                 if (!(objref instanceof UninitializedObjectType)) {
1722                     constraintViolated(o, "Expecting an UninitializedObjectType as 'objectref' on the stack, not a '" + objref
1723                         + "'. Otherwise, you couldn't invoke a method since an array has no methods (not to speak of a return address).");
1724                 }
1725                 objRefClassName = ((UninitializedObjectType) objref).getInitialized().getClassName();
1726             }
1727 
1728             final String theClass = o.getClassName(cpg);
1729             if (!Repository.instanceOf(objRefClassName, theClass)) {
1730                 constraintViolated(o, "The 'objref' item '" + objref + "' does not implement '" + theClass + "' as expected.");
1731             }
1732 
1733         } catch (final ClassNotFoundException e) {
1734             // FIXME: maybe not the best way to handle this
1735             throw new AssertionViolatedException("Missing class: " + e, e);
1736         }
1737     }
1738 
1739     /**
1740      * Ensures the specific preconditions of the said instruction.
1741      */
1742     @Override
1743     public void visitINVOKESTATIC(final INVOKESTATIC o) {
1744         try {
1745             // Method is not native, otherwise pass 3 would not happen.
1746             visitInvokeInternals(o);
1747         } catch (final ClassNotFoundException e) {
1748             // FIXME: maybe not the best way to handle this
1749             throw new AssertionViolatedException("Missing class: " + e, e);
1750         }
1751     }
1752 
1753     /**
1754      * Ensures the specific preconditions of the said instruction.
1755      */
1756     @Override
1757     public void visitINVOKEVIRTUAL(final INVOKEVIRTUAL o) {
1758         try {
1759             // the o.getClassType(cpg) type has passed pass 2; see visitLoadClass(o).
1760 
1761             final int nargs = visitInvokeInternals(o);
1762             Type objref = stack().peek(nargs);
1763             if (objref == Type.NULL) {
1764                 return;
1765             }
1766             if (!(objref instanceof ReferenceType)) {
1767                 constraintViolated(o, "Expecting a reference type as 'objectref' on the stack, not a '" + objref + "'.");
1768             }
1769             referenceTypeIsInitialized(o, (ReferenceType) objref);
1770             if (!(objref instanceof ObjectType)) {
1771                 if (!(objref instanceof ArrayType)) { // could be a ReturnaddressType
1772                     constraintViolated(o, "Expecting an ObjectType as 'objectref' on the stack, not a '" + objref + "'.");
1773                 } else {
1774                     objref = GENERIC_ARRAY;
1775                 }
1776             }
1777 
1778             final String objRefClassName = ((ObjectType) objref).getClassName();
1779 
1780             final String theClass = o.getClassName(cpg);
1781 
1782             if (objref != GENERIC_ARRAY && !Repository.instanceOf(objRefClassName, theClass)) {
1783                 constraintViolated(o, "The 'objref' item '" + objref + "' does not implement '" + theClass + "' as expected.");
1784             }
1785         } catch (final ClassNotFoundException e) {
1786             // FIXME: maybe not the best way to handle this
1787             throw new AssertionViolatedException("Missing class: " + e, e);
1788         }
1789     }
1790 
1791     /**
1792      * Ensures the specific preconditions of the said instruction.
1793      */
1794     @Override
1795     public void visitIOR(final IOR o) {
1796         if (stack().peek() != Type.INT) {
1797             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
1798         }
1799         if (stack().peek(1) != Type.INT) {
1800             constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'.");
1801         }
1802     }
1803 
1804     /**
1805      * Ensures the specific preconditions of the said instruction.
1806      */
1807     @Override
1808     public void visitIREM(final IREM o) {
1809         if (stack().peek() != Type.INT) {
1810             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
1811         }
1812         if (stack().peek(1) != Type.INT) {
1813             constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'.");
1814         }
1815     }
1816 
1817     /**
1818      * Ensures the specific preconditions of the said instruction.
1819      */
1820     @Override
1821     public void visitIRETURN(final IRETURN o) {
1822         if (stack().peek() != Type.INT) {
1823             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
1824         }
1825     }
1826 
1827     /**
1828      * Ensures the specific preconditions of the said instruction.
1829      */
1830     @Override
1831     public void visitISHL(final ISHL o) {
1832         if (stack().peek() != Type.INT) {
1833             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
1834         }
1835         if (stack().peek(1) != Type.INT) {
1836             constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'.");
1837         }
1838     }
1839 
1840     /**
1841      * Ensures the specific preconditions of the said instruction.
1842      */
1843     @Override
1844     public void visitISHR(final ISHR o) {
1845         if (stack().peek() != Type.INT) {
1846             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
1847         }
1848         if (stack().peek(1) != Type.INT) {
1849             constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'.");
1850         }
1851     }
1852 
1853     /**
1854      * Ensures the specific preconditions of the said instruction.
1855      */
1856     @Override
1857     public void visitISTORE(final ISTORE o) {
1858         // visitStoreInstruction(StoreInstruction) is called before.
1859 
1860         // Nothing else needs to be done here.
1861     }
1862 
1863     /**
1864      * Ensures the specific preconditions of the said instruction.
1865      */
1866     @Override
1867     public void visitISUB(final ISUB o) {
1868         if (stack().peek() != Type.INT) {
1869             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
1870         }
1871         if (stack().peek(1) != Type.INT) {
1872             constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'.");
1873         }
1874     }
1875 
1876     /**
1877      * Ensures the specific preconditions of the said instruction.
1878      */
1879     @Override
1880     public void visitIUSHR(final IUSHR o) {
1881         if (stack().peek() != Type.INT) {
1882             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
1883         }
1884         if (stack().peek(1) != Type.INT) {
1885             constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'.");
1886         }
1887     }
1888 
1889     /**
1890      * Ensures the specific preconditions of the said instruction.
1891      */
1892     @Override
1893     public void visitIXOR(final IXOR o) {
1894         if (stack().peek() != Type.INT) {
1895             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
1896         }
1897         if (stack().peek(1) != Type.INT) {
1898             constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'.");
1899         }
1900     }
1901 
1902     /**
1903      * Ensures the specific preconditions of the said instruction.
1904      */
1905     @Override
1906     public void visitJSR(final JSR o) {
1907         // nothing to do here.
1908     }
1909 
1910     /**
1911      * Ensures the specific preconditions of the said instruction.
1912      */
1913     @Override
1914     public void visitJSR_W(final JSR_W o) {
1915         // nothing to do here.
1916     }
1917 
1918     /**
1919      * Ensures the specific preconditions of the said instruction.
1920      */
1921     @Override
1922     public void visitL2D(final L2D o) {
1923         if (stack().peek() != Type.LONG) {
1924             constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'.");
1925         }
1926     }
1927 
1928     /**
1929      * Ensures the specific preconditions of the said instruction.
1930      */
1931     @Override
1932     public void visitL2F(final L2F o) {
1933         if (stack().peek() != Type.LONG) {
1934             constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'.");
1935         }
1936     }
1937 
1938     /**
1939      * Ensures the specific preconditions of the said instruction.
1940      */
1941     @Override
1942     public void visitL2I(final L2I o) {
1943         if (stack().peek() != Type.LONG) {
1944             constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'.");
1945         }
1946     }
1947 
1948     /**
1949      * Ensures the specific preconditions of the said instruction.
1950      */
1951     @Override
1952     public void visitLADD(final LADD o) {
1953         if (stack().peek() != Type.LONG) {
1954             constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'.");
1955         }
1956         if (stack().peek(1) != Type.LONG) {
1957             constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '" + stack().peek(1) + "'.");
1958         }
1959     }
1960 
1961     /**
1962      * Ensures the specific preconditions of the said instruction.
1963      */
1964     @Override
1965     public void visitLALOAD(final LALOAD o) {
1966         indexOfInt(o, stack().peek());
1967         if (stack().peek(1) == Type.NULL) {
1968             return;
1969         }
1970         if (!(stack().peek(1) instanceof ArrayType)) {
1971             constraintViolated(o, "Stack next-to-top must be of type long[] but is '" + stack().peek(1) + "'.");
1972         }
1973         final Type t = ((ArrayType) stack().peek(1)).getBasicType();
1974         if (t != Type.LONG) {
1975             constraintViolated(o, "Stack next-to-top must be of type long[] but is '" + stack().peek(1) + "'.");
1976         }
1977     }
1978 
1979     /**
1980      * Ensures the specific preconditions of the said instruction.
1981      */
1982     @Override
1983     public void visitLAND(final LAND o) {
1984         if (stack().peek() != Type.LONG) {
1985             constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'.");
1986         }
1987         if (stack().peek(1) != Type.LONG) {
1988             constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '" + stack().peek(1) + "'.");
1989         }
1990     }
1991 
1992     /**
1993      * Ensures the specific preconditions of the said instruction.
1994      */
1995     @Override
1996     public void visitLASTORE(final LASTORE o) {
1997         if (stack().peek() != Type.LONG) {
1998             constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'.");
1999         }
2000         indexOfInt(o, stack().peek(1));
2001         if (stack().peek(2) == Type.NULL) {
2002             return;
2003         }
2004         if (!(stack().peek(2) instanceof ArrayType)) {
2005             constraintViolated(o, "Stack next-to-next-to-top must be of type long[] but is '" + stack().peek(2) + "'.");
2006         }
2007         final Type t = ((ArrayType) stack().peek(2)).getBasicType();
2008         if (t != Type.LONG) {
2009             constraintViolated(o, "Stack next-to-next-to-top must be of type long[] but is '" + stack().peek(2) + "'.");
2010         }
2011     }
2012 
2013     /**
2014      * Ensures the specific preconditions of the said instruction.
2015      */
2016     @Override
2017     public void visitLCMP(final LCMP o) {
2018         if (stack().peek() != Type.LONG) {
2019             constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'.");
2020         }
2021         if (stack().peek(1) != Type.LONG) {
2022             constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '" + stack().peek(1) + "'.");
2023         }
2024     }
2025 
2026     /**
2027      * Ensures the specific preconditions of the said instruction.
2028      */
2029     @Override
2030     public void visitLCONST(final LCONST o) {
2031         // Nothing to do here.
2032     }
2033 
2034     /**
2035      * Ensures the specific preconditions of the said instruction.
2036      */
2037     @Override
2038     public void visitLDC(final LDC o) {
2039         // visitCPInstruction is called first.
2040 
2041         final Constant c = cpg.getConstant(o.getIndex());
2042         if (!(c instanceof ConstantInteger
2043                 || c instanceof ConstantFloat
2044                 || c instanceof ConstantString
2045                 || c instanceof ConstantClass
2046                 || c instanceof ConstantDynamic)) {
2047             constraintViolated(o,
2048                 "Referenced constant should be a CONSTANT_Integer, a CONSTANT_Float, a CONSTANT_String, a CONSTANT_Class, or a CONSTANT_Dynamic but is '"
2049                         + c + "'.");
2050         }
2051     }
2052 
2053     /**
2054      * Ensures the specific preconditions of the said instruction.
2055      *
2056      * @param o the instruction to visit.
2057      */
2058     public void visitLDC_W(final LDC_W o) {
2059         // visitCPInstruction is called first.
2060 
2061         final Constant c = cpg.getConstant(o.getIndex());
2062         if (!(c instanceof ConstantInteger || c instanceof ConstantFloat || c instanceof ConstantString || c instanceof ConstantClass)) {
2063             constraintViolated(o,
2064                 "Referenced constant should be a CONSTANT_Integer, a CONSTANT_Float, a CONSTANT_String or a CONSTANT_Class, but is '" + c + "'.");
2065         }
2066     }
2067 
2068     /**
2069      * Ensures the specific preconditions of the said instruction.
2070      */
2071     @Override
2072     public void visitLDC2_W(final LDC2_W o) {
2073         // visitCPInstruction is called first.
2074 
2075         final Constant c = cpg.getConstant(o.getIndex());
2076         if (!(c instanceof ConstantLong || c instanceof ConstantDouble)) {
2077             constraintViolated(o, "Referenced constant should be a CONSTANT_Integer, a CONSTANT_Float or a CONSTANT_String, but is '" + c + "'.");
2078         }
2079     }
2080 
2081     /**
2082      * Ensures the specific preconditions of the said instruction.
2083      */
2084     @Override
2085     public void visitLDIV(final LDIV o) {
2086         if (stack().peek() != Type.LONG) {
2087             constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'.");
2088         }
2089         if (stack().peek(1) != Type.LONG) {
2090             constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '" + stack().peek(1) + "'.");
2091         }
2092     }
2093 
2094     /**
2095      * Ensures the specific preconditions of the said instruction.
2096      */
2097     @Override
2098     public void visitLLOAD(final LLOAD o) {
2099         // visitLoadInstruction(LoadInstruction) is called before.
2100 
2101         // Nothing else needs to be done here.
2102     }
2103 
2104     /**
2105      * Ensures the specific preconditions of the said instruction.
2106      */
2107     @Override
2108     public void visitLMUL(final LMUL o) {
2109         if (stack().peek() != Type.LONG) {
2110             constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'.");
2111         }
2112         if (stack().peek(1) != Type.LONG) {
2113             constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '" + stack().peek(1) + "'.");
2114         }
2115     }
2116 
2117     /**
2118      * Ensures the specific preconditions of the said instruction.
2119      */
2120     @Override
2121     public void visitLNEG(final LNEG o) {
2122         if (stack().peek() != Type.LONG) {
2123             constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'.");
2124         }
2125     }
2126 
2127     /**
2128      * Assures the generic preconditions of a LoadClass instance. The referenced class is loaded and pass2-verified.
2129      */
2130     @Override
2131     public void visitLoadClass(final LoadClass o) {
2132         final ObjectType t = o.getLoadClassType(cpg);
2133         if (t != null) { // null means "no class is loaded"
2134             final Verifier v = VerifierFactory.getVerifier(t.getClassName());
2135             final VerificationResult vr = v.doPass2();
2136             if (vr.getStatus() != VerificationResult.VERIFIED_OK) {
2137                 constraintViolated((Instruction) o,
2138                     "Class '" + o.getLoadClassType(cpg).getClassName() + "' is referenced, but cannot be loaded and resolved: '" + vr + "'.");
2139             }
2140         }
2141     }
2142 
2143     /**
2144      * Assures the generic preconditions of a LoadInstruction instance.
2145      */
2146     @Override
2147     public void visitLoadInstruction(final LoadInstruction o) {
2148         // visitLocalVariableInstruction(o) is called before, because it is more generic.
2149 
2150         // LOAD instructions must not read Type.UNKNOWN
2151         if (locals().get(o.getIndex()) == Type.UNKNOWN) {
2152             constraintViolated(o, "Read-Access on local variable " + o.getIndex() + " with unknown content.");
2153         }
2154 
2155         // LOAD instructions, two-slot-values at index N must have Type.UNKNOWN
2156         // as a symbol for the higher halve at index N+1
2157         // [suppose some instruction put an int at N+1--- our double at N is defective]
2158         if (o.getType(cpg).getSize() == 2 && locals().get(o.getIndex() + 1) != Type.UNKNOWN) {
2159             constraintViolated(o,
2160                 "Reading a two-locals value from local variables " + o.getIndex() + " and " + (o.getIndex() + 1) + " where the latter one is destroyed.");
2161         }
2162 
2163         // LOAD instructions must read the correct type.
2164         if (!(o instanceof ALOAD)) {
2165             if (locals().get(o.getIndex()) != o.getType(cpg)) {
2166                 constraintViolated(o, "Local Variable type and LOADing Instruction type mismatch: Local Variable: '" + locals().get(o.getIndex())
2167                     + "'; Instruction type: '" + o.getType(cpg) + "'.");
2168             }
2169         } else if (!(locals().get(o.getIndex()) instanceof ReferenceType)) {
2170             constraintViolated(o, "Local Variable type and LOADing Instruction type mismatch: Local Variable: '" + locals().get(o.getIndex())
2171                 + "'; Instruction expects a ReferenceType.");
2172         }
2173         // ALOAD __IS ALLOWED__ to put uninitialized objects onto the stack!
2174         // referenceTypeIsInitialized(o, (ReferenceType) (locals().get(o.getIndex())));
2175 
2176         // LOAD instructions must have enough free stack slots.
2177         if (stack().maxStack() - stack().slotsUsed() < o.getType(cpg).getSize()) {
2178             constraintViolated(o, "Not enough free stack slots to load a '" + o.getType(cpg) + "' onto the OperandStack.");
2179         }
2180     }
2181 
2182     /**
2183      * Assures the generic preconditions of a LocalVariableInstruction instance. That is, the index of the local variable
2184      * must be valid.
2185      */
2186     @Override
2187     public void visitLocalVariableInstruction(final LocalVariableInstruction o) {
2188         if (locals().maxLocals() <= (o.getType(cpg).getSize() == 1 ? o.getIndex() : o.getIndex() + 1)) {
2189             constraintViolated(o, "The 'index' is not a valid index into the local variable array.");
2190         }
2191     }
2192 
2193     /**
2194      * Ensures the specific preconditions of the said instruction.
2195      */
2196     @Override
2197     public void visitLOOKUPSWITCH(final LOOKUPSWITCH o) {
2198         if (stack().peek() != Type.INT) {
2199             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
2200         }
2201         // See also pass 3a.
2202     }
2203 
2204     /**
2205      * Ensures the specific preconditions of the said instruction.
2206      */
2207     @Override
2208     public void visitLOR(final LOR o) {
2209         if (stack().peek() != Type.LONG) {
2210             constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'.");
2211         }
2212         if (stack().peek(1) != Type.LONG) {
2213             constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '" + stack().peek(1) + "'.");
2214         }
2215     }
2216 
2217     /**
2218      * Ensures the specific preconditions of the said instruction.
2219      */
2220     @Override
2221     public void visitLREM(final LREM o) {
2222         if (stack().peek() != Type.LONG) {
2223             constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'.");
2224         }
2225         if (stack().peek(1) != Type.LONG) {
2226             constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '" + stack().peek(1) + "'.");
2227         }
2228     }
2229 
2230     /**
2231      * Ensures the specific preconditions of the said instruction.
2232      */
2233     @Override
2234     public void visitLRETURN(final LRETURN o) {
2235         if (stack().peek() != Type.LONG) {
2236             constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'.");
2237         }
2238     }
2239 
2240     /**
2241      * Ensures the specific preconditions of the said instruction.
2242      */
2243     @Override
2244     public void visitLSHL(final LSHL o) {
2245         if (stack().peek() != Type.INT) {
2246             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
2247         }
2248         if (stack().peek(1) != Type.LONG) {
2249             constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '" + stack().peek(1) + "'.");
2250         }
2251     }
2252 
2253     /**
2254      * Ensures the specific preconditions of the said instruction.
2255      */
2256     @Override
2257     public void visitLSHR(final LSHR o) {
2258         if (stack().peek() != Type.INT) {
2259             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
2260         }
2261         if (stack().peek(1) != Type.LONG) {
2262             constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '" + stack().peek(1) + "'.");
2263         }
2264     }
2265 
2266     /**
2267      * Ensures the specific preconditions of the said instruction.
2268      */
2269     @Override
2270     public void visitLSTORE(final LSTORE o) {
2271         // visitStoreInstruction(StoreInstruction) is called before.
2272 
2273         // Nothing else needs to be done here.
2274     }
2275 
2276     /**
2277      * Ensures the specific preconditions of the said instruction.
2278      */
2279     @Override
2280     public void visitLSUB(final LSUB o) {
2281         if (stack().peek() != Type.LONG) {
2282             constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'.");
2283         }
2284         if (stack().peek(1) != Type.LONG) {
2285             constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '" + stack().peek(1) + "'.");
2286         }
2287     }
2288 
2289     /**
2290      * Ensures the specific preconditions of the said instruction.
2291      */
2292     @Override
2293     public void visitLUSHR(final LUSHR o) {
2294         if (stack().peek() != Type.INT) {
2295             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
2296         }
2297         if (stack().peek(1) != Type.LONG) {
2298             constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '" + stack().peek(1) + "'.");
2299         }
2300     }
2301 
2302     /**
2303      * Ensures the specific preconditions of the said instruction.
2304      */
2305     @Override
2306     public void visitLXOR(final LXOR o) {
2307         if (stack().peek() != Type.LONG) {
2308             constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'.");
2309         }
2310         if (stack().peek(1) != Type.LONG) {
2311             constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '" + stack().peek(1) + "'.");
2312         }
2313     }
2314 
2315     /**
2316      * Ensures the specific preconditions of the said instruction.
2317      */
2318     @Override
2319     public void visitMONITORENTER(final MONITORENTER o) {
2320         if (!(stack().peek() instanceof ReferenceType)) {
2321             constraintViolated(o, "The stack top should be of a ReferenceType, but is '" + stack().peek() + "'.");
2322         }
2323         // referenceTypeIsInitialized(o, (ReferenceType) (stack().peek()) );
2324     }
2325 
2326     /**
2327      * Ensures the specific preconditions of the said instruction.
2328      */
2329     @Override
2330     public void visitMONITOREXIT(final MONITOREXIT o) {
2331         if (!(stack().peek() instanceof ReferenceType)) {
2332             constraintViolated(o, "The stack top should be of a ReferenceType, but is '" + stack().peek() + "'.");
2333         }
2334         // referenceTypeIsInitialized(o, (ReferenceType) (stack().peek()) );
2335     }
2336 
2337     /**
2338      * Ensures the specific preconditions of the said instruction.
2339      */
2340     @Override
2341     public void visitMULTIANEWARRAY(final MULTIANEWARRAY o) {
2342         final int dimensions = o.getDimensions();
2343         // Dimensions argument is okay: see Pass 3a.
2344         for (int i = 0; i < dimensions; i++) {
2345             if (stack().peek(i) != Type.INT) {
2346                 constraintViolated(o, "The '" + dimensions + "' upper stack types should be 'int' but aren't.");
2347             }
2348         }
2349         // The runtime constant pool item at that index must be a symbolic reference to a class,
2350         // array, or interface type. See Pass 3a.
2351     }
2352 
2353     /**
2354      * Ensures the specific preconditions of the said instruction.
2355      */
2356     @Override
2357     public void visitNEW(final NEW o) {
2358         // visitCPInstruction(CPInstruction) has been called before.
2359         // visitLoadClass(LoadClass) has been called before.
2360 
2361         final Type t = o.getType(cpg);
2362         if (!(t instanceof ReferenceType)) {
2363             throw new AssertionViolatedException("NEW.getType() returning a non-reference type?!");
2364         }
2365         if (!(t instanceof ObjectType)) {
2366             constraintViolated(o, "Expecting a class type (ObjectType) to work on. Found: '" + t + "'.");
2367         }
2368         final ObjectType obj = (ObjectType) t;
2369 
2370         // for example: Don't instantiate interfaces
2371         try {
2372             if (!obj.referencesClassExact()) {
2373                 constraintViolated(o, "Expecting a class type (ObjectType) to work on. Found: '" + obj + "'.");
2374             }
2375         } catch (final ClassNotFoundException e) {
2376             constraintViolated(o, "Expecting a class type (ObjectType) to work on. Found: '" + obj + "'. which threw " + e);
2377         }
2378     }
2379 
2380     /**
2381      * Ensures the specific preconditions of the said instruction.
2382      */
2383     @Override
2384     public void visitNEWARRAY(final NEWARRAY o) {
2385         if (stack().peek() != Type.INT) {
2386             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
2387         }
2388     }
2389 
2390     /**
2391      * Ensures the specific preconditions of the said instruction.
2392      */
2393     @Override
2394     public void visitNOP(final NOP o) {
2395         // nothing is to be done here.
2396     }
2397 
2398     /**
2399      * Ensures the specific preconditions of the said instruction.
2400      */
2401     @Override
2402     public void visitPOP(final POP o) {
2403         if (stack().peek().getSize() != 1) {
2404             constraintViolated(o, "Stack top size should be 1 but stack top is '" + stack().peek() + "' of size '" + stack().peek().getSize() + "'.");
2405         }
2406     }
2407 
2408     /**
2409      * Ensures the specific preconditions of the said instruction.
2410      */
2411     @Override
2412     public void visitPOP2(final POP2 o) {
2413         if (stack().peek().getSize() != 2) {
2414             constraintViolated(o, "Stack top size should be 2 but stack top is '" + stack().peek() + "' of size '" + stack().peek().getSize() + "'.");
2415         }
2416     }
2417 
2418     /**
2419      * Ensures the specific preconditions of the said instruction.
2420      */
2421     @Override
2422     public void visitPUTFIELD(final PUTFIELD o) {
2423         try {
2424 
2425             final Type objectref = stack().peek(1);
2426             if (!(objectref instanceof ObjectType || objectref == Type.NULL)) {
2427                 constraintViolated(o, "Stack next-to-top should be an object reference that's not an array reference, but is '" + objectref + "'.");
2428             }
2429 
2430             final Field f = visitFieldInstructionInternals(o);
2431 
2432             if (f.isProtected()) {
2433                 final ObjectType classtype = getObjectType(o);
2434                 final ObjectType curr = ObjectType.getInstance(mg.getClassName());
2435 
2436                 if (classtype.equals(curr) || curr.subclassOf(classtype)) {
2437                     final Type tp = stack().peek(1);
2438                     if (tp == Type.NULL) {
2439                         return;
2440                     }
2441                     if (!(tp instanceof ObjectType)) {
2442                         constraintViolated(o, "The 'objectref' must refer to an object that's not an array. Found instead: '" + tp + "'.");
2443                     }
2444                     final ObjectType objreftype = (ObjectType) tp;
2445                     if (!(objreftype.equals(curr) || objreftype.subclassOf(curr))) {
2446                         constraintViolated(o,
2447                             "The referenced field has the ACC_PROTECTED modifier, and it's a member of the current class or"
2448                                 + " a superclass of the current class. However, the referenced object type '" + stack().peek()
2449                                 + "' is not the current class or a subclass of the current class.");
2450                     }
2451                 }
2452             }
2453 
2454             // TODO: Could go into Pass 3a.
2455             if (f.isStatic()) {
2456                 constraintViolated(o, "Referenced field '" + f + "' is static which it shouldn't be.");
2457             }
2458 
2459         } catch (final ClassNotFoundException e) {
2460             // FIXME: maybe not the best way to handle this
2461             throw new AssertionViolatedException("Missing class: " + e, e);
2462         }
2463     }
2464 
2465     /**
2466      * Ensures the specific preconditions of the said instruction.
2467      */
2468     @Override
2469     public void visitPUTSTATIC(final PUTSTATIC o) {
2470         try {
2471             visitFieldInstructionInternals(o);
2472         } catch (final ClassNotFoundException e) {
2473             // FIXME: maybe not the best way to handle this
2474             throw new AssertionViolatedException("Missing class: " + e, e);
2475         }
2476     }
2477 
2478     /**
2479      * Ensures the specific preconditions of the said instruction.
2480      */
2481     @Override
2482     public void visitRET(final RET o) {
2483         if (!(locals().get(o.getIndex()) instanceof ReturnaddressType)) {
2484             constraintViolated(o, "Expecting a ReturnaddressType in local variable " + o.getIndex() + ".");
2485         }
2486         if (locals().get(o.getIndex()) == ReturnaddressType.NO_TARGET) {
2487             throw new AssertionViolatedException("RET expecting a target!");
2488         }
2489         // Other constraints such as non-allowed overlapping subroutines are enforced
2490         // while building the Subroutines data structure.
2491     }
2492 
2493     /**
2494      * Ensures the specific preconditions of the said instruction.
2495      */
2496     @Override
2497     public void visitRETURN(final RETURN o) {
2498         if (mg.getName().equals(Const.CONSTRUCTOR_NAME) && Frame.getThis() != null && !mg.getClassName().equals(Type.OBJECT.getClassName())) {
2499             constraintViolated(o, "Leaving a constructor that itself did not call a constructor.");
2500         }
2501     }
2502 
2503     /**
2504      * Assures the generic preconditions of a ReturnInstruction instance.
2505      */
2506     @Override
2507     public void visitReturnInstruction(final ReturnInstruction o) {
2508         Type methodType = mg.getType();
2509         if (methodType == Type.BOOLEAN || methodType == Type.BYTE || methodType == Type.SHORT || methodType == Type.CHAR) {
2510             methodType = Type.INT;
2511         }
2512 
2513         if (o instanceof RETURN) {
2514             if (methodType == Type.VOID) {
2515                 return;
2516             }
2517             constraintViolated(o, "RETURN instruction in non-void method.");
2518         }
2519         if (o instanceof ARETURN) {
2520             if (methodType == Type.VOID) {
2521                 constraintViolated(o, "ARETURN instruction in void method.");
2522             }
2523             if (stack().peek() == Type.NULL) {
2524                 return;
2525             }
2526             if (!(stack().peek() instanceof ReferenceType)) {
2527                 constraintViolated(o, "Reference type expected on top of stack, but is: '" + stack().peek() + "'.");
2528             }
2529             referenceTypeIsInitialized(o, (ReferenceType) stack().peek());
2530             // ReferenceType objectref = (ReferenceType) (stack().peek());
2531             // TODO: This can only be checked if using Staerk-et-al's "set of object types" instead of a
2532             // "wider cast object type" created during verification.
2533             // if (! (objectref.isAssignmentCompatibleWith(mg.getType())) ) {
2534             // constraintViolated(o, "Type on stack top which should be returned is a '"+stack().peek()+
2535             // "' which is not assignment compatible with the return type of this method, '"+mg.getType()+"'.");
2536             // }
2537         } else if (!methodType.equals(stack().peek())) {
2538             constraintViolated(o, "Current method has return type of '" + mg.getType() + "' expecting a '" + methodType
2539                 + "' on top of the stack. But stack top is a '" + stack().peek() + "'.");
2540         }
2541     }
2542 
2543     /**
2544      * Ensures the specific preconditions of the said instruction.
2545      */
2546     @Override
2547     public void visitSALOAD(final SALOAD o) {
2548         indexOfInt(o, stack().peek());
2549         if (stack().peek(1) == Type.NULL) {
2550             return;
2551         }
2552         if (!(stack().peek(1) instanceof ArrayType)) {
2553             constraintViolated(o, "Stack next-to-top must be of type short[] but is '" + stack().peek(1) + "'.");
2554         }
2555         final Type t = ((ArrayType) stack().peek(1)).getBasicType();
2556         if (t != Type.SHORT) {
2557             constraintViolated(o, "Stack next-to-top must be of type short[] but is '" + stack().peek(1) + "'.");
2558         }
2559     }
2560 
2561     /**
2562      * Ensures the specific preconditions of the said instruction.
2563      */
2564     @Override
2565     public void visitSASTORE(final SASTORE o) {
2566         if (stack().peek() != Type.INT) {
2567             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
2568         }
2569         indexOfInt(o, stack().peek(1));
2570         if (stack().peek(2) == Type.NULL) {
2571             return;
2572         }
2573         if (!(stack().peek(2) instanceof ArrayType)) {
2574             constraintViolated(o, "Stack next-to-next-to-top must be of type short[] but is '" + stack().peek(2) + "'.");
2575         }
2576         final Type t = ((ArrayType) stack().peek(2)).getBasicType();
2577         if (t != Type.SHORT) {
2578             constraintViolated(o, "Stack next-to-next-to-top must be of type short[] but is '" + stack().peek(2) + "'.");
2579         }
2580     }
2581 
2582     /**
2583      * Ensures the specific preconditions of the said instruction.
2584      */
2585     @Override
2586     public void visitSIPUSH(final SIPUSH o) {
2587         // nothing to do here. Generic visitXXX() methods did the trick before.
2588     }
2589 
2590     /**
2591      * Ensures the general preconditions of an instruction that accesses the stack. This method is here because BCEL has no
2592      * such superinterface for the stack accessing instructions; and there are funny unexpected exceptions in the semantices
2593      * of the superinterfaces and superclasses provided. E.g. SWAP is a StackConsumer, but DUP_X1 is not a StackProducer.
2594      * Therefore, this method is called by all StackProducer, StackConsumer, and StackInstruction instances via their
2595      * visitXXX() method. Unfortunately, as the superclasses and superinterfaces overlap, some instructions cause this
2596      * method to be called two or three times. [TODO: Fix this.]
2597      *
2598      * @see #visitStackConsumer(StackConsumer o)
2599      * @see #visitStackProducer(StackProducer o)
2600      * @see #visitStackInstruction(StackInstruction o)
2601      */
2602     private void visitStackAccessor(final Instruction o) {
2603         final int consume = o.consumeStack(cpg); // Stack values are always consumed first; then produced.
2604         if (consume > stack().slotsUsed()) {
2605             constraintViolated(o, "Cannot consume " + consume + " stack slots: only " + stack().slotsUsed() + " slot(s) left on stack!\nStack:\n" + stack());
2606         }
2607 
2608         final int produce = o.produceStack(cpg) - o.consumeStack(cpg); // Stack values are always consumed first; then produced.
2609         if (produce + stack().slotsUsed() > stack().maxStack()) {
2610             constraintViolated(o, "Cannot produce " + produce + " stack slots: only " + (stack().maxStack() - stack().slotsUsed())
2611                 + " free stack slot(s) left.\nStack:\n" + stack());
2612         }
2613     }
2614 
2615     /**
2616      * Ensures the general preconditions of a StackConsumer instance.
2617      */
2618     @Override
2619     public void visitStackConsumer(final StackConsumer o) {
2620         visitStackAccessor((Instruction) o);
2621     }
2622 
2623     /**
2624      * Ensures the general preconditions of a StackInstruction instance.
2625      */
2626     @Override
2627     public void visitStackInstruction(final StackInstruction o) {
2628         visitStackAccessor(o);
2629     }
2630 
2631     /**
2632      * Ensures the general preconditions of a StackProducer instance.
2633      */
2634     @Override
2635     public void visitStackProducer(final StackProducer o) {
2636         visitStackAccessor((Instruction) o);
2637     }
2638 
2639     /**
2640      * Assures the generic preconditions of a StoreInstruction instance.
2641      */
2642     @Override
2643     public void visitStoreInstruction(final StoreInstruction o) {
2644         // visitLocalVariableInstruction(o) is called before, because it is more generic.
2645 
2646         if (stack().isEmpty()) { // Don't bother about 1 or 2 stack slots used. This check is implicitly done below while type checking.
2647             constraintViolated(o, "Cannot STORE: Stack to read from is empty.");
2648         }
2649 
2650         if (!(o instanceof ASTORE)) {
2651             if (!(stack().peek() == o.getType(cpg))) { // the other xSTORE types are singletons in BCEL.
2652                 constraintViolated(o,
2653                     "Stack top type and STOREing Instruction type mismatch: Stack top: '" + stack().peek() + "'; Instruction type: '" + o.getType(cpg) + "'.");
2654             }
2655         } else { // we deal with ASTORE
2656             final Type stacktop = stack().peek();
2657             if (!(stacktop instanceof ReferenceType) && !(stacktop instanceof ReturnaddressType)) {
2658                 constraintViolated(o, "Stack top type and STOREing Instruction type mismatch: Stack top: '" + stack().peek()
2659                     + "'; Instruction expects a ReferenceType or a ReturnadressType.");
2660             }
2661             // if (stacktop instanceof ReferenceType) {
2662             // referenceTypeIsInitialized(o, (ReferenceType) stacktop);
2663             // }
2664         }
2665     }
2666 
2667     /**
2668      * Ensures the specific preconditions of the said instruction.
2669      */
2670     @Override
2671     public void visitSWAP(final SWAP o) {
2672         if (stack().peek().getSize() != 1) {
2673             constraintViolated(o, "The value at the stack top is not of size '1', but of size '" + stack().peek().getSize() + "'.");
2674         }
2675         if (stack().peek(1).getSize() != 1) {
2676             constraintViolated(o, "The value at the stack next-to-top is not of size '1', but of size '" + stack().peek(1).getSize() + "'.");
2677         }
2678     }
2679 
2680     /**
2681      * Ensures the specific preconditions of the said instruction.
2682      */
2683     @Override
2684     public void visitTABLESWITCH(final TABLESWITCH o) {
2685         indexOfInt(o, stack().peek());
2686         // See Pass 3a.
2687     }
2688 
2689 }