View Javadoc

    1   /*
    2    * Copyright  2000-2004 The Apache Software Foundation
    3    *
    4    *  Licensed under the Apache License, Version 2.0 (the "License");
    5    *  you may not use this file except in compliance with the License.
    6    *  You may obtain a copy of the License at
    7    *
    8    *      http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   *  Unless required by applicable law or agreed to in writing, software
    11   *  distributed under the License is distributed on an "AS IS" BASIS,
    12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   *  See the License for the specific language governing permissions and
    14   *  limitations under the License.
    15   *
    16   */
    17  package org.apache.bcel.verifier.statics;
    18
    19
    20  import org.apache.bcel.Constants;
    21  import org.apache.bcel.Repository;
    22  import org.apache.bcel.classfile.Attribute;
    23  import org.apache.bcel.classfile.Code;
    24  import org.apache.bcel.classfile.CodeException;
    25  import org.apache.bcel.classfile.Constant;
    26  import org.apache.bcel.classfile.ConstantClass;
    27  import org.apache.bcel.classfile.ConstantDouble;
    28  import org.apache.bcel.classfile.ConstantFieldref;
    29  import org.apache.bcel.classfile.ConstantFloat;
    30  import org.apache.bcel.classfile.ConstantInteger;
    31  import org.apache.bcel.classfile.ConstantInterfaceMethodref;
    32  import org.apache.bcel.classfile.ConstantLong;
    33  import org.apache.bcel.classfile.ConstantMethodref;
    34  import org.apache.bcel.classfile.ConstantNameAndType;
    35  import org.apache.bcel.classfile.ConstantString;
    36  import org.apache.bcel.classfile.ConstantUtf8;
    37  import org.apache.bcel.classfile.Field;
    38  import org.apache.bcel.classfile.JavaClass;
    39  import org.apache.bcel.classfile.LineNumber;
    40  import org.apache.bcel.classfile.LineNumberTable;
    41  import org.apache.bcel.classfile.LocalVariable;
    42  import org.apache.bcel.classfile.LocalVariableTable;
    43  import org.apache.bcel.classfile.Method;
    44  import org.apache.bcel.generic.ALOAD;
    45  import org.apache.bcel.generic.ANEWARRAY;
    46  import org.apache.bcel.generic.ASTORE;
    47  import org.apache.bcel.generic.ATHROW;
    48  import org.apache.bcel.generic.ArrayType;
    49  import org.apache.bcel.generic.BREAKPOINT;
    50  import org.apache.bcel.generic.CHECKCAST;
    51  import org.apache.bcel.generic.ConstantPoolGen;
    52  import org.apache.bcel.generic.DLOAD;
    53  import org.apache.bcel.generic.DSTORE;
    54  import org.apache.bcel.generic.FLOAD;
    55  import org.apache.bcel.generic.FSTORE;
    56  import org.apache.bcel.generic.FieldInstruction;
    57  import org.apache.bcel.generic.GETSTATIC;
    58  import org.apache.bcel.generic.GotoInstruction;
    59  import org.apache.bcel.generic.IINC;
    60  import org.apache.bcel.generic.ILOAD;
    61  import org.apache.bcel.generic.IMPDEP1;
    62  import org.apache.bcel.generic.IMPDEP2;
    63  import org.apache.bcel.generic.INSTANCEOF;
    64  import org.apache.bcel.generic.INVOKEINTERFACE;
    65  import org.apache.bcel.generic.INVOKESPECIAL;
    66  import org.apache.bcel.generic.INVOKESTATIC;
    67  import org.apache.bcel.generic.INVOKEVIRTUAL;
    68  import org.apache.bcel.generic.ISTORE;
    69  import org.apache.bcel.generic.Instruction;
    70  import org.apache.bcel.generic.InstructionHandle;
    71  import org.apache.bcel.generic.InstructionList;
    72  import org.apache.bcel.generic.InvokeInstruction;
    73  import org.apache.bcel.generic.JsrInstruction;
    74  import org.apache.bcel.generic.LDC;
    75  import org.apache.bcel.generic.LDC2_W;
    76  import org.apache.bcel.generic.LLOAD;
    77  import org.apache.bcel.generic.LOOKUPSWITCH;
    78  import org.apache.bcel.generic.LSTORE;
    79  import org.apache.bcel.generic.LoadClass;
    80  import org.apache.bcel.generic.MULTIANEWARRAY;
    81  import org.apache.bcel.generic.NEW;
    82  import org.apache.bcel.generic.NEWARRAY;
    83  import org.apache.bcel.generic.ObjectType;
    84  import org.apache.bcel.generic.PUTSTATIC;
    85  import org.apache.bcel.generic.RET;
    86  import org.apache.bcel.generic.ReturnInstruction;
    87  import org.apache.bcel.generic.TABLESWITCH;
    88  import org.apache.bcel.generic.Type;
    89  import org.apache.bcel.verifier.PassVerifier;
    90  import org.apache.bcel.verifier.VerificationResult;
    91  import org.apache.bcel.verifier.Verifier;
    92  import org.apache.bcel.verifier.VerifierFactory;
    93  import org.apache.bcel.verifier.exc.AssertionViolatedException;
    94  import org.apache.bcel.verifier.exc.ClassConstraintException;
    95  import org.apache.bcel.verifier.exc.InvalidMethodException;
    96  import org.apache.bcel.verifier.exc.StaticCodeConstraintException;
    97  import org.apache.bcel.verifier.exc.StaticCodeInstructionConstraintException;
    98  import org.apache.bcel.verifier.exc.StaticCodeInstructionOperandConstraintException;
    99
    100 /***
    101  * This PassVerifier verifies a class file according to
    102  * pass 3, static part as described in The Java Virtual
    103  * Machine Specification, 2nd edition.
    104  * More detailed information is to be found at the do_verify()
    105  * method's documentation.
    106  *
    107  * @version $Id: Pass3aVerifier.java 386056 2006-03-15 11:31:56Z tcurdt $
    108  * @author Enver Haase
    109  * @see #do_verify()
    110  */
    111 public final class Pass3aVerifier extends PassVerifier{
    112
    113 	/*** The Verifier that created this. */
    114 	private Verifier myOwner;
    115
    116 	/***
    117 	 * The method number to verify.
    118 	 * This is the index in the array returned
    119 	 * by JavaClass.getMethods().
    120 	 */
    121 	private int method_no;
    122
    123 	/*** The one and only InstructionList object used by an instance of this class. It's here for performance reasons by do_verify() and its callees. */
    124 	InstructionList instructionList;
    125 	/*** The one and only Code object used by an instance of this class. It's here for performance reasons by do_verify() and its callees. */
    126 	Code code;
    127
    128 	/*** Should only be instantiated by a Verifier. */
    129 	public Pass3aVerifier(Verifier owner, int method_no){
    130 		myOwner = owner;
    131 		this.method_no = method_no;
    132 	}
    133
    134 	/***
    135 	 * Pass 3a is the verification of static constraints of
    136 	 * JVM code (such as legal targets of branch instructions).
    137 	 * This is the part of pass 3 where you do not need data
    138 	 * flow analysis.
    139 	 * JustIce also delays the checks for a correct exception
    140 	 * table of a Code attribute and correct line number entries
    141 	 * in a LineNumberTable attribute of a Code attribute (which
    142 	 * conceptually belong to pass 2) to this pass. Also, most
    143 	 * of the check for valid local variable entries in a
    144 	 * LocalVariableTable attribute of a Code attribute is
    145 	 * delayed until this pass.
    146 	 * All these checks need access to the code array of the
    147 	 * Code attribute.
    148 	 *
    149 	 * @throws InvalidMethodException if the method to verify does not exist.
    150 	 */
    151 	public VerificationResult do_verify(){
    152 	    try {
    153 		if (myOwner.doPass2().equals(VerificationResult.VR_OK)){
    154 			// Okay, class file was loaded correctly by Pass 1
    155 			// and satisfies static constraints of Pass 2.
    156 			JavaClass jc = Repository.lookupClass(myOwner.getClassName());
    157 			Method[] methods = jc.getMethods();
    158 			if (method_no >= methods.length){
    159 				throw new InvalidMethodException("METHOD DOES NOT EXIST!");
    160 			}
    161 			Method method = methods[method_no];
    162 			code = method.getCode();
    163
    164 			// No Code? Nothing to verify!
    165 			if ( method.isAbstract() || method.isNative() ){ // IF mg HAS NO CODE (static constraint of Pass 2)
    166 				return VerificationResult.VR_OK;
    167 			}
    168
    169 			// TODO:
    170 			// We want a very sophisticated code examination here with good explanations
    171 			// on where to look for an illegal instruction or such.
    172 			// Only after that we should try to build an InstructionList and throw an
    173 			// AssertionViolatedException if after our examination InstructionList building
    174 			// still fails.
    175 			// That examination should be implemented in a byte-oriented way, i.e. look for
    176 			// an instruction, make sure its validity, count its length, find the next
    177 			// instruction and so on.
    178 			try{
    179 				instructionList = new InstructionList(method.getCode().getCode());
    180 			}
    181 			catch(RuntimeException re){
    182 				return new VerificationResult(VerificationResult.VERIFIED_REJECTED, "Bad bytecode in the code array of the Code attribute of method '"+method+"'.");
    183 			}
    184
    185 			instructionList.setPositions(true);
    186
    187 			// Start verification.
    188 			VerificationResult vr = VerificationResult.VR_OK; //default
    189 			try{
    190 				delayedPass2Checks();
    191 			}
    192 			catch(ClassConstraintException cce){
    193 				vr = new VerificationResult(VerificationResult.VERIFIED_REJECTED, cce.getMessage());
    194 				return vr;
    195 			}
    196 			try{
    197 				pass3StaticInstructionChecks();
    198 				pass3StaticInstructionOperandsChecks();
    199 			}
    200 			catch(StaticCodeConstraintException scce){
    201 				vr = new VerificationResult(VerificationResult.VERIFIED_REJECTED, scce.getMessage());
    202 			}
    203 			catch(ClassCastException cce){
    204 				vr = new VerificationResult(VerificationResult.VERIFIED_REJECTED, "Class Cast Exception: " + cce.getMessage());
    205 			}
    206 			return vr;
    207 		}
    208 		else{ //did not pass Pass 2.
    209 			return VerificationResult.VR_NOTYET;
    210 		}
    211 	    } catch (ClassNotFoundException e) {
    212 		// FIXME: maybe not the best way to handle this
    213 		throw new AssertionViolatedException("Missing class: " + e.toString());
    214 	    }
    215 	}
    216
    217 	/***
    218 	 * These are the checks that could be done in pass 2 but are delayed to pass 3
    219 	 * for performance reasons. Also, these checks need access to the code array
    220 	 * of the Code attribute of a Method so it's okay to perform them here.
    221 	 * Also see the description of the do_verify() method.
    222 	 *
    223 	 * @throws ClassConstraintException if the verification fails.
    224 	 * @see #do_verify()
    225 	 */
    226 	private void delayedPass2Checks(){
    227
    228 		int[] instructionPositions = instructionList.getInstructionPositions();
    229 		int codeLength = code.getCode().length;
    230
    231 		/////////////////////
    232 		// LineNumberTable //
    233 		/////////////////////
    234 		LineNumberTable lnt = code.getLineNumberTable();
    235 		if (lnt != null){
    236 			LineNumber[] lineNumbers = lnt.getLineNumberTable();
    237 			IntList offsets = new IntList();
    238 			lineNumber_loop: for (int i=0; i < lineNumbers.length; i++){ // may appear in any order.
    239 				for (int j=0; j < instructionPositions.length; j++){
    240 					// TODO: Make this a binary search! The instructionPositions array is naturally ordered!
    241 					int offset = lineNumbers[i].getStartPC();
    242 					if (instructionPositions[j] == offset){
    243 						if (offsets.contains(offset)){
    244 							addMessage("LineNumberTable attribute '"+code.getLineNumberTable()+"' refers to the same code offset ('"+offset+"') more than once which is violating the semantics [but is sometimes produced by IBM's 'jikes' compiler].");
    245 						}
    246 						else{
    247 							offsets.add(offset);
    248 						}
    249 						continue lineNumber_loop;
    250 					}
    251 				}
    252 				throw new ClassConstraintException("Code attribute '"+code+"' has a LineNumberTable attribute '"+code.getLineNumberTable()+"' referring to a code offset ('"+lineNumbers[i].getStartPC()+"') that does not exist.");
    253 			}
    254 		}
    255
    256 		///////////////////////////
    257 		// LocalVariableTable(s) //
    258 		///////////////////////////
    259 		/* We cannot use code.getLocalVariableTable() because there could be more
    260 		   than only one. This is a bug in BCEL. */
    261 		Attribute[] atts = code.getAttributes();
    262 		for (int a=0; a<atts.length; a++){
    263 			if (atts[a] instanceof LocalVariableTable){
    264 				LocalVariableTable lvt = (LocalVariableTable) atts[a];
    265 				if (lvt != null){
    266 					LocalVariable[] localVariables = lvt.getLocalVariableTable();
    267 					for (int i=0; i<localVariables.length; i++){
    268 						int startpc = localVariables[i].getStartPC();
    269 						int length  = localVariables[i].getLength();
    270
    271 						if (!contains(instructionPositions, startpc)){
    272 							throw new ClassConstraintException("Code attribute '"+code+"' has a LocalVariableTable attribute '"+code.getLocalVariableTable()+"' referring to a code offset ('"+startpc+"') that does not exist.");
    273 						}
    274 						if ( (!contains(instructionPositions, startpc+length)) && (startpc+length != codeLength) ){
    275 							throw new ClassConstraintException("Code attribute '"+code+"' has a LocalVariableTable attribute '"+code.getLocalVariableTable()+"' referring to a code offset start_pc+length ('"+(startpc+length)+"') that does not exist.");
    276 						}
    277 					}
    278 				}
    279 			}
    280 		}
    281
    282 		////////////////////
    283 		// ExceptionTable //
    284 		////////////////////
    285 		// In BCEL's "classfile" API, the startPC/endPC-notation is
    286 		// inclusive/exclusive as in the Java Virtual Machine Specification.
    287 		// WARNING: This is not true for BCEL's "generic" API.
    288 		CodeException[] exceptionTable = code.getExceptionTable();
    289 		for (int i=0; i<exceptionTable.length; i++){
    290 			int startpc = exceptionTable[i].getStartPC();
    291 			int endpc = exceptionTable[i].getEndPC();
    292 			int handlerpc = exceptionTable[i].getHandlerPC();
    293 			if (startpc >= endpc){
    294 				throw new ClassConstraintException("Code attribute '"+code+"' has an exception_table entry '"+exceptionTable[i]+"' that has its start_pc ('"+startpc+"') not smaller than its end_pc ('"+endpc+"').");
    295 			}
    296 			if (!contains(instructionPositions, startpc)){
    297 				throw new ClassConstraintException("Code attribute '"+code+"' has an exception_table entry '"+exceptionTable[i]+"' that has a non-existant bytecode offset as its start_pc ('"+startpc+"').");
    298 			}
    299 			if ( (!contains(instructionPositions, endpc)) && (endpc != codeLength)){
    300 				throw new ClassConstraintException("Code attribute '"+code+"' has an exception_table entry '"+exceptionTable[i]+"' that has a non-existant bytecode offset as its end_pc ('"+startpc+"') [that is also not equal to code_length ('"+codeLength+"')].");
    301 			}
    302 			if (!contains(instructionPositions, handlerpc)){
    303 				throw new ClassConstraintException("Code attribute '"+code+"' has an exception_table entry '"+exceptionTable[i]+"' that has a non-existant bytecode offset as its handler_pc ('"+handlerpc+"').");
    304 			}
    305 		}
    306 	}
    307
    308 	/***
    309 	 * These are the checks if constraints are satisfied which are described in the
    310 	 * Java Virtual Machine Specification, Second Edition as Static Constraints on
    311 	 * the instructions of Java Virtual Machine Code (chapter 4.8.1).
    312 	 *
    313 	 * @throws StaticCodeConstraintException if the verification fails.
    314 	 */
    315 	private void pass3StaticInstructionChecks(){
    316
    317 		// Code array must not be empty:
    318 		// Enforced in pass 2 (also stated in the static constraints of the Code
    319 		// array in vmspec2), together with pass 1 (reading code_length bytes and
    320 		// interpreting them as code[]). So this must not be checked again here.
    321
    322 		if (! (code.getCode().length < 65536)){// contradicts vmspec2 page 152 ("Limitations"), but is on page 134.
    323 			throw new StaticCodeInstructionConstraintException("Code array in code attribute '"+code+"' too big: must be smaller than 65536 bytes.");
    324 		}
    325
    326 		// First opcode at offset 0: okay, that's clear. Nothing to do.
    327
    328 		// Only instances of the instructions documented in Section 6.4 may appear in
    329 		// the code array.
    330
    331 		// For BCEL's sake, we cannot handle WIDE stuff, but hopefully BCEL does its job right :)
    332
    333 		// The last byte of the last instruction in the code array must be the byte at index
    334 		// code_length-1 : See the do_verify() comments. We actually don't iterate through the
    335 		// byte array, but use an InstructionList so we cannot check for this. But BCEL does
    336 		// things right, so it's implicitly okay.
    337
    338 		// TODO: Check how BCEL handles (and will handle) instructions like IMPDEP1, IMPDEP2,
    339 		//       BREAKPOINT... that BCEL knows about but which are illegal anyway.
    340 		//       We currently go the safe way here.
    341 		InstructionHandle ih = instructionList.getStart();
    342 		while (ih != null){
    343 			Instruction i = ih.getInstruction();
    344 			if (i instanceof IMPDEP1){
    345 				throw new StaticCodeInstructionConstraintException("IMPDEP1 must not be in the code, it is an illegal instruction for _internal_ JVM use!");
    346 			}
    347 			if (i instanceof IMPDEP2){
    348 				throw new StaticCodeInstructionConstraintException("IMPDEP2 must not be in the code, it is an illegal instruction for _internal_ JVM use!");
    349 			}
    350 			if (i instanceof BREAKPOINT){
    351 				throw new StaticCodeInstructionConstraintException("BREAKPOINT must not be in the code, it is an illegal instruction for _internal_ JVM use!");
    352 			}
    353 			ih = ih.getNext();
    354 		}
    355
    356 		// The original verifier seems to do this check here, too.
    357 		// An unreachable last instruction may also not fall through the
    358 		// end of the code, which is stupid -- but with the original
    359 		// verifier's subroutine semantics one cannot predict reachability.
    360 		Instruction last = instructionList.getEnd().getInstruction();
    361 		if (! ((last instanceof ReturnInstruction)	||
    362 					(last instanceof RET)    							||
    363 					(last instanceof GotoInstruction)			||
    364 					(last instanceof ATHROW) )) {
    365             throw new StaticCodeInstructionConstraintException("Execution must not fall off the bottom of the code array. This constraint is enforced statically as some existing verifiers do - so it may be a false alarm if the last instruction is not reachable.");
    366         }
    367 	}
    368
    369 	/***
    370 	 * These are the checks for the satisfaction of constraints which are described in the
    371 	 * Java Virtual Machine Specification, Second Edition as Static Constraints on
    372 	 * the operands of instructions of Java Virtual Machine Code (chapter 4.8.1).
    373 	 * BCEL parses the code array to create an InstructionList and therefore has to check
    374 	 * some of these constraints. Additional checks are also implemented here.
    375 	 *
    376 	 * @throws StaticCodeConstraintException if the verification fails.
    377 	 */
    378 	private void pass3StaticInstructionOperandsChecks(){
    379 	    try {
    380 		// When building up the InstructionList, BCEL has already done all those checks
    381 		// mentioned in The Java Virtual Machine Specification, Second Edition, as
    382 		// "static constraints on the operands of instructions in the code array".
    383 		// TODO: see the do_verify() comments. Maybe we should really work on the
    384 		//       byte array first to give more comprehensive messages.
    385 		// TODO: Review Exception API, possibly build in some "offending instruction" thing
    386 		//       when we're ready to insulate the offending instruction by doing the
    387 		//       above thing.
    388
    389 		// TODO: Implement as much as possible here. BCEL does _not_ check everything.
    390
    391 		ConstantPoolGen cpg = new ConstantPoolGen(Repository.lookupClass(myOwner.getClassName()).getConstantPool());
    392 		InstOperandConstraintVisitor v = new InstOperandConstraintVisitor(cpg);
    393
    394 		// Checks for the things BCEL does _not_ handle itself.
    395 		InstructionHandle ih = instructionList.getStart();
    396 		while (ih != null){
    397 			Instruction i = ih.getInstruction();
    398
    399 			// An "own" constraint, due to JustIce's new definition of what "subroutine" means.
    400 			if (i instanceof JsrInstruction){
    401 				InstructionHandle target = ((JsrInstruction) i).getTarget();
    402 				if (target == instructionList.getStart()){
    403 					throw new StaticCodeInstructionOperandConstraintException("Due to JustIce's clear definition of subroutines, no JSR or JSR_W may have a top-level instruction (such as the very first instruction, which is targeted by instruction '"+ih+"' as its target.");
    404 				}
    405 				if (!(target.getInstruction() instanceof ASTORE)){
    406 					throw new StaticCodeInstructionOperandConstraintException("Due to JustIce's clear definition of subroutines, no JSR or JSR_W may target anything else than an ASTORE instruction. Instruction '"+ih+"' targets '"+target+"'.");
    407 				}
    408 			}
    409
    410 			// vmspec2, page 134-137
    411 			ih.accept(v);
    412
    413 			ih = ih.getNext();
    414 		}
    415
    416 	    } catch (ClassNotFoundException e) {
    417 		// FIXME: maybe not the best way to handle this
    418 		throw new AssertionViolatedException("Missing class: " + e.toString());
    419 	    }
    420 	}
    421
    422 	/*** A small utility method returning if a given int i is in the given int[] ints. */
    423 	private static boolean contains(int[] ints, int i){
    424 		for (int j=0; j<ints.length; j++){
    425 			if (ints[j]==i) {
    426                 return true;
    427             }
    428 		}
    429 		return false;
    430 	}
    431
    432 	/*** Returns the method number as supplied when instantiating. */
    433 	public int getMethodNo(){
    434 		return method_no;
    435 	}
    436
    437 	/***
    438 	 * This visitor class does the actual checking for the instruction
    439 	 * operand's constraints.
    440 	 */
    441 	private class InstOperandConstraintVisitor extends org.apache.bcel.generic.EmptyVisitor{
    442 		/*** The ConstantPoolGen instance this Visitor operates on. */
    443 		private ConstantPoolGen cpg;
    444
    445 		/*** The only Constructor. */
    446 		InstOperandConstraintVisitor(ConstantPoolGen cpg){
    447 			this.cpg = cpg;
    448 		}
    449
    450 		/***
    451 		 * Utility method to return the max_locals value of the method verified
    452 		 * by the surrounding Pass3aVerifier instance.
    453 		 */
    454 		private int max_locals(){
    455 		   try {
    456 			return Repository.lookupClass(myOwner.getClassName()).getMethods()[method_no].getCode().getMaxLocals();
    457 		    } catch (ClassNotFoundException e) {
    458 			// FIXME: maybe not the best way to handle this
    459 			throw new AssertionViolatedException("Missing class: " + e.toString());
    460 		    }
    461 		}
    462
    463 		/***
    464 		 * A utility method to always raise an exeption.
    465 		 */
    466 		private void constraintViolated(Instruction i, String message) {
    467 			throw new StaticCodeInstructionOperandConstraintException("Instruction "+i+" constraint violated: "+message);
    468 		}
    469
    470 		/***
    471 		 * A utility method to raise an exception if the index is not
    472 		 * a valid constant pool index.
    473 		 */
    474 		private void indexValid(Instruction i, int idx){
    475 			if (idx < 0 || idx >= cpg.getSize()){
    476 				constraintViolated(i, "Illegal constant pool index '"+idx+"'.");
    477 			}
    478 		}
    479
    480 		///////////////////////////////////////////////////////////
    481 		// The Java Virtual Machine Specification, pages 134-137 //
    482 		///////////////////////////////////////////////////////////
    483 		/***
    484 		 * Assures the generic preconditions of a LoadClass instance.
    485 		 * The referenced class is loaded and pass2-verified.
    486 		 */
    487 		public void visitLoadClass(LoadClass o){
    488 			ObjectType t = o.getLoadClassType(cpg);
    489 			if (t != null){// null means "no class is loaded"
    490 				Verifier v = VerifierFactory.getVerifier(t.getClassName());
    491 				VerificationResult vr = v.doPass1();
    492 				if (vr.getStatus() != VerificationResult.VERIFIED_OK){
    493 					constraintViolated((Instruction) o, "Class '"+o.getLoadClassType(cpg).getClassName()+"' is referenced, but cannot be loaded: '"+vr+"'.");
    494 				}
    495 			}
    496 		}
    497
    498 		// The target of each jump and branch instruction [...] must be the opcode [...]
    499 		// BCEL _DOES_ handle this.
    500
    501 		// tableswitch: BCEL will do it, supposedly.
    502
    503 		// lookupswitch: BCEL will do it, supposedly.
    504
    505 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    506 		// LDC and LDC_W (LDC_W is a subclass of LDC in BCEL's model)
    507 		public void visitLDC(LDC o){
    508 			indexValid(o, o.getIndex());
    509 			Constant c = cpg.getConstant(o.getIndex());
    510 			if (c instanceof ConstantClass){
    511 			  addMessage("Operand of LDC or LDC_W is CONSTANT_Class '"+c+"' - this is only supported in JDK 1.5 and higher.");
    512 			}
    513 			else{
    514 			  if (! ( (c instanceof ConstantInteger)	||
    515 			          (c instanceof ConstantFloat) 		||
    516                 (c instanceof ConstantString) ) ){
    517             constraintViolated(o, "Operand of LDC or LDC_W must be one of CONSTANT_Integer, CONSTANT_Float or CONSTANT_String, but is '"+c+"'.");
    518 			  }
    519 			}
    520 		}
    521
    522 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    523 		// LDC2_W
    524 		public void visitLDC2_W(LDC2_W o){
    525 			indexValid(o, o.getIndex());
    526 			Constant c = cpg.getConstant(o.getIndex());
    527 			if (! ( (c instanceof ConstantLong)	||
    528 							(c instanceof ConstantDouble) ) ){
    529 				constraintViolated(o, "Operand of LDC2_W must be CONSTANT_Long or CONSTANT_Double, but is '"+c+"'.");
    530 			}
    531 			try{
    532 				indexValid(o, o.getIndex()+1);
    533 			}
    534 			catch(StaticCodeInstructionOperandConstraintException e){
    535 				throw new AssertionViolatedException("OOPS: Does not BCEL handle that? LDC2_W operand has a problem.");
    536 			}
    537 		}
    538
    539 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    540  		//getfield, putfield, getstatic, putstatic
    541  		public void visitFieldInstruction(FieldInstruction o){
    542 		   try {
    543 			indexValid(o, o.getIndex());
    544 			Constant c = cpg.getConstant(o.getIndex());
    545 			if (! (c instanceof ConstantFieldref)){
    546 				constraintViolated(o, "Indexing a constant that's not a CONSTANT_Fieldref but a '"+c+"'.");
    547 			}
    548
    549 			String field_name = o.getFieldName(cpg);
    550
    551 			JavaClass jc = Repository.lookupClass(o.getClassType(cpg).getClassName());
    552 			Field[] fields = jc.getFields();
    553 			Field f = null;
    554 			for (int i=0; i<fields.length; i++){
    555 				if (fields[i].getName().equals(field_name)){
    556 				  Type f_type = Type.getType(fields[i].getSignature());
    557 				  Type o_type = o.getType(cpg);
    558 					/* TODO: Check if assignment compatibility is sufficient.
    559 				   * What does Sun do?
    560 				   */
    561 				  if (f_type.equals(o_type)){
    562 						f = fields[i];
    563 						break;
    564 					}
    565 				}
    566 			}
    567 			if (f == null){
    568 				JavaClass[] superclasses = jc.getSuperClasses();
    569 				outer:
    570 				for (int j=0; j<superclasses.length; j++){
    571 					fields = superclasses[j].getFields();
    572 					for (int i=0; i<fields.length; i++){
    573 						if (fields[i].getName().equals(field_name)){
    574 							Type f_type = Type.getType(fields[i].getSignature());
    575 							Type o_type = o.getType(cpg);
    576 							if (f_type.equals(o_type)){
    577 								f = fields[i];
    578 								if ((f.getAccessFlags() & (Constants.ACC_PUBLIC | Constants.ACC_PROTECTED)) == 0) {
    579                                     f = null;
    580                                 }
    581 								break outer;
    582 							}
    583 						}
    584 					}
    585 				}
    586 				if (f == null) {
    587                     constraintViolated(o, "Referenced field '"+field_name+"' does not exist in class '"+jc.getClassName()+"'.");
    588                 }
    589 			}
    590 			else{
    591 				/* TODO: Check if assignment compatibility is sufficient.
    592 				   What does Sun do? */
    593 				Type f_type = Type.getType(f.getSignature());
    594 				Type o_type = o.getType(cpg);
    595
    596 				// Argh. Sun's implementation allows us to have multiple fields of
    597 				// the same name but with a different signature.
    598 				//if (! f_type.equals(o_type)){
    599 				//	constraintViolated(o, "Referenced field '"+field_name+"' has type '"+f_type+"' instead of '"+o_type+"' as expected.");
    600 				//}
    601
    602 				/* TODO: Check for access modifiers here. */
    603 			}
    604 		    } catch (ClassNotFoundException e) {
    605 			// FIXME: maybe not the best way to handle this
    606 			throw new AssertionViolatedException("Missing class: " + e.toString());
    607 		    }
    608 		}
    609
    610 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    611 		public void visitInvokeInstruction(InvokeInstruction o){
    612 			indexValid(o, o.getIndex());
    613 			if (	(o instanceof INVOKEVIRTUAL)	||
    614 						(o instanceof INVOKESPECIAL)	||
    615 						(o instanceof INVOKESTATIC)	){
    616 				Constant c = cpg.getConstant(o.getIndex());
    617 				if (! (c instanceof ConstantMethodref)){
    618 					constraintViolated(o, "Indexing a constant that's not a CONSTANT_Methodref but a '"+c+"'.");
    619 				}
    620 				else{
    621 					// Constants are okay due to pass2.
    622 					ConstantNameAndType cnat = (ConstantNameAndType) (cpg.getConstant(((ConstantMethodref) c).getNameAndTypeIndex()));
    623 					ConstantUtf8 cutf8 = (ConstantUtf8) (cpg.getConstant(cnat.getNameIndex()));
    624 					if (cutf8.getBytes().equals(Constants.CONSTRUCTOR_NAME) && (!(o instanceof INVOKESPECIAL)) ){
    625 						constraintViolated(o, "Only INVOKESPECIAL is allowed to invoke instance initialization methods.");
    626 					}
    627 					if ( (! (cutf8.getBytes().equals(Constants.CONSTRUCTOR_NAME)) ) && (cutf8.getBytes().startsWith("<")) ){
    628 						constraintViolated(o, "No method with a name beginning with '<' other than the instance initialization methods may be called by the method invocation instructions.");
    629 					}
    630 				}
    631 			}
    632 			else{ //if (o instanceof INVOKEINTERFACE){
    633 				Constant c = cpg.getConstant(o.getIndex());
    634 				if (! (c instanceof ConstantInterfaceMethodref)){
    635 					constraintViolated(o, "Indexing a constant that's not a CONSTANT_InterfaceMethodref but a '"+c+"'.");
    636 				}
    637 				// TODO: From time to time check if BCEL allows to detect if the
    638 				// 'count' operand is consistent with the information in the
    639 				// CONSTANT_InterfaceMethodref and if the last operand is zero.
    640 				// By now, BCEL hides those two operands because they're superfluous.
    641
    642 				// Invoked method must not be <init> or <clinit>
    643 				ConstantNameAndType cnat = (ConstantNameAndType) (cpg.getConstant(((ConstantInterfaceMethodref)c).getNameAndTypeIndex()));
    644 				String name = ((ConstantUtf8) (cpg.getConstant(cnat.getNameIndex()))).getBytes();
    645 				if (name.equals(Constants.CONSTRUCTOR_NAME)){
    646 					constraintViolated(o, "Method to invoke must not be '"+Constants.CONSTRUCTOR_NAME+"'.");
    647 				}
    648 				if (name.equals(Constants.STATIC_INITIALIZER_NAME)){
    649 					constraintViolated(o, "Method to invoke must not be '"+Constants.STATIC_INITIALIZER_NAME+"'.");
    650 				}
    651 			}
    652
    653 			// The LoadClassType is the method-declaring class, so we have to check the other types.
    654
    655 			Type t = o.getReturnType(cpg);
    656 			if (t instanceof ArrayType){
    657 				t = ((ArrayType) t).getBasicType();
    658 			}
    659 			if (t instanceof ObjectType){
    660 				Verifier v = VerifierFactory.getVerifier(((ObjectType) t).getClassName());
    661 				VerificationResult vr = v.doPass2();
    662 				if (vr.getStatus() != VerificationResult.VERIFIED_OK){
    663 					constraintViolated(o, "Return type class/interface could not be verified successfully: '"+vr.getMessage()+"'.");
    664 				}
    665 			}
    666
    667 			Type[] ts = o.getArgumentTypes(cpg);
    668 			for (int i=0; i<ts.length; i++){
    669 				t = ts[i];
    670 				if (t instanceof ArrayType){
    671 					t = ((ArrayType) t).getBasicType();
    672 				}
    673 				if (t instanceof ObjectType){
    674 					Verifier v = VerifierFactory.getVerifier(((ObjectType) t).getClassName());
    675 					VerificationResult vr = v.doPass2();
    676 					if (vr.getStatus() != VerificationResult.VERIFIED_OK){
    677 						constraintViolated(o, "Argument type class/interface could not be verified successfully: '"+vr.getMessage()+"'.");
    678 					}
    679 				}
    680 			}
    681
    682 		}
    683
    684 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    685 		public void visitINSTANCEOF(INSTANCEOF o){
    686 			indexValid(o, o.getIndex());
    687 			Constant c = cpg.getConstant(o.getIndex());
    688 			if (!	(c instanceof ConstantClass)){
    689 				constraintViolated(o, "Expecting a CONSTANT_Class operand, but found a '"+c+"'.");
    690 			}
    691 		}
    692
    693 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    694 		public void visitCHECKCAST(CHECKCAST o){
    695 			indexValid(o, o.getIndex());
    696 			Constant c = cpg.getConstant(o.getIndex());
    697 			if (!	(c instanceof ConstantClass)){
    698 				constraintViolated(o, "Expecting a CONSTANT_Class operand, but found a '"+c+"'.");
    699 			}
    700 		}
    701
    702 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    703 		public void visitNEW(NEW o){
    704 			indexValid(o, o.getIndex());
    705 			Constant c = cpg.getConstant(o.getIndex());
    706 			if (!	(c instanceof ConstantClass)){
    707 				constraintViolated(o, "Expecting a CONSTANT_Class operand, but found a '"+c+"'.");
    708 			}
    709 			else{
    710 				ConstantUtf8 cutf8 = (ConstantUtf8) (cpg.getConstant( ((ConstantClass) c).getNameIndex() ));
    711 				Type t = Type.getType("L"+cutf8.getBytes()+";");
    712 				if (t instanceof ArrayType){
    713 					constraintViolated(o, "NEW must not be used to create an array.");
    714 				}
    715 			}
    716
    717 		}
    718
    719 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    720 		public void visitMULTIANEWARRAY(MULTIANEWARRAY o){
    721 			indexValid(o, o.getIndex());
    722 			Constant c = cpg.getConstant(o.getIndex());
    723 			if (!	(c instanceof ConstantClass)){
    724 				constraintViolated(o, "Expecting a CONSTANT_Class operand, but found a '"+c+"'.");
    725 			}
    726 			int dimensions2create = o.getDimensions();
    727 			if (dimensions2create < 1){
    728 				constraintViolated(o, "Number of dimensions to create must be greater than zero.");
    729 			}
    730 			Type t = o.getType(cpg);
    731 			if (t instanceof ArrayType){
    732 				int dimensions = ((ArrayType) t).getDimensions();
    733 				if (dimensions < dimensions2create){
    734 					constraintViolated(o, "Not allowed to create array with more dimensions ('+dimensions2create+') than the one referenced by the CONSTANT_Class '"+t+"'.");
    735 				}
    736 			}
    737 			else{
    738 				constraintViolated(o, "Expecting a CONSTANT_Class referencing an array type. [Constraint not found in The Java Virtual Machine Specification, Second Edition, 4.8.1]");
    739 			}
    740 		}
    741
    742 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    743 		public void visitANEWARRAY(ANEWARRAY o){
    744 			indexValid(o, o.getIndex());
    745 			Constant c = cpg.getConstant(o.getIndex());
    746 			if (!	(c instanceof ConstantClass)){
    747 				constraintViolated(o, "Expecting a CONSTANT_Class operand, but found a '"+c+"'.");
    748 			}
    749 			Type t = o.getType(cpg);
    750 			if (t instanceof ArrayType){
    751 				int dimensions = ((ArrayType) t).getDimensions();
    752 				if (dimensions >= 255){
    753 					constraintViolated(o, "Not allowed to create an array with more than 255 dimensions.");
    754 				}
    755 			}
    756 		}
    757
    758 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    759 		public void visitNEWARRAY(NEWARRAY o){
    760 			byte t = o.getTypecode();
    761 			if (!	(	(t == Constants.T_BOOLEAN)	||
    762 							(t == Constants.T_CHAR)			||
    763 							(t == Constants.T_FLOAT)		||
    764 							(t == Constants.T_DOUBLE)		||
    765 							(t == Constants.T_BYTE)			||
    766 							(t == Constants.T_SHORT)		||
    767 							(t == Constants.T_INT)			||
    768 							(t == Constants.T_LONG)	)	){
    769 				constraintViolated(o, "Illegal type code '+t+' for 'atype' operand.");
    770 			}
    771 		}
    772
    773 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    774 		public void visitILOAD(ILOAD o){
    775 			int idx = o.getIndex();
    776 			if (idx < 0){
    777 				constraintViolated(o, "Index '"+idx+"' must be non-negative.");
    778 			}
    779 			else{
    780 				int maxminus1 =  max_locals()-1;
    781 				if (idx > maxminus1){
    782 					constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'.");
    783 				}
    784 			}
    785 		}
    786
    787 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    788 		public void visitFLOAD(FLOAD o){
    789 			int idx = o.getIndex();
    790 			if (idx < 0){
    791 				constraintViolated(o, "Index '"+idx+"' must be non-negative.");
    792 			}
    793 			else{
    794 				int maxminus1 =  max_locals()-1;
    795 				if (idx > maxminus1){
    796 					constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'.");
    797 				}
    798 			}
    799 		}
    800
    801 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    802 		public void visitALOAD(ALOAD o){
    803 			int idx = o.getIndex();
    804 			if (idx < 0){
    805 				constraintViolated(o, "Index '"+idx+"' must be non-negative.");
    806 			}
    807 			else{
    808 				int maxminus1 =  max_locals()-1;
    809 				if (idx > maxminus1){
    810 					constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'.");
    811 				}
    812 			}
    813 		}
    814
    815 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    816 		public void visitISTORE(ISTORE o){
    817 			int idx = o.getIndex();
    818 			if (idx < 0){
    819 				constraintViolated(o, "Index '"+idx+"' must be non-negative.");
    820 			}
    821 			else{
    822 				int maxminus1 =  max_locals()-1;
    823 				if (idx > maxminus1){
    824 					constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'.");
    825 				}
    826 			}
    827 		}
    828
    829 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    830 		public void visitFSTORE(FSTORE o){
    831 			int idx = o.getIndex();
    832 			if (idx < 0){
    833 				constraintViolated(o, "Index '"+idx+"' must be non-negative.");
    834 			}
    835 			else{
    836 				int maxminus1 =  max_locals()-1;
    837 				if (idx > maxminus1){
    838 					constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'.");
    839 				}
    840 			}
    841 		}
    842
    843 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    844 		public void visitASTORE(ASTORE o){
    845 			int idx = o.getIndex();
    846 			if (idx < 0){
    847 				constraintViolated(o, "Index '"+idx+"' must be non-negative.");
    848 			}
    849 			else{
    850 				int maxminus1 =  max_locals()-1;
    851 				if (idx > maxminus1){
    852 					constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'.");
    853 				}
    854 			}
    855 		}
    856
    857 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    858 		public void visitIINC(IINC o){
    859 			int idx = o.getIndex();
    860 			if (idx < 0){
    861 				constraintViolated(o, "Index '"+idx+"' must be non-negative.");
    862 			}
    863 			else{
    864 				int maxminus1 =  max_locals()-1;
    865 				if (idx > maxminus1){
    866 					constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'.");
    867 				}
    868 			}
    869 		}
    870
    871 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    872 		public void visitRET(RET o){
    873 			int idx = o.getIndex();
    874 			if (idx < 0){
    875 				constraintViolated(o, "Index '"+idx+"' must be non-negative.");
    876 			}
    877 			else{
    878 				int maxminus1 =  max_locals()-1;
    879 				if (idx > maxminus1){
    880 					constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'.");
    881 				}
    882 			}
    883 		}
    884
    885 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    886 		public void visitLLOAD(LLOAD o){
    887 			int idx = o.getIndex();
    888 			if (idx < 0){
    889 				constraintViolated(o, "Index '"+idx+"' must be non-negative. [Constraint by JustIce as an analogon to the single-slot xLOAD/xSTORE instructions; may not happen anyway.]");
    890 			}
    891 			else{
    892 				int maxminus2 =  max_locals()-2;
    893 				if (idx > maxminus2){
    894 					constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-2 '"+maxminus2+"'.");
    895 				}
    896 			}
    897 		}
    898
    899 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    900 		public void visitDLOAD(DLOAD o){
    901 			int idx = o.getIndex();
    902 			if (idx < 0){
    903 				constraintViolated(o, "Index '"+idx+"' must be non-negative. [Constraint by JustIce as an analogon to the single-slot xLOAD/xSTORE instructions; may not happen anyway.]");
    904 			}
    905 			else{
    906 				int maxminus2 =  max_locals()-2;
    907 				if (idx > maxminus2){
    908 					constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-2 '"+maxminus2+"'.");
    909 				}
    910 			}
    911 		}
    912
    913 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    914 		public void visitLSTORE(LSTORE o){
    915 			int idx = o.getIndex();
    916 			if (idx < 0){
    917 				constraintViolated(o, "Index '"+idx+"' must be non-negative. [Constraint by JustIce as an analogon to the single-slot xLOAD/xSTORE instructions; may not happen anyway.]");
    918 			}
    919 			else{
    920 				int maxminus2 =  max_locals()-2;
    921 				if (idx > maxminus2){
    922 					constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-2 '"+maxminus2+"'.");
    923 				}
    924 			}
    925 		}
    926
    927 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    928 		public void visitDSTORE(DSTORE o){
    929 			int idx = o.getIndex();
    930 			if (idx < 0){
    931 				constraintViolated(o, "Index '"+idx+"' must be non-negative. [Constraint by JustIce as an analogon to the single-slot xLOAD/xSTORE instructions; may not happen anyway.]");
    932 			}
    933 			else{
    934 				int maxminus2 =  max_locals()-2;
    935 				if (idx > maxminus2){
    936 					constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-2 '"+maxminus2+"'.");
    937 				}
    938 			}
    939 		}
    940
    941 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    942 		public void visitLOOKUPSWITCH(LOOKUPSWITCH o){
    943 			int[] matchs = o.getMatchs();
    944 			int max = Integer.MIN_VALUE;
    945 			for (int i=0; i<matchs.length; i++){
    946 				if (matchs[i] == max && i != 0){
    947 					constraintViolated(o, "Match '"+matchs[i]+"' occurs more than once.");
    948 				}
    949 				if (matchs[i] < max){
    950 					constraintViolated(o, "Lookup table must be sorted but isn't.");
    951 				}
    952 				else{
    953 					max = matchs[i];
    954 				}
    955 			}
    956 		}
    957
    958 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    959 		public void visitTABLESWITCH(TABLESWITCH o){
    960 			// "high" must be >= "low". We cannot check this, as BCEL hides
    961 			// it from us.
    962 		}
    963
    964 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    965 		public void visitPUTSTATIC(PUTSTATIC o){
    966 		    try {
    967 			String field_name = o.getFieldName(cpg);
    968 			JavaClass jc = Repository.lookupClass(o.getClassType(cpg).getClassName());
    969 			Field[] fields = jc.getFields();
    970 			Field f = null;
    971 			for (int i=0; i<fields.length; i++){
    972 				if (fields[i].getName().equals(field_name)){
    973 					f = fields[i];
    974 					break;
    975 				}
    976 			}
    977 			if (f == null){
    978 				throw new AssertionViolatedException("Field not found?!?");
    979 			}
    980
    981 			if (f.isFinal()){
    982 				if (!(myOwner.getClassName().equals(o.getClassType(cpg).getClassName()))){
    983 					constraintViolated(o, "Referenced field '"+f+"' is final and must therefore be declared in the current class '"+myOwner.getClassName()+"' which is not the case: it is declared in '"+o.getClassType(cpg).getClassName()+"'.");
    984 				}
    985 			}
    986
    987 			if (! (f.isStatic())){
    988 				constraintViolated(o, "Referenced field '"+f+"' is not static which it should be.");
    989 			}
    990
    991 			String meth_name = Repository.lookupClass(myOwner.getClassName()).getMethods()[method_no].getName();
    992
    993 			// If it's an interface, it can be set only in <clinit>.
    994 			if ((!(jc.isClass())) && (!(meth_name.equals(Constants.STATIC_INITIALIZER_NAME)))){
    995 				constraintViolated(o, "Interface field '"+f+"' must be set in a '"+Constants.STATIC_INITIALIZER_NAME+"' method.");
    996 			}
    997 		    } catch (ClassNotFoundException e) {
    998 			// FIXME: maybe not the best way to handle this
    999 			throw new AssertionViolatedException("Missing class: " + e.toString());
    1000 		    }
    1001 		}
    1002
    1003 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    1004 		public void visitGETSTATIC(GETSTATIC o){
    1005 		    try {
    1006 			String field_name = o.getFieldName(cpg);
    1007 			JavaClass jc = Repository.lookupClass(o.getClassType(cpg).getClassName());
    1008 			Field[] fields = jc.getFields();
    1009 			Field f = null;
    1010 			for (int i=0; i<fields.length; i++){
    1011 				if (fields[i].getName().equals(field_name)){
    1012 					f = fields[i];
    1013 					break;
    1014 				}
    1015 			}
    1016 			if (f == null){
    1017 				throw new AssertionViolatedException("Field not found?!?");
    1018 			}
    1019
    1020 			if (! (f.isStatic())){
    1021 				constraintViolated(o, "Referenced field '"+f+"' is not static which it should be.");
    1022 			}
    1023 		    } catch (ClassNotFoundException e) {
    1024 			// FIXME: maybe not the best way to handle this
    1025 			throw new AssertionViolatedException("Missing class: " + e.toString());
    1026 		    }
    1027 		}
    1028
    1029 		/* Checks if the constraints of operands of the said instruction(s) are satisfied. */
    1030 		//public void visitPUTFIELD(PUTFIELD o){
    1031 			// for performance reasons done in Pass 3b
    1032 		//}
    1033
    1034 		/* Checks if the constraints of operands of the said instruction(s) are satisfied. */
    1035 		//public void visitGETFIELD(GETFIELD o){
    1036 			// for performance reasons done in Pass 3b
    1037 		//}
    1038
    1039 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    1040 		public void visitINVOKEINTERFACE(INVOKEINTERFACE o){
    1041 		    try {
    1042 			// INVOKEINTERFACE is a LoadClass; the Class where the referenced method is declared in,
    1043 			// is therefore resolved/verified.
    1044 			// INVOKEINTERFACE is an InvokeInstruction, the argument and return types are resolved/verified,
    1045 			// too. So are the allowed method names.
    1046 			String classname = o.getClassName(cpg);
    1047 			JavaClass jc = Repository.lookupClass(classname);
    1048 			Method[] ms = jc.getMethods();
    1049 			Method m = null;
    1050 			for (int i=0; i<ms.length; i++){
    1051 				if ( (ms[i].getName().equals(o.getMethodName(cpg))) &&
    1052 				     (Type.getReturnType(ms[i].getSignature()).equals(o.getReturnType(cpg))) &&
    1053 				     (objarrayequals(Type.getArgumentTypes(ms[i].getSignature()), o.getArgumentTypes(cpg))) ){
    1054 					m = ms[i];
    1055 					break;
    1056 				}
    1057 			}
    1058 			if (m == null){
    1059 				constraintViolated(o, "Referenced method '"+o.getMethodName(cpg)+"' with expected signature '"+o.getSignature(cpg)+"' not found in class '"+jc.getClassName()+"'. The native verifier does allow the method to be declared in some superinterface, which the Java Virtual Machine Specification, Second Edition does not.");
    1060 			}
    1061 			if (jc.isClass()){
    1062 				constraintViolated(o, "Referenced class '"+jc.getClassName()+"' is a class, but not an interface as expected.");
    1063 			}
    1064 		    } catch (ClassNotFoundException e) {
    1065 			// FIXME: maybe not the best way to handle this
    1066 			throw new AssertionViolatedException("Missing class: " + e.toString());
    1067 		    }
    1068 		}
    1069
    1070 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    1071 		public void visitINVOKESPECIAL(INVOKESPECIAL o){
    1072 		    try {
    1073 			// INVOKESPECIAL is a LoadClass; the Class where the referenced method is declared in,
    1074 			// is therefore resolved/verified.
    1075 			// INVOKESPECIAL is an InvokeInstruction, the argument and return types are resolved/verified,
    1076 			// too. So are the allowed method names.
    1077 			String classname = o.getClassName(cpg);
    1078 			JavaClass jc = Repository.lookupClass(classname);
    1079 			Method[] ms = jc.getMethods();
    1080 			Method m = null;
    1081 			for (int i=0; i<ms.length; i++){
    1082 				if ( (ms[i].getName().equals(o.getMethodName(cpg))) &&
    1083 				     (Type.getReturnType(ms[i].getSignature()).equals(o.getReturnType(cpg))) &&
    1084 				     (objarrayequals(Type.getArgumentTypes(ms[i].getSignature()), o.getArgumentTypes(cpg))) ){
    1085 					m = ms[i];
    1086 					break;
    1087 				}
    1088 			}
    1089 			if (m == null){
    1090 				constraintViolated(o, "Referenced method '"+o.getMethodName(cpg)+"' with expected signature '"+o.getSignature(cpg)+"' not found in class '"+jc.getClassName()+"'. The native verifier does allow the method to be declared in some superclass or implemented interface, which the Java Virtual Machine Specification, Second Edition does not.");
    1091 			}
    1092
    1093 			JavaClass current = Repository.lookupClass(myOwner.getClassName());
    1094 			if (current.isSuper()){
    1095
    1096 				if ((Repository.instanceOf( current, jc )) && (!current.equals(jc))){
    1097
    1098 					if (! (o.getMethodName(cpg).equals(Constants.CONSTRUCTOR_NAME) )){
    1099 						// Special lookup procedure for ACC_SUPER classes.
    1100
    1101 						int supidx = -1;
    1102
    1103 						Method meth = null;
    1104 						while (supidx != 0){
    1105 							supidx = current.getSuperclassNameIndex();
    1106 							current = Repository.lookupClass(current.getSuperclassName());
    1107
    1108 							Method[] meths = current.getMethods();
    1109 							for (int i=0; i<meths.length; i++){
    1110 								if	( (meths[i].getName().equals(o.getMethodName(cpg))) &&
    1111 				     				(Type.getReturnType(meths[i].getSignature()).equals(o.getReturnType(cpg))) &&
    1112 				     				(objarrayequals(Type.getArgumentTypes(meths[i].getSignature()), o.getArgumentTypes(cpg))) ){
    1113 									meth = meths[i];
    1114 									break;
    1115 								}
    1116 							}
    1117 							if (meth != null) {
    1118                                 break;
    1119                             }
    1120 						}
    1121 						if (meth == null){
    1122 							constraintViolated(o, "ACC_SUPER special lookup procedure not successful: method '"+o.getMethodName(cpg)+"' with proper signature not declared in superclass hierarchy.");
    1123 						}
    1124 					}
    1125 				}
    1126 			}
    1127
    1128 		    } catch (ClassNotFoundException e) {
    1129 			// FIXME: maybe not the best way to handle this
    1130 			throw new AssertionViolatedException("Missing class: " + e.toString());
    1131 		    }
    1132
    1133 		}
    1134
    1135 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    1136 		public void visitINVOKESTATIC(INVOKESTATIC o){
    1137 		    try {
    1138 			// INVOKESTATIC is a LoadClass; the Class where the referenced method is declared in,
    1139 			// is therefore resolved/verified.
    1140 			// INVOKESTATIC is an InvokeInstruction, the argument and return types are resolved/verified,
    1141 			// too. So are the allowed method names.
    1142 			String classname = o.getClassName(cpg);
    1143 			JavaClass jc = Repository.lookupClass(classname);
    1144 			Method[] ms = jc.getMethods();
    1145 			Method m = null;
    1146 			for (int i=0; i<ms.length; i++){
    1147 				if ( (ms[i].getName().equals(o.getMethodName(cpg))) &&
    1148 				     (Type.getReturnType(ms[i].getSignature()).equals(o.getReturnType(cpg))) &&
    1149 				     (objarrayequals(Type.getArgumentTypes(ms[i].getSignature()), o.getArgumentTypes(cpg))) ){
    1150 					m = ms[i];
    1151 					break;
    1152 				}
    1153 			}
    1154 			if (m == null){
    1155 				constraintViolated(o, "Referenced method '"+o.getMethodName(cpg)+"' with expected signature '"+o.getSignature(cpg) +"' not found in class '"+jc.getClassName()+"'. The native verifier possibly allows the method to be declared in some superclass or implemented interface, which the Java Virtual Machine Specification, Second Edition does not.");
    1156 			} else if (! (m.isStatic())){ // implies it's not abstract, verified in pass 2.
    1157 				constraintViolated(o, "Referenced method '"+o.getMethodName(cpg)+"' has ACC_STATIC unset.");
    1158 			}
    1159
    1160 		    } catch (ClassNotFoundException e) {
    1161 			// FIXME: maybe not the best way to handle this
    1162 			throw new AssertionViolatedException("Missing class: " + e.toString());
    1163 		    }
    1164 		}
    1165
    1166
    1167 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    1168 		public void visitINVOKEVIRTUAL(INVOKEVIRTUAL o){
    1169 		    try {
    1170 			// INVOKEVIRTUAL is a LoadClass; the Class where the referenced method is declared in,
    1171 			// is therefore resolved/verified.
    1172 			// INVOKEVIRTUAL is an InvokeInstruction, the argument and return types are resolved/verified,
    1173 			// too. So are the allowed method names.
    1174 			String classname = o.getClassName(cpg);
    1175 			JavaClass jc = Repository.lookupClass(classname);
    1176 			Method[] ms = jc.getMethods();
    1177 			Method m = null;
    1178 			for (int i=0; i<ms.length; i++){
    1179 				if ( (ms[i].getName().equals(o.getMethodName(cpg))) &&
    1180 				     (Type.getReturnType(ms[i].getSignature()).equals(o.getReturnType(cpg))) &&
    1181 				     (objarrayequals(Type.getArgumentTypes(ms[i].getSignature()), o.getArgumentTypes(cpg))) ){
    1182 					m = ms[i];
    1183 					break;
    1184 				}
    1185 			}
    1186 			if (m == null){
    1187 				constraintViolated(o, "Referenced method '"+o.getMethodName(cpg)+"' with expected signature '"+o.getSignature(cpg)+"' not found in class '"+jc.getClassName()+"'. The native verifier does allow the method to be declared in some superclass or implemented interface, which the Java Virtual Machine Specification, Second Edition does not.");
    1188 			}
    1189 			if (! (jc.isClass())){
    1190 				constraintViolated(o, "Referenced class '"+jc.getClassName()+"' is an interface, but not a class as expected.");
    1191 			}
    1192
    1193 		    } catch (ClassNotFoundException e) {
    1194 			// FIXME: maybe not the best way to handle this
    1195 			throw new AssertionViolatedException("Missing class: " + e.toString());
    1196 		    }
    1197 		}
    1198
    1199
    1200 		// WIDE stuff is BCEL-internal and cannot be checked here.
    1201
    1202 		/***
    1203 		 * A utility method like equals(Object) for arrays.
    1204 		 * The equality of the elements is based on their equals(Object)
    1205 		 * method instead of their object identity.
    1206 		 */
    1207 		private boolean objarrayequals(Object[] o, Object[] p){
    1208 			if (o.length != p.length){
    1209 				return false;
    1210 			}
    1211
    1212 			for (int i=0; i<o.length; i++){
    1213 				if (! (o[i].equals(p[i])) ){
    1214 					return false;
    1215 				}
    1216 			}
    1217
    1218 			return true;
    1219 		}
    1220
    1221 	}
    1222 }