1 19 20 package org.objectweb.jac.core.translators; 21 22 import java.lang.reflect.Modifier ; 23 import java.util.Arrays ; 24 import java.util.Collection ; 25 import java.util.HashMap ; 26 import java.util.Iterator ; 27 import java.util.LinkedList ; 28 import java.util.List ; 29 import java.util.Map ; 30 import java.util.Vector ; 31 import org.apache.bcel.Constants; 32 import org.apache.bcel.Repository; 33 import org.apache.bcel.classfile.*; 34 import org.apache.bcel.generic.*; 35 import org.apache.bcel.generic.BranchInstruction; 36 import org.apache.log4j.Logger; 37 import org.objectweb.jac.core.JacLoader; 38 import org.objectweb.jac.core.JacPropLoader; 39 import org.objectweb.jac.core.WrappeeTranslator; 40 import org.objectweb.jac.core.rtti.InvokeInfo; 41 import org.objectweb.jac.core.rtti.LoadtimeRTTI; 42 import org.objectweb.jac.util.ExtArrays; 43 import org.objectweb.jac.util.Stack; 44 45 public class WrappeeTranslator_BCEL implements WrappeeTranslator { 46 static Logger logger = Logger.getLogger("translator"); 47 static Logger loggerRtti = Logger.getLogger("rtti.detect"); 48 static Logger loggerBytecode = Logger.getLogger("translator.bytecode"); 49 50 LoadtimeRTTI rtti; 51 52 54 55 public WrappeeTranslator_BCEL(LoadtimeRTTI rtti) { 56 this.rtti = rtti; 57 } 58 59 private static final String nextWrapper_signature = 60 "(Lorg/objectweb/jac/core/Interaction;)Ljava/lang/Object;"; 61 62 private static final String newInteraction_signature = 63 "(Lorg/objectweb/jac/core/WrappingChain;Lorg/objectweb/jac/core/Wrappee;"+ 64 "Lorg/objectweb/jac/core/rtti/AbstractMethodItem;"+ 65 "[Ljava/lang/Object;)V"; 66 67 private static final String getWrappingChain_signature = 68 "(Lorg/objectweb/jac/core/Wrappee;Lorg/objectweb/jac/core/rtti/AbstractMethodItem;)Lorg/objectweb/jac/core/WrappingChain;"; 69 70 private String primitiveTypeName(Type t) 71 { 72 if (t==Type.BOOLEAN) 73 return "boolean"; 74 if (t==Type.BYTE) 75 return "byte"; 76 if (t==Type.INT) 77 return "int"; 78 if (t==Type.LONG) 79 return "long"; 80 if (t==Type.SHORT) 81 return "short"; 82 if (t==Type.FLOAT) 83 return "float"; 84 if (t==Type.CHAR) 85 return "char"; 86 if (t==Type.DOUBLE) 87 return "double"; 88 return null; 89 } 90 91 private String primitiveTypeAsObject(Type t) 92 { 93 if (t==Type.BOOLEAN) 94 return "java.lang.Boolean"; 95 if (t==Type.BYTE) 96 return "java.lang.Byte"; 97 if (t==Type.INT) 98 return "java.lang.Integer"; 99 if (t==Type.LONG) 100 return "java.lang.Long"; 101 if (t==Type.SHORT) 102 return "java.lang.Short"; 103 if (t==Type.FLOAT) 104 return "java.lang.Float"; 105 if (t==Type.CHAR) 106 return "java.lang.Character"; 107 if (t==Type.DOUBLE) 108 return "java.lang.Double"; 109 return null; 110 } 111 112 private void generateStubMethod(ClassGen classGen, 113 ConstantPoolGen constPool, 114 Method method, String gSNewName, 115 int staticFieldIndex, 116 List staticFieldIndexes, 117 int wrappingChainIndex, 118 List wrappingChainIndexes, 119 InstructionList callSuper) 120 { 121 logger.debug("Generating stub method "+ 122 method.getName()+method.getSignature()); 123 InstructionList il = new InstructionList(); 124 InstructionFactory ifactory = new InstructionFactory(classGen); 125 127 Type[] argumentTypes = Type.getArgumentTypes(method.getSignature()); 128 Type returnType = Type.getReturnType(method.getSignature()); 129 MethodGen stubMethod = 130 new MethodGen( 131 method.getAccessFlags(), 132 returnType,argumentTypes, 133 null, 134 method.getName(),classGen.getClassName(), 135 il,constPool); 136 int lineNumber = 0; 137 if (stubMethod.getName().equals("<init>")) { 139 logger.debug("Generating stub method "+ 140 classGen.getClassName()+"."+ 141 method.getName()+method.getSignature()); 142 if (callSuper!=null) { 143 logger.debug(" insert call to super"); 144 il.append(callSuper); 145 } else { 146 logger.debug(" insert super()"); 147 il.append(new ALOAD(0)); 148 il.append( 149 ifactory.createInvoke(classGen.getSuperclassName(), "<init>", 150 Type.VOID, 151 emptyTypeArray, 152 Constants.INVOKESPECIAL)); 153 } 154 for(int i=0;i<wrappingChainIndexes.size();i++) { 156 if(wrappingChainIndexes.get(i)==null) continue; 157 il.append(InstructionFactory.createThis()); 158 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 159 il.append(InstructionFactory.createThis()); 160 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 161 il.append(new GETSTATIC( 162 ((Integer )staticFieldIndexes.get(i)).intValue())); 163 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 164 il.append(ifactory.createInvoke( 165 "org.objectweb.jac.core.Wrapping", "getWrappingChain", 166 Type.getReturnType(getWrappingChain_signature), 167 Type.getArgumentTypes(getWrappingChain_signature), 168 Constants.INVOKESTATIC)); 169 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 170 WCIndex chainIndex = (WCIndex)wrappingChainIndexes.get(i); 171 if (chainIndex.isStatic) { 172 il.append(new PUTSTATIC(chainIndex.index)); 173 } else { 174 il.append(new PUTFIELD(chainIndex.index)); 175 } 176 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 177 } 178 } 179 180 stubMethod.removeExceptionHandlers(); 184 185 il.append(ifactory.createNew("org.objectweb.jac.core.Interaction")); 187 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 188 il.append(new DUP()); 189 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 190 191 if (method.isStatic()) { 193 il.append(new GETSTATIC(wrappingChainIndex)); 194 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 195 } else { 196 il.append(InstructionFactory.createThis()); 197 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 198 il.append(new GETFIELD(wrappingChainIndex)); 199 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 200 } 201 202 if( !stubMethod.isStatic() ) { 204 il.append(InstructionFactory.createThis()); 205 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 206 } else { 207 il.append(new ACONST_NULL()); 208 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 209 } 210 211 il.append(new GETSTATIC(staticFieldIndex)); 213 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 214 215 if (argumentTypes.length==0) { 218 il.append( 219 ifactory.createGetStatic( 220 "org.objectweb.jac.core.Wrapping", 221 "emptyArray", 222 Type.getType("[Ljava.lang.Object;"))); 223 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 224 } else { 225 il.append(new PUSH(constPool, argumentTypes.length)); 226 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 227 il.append((Instruction)ifactory.createNewArray(Type.OBJECT,(short)1)); 229 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 230 int j = (stubMethod.isStatic())?0:1; for (int i=0; i<argumentTypes.length; i++) 232 { 233 il.append(InstructionFactory.createDup(1)); 235 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 236 il.append(new PUSH(constPool, i)); 238 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 239 if (!Utils.isPrimitive(argumentTypes[i])) { 241 il.append(InstructionFactory.createLoad(Type.OBJECT,j)); 243 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 244 il.append(InstructionFactory.createArrayStore(Type.OBJECT)); 246 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 247 j++; 249 } else { 250 String objectType = primitiveTypeAsObject(argumentTypes[i]); 252 il.append (ifactory.createNew(objectType)); 253 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 254 il.append(InstructionFactory.createDup(1)); 256 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 257 il.append(InstructionFactory.createLoad(argumentTypes[i],j)); 258 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 259 il.append(ifactory.createInvoke(objectType, "<init>", Type.VOID, 260 new Type[] {argumentTypes[i]}, 261 Constants.INVOKESPECIAL)); 262 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 263 il.append(InstructionFactory.createArrayStore(Type.OBJECT)); 265 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 266 j++; 267 if (argumentTypes[i]==Type.LONG || 268 argumentTypes[i]==Type.DOUBLE) 269 j++; 271 } 272 273 } 274 } 275 276 il.append( 278 ifactory.createInvoke( 279 "org.objectweb.jac.core.Interaction", "<init>", 280 Type.getReturnType(newInteraction_signature), 281 Type.getArgumentTypes(newInteraction_signature), 282 Constants.INVOKESPECIAL)); 283 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 284 285 if (method.isStatic()||method.getName().equals("<init>")) { 287 il.append( 288 ifactory.createInvoke( 289 "org.objectweb.jac.core.Wrapping", "nextWrapper", 290 Type.getReturnType(nextWrapper_signature), 291 Type.getArgumentTypes(nextWrapper_signature), 292 Constants.INVOKESTATIC)); 293 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 294 } else { 295 il.append( 296 ifactory.createInvoke( 297 "org.objectweb.jac.core.Wrapping", "methodNextWrapper", 298 Type.getReturnType(nextWrapper_signature), 299 Type.getArgumentTypes(nextWrapper_signature), 300 Constants.INVOKESTATIC)); 301 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 302 } 303 304 if (Utils.isPrimitive(returnType)) 306 { 307 311 il.append( 312 ifactory.createCheckCast( 313 (ReferenceType)Type.getReturnType( 314 "()L"+primitiveTypeAsObject(returnType).replace('.','/')+";"))); 315 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 316 317 il.append( 319 ifactory.createInvoke( 320 primitiveTypeAsObject(returnType), 321 primitiveTypeName(returnType)+"Value", 322 stubMethod.getReturnType(), emptyTypeArray, 323 Constants.INVOKEVIRTUAL)); 324 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 325 } 326 else 329 if (stubMethod.getReturnType()!=Type.VOID) { 330 il.append ( 331 ifactory.createCheckCast((ReferenceType)returnType)); 332 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 333 } 334 il.append (InstructionFactory.createReturn(returnType)); 336 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 337 stubMethod.setMaxLocals(); 339 stubMethod.setMaxStack(); 340 classGen.addMethod(stubMethod.getMethod()); 342 } 343 344 351 private void generateDefaultConstructor(ClassGen classGen) 352 { 353 logger.debug("class "+classGen.getClassName()+ 354 " ==> Generating default constructor"); 355 ConstantPoolGen constPool = classGen.getConstantPool(); 356 InstructionList instructions = new InstructionList(); 357 InstructionFactory ifactory = new InstructionFactory(classGen); 358 359 instructions.append(new ALOAD(0)); 360 instructions.append(ifactory.createInvoke(classGen.getSuperclassName(), 361 "<init>", 362 Type.VOID, 363 emptyTypeArray, 364 Constants.INVOKESPECIAL)); 365 366 instructions.append(new RETURN()); 367 368 MethodGen constructor = new MethodGen(Modifier.PUBLIC, 369 Type.VOID, 370 new Type[] {}, new String [] {}, 371 "<init>", classGen.getClassName(), 372 instructions, constPool); 373 374 constructor.setMaxLocals(); 375 constructor.setMaxStack(); 376 classGen.addMethod(constructor.getMethod()); 377 } 378 379 390 private void translateConstructor(ClassGen classGen, 391 Method origConstructor, 392 MethodGen constructor, 393 InstructionList callSuper, 394 boolean removeSuperCall) { 395 logger.debug("constructor translation of "+ 396 constructor.getName()+constructor.getSignature()); 397 InstructionList instructions = constructor.getInstructionList(); 398 ConstantPoolGen constPool = classGen.getConstantPool(); 399 InstructionFactory ifactory = new InstructionFactory(classGen); 400 instructions.setPositions(); 401 int i=0; 402 boolean superRemoved = false; 405 VMStack stack = new VMStack(constPool,origConstructor.getCode(), 406 constructor.getArgumentTypes().length,false); 407 InstructionHandle first = null; 408 Iterator it = instructions.iterator(); 409 while(it.hasNext()) { 410 InstructionHandle ih = (InstructionHandle)it.next(); 411 InstructionHandle next = ih.getNext(); 412 if (first==null) 413 first = ih; 414 Instruction instruction = ih.getInstruction(); 415 stack.preExecute(ih); 416 if (!superRemoved && !constructor.getName().equals("this")) { 417 if (callSuper!=null) { 418 if (instruction instanceof BranchInstruction) { 419 callSuper.append((BranchInstruction)instruction); 420 } else { 421 callSuper.append(instruction); 422 } 423 } 424 if (instruction instanceof INVOKESPECIAL && 426 stack.getSubstance((INVOKESPECIAL)instruction)==VMStack.thisPointer) 427 { 428 superRemoved = true; 429 INVOKESPECIAL invoke = (INVOKESPECIAL)instruction; 430 if (removeSuperCall) { 431 if (!invoke.getClassName(constPool).equals(classGen.getClassName())) 432 { 433 try { 434 logger.debug("deleting call to super, callSuper = \n"+callSuper); 435 instructions.delete(first,ih); 436 } catch (TargetLostException e) { 437 logger.debug("TargetLostException..., callSuper = \n"+callSuper); 438 InstructionHandle[] targets = e.getTargets(); 439 for(int j=0; j<targets.length; j++) { 440 InstructionTargeter[] targeters = 441 targets[j].getTargeters(); 442 for(int k=0; k<targeters.length; k++) 443 targeters[k].updateTarget(targets[j], next); 444 } 445 } 446 } else { 447 ih.setInstruction( 454 ifactory.createInvoke( 455 classGen.getClassName(), 456 prefix+classGen.getClassName() 457 .substring(classGen.getClassName().lastIndexOf(".")+1), 458 Type.VOID, 459 invoke.getArgumentTypes(constPool), 460 Constants.INVOKEVIRTUAL 461 ) 462 ); 463 } 465 } 466 } 467 stack.execute(instruction,ih); 468 } else if (JacPropLoader.translateFields(constructor.getClassName())) { 469 470 473 if (instruction instanceof PUTFIELD && 474 stack.peek(1) == VMStack.thisPointer && 475 stack.peek() instanceof VMStack.Instance && 476 isCollection(((VMStack.Instance)stack.peek()).type) ) { 477 PUTFIELD putfield = (PUTFIELD)instruction; 479 if (!classGen.containsField(putfield.getFieldName(constPool)).isTransient()) { 480 VMStack.Instance collection = (VMStack.Instance)stack.peek(); 481 486 collection.newHandle.setInstruction( 487 ifactory.createNew("org.objectweb.jac.lib."+collection.type)); 488 collection.initHandle.setInstruction( 489 ifactory.createInvoke( 490 "org.objectweb.jac.lib."+collection.type, 491 "<init>", 492 Type.VOID, 493 ((INVOKESPECIAL)collection.initHandle.getInstruction()).getArgumentTypes(constPool), 494 Constants.INVOKESPECIAL)); 495 logger.debug("Found collection field initialization: "+ 496 putfield.getFieldName(constPool)); 497 } 498 } else if (instruction instanceof INVOKESPECIAL) { 499 INVOKESPECIAL invoke = (INVOKESPECIAL)instruction; 500 Object substance = 501 stack.peek(VMStack.getConsumed(invoke,constPool)-1); 502 if (substance instanceof VMStack.Instance) { 503 logger.debug("Found collection <init> for "+substance); 504 ((VMStack.Instance)substance).initHandle = ih; 505 } 506 } 507 stack.execute(instruction,ih); 508 } 509 i++; 510 } 511 logger.debug("callSuper = \n"+callSuper); 512 instructions.setPositions(); 513 constructor.setInstructionList(instructions); 514 constructor.removeLineNumbers(); 515 } 516 517 531 private String renameMethod(ClassGen classGen, ConstantPoolGen constPool, 532 Method method, String newProposedName, 533 InstructionList callSuper) 534 { 535 logger.debug("Rename "+method.getName()+" -> "+newProposedName); 536 if (method.getName().equals("<init>")) { 538 MethodGen newNamedMethod = 539 new MethodGen(method, classGen.getClassName(), constPool); 540 newNamedMethod.setName(newProposedName); 541 translateConstructor(classGen,method,newNamedMethod,callSuper,true); 542 newNamedMethod.removeLocalVariables(); 544 classGen.replaceMethod(method, newNamedMethod.getMethod()); 548 } else { 549 Method newMethod = new Method(method); 550 newMethod.setNameIndex(constPool.addUtf8(newProposedName)); 551 classGen.replaceMethod(method,newMethod); 552 } 553 return newProposedName; 554 } 555 556 564 Method fillRTTI(ClassGen classGen, ConstantPoolGen constPool, Method method, 565 boolean passive) 566 { 567 String className = classGen.getClassName(); 568 String methodName = method.getName(); 569 MethodGen methodGen = new MethodGen(method,className,constPool); 570 Iterator instructions = methodGen.getInstructionList().iterator(); 571 String methodSign = null; 572 if (methodName.startsWith(prefix)) { 573 methodName = methodName.substring(prefix.length()); 574 } 575 methodSign = className+"."+getMethodFullName(method); 576 VMStack stack = new VMStack(constPool,method.getCode(), 577 methodGen.getArgumentTypes().length,method.isStatic()); 578 loggerRtti.debug("detecting RTTI for "+methodSign); 579 while (instructions.hasNext()) { 580 InstructionHandle ih=(InstructionHandle)instructions.next(); 581 Instruction instruction = ih.getInstruction(); 582 loggerBytecode.debug("offset: "+ih.getPosition()); 583 stack.preExecute(ih); 584 585 if (instruction instanceof PUTFIELD && 586 stack.peek(1)==VMStack.thisPointer) { 587 PUTFIELD putfield = (PUTFIELD)instruction; 589 String fieldName = putfield.getFieldName(constPool); 590 if (!isSystemField(fieldName)) { 591 if (stack.peek() instanceof VMStack.Argument) { 592 loggerRtti.debug(" sets field "+fieldName); 593 rtti.addltSetField(className,methodSign,fieldName); 594 } 596 loggerRtti.debug(" modifies field "+fieldName); 597 rtti.addltModifiedField(className,methodSign,fieldName); 598 } 599 } else if (instruction instanceof PUTSTATIC && 600 ((PUTSTATIC)instruction).getClassName(constPool).equals(classGen.getClassName())) { 601 PUTSTATIC putfield = (PUTSTATIC)instruction; 603 String fieldName = putfield.getFieldName(constPool); 604 if (!isSystemField(fieldName)) { 605 if (stack.peek() instanceof VMStack.Argument) { 606 loggerRtti.debug(methodSign+" sets static field "+fieldName); 607 rtti.addltSetField(className,methodSign,fieldName); 608 } 610 loggerRtti.debug(" modifies static field "+fieldName); 611 rtti.addltModifiedField(className,methodSign,fieldName); 612 } 613 } else if (instruction instanceof ReturnInstruction && 614 !(instruction instanceof RETURN)) { 615 if (stack.peek() instanceof VMStack.FieldValue) { 616 VMStack.FieldValue fieldValue = (VMStack.FieldValue)stack.peek(); 618 if (!isSystemField(fieldValue.field)) { 619 if (fieldValue.substance==VMStack.thisPointer) { 620 loggerRtti.debug(" returns field "+fieldValue.field); 621 rtti.addltReturnedField(className,methodSign,fieldValue.field); 622 } else { 623 loggerRtti.debug(" returns "+stack.peek()); 624 rtti.addltReturnedField(className,methodSign,null); 625 rtti.setltIsGetter(className,methodSign,false); 626 } 627 } 628 } else { 629 loggerRtti.debug(" returns "+stack.peek()); 630 rtti.setltIsGetter(className,methodSign,false); 631 } 632 } else if (instruction instanceof GETFIELD && 633 stack.peek()==VMStack.thisPointer) { 634 String fieldName = ((GETFIELD)instruction).getFieldName(constPool); 636 if (!isSystemField(fieldName)) { 637 loggerRtti.debug(" accesses field "+fieldName); 638 rtti.addltAccessedField(className,methodSign,fieldName); 639 } 640 } else if (instruction instanceof GETSTATIC && 641 ((GETSTATIC)instruction).getClassName(constPool).equals(classGen.getClassName())) { 642 String fieldName = ((GETSTATIC)instruction).getFieldName(constPool); 644 if (!isSystemField(fieldName)) { 645 loggerRtti.debug(" accesses static field "+fieldName); 646 rtti.addltAccessedField(className,methodSign,fieldName); 647 } 648 } else if ((instruction instanceof INVOKEVIRTUAL || 649 instruction instanceof INVOKEINTERFACE) && 650 !className.startsWith("org.objectweb.jac.lib.java")) { 651 InvokeInstruction invoke = (InvokeInstruction)instruction; 653 String invokedClass = invoke.getClassName(constPool); 654 String invokedMethodName = invoke.getMethodName(constPool); 655 int numArgs = invoke.getArgumentTypes(constPool).length; 656 Object substance = stack.invokedObject(invoke); 657 loggerBytecode.info("substance="+substance); 658 if (substance instanceof VMStack.FieldValue) { 659 VMStack.FieldValue fieldValue = (VMStack.FieldValue)substance; 660 loggerBytecode.info("detected INVOKE on field "+substance); 661 ConstantFieldref fieldref = 662 (ConstantFieldref)constPool.getConstant(fieldValue.index); 663 ConstantNameAndType nameAndType = 664 (ConstantNameAndType)constPool.getConstant( 665 fieldref.getNameAndTypeIndex()); 666 String signature = 667 nameAndType.getSignature(constPool.getConstantPool()); 668 String fieldName = 669 nameAndType.getName(constPool.getConstantPool()); 670 loggerBytecode.debug("field signature: "+signature); 671 loggerBytecode.debug("invoked class name: "+invokedClass); 672 if (signature.startsWith("Lorg/objectweb/jac/lib/java") && 673 !invokedClass.startsWith("org.objectweb.jac.lib.java")) { 674 loggerBytecode.info("FIXING INCOMPATIBLE TYPES "+ 675 signature+" AND "+invokedClass+ 676 " for "+nameAndType); 677 loggerBytecode.info(" ==> "+ 678 signature.substring(1,signature.length()-1)); 679 invoke.setIndex( 680 constPool.addMethodref( 681 signature.substring(1,signature.length()-1), 682 invoke.getName(constPool), 683 invoke.getSignature(constPool))); 684 } 685 686 if (fieldValue.substance==VMStack.thisPointer && 688 (invoke.getClassType(constPool).isCastableTo(Type.getType(Collection .class)) || 689 invoke.getClassType(constPool).isCastableTo(Type.getType(Map .class)))) 690 { 691 if (invokedMethodName.equals("add")) { 692 if ((numArgs==1 && areArguments(stack,numArgs)) || 693 (numArgs==2 && isArgument(stack,0))) { 694 loggerRtti.debug(methodSign+" is adder for "+ 695 nameAndType.getName(constPool.getConstantPool())); 696 rtti.addltAddedCollection(className,methodSign,fieldName); 697 } else { 698 loggerRtti.debug(methodSign+" is modifier for "+ 699 nameAndType.getName(constPool.getConstantPool())); 700 rtti.addltModifiedCollection(className,methodSign,fieldName); 701 } 702 if (numArgs==2) { 703 VMStack.Argument arg = getArgument(stack,1); 704 int n; 705 if (arg!=null) { 706 n = arg.n - (method.isStatic() ? 0 : 1); 707 loggerRtti.debug(" has collectionIndexArgument "+n); 708 rtti.setCollectionIndexArgument(className,methodSign,n); 709 } 710 arg = getArgument(stack,0); 711 if (arg!=null) { 712 n = arg.n - (method.isStatic() ? 0 : 1); 713 loggerRtti.debug(" has collectionItemArgument "+n); 714 rtti.setCollectionItemArgument(className,methodSign,n); 715 } 716 } 717 } else if (invokedMethodName.equals("put")) { 718 if (isArgument(stack,0)) { 719 loggerRtti.debug(" is putter for "+ 720 nameAndType.getName(constPool.getConstantPool())); 721 rtti.addltAddedCollection(className,methodSign,fieldName); 722 } else { 723 loggerRtti.debug(" is modifier for "+ 724 nameAndType.getName(constPool.getConstantPool())); 725 rtti.addltModifiedCollection(className,methodSign,fieldName); 726 } 727 } else if (invokedMethodName.equals("remove")) { 728 if (areArguments(stack,numArgs)) { 729 loggerRtti.debug(" is remover for "+ 730 nameAndType.getName(constPool.getConstantPool())); 731 rtti.addltRemovedCollection(className,methodSign,fieldName); 732 } else { 733 loggerRtti.debug(" is modifier for "+ 734 nameAndType.getName(constPool.getConstantPool())); 735 rtti.addltModifiedCollection(className,methodSign,fieldName); 736 } 737 } else if (invokedMethodName.equals("set") || 738 invokedMethodName.equals("clear") || 739 invokedMethodName.equals("addAll") || 740 invokedMethodName.equals("removeAll") || 741 invokedMethodName.equals("retainAll")) { 742 loggerRtti.debug(" is modifier for "+ 743 nameAndType.getName(constPool.getConstantPool())); 744 rtti.addltModifiedCollection(className,methodSign,fieldName); 745 if (numArgs==2 && isArgument(stack,1)) { 746 loggerRtti.debug(" has collectionIndexArgument 0"); 747 rtti.setCollectionIndexArgument(className,methodSign,0); 748 } 749 } 750 } 751 } 752 753 if (JacLoader.classIsToBeAdapted(invokedClass) && 754 !(invokedMethodName.equals(methodName) && 755 invokedClass.equals(className))) 756 rtti.addInvokedMethod(className,methodSign, 757 new InvokeInfo( 758 stack.getSubstance(invoke), 759 invokedClass,invokedMethodName)); 760 } else if (instruction instanceof INVOKESPECIAL) { 761 INVOKESPECIAL invoke = (INVOKESPECIAL)instruction; 762 Object substance = stack.getSubstance(invoke); 763 loggerRtti.debug(" invokespecial "+ 764 invoke.getMethodName(constPool)+" on "+substance); 765 if (substance==VMStack.thisPointer && 766 invoke.getMethodName(constPool).equals(methodName) && 767 Arrays.equals(invoke.getArgumentTypes(constPool),method.getArgumentTypes())) 768 { 769 loggerRtti.debug(" calls super"); 770 rtti.setCallSuper(className,methodSign); 771 } 772 } 773 stack.execute(instruction,ih); 774 } 775 return methodGen.getMethod(); 776 } 777 778 static boolean isSystemField(String fieldName) { 779 return fieldName.indexOf('$')!=-1; 780 } 781 782 788 static boolean areArguments(Stack stack, int n) { 789 for (;n>0; n--) { 790 if (!isArgument(stack,n-1)) 791 return false; 792 } 793 return true; 794 } 795 796 803 static boolean isArgument(Stack stack, int n) { 804 return !( !(stack.peek(n) instanceof VMStack.Argument) && 805 !(stack.peek(n) instanceof VMStack.PrimitiveValue && 806 ((VMStack.PrimitiveValue)stack.peek(n)).wrappedValue 807 instanceof VMStack.Argument) ); 808 } 809 810 static VMStack.Argument getArgument(Stack stack, int n) { 811 Object elt = stack.peek(n); 812 if (elt instanceof VMStack.Argument) { 813 return (VMStack.Argument)elt; 814 } else if (elt instanceof VMStack.PrimitiveValue && 815 ((VMStack.PrimitiveValue)elt).wrappedValue 816 instanceof VMStack.Argument) { 817 return (VMStack.Argument)((VMStack.PrimitiveValue)elt).wrappedValue; 818 } 819 return null; 820 } 821 822 827 private void translateField(ClassGen classGen, Field field) 828 { 829 String type = Type.getType(field.getSignature()).toString(); 830 String translatedType = (String )collectionTypes.get(type); 831 if (translatedType != null) { 832 logger.info("field "+ 833 field.getName()+" "+type+ 834 " -> "+translatedType); 835 ConstantPoolGen constPool = classGen.getConstantPool(); 836 FieldGen newField = new FieldGen(field,constPool); 837 newField.setType(Type.getType(translatedType)); 838 classGen.replaceField(field,newField.getField()); 839 constPool.setConstant( 841 constPool.lookupFieldref(classGen.getClassName(), 842 field.getName(), 843 field.getSignature()), 844 new ConstantFieldref( 845 classGen.getClassNameIndex(), 846 constPool.addNameAndType(field.getName(), 847 translatedType))); 848 } 849 } 850 851 static final String prefix="_org_"; 852 853 865 private void translateMethod(ClassGen classGen, ConstantPoolGen constPool, 866 Method method, int staticFieldIndex, 867 List staticFieldIndexes, 868 int wrappingChainIndex, 869 List wrappingChainIndexes) 870 { 871 logger.debug("Translating method "+ 872 method.getName()+"("+method.getNameIndex()+")"); 873 String tmpname; 875 876 tmpname = method.getName(); 877 String newName = null; 880 InstructionList callSuper; 881 String className = classGen.getClassName() 882 .substring(classGen.getClassName().lastIndexOf(".")+1); 883 if (tmpname.equals("<init>")) { 884 if (!method.isPublic()) { 885 MethodGen copyMethod = 889 new MethodGen(method,classGen.getClassName(),constPool); 890 translateConstructor(classGen,method,copyMethod,null,false); 891 classGen.addMethod(copyMethod.getMethod()); 892 } 893 callSuper = new InstructionList(); 894 newName = renameMethod( 895 classGen, constPool, method, 896 prefix+className, 897 callSuper); 898 logger.debug("callSuper = "+callSuper); 899 callSuper.setPositions(); 900 } else { 901 callSuper = null; 902 classGen.removeMethod(method); 903 if (!classGen.getClassName().startsWith("org.objectweb.jac.lib.java")) { 904 method = fillRTTI(classGen,constPool,method,false); 905 } 906 newName = renameMethod(classGen, constPool, method, 907 prefix+tmpname+ 908 (method.isStatic()?"":"_"+className), 910 callSuper); 911 } 912 if (!tmpname.equals("<init>") || method.isPublic()) { 913 generateStubMethod(classGen,constPool,method,newName, 914 staticFieldIndex,staticFieldIndexes, 915 wrappingChainIndex,wrappingChainIndexes, 916 callSuper); 917 } else { 918 logger.debug("skipping stub method generation for "+method); 919 } 920 } 921 922 927 boolean isTranslatable(String className,Method method) { 928 String methodName = method.getName(); 929 if ((!method.isPublic()) || 930 method.isAbstract() || 931 method.isInterface()) return false; 932 if (method.isStatic() 933 && (methodName.equals("get") || 934 methodName.equals("main") || 935 methodName.equals("<clinit>"))) 936 return false; 937 if ( (methodName.equals("toString") && 938 method.getSignature().startsWith("()")) || 939 (methodName.equals("equals") && 940 method.getSignature().startsWith("(Ljava/lang/Object;)")) || 941 (methodName.equals("hashCode") && 942 method.getSignature().startsWith("()")) ) 943 return false; 944 Map wrappableMethods = JacPropLoader.wrappableMethods; 945 if(!wrappableMethods.containsKey(className)) { 946 logger.debug(className+" has all methods wrappable"); 947 return true; 948 } 949 if (methodName.equals("<init>")) 951 return true; 952 List methods = (List )wrappableMethods.get(className); 953 Iterator it = methods.iterator(); 954 while(it.hasNext()) { 955 String cur = (String )it.next(); 956 if (cur.equals(methodName)) { 957 logger.debug(methodName+" is wrappable"); 958 return true; 959 } 960 } 961 logger.debug(methodName+" is not wrappable"); 962 963 return false; 964 } 965 966 971 int createMethodStaticField(ClassGen classGen, ConstantPoolGen cp, 972 String fieldName) { 973 FieldGen fieldGen = 974 new FieldGen(Constants.ACC_STATIC | 975 Constants.ACC_PUBLIC | 976 Constants.ACC_TRANSIENT | 977 Constants.ACC_FINAL, 978 Type.getType("Lorg/objectweb/jac/core/rtti/AbstractMethodItem;"), 979 fieldName, 980 cp); 981 Field field = fieldGen.getField(); 982 classGen.addField(field); 984 return cp.addFieldref(classGen.getClassName(), 985 field.getName(), 986 field.getSignature()); 987 } 988 989 int createWrappingChainField(ClassGen classGen, 990 ConstantPoolGen constPool, 991 String fieldName, 992 boolean isStatic) { 993 FieldGen fieldGen=new FieldGen(Constants.ACC_PUBLIC | 994 Constants.ACC_TRANSIENT | 995 Constants.ACC_FINAL | 996 (isStatic?Constants.ACC_STATIC:0), 997 Type.getType("Lorg.objectweb.jac.core.WrappingChain;"), 998 fieldName, 999 constPool); 1000 Field field = fieldGen.getField(); 1001 classGen.addField(field); 1002 return constPool.addFieldref( 1003 classGen.getClassName(), 1004 field.getName(),field.getSignature()); 1005 } 1006 1007 1014 private void startingTranslation(ClassGen classGen) 1015 { 1016 1017 ConstantPoolGen constPool = classGen.getConstantPool(); 1018 int objectIndexRef = constPool.lookupClass("java.lang.Object"); 1019 1020 FieldGen fgJT = new FieldGen ( 1022 Constants.ACC_STATIC | 1023 Constants.ACC_PUBLIC | 1024 (classGen.isInterface() ? Constants.ACC_FINAL : Constants.ACC_TRANSIENT), 1025 Type.BOOLEAN, 1026 "__JAC_TRANSLATED", 1027 constPool); 1028 classGen.addField (fgJT.getField()); 1029 1030 classGen.addInterface("org.objectweb.jac.core.Wrappee"); 1031 1032 if (!classGen.isInterface() && 1033 classGen.containsMethod("<init>","()V")==null) { 1034 generateDefaultConstructor(classGen); 1035 } 1036 } 1037 1038 1042 protected boolean isTranslated(JavaClass javaClass) { 1043 Field[] fields = javaClass.getFields(); 1044 for (int i=0; (i<fields.length); i++) 1045 if (fields[i].getName().equals("__JAC_TRANSLATED")) 1046 return true; 1047 return false; 1048 } 1049 1050 1055 String getMethodFullName(Method method) { 1056 String fullName=method.getName()+"("; 1057 Type[] argumentTypes = Type.getArgumentTypes(method.getSignature()); 1058 for(int i=0;i<argumentTypes.length;i++) { 1059 fullName+=argumentTypes[i]; 1060 if (i<argumentTypes.length-1) 1061 fullName+=","; 1062 } 1063 fullName+=")"; 1064 return fullName; 1065 } 1066 1067 1076 void initStaticFields(ClassGen classGen, List fields, Method clinit) { 1077 Method[] methods = classGen.getMethods(); 1079 ConstantPoolGen constPool = classGen.getConstantPool(); 1080 MethodGen methodGen; 1081 InstructionFactory ifactory = new InstructionFactory (classGen); 1082 logger.info("initStaticFields for "+ 1083 classGen.getClassName()); 1084 if (clinit==null) 1087 { 1088 methodGen = new MethodGen (Constants.ACC_STATIC, 1089 Type.VOID, emptyTypeArray, 1090 ExtArrays.emptyStringArray, 1091 Constants.STATIC_INITIALIZER_NAME, 1092 classGen.getClassName(), 1093 new InstructionList(), 1094 constPool); 1095 } else { 1096 if (!clinit.getName().equals(Constants.STATIC_INITIALIZER_NAME)) { 1098 logger.error("This is not a class initializer: "+clinit.getName()); 1099 } 1100 methodGen = new MethodGen (clinit, 1101 classGen.getClassName(), 1102 constPool); 1103 } 1104 InstructionList il = new InstructionList(); 1105 1106 il.append( 1108 ifactory.createInvoke("org.objectweb.jac.core.rtti.ClassRepository","get", 1109 Type.getType("Lorg/objectweb/jac/core/rtti/ClassRepository;"), 1110 emptyTypeArray, 1111 Constants.INVOKESTATIC)); 1112 1113 int classNameIndex = constPool.addString(classGen.getClassName()); 1115 il.append(new LDC(classNameIndex)); 1116 il.append( 1117 ifactory.createInvoke("org.objectweb.jac.core.rtti.ClassRepository","getClass", 1118 Type.getType("Lorg/objectweb/jac/core/rtti/ClassItem;"), 1119 new Type[] {Type.STRING}, 1120 Constants.INVOKEVIRTUAL)); 1121 1122 Iterator it = fields.iterator(); 1125 while (it.hasNext()) { 1126 StaticField field = (StaticField)it.next(); 1127 logger.info("initStaticField("+ 1128 field.fieldName+","+field.methodName+")"); 1129 1130 il.append(new DUP()); 1131 il.append(new LDC(constPool.addString(field.methodName))); 1132 il.append( 1133 ifactory.createInvoke( 1134 "org.objectweb.jac.core.rtti.ClassItem","getAbstractMethod", 1135 Type.getType("Lorg/objectweb/jac/core/rtti/AbstractMethodItem;"), 1136 new Type[] {Type.STRING}, 1137 Constants.INVOKEVIRTUAL)); 1138 il.append(new PUTSTATIC(field.fieldIndex)); 1139 } 1140 il.append(new POP()); 1141 il.append (methodGen.getInstructionList()); 1142 if (clinit==null) { 1143 il.append (InstructionFactory.createReturn(Type.VOID)); 1144 } 1145 1146 methodGen.setInstructionList(il); 1147 methodGen.removeNOPs(); 1148 methodGen.removeLocalVariables(); 1149 methodGen.setMaxLocals(); 1150 methodGen.setMaxStack(); 1151 1152 if (clinit!=null) 1153 classGen.removeMethod(clinit); 1154 classGen.addMethod (methodGen.getMethod()); 1155 1156 } 1157 1158 static class StaticField { 1159 public String fieldName; 1160 public String methodName; 1161 public int fieldIndex; 1162 public StaticField(String fieldName, String methodName, int fieldIndex) { 1163 this.fieldName = fieldName; 1164 this.methodName = methodName; 1165 this.fieldIndex = fieldIndex; 1166 } 1167 } 1168 1169 1174 public byte[] translateClass(String aClass) throws Exception 1175 { 1176 JavaClass originalClass = Repository.lookupClass(aClass); 1177 if (originalClass==null) { 1178 logger.info("CLASS NOT FOUND "+aClass); 1179 throw new ClassNotFoundException ("Class not found: "+aClass); 1180 } 1181 1182 1189 if (!isTranslated(originalClass)) 1191 { 1192 1193 1194 logger.info("TRANSLATING "+aClass); 1195 1196 ClassGen newClassGen = new ClassGen (originalClass); 1198 startingTranslation(newClassGen); 1199 1200 if (originalClass.isInterface()) { 1202 logger.info("skipping interface "+aClass); 1203 return newClassGen.getJavaClass().getBytes(); 1204 } 1205 1206 Method clinit = newClassGen.containsMethod("<clinit>","()V"); 1207 if (clinit!=null) 1208 logger.debug("clinit = "+clinit+"("+clinit.getNameIndex()+")"); 1209 else 1210 logger.debug("no <clinit>"); 1211 1212 Field[] fields = newClassGen.getFields(); 1215 if (JacPropLoader.translateFields(newClassGen.getClassName())) { 1216 for (int i=0; i<fields.length; i++) { 1217 if (!fields[i].isTransient() && !fields[i].isStatic()) 1218 translateField(newClassGen, fields[i]); 1219 } 1220 } 1221 1222 ConstantPoolGen constPool = newClassGen.getConstantPool(); 1223 1224 Method[] methods = newClassGen.getMethods(); 1226 LinkedList staticFields = new LinkedList (); 1227 List staticFieldIndexes = new Vector (); 1228 List wrappingChainIndexes = new Vector (); 1229 1230 for (int i=0; i<methods.length; i++) { 1232 if (isTranslatable(newClassGen.getClassName(),methods[i])) { 1233 staticFieldIndexes.add(new Integer ( 1236 createMethodStaticField(newClassGen,constPool, 1237 "__JAC_method_"+i))); 1238 wrappingChainIndexes.add(new WCIndex( 1239 methods[i].isStatic(), 1240 createWrappingChainField(newClassGen, 1241 constPool,"__JAC_wc_"+i, 1242 methods[i].isStatic()))); 1243 } else { 1244 staticFieldIndexes.add(null); 1245 wrappingChainIndexes.add(null); 1246 } 1247 } 1248 1249 for (int i=0; i<methods.length; i++) { 1250 if (isTranslatable(newClassGen.getClassName(),methods[i])) { 1251 1252 try { 1253 translateMethod( 1254 newClassGen,constPool, 1255 methods[i], 1256 ((Integer )staticFieldIndexes.get(i)).intValue(), 1257 staticFieldIndexes, 1258 ((WCIndex)wrappingChainIndexes.get(i)).index, 1259 wrappingChainIndexes); 1260 1261 staticFields.add(new StaticField( 1262 "__JAC_method_"+i, 1263 getMethodFullName(methods[i]), 1264 ((Integer )staticFieldIndexes.get(i)).intValue())); 1265 } catch(Exception e) { 1266 logger.error("translateClass: failed to translate method "+ 1267 newClassGen.getClassName()+"."+methods[i]+": "+e); 1268 throw e; 1269 } 1270 1271 } else { 1272 1273 if (methods[i].getName().equals("<init>") && 1276 !methods[i].isPublic()) 1277 { 1278 translateMethod( 1279 newClassGen,constPool, 1280 methods[i], 1281 0,null,0,null); 1282 } else if (methods[i].getName().equals("this")) { 1283 MethodGen methodGen = 1284 new MethodGen(methods[i], newClassGen.getClassName(), constPool); 1285 translateConstructor(newClassGen,methods[i],methodGen,null,true); 1286 newClassGen.replaceMethod(methods[i],methodGen.getMethod()); 1287 } 1288 1289 logger.debug("skipping "+methods[i]+ 1290 "("+methods[i].getNameIndex()+")"); 1291 if (methods[i].getName().startsWith("<init>")) { 1292 logger.warn("Constructor not translated: "+aClass+"."+methods[i]); 1293 } 1294 } 1295 } 1296 1297 initStaticFields(newClassGen,staticFields,clinit); 1299 1300 return newClassGen.getJavaClass().getBytes(); 1301 1302 } else { 1303 1304 logger.info("ALREADY TRANSLATED "+aClass); 1305 ConstantPoolGen constPool = 1306 new ConstantPoolGen(originalClass.getConstantPool()); 1307 Method[] methods = originalClass.getMethods(); 1308 1314 return originalClass.getBytes(); 1315 } 1316 1317 } 1318 1319 1324 public byte[] fillClassRTTI(String aClass) throws Exception 1325 { 1326 JavaClass originalClass = Repository.lookupClass(aClass); 1327 if (originalClass==null) { 1328 logger.info("CLASS NOT FOUND "+aClass); 1329 throw new ClassNotFoundException ("Class not found: "+aClass); 1330 } 1331 1332 if (originalClass.isInterface()) { 1334 logger.info("skipping interface "+aClass); 1335 return null; 1336 } 1337 1338 1339 1340 logger.info("LOADING "+aClass); 1341 1342 ClassGen newClassGen = new ClassGen(originalClass); 1344 ConstantPoolGen constPool = newClassGen.getConstantPool(); 1345 1346 Method[] methods = newClassGen.getMethods(); 1348 1349 for (int i=0; i<methods.length; i++) { 1350 logger.info("Analyzing "+methods[i]); 1351 fillRTTI(newClassGen,constPool,methods[i],true); 1352 } 1353 1354 return newClassGen.getJavaClass().getBytes(); 1355 1356 } 1357 1358 static public boolean isCollection(String type) { 1359 return collectionTypes.containsKey(type); 1360 } 1361 1362 static class WCIndex { 1363 boolean isStatic; 1364 int index; 1365 public WCIndex(boolean isStatic, int index) { 1366 this.isStatic = isStatic; 1367 this.index = index; 1368 } 1369 } 1370 1371 static HashMap collectionTypes = new HashMap (); 1372 { 1373 collectionTypes.put("java.util.Vector","Lorg/objectweb/jac/lib/java/util/Vector;"); 1374 collectionTypes.put("java.util.Hashtable","Lorg/objectweb/jac/lib/java/util/Hashtable;"); 1375 collectionTypes.put("java.util.HashMap","Lorg/objectweb/jac/lib/java/util/HashMap;"); 1376 collectionTypes.put("java.util.HashSet","Lorg/objectweb/jac/lib/java/util/HashSet;"); 1377 } 1378 1379 static final Type[] emptyTypeArray = new Type[0]; 1380} 1381 1382 | Popular Tags |