001 package edu.rice.cs.cunit.instrumentors.threadCheck;
002
003 import edu.rice.cs.cunit.classFile.ClassFile;
004 import edu.rice.cs.cunit.classFile.ClassFileTools;
005 import edu.rice.cs.cunit.classFile.MethodInfo;
006 import edu.rice.cs.cunit.classFile.attributes.CodeAttributeInfo;
007 import edu.rice.cs.cunit.classFile.code.InstructionList;
008 import edu.rice.cs.cunit.classFile.code.Opcode;
009 import edu.rice.cs.cunit.classFile.code.instructions.GenericInstruction;
010 import edu.rice.cs.cunit.classFile.code.instructions.ReferenceInstruction;
011 import edu.rice.cs.cunit.classFile.constantPool.*;
012 import edu.rice.cs.cunit.classFile.constantPool.visitors.ADefaultPoolInfoVisitor;
013 import edu.rice.cs.cunit.classFile.constantPool.visitors.CheckMethodVisitor;
014 import edu.rice.cs.cunit.classFile.constantPool.visitors.CheckUTFVisitor;
015 import edu.rice.cs.cunit.classFile.constantPool.visitors.CheckClassVisitor;
016 import edu.rice.cs.cunit.threadCheck.OnlyRunBy;
017 import edu.rice.cs.cunit.threadCheck.ThreadCheck;
018 import edu.rice.cs.cunit.threadCheck.ThreadCheckException;
019 import edu.rice.cs.cunit.util.Types;
020
021 import java.io.IOException;
022 import java.util.ArrayList;
023 import java.util.List;
024
025 /**
026 * Instrumentor to add calls to ThreadCheck.checkCurrentThreadReflection to check if the current thread is not
027 * allowed to execute a class or method.
028 *
029 * @author Mathias Ricken
030 */
031 public class AddReflectionThreadCheckStrategy extends AAddThreadCheckStrategy {
032 /**
033 * Constructor for this strategy.
034 * @param shared data shared among all AThreadCheckStrategy instances
035 * @param sharedAdd data for all AAddThreadCheckStrategy instances
036 */
037 public AddReflectionThreadCheckStrategy(SharedData shared, SharedAddData sharedAdd) {
038 this(new ArrayList<String>(), shared, sharedAdd);
039 }
040
041 /**
042 * Constructor for this strategy.
043 * @param parameters parameters for the instrumentors
044 * @param shared data shared among all AThreadCheckStrategy instances
045 * @param sharedAdd data for all AAddThreadCheckStrategy instances
046 */
047 public AddReflectionThreadCheckStrategy(List<String> parameters, SharedData shared, SharedAddData sharedAdd) {
048 super(parameters, shared, sharedAdd);
049 }
050
051 /**
052 * Instrument the class.
053 *
054 * @param cf class file info
055 */
056 public void instrument(final ClassFile cf) {
057 _sharedData.setCurrentClassName(cf.getThisClassName());
058 ReferenceInstruction checkCallInstr = new ReferenceInstruction(Opcode.INVOKESTATIC, (short)0);
059 ReferenceInstruction loadInstr = new ReferenceInstruction(Opcode.LDC_W, (short)0);
060 int checkReflCallIndex = 0;
061
062 // process all methods in this class
063 for(MethodInfo mi : cf.getMethods()) {
064 // proces if not a native or abstract method, should have a body
065 if ((mi.getAccessFlags() & (ClassFile.ACC_NATIVE | ClassFile.ACC_ABSTRACT)) == 0) {
066 long beginMillis = System.currentTimeMillis();
067 ThreadCheckAnnotationRecord methodAR = getMethodAnnotations(cf, mi);
068 long endMillis = System.currentTimeMillis();
069 _sharedAddData.cacheInfo.addTimeSpent(endMillis-beginMillis);
070
071 if (!methodAR.empty()) {
072 boolean changed = false;
073 InstructionList il = new InstructionList(mi.getCodeAttributeInfo().getCode());
074
075 // if this is a constructor ("<init>"), then we should perhaps wait until
076 // after the this() or super() call; try to find it
077 if (mi.getName().toString().equals("<init>")) {
078 // check if this ctor calls other ctors
079 boolean ctorCalled = false;
080 do {
081 if (il.getOpcode() == Opcode.INVOKESPECIAL) {
082 ReferenceInstruction ri = (ReferenceInstruction)il.getInstr();
083 short method = Types.shortFromBytes(ri.getBytecode(), 1);
084 MethodPoolInfo mpi = cf.getConstantPoolItem(method).execute(CheckMethodVisitor.singleton(), null);
085 if (mpi.getNameAndType().getName().toString().equals("<init>")) {
086 ClassFile curcf = cf;
087 while((curcf.getThisClassName()!=null) && (!curcf.getThisClassName().equals(""))) {
088 if (curcf.getThisClass().toString().equals(mpi.getClassInfo().getName().toString())) {
089 // super() call
090 ctorCalled = true;
091 break;
092 }
093 ClassFileTools.ClassLocation cl = null;
094 try {
095 cl = ClassFileTools.findClassFile(curcf.getSuperClassName(), _sharedData.getClassPath());
096 if (cl != null) {
097 curcf = cl.getClassFile();
098 }
099 else {
100 _sharedData.addClassNotFoundWarning(new ClassNotFoundWarning(curcf.getSuperClassName(),_sharedData.getCurrentClassName()));
101 //Debug.out.println("Warning: Could not find " + curcf.getSuperClassName());
102 break;
103 }
104 }
105 finally {
106 try { if (cl!=null) cl.close(); }
107 catch(IOException e) { /* ignore; shouldn't cause any problems except on Windows with read locks */ }
108 }
109 }
110 if (ctorCalled) { break; }
111 }
112 }
113 } while(il.advanceIndex());
114 if (ctorCalled) {
115 // super call found
116 // advance one past the super call
117 boolean res = il.advanceIndex();
118 assert res == true;
119 }
120 else {
121 // no this() or super() call found, start at the beginning
122 il.setIndex(0);
123 _sharedAddData.otherWarnings.add(new OnlyAfterRealizedWarning("ignored, no this() or super() call found in constructor "+
124 cf.getThisClassName()+"."+mi.getName()+mi.getDescriptor()));
125 methodAR.allowEventThread = OnlyRunBy.EVENT_THREAD.NO;
126 }
127 }
128
129 // =====================
130 // Predicate Annotations
131 // =====================
132 if (methodAR.predicateAnnotations.size()>0) {
133 for (PredicateAnnotationRecord par: methodAR.predicateAnnotations) {
134 changed = true;
135 // System.out.println(cf.getThisClassName()+CLASS_SIG_SEPARATOR_STRING+mi.getName().toString()+mi.getDescriptor()+":");
136 if (checkReflCallIndex==0) {
137 checkReflCallIndex = cf.addMethodToConstantPool(ThreadCheck.class.getName().replace('.','/'),
138 "checkCurrentThreadReflection",
139 "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;[Ljava/lang/Object;)V");
140 }
141 checkCallInstr.setReference(checkReflCallIndex);
142
143 boolean res;
144
145 // add the class
146 loadInstr.setReference(cf.getConstantPool().indexOf(cf.getThisClass()));
147 il.insertInstr(loadInstr, mi.getCodeAttributeInfo());
148 res = il.advanceIndex();
149 assert res == true;
150
151 // add the name
152 StringPoolInfo spi = new StringPoolInfo(mi.getName(), cf.getConstantPool());
153 int[] l = cf.addConstantPoolItems(new APoolInfo[]{spi});
154 spi = cf.getConstantPoolItem(l[0]).execute(new ADefaultPoolInfoVisitor<StringPoolInfo, Object>() {
155 public StringPoolInfo defaultCase(APoolInfo host, Object o) {
156 throw new ClassFormatError("Info is of type " + host.getClass().getName() + ", needs to be StringPoolInfo");
157 }
158 public StringPoolInfo stringCase(StringPoolInfo host, Object o) {
159 return host;
160 }
161 }, null);
162
163 loadInstr.setReference(l[0]);
164 il.insertInstr(loadInstr, mi.getCodeAttributeInfo());
165 res = il.advanceIndex();
166 assert res == true;
167
168 // add the descriptor
169 spi = new StringPoolInfo(mi.getDescriptor(), cf.getConstantPool());
170 l = cf.addConstantPoolItems(new APoolInfo[]{spi});
171 spi = cf.getConstantPoolItem(l[0]).execute(new ADefaultPoolInfoVisitor<StringPoolInfo, Object>() {
172 public StringPoolInfo defaultCase(APoolInfo host, Object o) {
173 throw new ClassFormatError("Info is of type " + host.getClass().getName() + ", needs to be StringPoolInfo");
174 }
175 public StringPoolInfo stringCase(StringPoolInfo host, Object o) {
176 return host;
177 }
178 }, null);
179
180 loadInstr.setReference(l[0]);
181 il.insertInstr(loadInstr, mi.getCodeAttributeInfo());
182 res = il.advanceIndex();
183 assert res == true;
184
185 // add "this" or null if static
186 if ((mi.getAccessFlags() & ClassFile.ACC_STATIC)==0) {
187 // not static, add "this"
188 il.insertInstr(new GenericInstruction(new byte[] { Opcode.ALOAD_0 }), mi.getCodeAttributeInfo());
189 res = il.advanceIndex();
190 assert res == true;
191 }
192 else {
193 // static, add null
194 il.insertInstr(new GenericInstruction(new byte[] { Opcode.ACONST_NULL }), mi.getCodeAttributeInfo());
195 res = il.advanceIndex();
196 assert res == true;
197 }
198
199 if (par.passArguments) {
200 // add a new name for the element type
201 AUTFPoolInfo objectClassName = new ASCIIPoolInfo("java/lang/Object", cf.getConstantPool());
202 l = cf.addConstantPoolItems(new APoolInfo[]{objectClassName});
203 objectClassName = cf.getConstantPoolItem(l[0]).execute(CheckUTFVisitor.singleton(), null);
204
205 // add a new class item for the element class
206 ClassPoolInfo objectClass = new ClassPoolInfo(objectClassName, cf.getConstantPool());
207 l = cf.addConstantPoolItems(new APoolInfo[]{objectClass});
208 objectClass = cf.getConstantPoolItem(l[0]).execute(CheckClassVisitor.singleton(), null);
209
210 ReferenceInstruction anewarray = new ReferenceInstruction(Opcode.ANEWARRAY, cf.getConstantPool().indexOf(objectClass));
211
212 // add number of elements to class pool
213 String sig = mi.getDescriptor().toString();
214 List<String> methodArgTypes = ClassFileTools.getSignatures(sig.substring(1,sig.lastIndexOf(')')));
215 IntegerPoolInfo count = new IntegerPoolInfo(methodArgTypes.size(), cf.getConstantPool());
216 l = cf.addConstantPoolItems(new APoolInfo[]{count});
217 count = cf.getConstantPoolItem(l[0]).execute(new ADefaultPoolInfoVisitor<IntegerPoolInfo, Object>() {
218 public IntegerPoolInfo defaultCase(APoolInfo host, Object param) {
219 throw new ClassFormatError("Info is of type " + host.getClass().getName() + ", needs to be IntegerPoolInfo");
220 }
221 public IntegerPoolInfo intCase(IntegerPoolInfo host, Object param) {
222 return host;
223 }
224 }, null);
225
226 // load number of arguments onto stack
227 il.insertInstr(new ReferenceInstruction(Opcode.LDC_W, cf.getConstantPool().indexOf(count)), mi.getCodeAttributeInfo());
228 res = il.advanceIndex();
229 assert res == true;
230
231 // create an array of objects of that size
232 il.insertInstr(anewarray, mi.getCodeAttributeInfo());
233 res = il.advanceIndex();
234 assert res == true;
235
236 // top of stack: array-ref
237
238 // for static methods, the first method argument has to be loaded with ALOAD_0;
239 // for non-static methods, it's ALOAD_1
240 int lvIndex = (ClassFile.ACC_STATIC == (mi.getAccessFlags() & ClassFile.ACC_STATIC))?0:1;
241 int nextLVIndex;
242 int arrayIndex = 0;
243 for(String type: methodArgTypes) {
244 IntegerPoolInfo pi;
245 ReferenceInstruction ldc_w;
246 switch(type.charAt(0)) {
247 case '[':
248 case 'L':
249 nextLVIndex = lvIndex + 1;
250
251 // top of stack: array-ref
252 il.insertInstr(new GenericInstruction(Opcode.DUP), mi.getCodeAttributeInfo());
253 res = il.advanceIndex();
254 assert res == true;
255
256 // top of stack: array-ref array-ref
257
258 pi = new IntegerPoolInfo(arrayIndex, cf.getConstantPool());
259 l = cf.addConstantPoolItems(new APoolInfo[]{pi});
260 pi = cf.getConstantPoolItem(l[0]).execute(new ADefaultPoolInfoVisitor<IntegerPoolInfo, Object>() {
261 public IntegerPoolInfo defaultCase(APoolInfo host, Object o) {
262 throw new ClassFormatError("Info is of type " + host.getClass().getName() + ", needs to be IntegerPoolInfo");
263 }
264 public IntegerPoolInfo intCase(IntegerPoolInfo host, Object o) {
265 return host;
266 }
267 }, null);
268 ldc_w = new ReferenceInstruction(Opcode.LDC_W, cf.getConstantPool().indexOf(pi));
269 il.insertInstr(ldc_w, mi.getCodeAttributeInfo());
270 res = il.advanceIndex();
271 assert res == true;
272
273 // top of stack: array-ref array-ref index
274
275 il.insertInstr(Opcode.getShortestLoadStoreInstruction(Opcode.ALOAD, (short)lvIndex), mi.getCodeAttributeInfo());
276 res = il.advanceIndex();
277 assert res == true;
278 break;
279
280 // top of stack: array-ref array-ref index ref
281 case 'B':
282 nextLVIndex = lvIndex + 1;
283
284 // top of stack: array-ref
285 il.insertInstr(new GenericInstruction(Opcode.DUP), mi.getCodeAttributeInfo());
286 res = il.advanceIndex();
287 assert res == true;
288
289 // top of stack: array-ref array-ref
290
291 pi = new IntegerPoolInfo(arrayIndex, cf.getConstantPool());
292 l = cf.addConstantPoolItems(new APoolInfo[]{pi});
293 pi = cf.getConstantPoolItem(l[0]).execute(new ADefaultPoolInfoVisitor<IntegerPoolInfo, Object>() {
294 public IntegerPoolInfo defaultCase(APoolInfo host, Object o) {
295 throw new ClassFormatError("Info is of type " + host.getClass().getName() + ", needs to be IntegerPoolInfo");
296 }
297 public IntegerPoolInfo intCase(IntegerPoolInfo host, Object o) {
298 return host;
299 }
300 }, null);
301 ldc_w = new ReferenceInstruction(Opcode.LDC_W, cf.getConstantPool().indexOf(pi));
302 il.insertInstr(ldc_w, mi.getCodeAttributeInfo());
303 res = il.advanceIndex();
304 assert res == true;
305
306 // top of stack: array-ref array-ref index
307
308 insertCtorCall(cf, mi, il, "java/lang/Byte", "(B)V",
309 Opcode.getShortestLoadStoreInstruction(Opcode.ILOAD, (short)lvIndex));
310
311 // top of stack: array-ref array-ref index Byte-ref
312 break;
313 case 'C':
314 nextLVIndex = lvIndex + 1;
315
316 // top of stack: array-ref
317 il.insertInstr(new GenericInstruction(Opcode.DUP), mi.getCodeAttributeInfo());
318 res = il.advanceIndex();
319 assert res == true;
320
321 // top of stack: array-ref array-ref
322
323 pi = new IntegerPoolInfo(arrayIndex, cf.getConstantPool());
324 l = cf.addConstantPoolItems(new APoolInfo[]{pi});
325 pi = cf.getConstantPoolItem(l[0]).execute(new ADefaultPoolInfoVisitor<IntegerPoolInfo, Object>() {
326 public IntegerPoolInfo defaultCase(APoolInfo host, Object o) {
327 throw new ClassFormatError("Info is of type " + host.getClass().getName() + ", needs to be IntegerPoolInfo");
328 }
329 public IntegerPoolInfo intCase(IntegerPoolInfo host, Object o) {
330 return host;
331 }
332 }, null);
333 ldc_w = new ReferenceInstruction(Opcode.LDC_W, cf.getConstantPool().indexOf(pi));
334 il.insertInstr(ldc_w, mi.getCodeAttributeInfo());
335 res = il.advanceIndex();
336 assert res == true;
337
338 // top of stack: array-ref array-ref index
339
340 insertCtorCall(cf, mi, il, "java/lang/Character", "(C)V",
341 Opcode.getShortestLoadStoreInstruction(Opcode.ILOAD, (short)lvIndex));
342
343 // top of stack: array-ref array-ref index Char-ref
344 break;
345 case 'I':
346 nextLVIndex = lvIndex + 1;
347
348 // top of stack: array-ref
349 il.insertInstr(new GenericInstruction(Opcode.DUP), mi.getCodeAttributeInfo());
350 res = il.advanceIndex();
351 assert res == true;
352
353 // top of stack: array-ref array-ref
354
355 pi = new IntegerPoolInfo(arrayIndex, cf.getConstantPool());
356 l = cf.addConstantPoolItems(new APoolInfo[]{pi});
357 pi = cf.getConstantPoolItem(l[0]).execute(new ADefaultPoolInfoVisitor<IntegerPoolInfo, Object>() {
358 public IntegerPoolInfo defaultCase(APoolInfo host, Object o) {
359 throw new ClassFormatError("Info is of type " + host.getClass().getName() + ", needs to be IntegerPoolInfo");
360 }
361 public IntegerPoolInfo intCase(IntegerPoolInfo host, Object o) {
362 return host;
363 }
364 }, null);
365 ldc_w = new ReferenceInstruction(Opcode.LDC_W, cf.getConstantPool().indexOf(pi));
366 il.insertInstr(ldc_w, mi.getCodeAttributeInfo());
367 res = il.advanceIndex();
368 assert res == true;
369
370 // top of stack: array-ref array-ref index
371
372 insertCtorCall(cf, mi, il, "java/lang/Integer", "(I)V",
373 Opcode.getShortestLoadStoreInstruction(Opcode.ILOAD, (short)lvIndex));
374
375 // top of stack: array-ref array-ref index Integer-ref
376 break;
377 case 'S':
378 nextLVIndex = lvIndex + 1;
379
380 // top of stack: array-ref
381 il.insertInstr(new GenericInstruction(Opcode.DUP), mi.getCodeAttributeInfo());
382 res = il.advanceIndex();
383 assert res == true;
384
385 // top of stack: array-ref array-ref
386
387 pi = new IntegerPoolInfo(arrayIndex, cf.getConstantPool());
388 l = cf.addConstantPoolItems(new APoolInfo[]{pi});
389 pi = cf.getConstantPoolItem(l[0]).execute(new ADefaultPoolInfoVisitor<IntegerPoolInfo, Object>() {
390 public IntegerPoolInfo defaultCase(APoolInfo host, Object o) {
391 throw new ClassFormatError("Info is of type " + host.getClass().getName() + ", needs to be IntegerPoolInfo");
392 }
393 public IntegerPoolInfo intCase(IntegerPoolInfo host, Object o) {
394 return host;
395 }
396 }, null);
397 ldc_w = new ReferenceInstruction(Opcode.LDC_W, cf.getConstantPool().indexOf(pi));
398 il.insertInstr(ldc_w, mi.getCodeAttributeInfo());
399 res = il.advanceIndex();
400 assert res == true;
401
402 // top of stack: array-ref array-ref index
403
404 insertCtorCall(cf, mi, il, "java/lang/Short", "(S)V",
405 Opcode.getShortestLoadStoreInstruction(Opcode.ILOAD, (short)lvIndex));
406
407 // top of stack: array-ref array-ref index Short-ref
408 break;
409 case 'Z':
410 nextLVIndex = lvIndex + 1;
411
412 // top of stack: array-ref
413 il.insertInstr(new GenericInstruction(Opcode.DUP), mi.getCodeAttributeInfo());
414 res = il.advanceIndex();
415 assert res == true;
416
417 // top of stack: array-ref array-ref
418
419 pi = new IntegerPoolInfo(arrayIndex, cf.getConstantPool());
420 l = cf.addConstantPoolItems(new APoolInfo[]{pi});
421 pi = cf.getConstantPoolItem(l[0]).execute(new ADefaultPoolInfoVisitor<IntegerPoolInfo, Object>() {
422 public IntegerPoolInfo defaultCase(APoolInfo host, Object o) {
423 throw new ClassFormatError("Info is of type " + host.getClass().getName() + ", needs to be IntegerPoolInfo");
424 }
425 public IntegerPoolInfo intCase(IntegerPoolInfo host, Object o) {
426 return host;
427 }
428 }, null);
429 ldc_w = new ReferenceInstruction(Opcode.LDC_W, cf.getConstantPool().indexOf(pi));
430 il.insertInstr(ldc_w, mi.getCodeAttributeInfo());
431 res = il.advanceIndex();
432 assert res == true;
433
434 // top of stack: array-ref array-ref index
435
436 insertCtorCall(cf, mi, il, "java/lang/Boolean", "(Z)V",
437 Opcode.getShortestLoadStoreInstruction(Opcode.ILOAD, (short)lvIndex));
438
439 // top of stack: array-ref array-ref index Boolean-ref
440 break;
441 case 'F':
442 nextLVIndex = lvIndex + 1;
443
444 // top of stack: array-ref
445 il.insertInstr(new GenericInstruction(Opcode.DUP), mi.getCodeAttributeInfo());
446 res = il.advanceIndex();
447 assert res == true;
448
449 // top of stack: array-ref array-ref
450
451 pi = new IntegerPoolInfo(arrayIndex, cf.getConstantPool());
452 l = cf.addConstantPoolItems(new APoolInfo[]{pi});
453 pi = cf.getConstantPoolItem(l[0]).execute(new ADefaultPoolInfoVisitor<IntegerPoolInfo, Object>() {
454 public IntegerPoolInfo defaultCase(APoolInfo host, Object o) {
455 throw new ClassFormatError("Info is of type " + host.getClass().getName() + ", needs to be IntegerPoolInfo");
456 }
457 public IntegerPoolInfo intCase(IntegerPoolInfo host, Object o) {
458 return host;
459 }
460 }, null);
461 ldc_w = new ReferenceInstruction(Opcode.LDC_W, cf.getConstantPool().indexOf(pi));
462 il.insertInstr(ldc_w, mi.getCodeAttributeInfo());
463 res = il.advanceIndex();
464 assert res == true;
465
466 // top of stack: array-ref array-ref index
467
468 insertCtorCall(cf, mi, il, "java/lang/Float", "(F)V",
469 Opcode.getShortestLoadStoreInstruction(Opcode.FLOAD, (short)lvIndex));
470
471 // top of stack: array-ref array-ref index Float-ref
472 break;
473 case 'J':
474 nextLVIndex = lvIndex + 2;
475
476 // top of stack: array-ref
477 il.insertInstr(new GenericInstruction(Opcode.DUP), mi.getCodeAttributeInfo());
478 res = il.advanceIndex();
479 assert res == true;
480
481 // top of stack: array-ref array-ref
482
483 pi = new IntegerPoolInfo(arrayIndex, cf.getConstantPool());
484 l = cf.addConstantPoolItems(new APoolInfo[]{pi});
485 pi = cf.getConstantPoolItem(l[0]).execute(new ADefaultPoolInfoVisitor<IntegerPoolInfo, Object>() {
486 public IntegerPoolInfo defaultCase(APoolInfo host, Object o) {
487 throw new ClassFormatError("Info is of type " + host.getClass().getName() + ", needs to be IntegerPoolInfo");
488 }
489 public IntegerPoolInfo intCase(IntegerPoolInfo host, Object o) {
490 return host;
491 }
492 }, null);
493 ldc_w = new ReferenceInstruction(Opcode.LDC_W, cf.getConstantPool().indexOf(pi));
494 il.insertInstr(ldc_w, mi.getCodeAttributeInfo());
495 res = il.advanceIndex();
496 assert res == true;
497
498 // top of stack: array-ref array-ref index
499
500 insertCtorCall(cf, mi, il, "java/lang/Long", "(L)V",
501 Opcode.getShortestLoadStoreInstruction(Opcode.LLOAD, (short)lvIndex));
502
503 // top of stack: array-ref array-ref index Long-ref
504 break;
505 case 'D':
506 nextLVIndex = lvIndex + 2;
507
508 // top of stack: array-ref
509 il.insertInstr(new GenericInstruction(Opcode.DUP), mi.getCodeAttributeInfo());
510 res = il.advanceIndex();
511 assert res == true;
512
513 // top of stack: array-ref array-ref
514
515 pi = new IntegerPoolInfo(arrayIndex, cf.getConstantPool());
516 l = cf.addConstantPoolItems(new APoolInfo[]{pi});
517 pi = cf.getConstantPoolItem(l[0]).execute(new ADefaultPoolInfoVisitor<IntegerPoolInfo, Object>() {
518 public IntegerPoolInfo defaultCase(APoolInfo host, Object o) {
519 throw new ClassFormatError("Info is of type " + host.getClass().getName() + ", needs to be IntegerPoolInfo");
520 }
521 public IntegerPoolInfo intCase(IntegerPoolInfo host, Object o) {
522 return host;
523 }
524 }, null);
525 ldc_w = new ReferenceInstruction(Opcode.LDC_W, cf.getConstantPool().indexOf(pi));
526 il.insertInstr(ldc_w, mi.getCodeAttributeInfo());
527 res = il.advanceIndex();
528 assert res == true;
529
530 // top of stack: array-ref array-ref index
531
532 insertCtorCall(cf, mi, il, "java/lang/Double", "(D)V",
533 Opcode.getShortestLoadStoreInstruction(Opcode.DLOAD, (short)lvIndex));
534
535 // top of stack: array-ref array-ref index Double-ref
536 break;
537 case 'V':
538 throw new ThreadCheckException("One of the method parameters had type void (processing "+
539 cf.getThisClassName()+", "+mi.getName().toString()+
540 mi.getDescriptor().toString()+")");
541 default:
542 throw new ThreadCheckException("One of the method parameters had an unknown type '"+type.charAt(0)+"' (processing "+
543 cf.getThisClassName()+", "+mi.getName().toString()+
544 mi.getDescriptor().toString()+")");
545 }
546
547 // top of stack: array-ref array-ref index value
548
549 il.insertInstr(new GenericInstruction(Opcode.AASTORE), mi.getCodeAttributeInfo());
550 res = il.advanceIndex();
551 assert res == true;
552
553 // top of stack: array-ref
554 ++arrayIndex;
555 lvIndex = nextLVIndex;
556 }
557
558 // on stack: {array-ref}
559 }
560 else {
561 // no arguments
562 il.insertInstr(new GenericInstruction(new byte[] { Opcode.ACONST_NULL }), mi.getCodeAttributeInfo());
563 res = il.advanceIndex();
564 assert res == true;
565 }
566
567 il.insertInstr(checkCallInstr, mi.getCodeAttributeInfo());
568 res = il.advanceIndex();
569 assert res == true;
570 }
571 }
572
573 if (changed) {
574 // write code back
575 mi.getCodeAttributeInfo().setCode(il.getCode());
576
577 // make sure we have at least five slots on the stack
578 CodeAttributeInfo.CodeProperties cProps = mi.getCodeAttributeInfo().getProperties();
579 cProps.maxStack = Math.max(11, cProps.maxStack);
580 mi.getCodeAttributeInfo().setProperties(cProps.maxStack, cProps.maxLocals);
581 }
582 }
583 }
584 }
585 }
586 }