001 /* 002 Copyright (C) 2002-2003 Fabrice Legond-Aubry, Renaud Pawlak, 003 Lionel Seinturier, Laurent Martelli 004 005 This program is free software; you can redistribute it and/or modify 006 it under the terms of the GNU Lesser General Public License as 007 published by the Free Software Foundation; either version 2 of the 008 License, or (at your option) any later version. 009 010 This program is distributed in the hope that it will be useful, but 011 WITHOUT ANY WARRANTY; without even the implied warranty of 012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 Lesser General Public License for more details. 014 015 You should have received a copy of the GNU Lesser General Public 016 License along with this program; if not, write to the Free Software 017 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 018 USA */ 019 020 package org.objectweb.jac.core.translators; 021 022 import java.lang.reflect.Modifier; 023 import java.util.Arrays; 024 import java.util.Collection; 025 import java.util.HashMap; 026 import java.util.Iterator; 027 import java.util.LinkedList; 028 import java.util.List; 029 import java.util.Map; 030 import java.util.Vector; 031 import org.apache.bcel.Constants; 032 import org.apache.bcel.Repository; 033 import org.apache.bcel.classfile.*; 034 import org.apache.bcel.generic.*; 035 import org.apache.bcel.generic.BranchInstruction; 036 import org.apache.log4j.Logger; 037 import org.objectweb.jac.core.JacLoader; 038 import org.objectweb.jac.core.JacPropLoader; 039 import org.objectweb.jac.core.WrappeeTranslator; 040 import org.objectweb.jac.core.rtti.InvokeInfo; 041 import org.objectweb.jac.core.rtti.LoadtimeRTTI; 042 import org.objectweb.jac.util.ExtArrays; 043 import org.objectweb.jac.util.Stack; 044 045 public class WrappeeTranslator_BCEL implements WrappeeTranslator { 046 static Logger logger = Logger.getLogger("translator"); 047 static Logger loggerRtti = Logger.getLogger("rtti.detect"); 048 static Logger loggerBytecode = Logger.getLogger("translator.bytecode"); 049 050 LoadtimeRTTI rtti; 051 052 /** 053 * Translator initializator. */ 054 055 public WrappeeTranslator_BCEL(LoadtimeRTTI rtti) { 056 this.rtti = rtti; 057 } 058 059 private static final String nextWrapper_signature = 060 "(Lorg/objectweb/jac/core/Interaction;)Ljava/lang/Object;"; 061 062 private static final String newInteraction_signature = 063 "(Lorg/objectweb/jac/core/WrappingChain;Lorg/objectweb/jac/core/Wrappee;"+ 064 "Lorg/objectweb/jac/core/rtti/AbstractMethodItem;"+ 065 "[Ljava/lang/Object;)V"; 066 067 private static final String getWrappingChain_signature = 068 "(Lorg/objectweb/jac/core/Wrappee;Lorg/objectweb/jac/core/rtti/AbstractMethodItem;)Lorg/objectweb/jac/core/WrappingChain;"; 069 070 private String primitiveTypeName(Type t) 071 { 072 if (t==Type.BOOLEAN) 073 return "boolean"; 074 if (t==Type.BYTE) 075 return "byte"; 076 if (t==Type.INT) 077 return "int"; 078 if (t==Type.LONG) 079 return "long"; 080 if (t==Type.SHORT) 081 return "short"; 082 if (t==Type.FLOAT) 083 return "float"; 084 if (t==Type.CHAR) 085 return "char"; 086 if (t==Type.DOUBLE) 087 return "double"; 088 return null; 089 } 090 091 private String primitiveTypeAsObject(Type t) 092 { 093 if (t==Type.BOOLEAN) 094 return "java.lang.Boolean"; 095 if (t==Type.BYTE) 096 return "java.lang.Byte"; 097 if (t==Type.INT) 098 return "java.lang.Integer"; 099 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 //create the stub method 126 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 // generate the super call when its a constructor 138 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 // initialize the wrapping chains 155 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 /////////////////////////////////// 181 // LOOK AT THIS ! NEED TEST 182 /////////////////////////////////////// 183 stubMethod.removeExceptionHandlers(); 184 185 // create an Interaction object 186 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 // get the wrapping chain 192 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 // push the ref on this object in case of a non-static method on stack 203 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 // push the static field containing the AbstractMethodItem on the stack 212 il.append(new GETSTATIC(staticFieldIndex)); 213 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 214 215 //create an array of Objects that are the parameters for the 216 //original method 217 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 //create a array and put its ref on the stack 228 il.append((Instruction)ifactory.createNewArray(Type.OBJECT,(short)1)); 229 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 230 int j = (stubMethod.isStatic())?0:1; // index of argument on the stack 231 for (int i=0; i<argumentTypes.length; i++) 232 { 233 //duplicate the ref on the array to keep it for next operation 234 il.append(InstructionFactory.createDup(1)); 235 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 236 //get the index [in the array] in which we will store the ref 237 il.append(new PUSH(constPool, i)); 238 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 239 // is the parameter an object ? 240 if (!Utils.isPrimitive(argumentTypes[i])) { 241 //get the ref of the j st parameter of the local function 242 il.append(InstructionFactory.createLoad(Type.OBJECT,j)); 243 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 244 //effectively store the ref in the array 245 il.append(InstructionFactory.createArrayStore(Type.OBJECT)); 246 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 247 //increment the counter for the next object 248 j++; 249 } else { 250 //create a new object similar to the primitive type 251 String objectType = primitiveTypeAsObject(argumentTypes[i]); 252 il.append (ifactory.createNew(objectType)); 253 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 254 //call the constructor of the new object with the primitive value 255 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 //store the new object in the array 264 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 // long and double take 2 slots on the stack 270 j++; 271 } 272 273 } 274 } 275 276 // <init> the Interaction 277 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 //make invocation of "nextWrapper" 286 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 //parse the return value if it is a primitive one 305 if (Utils.isPrimitive(returnType)) 306 { 307 //ouch ! the return primitive types are also wrapped. 308 //test the cast for the object returned .... 309 //is this really usefull ? 310 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 //get the value wrapped in the object 318 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 make a simple checkcast (avoid the checkcast on the VOID type) 327 //is this also really useful ? 328 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 // finally return ! HOURRA ! 335 il.append (InstructionFactory.createReturn(returnType)); 336 stubMethod.addLineNumber(il.getEnd(),il.size()-1); 337 // compile all this stuff, generate the method 338 stubMethod.setMaxLocals(); 339 stubMethod.setMaxStack(); 340 //System.out.println ("il=\n"+il); 341 classGen.addMethod(stubMethod.getMethod()); 342 } 343 344 /** 345 * Generate a default constructor --which takes no argument-- which 346 * just calls super(). 347 * 348 * !!! IT SHOULD ALSO INITIALIZE FIELDS !!! 349 * We could use the "this" method generated by jikes-1.18 350 */ 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 /** 380 * Remove call to super() 381 * Replace collection attributes with the wrappable org.objectweb.jac.lib version 382 * 383 * @param classGen the class of the constructor 384 * @param origConstructor 385 * @param constructor the constructor to translate 386 * @param callSuper store bytecodes that do the call to the super 387 * constructor in it 388 * @param removeSuperCall wether to remove the call to super bytecodes 389 */ 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 // Represents the state of the JVM stack 403 // (contains ThisPointer or DontCare) 404 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 // remove call to super <init> 425 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 //if(classGen.containsMethod( 448 // invoke.getMethodName(constPool), 449 // invoke.getSignature(constPool)).isPublic()) 450 //{ 451 // if it calls another constructor of the same class, 452 // replace it with a call to the renamed constructor 453 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 //} 464 } 465 } 466 } 467 stack.execute(instruction,ih); 468 } else if (JacPropLoader.translateFields(constructor.getClassName())) { 469 470 // Replace java.util. with org.objectweb.jac.lib.java.util 471 // for collections 472 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 // this.putfield(...) 478 PUTFIELD putfield = (PUTFIELD)instruction; 479 if (!classGen.containsField(putfield.getFieldName(constPool)).isTransient()) { 480 VMStack.Instance collection = (VMStack.Instance)stack.peek(); 481 /* 482 System.out.println("collection: "+collection.type+"( new="+ 483 collection.newHandle+",init="+ 484 collection.initHandle+")"); 485 */ 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 /** 518 * Rename the method "xxx" in "_org_xxx". 519 * 520 * <p>If the method is a constructor, it's translated.</p> 521 * 522 * @param classGen the class of the method to rename 523 * @param constPool 524 * @param method the method to rename 525 * @param newProposedName new name for the translated method 526 * @param callSuper store bytecodes that do the call to the super 527 * constructor in this list 528 * 529 * @see #translateConstructor(ClassGen,Method,MethodGen,InstructionList) 530 */ 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 // handles constructors specific translations 537 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 //why the hell is all this stuff necessary ?! 543 newNamedMethod.removeLocalVariables(); 544 // newNamedMethod.setMaxLocals(); 545 // newNamedMethod.setMaxStack(); 546 //move the original method into the new "_org_xxx" method 547 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 /** 557 * Generate RTTI information for a method. 558 * 559 * @param classGen the class of the method 560 * @param constPool the constant pool of the method 561 * @param method the method 562 * @param passive if true, do not perform any translation 563 */ 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 // setters and modifiers 588 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 // TODO: check if the type is translated collection 595 } 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 // static setters and modifiers 602 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 // TODO: check if the type is translated collection 609 } 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 // *the* getter 617 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 // getters 635 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 // getters 643 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 // adders and removers 652 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 // check that the field value belongs to "this" 687 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 /** 783 * Returns true if the n top elements of the stack are arguments 784 * @param stack a stack 785 * @param n number of elements to check 786 * @return true if the n top elements of the stack are arguments 787 */ 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 /** 797 * Returns true if the nth top element of the stack is an argument 798 * 799 * @param stack a stack 800 * @param n index element to check 801 * @return true if stack.peek(n) is an argument 802 */ 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 /** 823 * Change the type of collection fields to use org.objectweb.jac.lib types 824 * @param classGen the class holding the field 825 * @param field the field whose type to change 826 */ 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 // replace the Fieldref entry in the constant pool 840 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 /** 854 * Translate a method (rename it and generate a stub). 855 * 856 * @param classGen the ClassGen holding the method 857 * @param constPool the constant pool 858 * @param method the method to translate 859 * @param staticFieldIndex index of the static field holding the 860 * reference to the MethodItem of the method 861 * @param wrappingChainIndex index of the static field holding the 862 * wrapping chain for that method. 863 * @param wrappingChainIndexes 864 */ 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 // get all methods 874 String tmpname; 875 876 tmpname = method.getName(); 877 //rename the method "xxx" in "_org_xxx" (except for 878 //constructors, where it's called _org_<class_name>) 879 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 // We keep a copy of non public constructors because 886 // they may be called from other constructors and we 887 // won't generate a stub for them 888 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 // Renamed methods should not override each other 909 (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 /** 923 * Returns true is the method should be translated 924 * @param className name of the class 925 * @param method the method 926 */ 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 // constructors should always be wrappable 950 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 /** 967 * Create a static field containing a reference to an 968 * AbstractMethodItem for method. 969 * @return the index in the constant pool of created field 970 */ 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 // int fieldIndex = field.getConstantValue().getConstantValueIndex(); 983 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 /** 1008 * Setup class before really translating it. 1009 * 1010 * <p>The Wrappee interface is added, and the __JAC_TRANSLATED 1011 * field is added too. A default constructor is created if none 1012 * exists.</p> 1013 * @param classGen translated class */ 1014 private void startingTranslation(ClassGen classGen) 1015 { 1016 1017 ConstantPoolGen constPool = classGen.getConstantPool(); 1018 int objectIndexRef = constPool.lookupClass("java.lang.Object"); 1019 1020 // Add the __JAC_TRANSLATED field 1021 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 /** 1039 * Returns true if the class is already translated (ie it contains 1040 * a field named __JAC_TRANSLATED) 1041 */ 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 /** 1051 * Returns the full name of a method as required by RTTI 1052 * @param method the method 1053 * @return full name of the method (something like 1054 * myMethod(java.lang.String,int) */ 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 /** 1068 * Create code to initialize static fields that hold MethodItems 1069 * and wrapping chains. 1070 * 1071 * @param classGen the class to build static fields initialization for 1072 * @param fields a list of StaticField 1073 * @param clinit the static class initialization method if one 1074 * already exists 1075 */ 1076 void initStaticFields(ClassGen classGen, List fields, Method clinit) { 1077 //search for the static {} method 1078 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 there is no static method 1085 // then we will need to build one from scratch 1086 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 //else we need to update the already existing one 1097 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 // ClassRepository.get() ... 1107 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 // ... .getClass(<className>) 1114 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 // We now have the ClassItem on the stack 1123 // Let's call getMethod on it. 1124 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 /** 1170 * Translate a class 1171 * @param aClass name of the class to translate 1172 * @return bytecode of the translated class 1173 */ 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 // test if it is public (for security resons, protected and 1183 // private classes are not translated). 1184 //if (!originalClass.isPublic()) { 1185 // logger.info("skipping non public class "+aClass); 1186 // return null; 1187 //} 1188 1189 // test if the class is already translated/adapted. 1190 if (!isTranslated(originalClass)) 1191 { 1192 /** None of the above mentionned cases are verified. Adapt the class. */ 1193 1194 logger.info("TRANSLATING "+aClass); 1195 1196 // Mark it as translated 1197 ClassGen newClassGen = new ClassGen (originalClass); 1198 startingTranslation(newClassGen); 1199 1200 // test if a real class (not an interface) 1201 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 // translate fields 1213 // (java.util.<collection> -> org.objectweb.jac.lib.java.util.<collection>) 1214 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 // get all methods and translate them 1225 Method[] methods = newClassGen.getMethods(); 1226 LinkedList staticFields = new LinkedList(); 1227 List staticFieldIndexes = new Vector(); 1228 List wrappingChainIndexes = new Vector(); 1229 1230 // first pass to get the field indexes 1231 for (int i=0; i<methods.length; i++) { 1232 if (isTranslatable(newClassGen.getClassName(),methods[i])) { 1233 // create a static field containing a ref to the 1234 // AbstractMethodItem 1235 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 // translate private or protected contructors (not 1274 // stored in rtti) 1275 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 // initialize static fields 1298 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 /* 1309 for (int i=0; i<methods.length; i++) { 1310 if (methods[i].getName().startsWith(prefix)) 1311 fillRTTI(originalClass.getClassName(), constPool, methods[i]); 1312 } 1313 */ 1314 return originalClass.getBytes(); 1315 } 1316 1317 } 1318 1319 /** 1320 * Computes RTTI info for a class and gets its bytecode 1321 * @param aClass name of the class analyze 1322 * @return bytecode of the class 1323 */ 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 // test if a real class (not an interface) 1333 if (originalClass.isInterface()) { 1334 logger.info("skipping interface "+aClass); 1335 return null; 1336 } 1337 1338 /** None of the above mentionned cases are verified. Load the class. */ 1339 1340 logger.info("LOADING "+aClass); 1341 1342 // Mark it as translated 1343 ClassGen newClassGen = new ClassGen(originalClass); 1344 ConstantPoolGen constPool = newClassGen.getConstantPool(); 1345 1346 // get all methods and translate them 1347 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