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