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 }