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 }