| 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 |