001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   https://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.bcel.verifier.structurals;
020
021import org.apache.bcel.Const;
022import org.apache.bcel.Repository;
023import org.apache.bcel.classfile.Constant;
024import org.apache.bcel.classfile.ConstantClass;
025import org.apache.bcel.classfile.ConstantDouble;
026import org.apache.bcel.classfile.ConstantDynamic;
027import org.apache.bcel.classfile.ConstantFieldref;
028import org.apache.bcel.classfile.ConstantFloat;
029import org.apache.bcel.classfile.ConstantInteger;
030import org.apache.bcel.classfile.ConstantLong;
031import org.apache.bcel.classfile.ConstantString;
032import org.apache.bcel.classfile.Field;
033import org.apache.bcel.classfile.JavaClass;
034import org.apache.bcel.verifier.VerificationResult;
035import org.apache.bcel.verifier.Verifier;
036import org.apache.bcel.verifier.VerifierFactory;
037import org.apache.bcel.verifier.exc.AssertionViolatedException;
038import org.apache.bcel.verifier.exc.StructuralCodeConstraintException;
039
040//CHECKSTYLE:OFF (there are lots of references!)
041import org.apache.bcel.generic.*;
042//CHECKSTYLE:ON
043
044/**
045 * A Visitor class testing for valid preconditions of JVM instructions. The instance of this class will throw a
046 * StructuralCodeConstraintException instance if an instruction is visitXXX()ed which has preconditions that are not
047 * satisfied. TODO: Currently, the JVM's behavior concerning monitors (MONITORENTER, MONITOREXIT) is not modeled in
048 * JustIce.
049 *
050 * @see StructuralCodeConstraintException
051 */
052public class InstConstraintVisitor extends EmptyVisitor {
053
054    private static final ObjectType GENERIC_ARRAY = ObjectType.getInstance(GenericArray.class.getName());
055
056    /**
057     * The Execution Frame we're working on.
058     *
059     * @see #setFrame(Frame f)
060     * @see #locals()
061     * @see #stack()
062     */
063    private Frame frame;
064
065    /**
066     * The ConstantPoolGen we're working on.
067     *
068     * @see #setConstantPoolGen(ConstantPoolGen cpg)
069     */
070    private ConstantPoolGen cpg;
071
072    /**
073     * The MethodGen we're working on.
074     *
075     * @see #setMethodGen(MethodGen mg)
076     */
077    private MethodGen mg;
078
079    /**
080     * The constructor. Constructs a new instance of this class.
081     */
082    public InstConstraintVisitor() {
083    }
084
085    /**
086     * Assures arrayref is of ArrayType or NULL; returns true if and only if arrayref is non-NULL.
087     *
088     * @throws StructuralCodeConstraintException if the above constraint is violated.
089     */
090    private boolean arrayrefOfArrayType(final Instruction o, final Type arrayref) {
091        if (!(arrayref instanceof ArrayType || arrayref.equals(Type.NULL))) {
092            constraintViolated(o, "The 'arrayref' does not refer to an array but is of type " + arrayref + ".");
093        }
094        return arrayref instanceof ArrayType;
095    }
096
097    /**
098     * This method is called by the visitXXX() to notify the acceptor of this InstConstraintVisitor that a constraint
099     * 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}