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