KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > jac > core > translators > WrappeeTranslator_BCEL


1 /*
2   Copyright (C) 2002-2003 Fabrice Legond-Aubry, Renaud Pawlak,
3   Lionel Seinturier, Laurent Martelli
4
5   This program is free software; you can redistribute it and/or modify
6   it under the terms of the GNU Lesser General Public License as
7   published by the Free Software Foundation; either version 2 of the
8   License, or (at your option) any later version.
9
10   This program is distributed in the hope that it will be useful, but
11   WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13   Lesser General Public License for more details.
14
15   You should have received a copy of the GNU Lesser General Public
16   License along with this program; if not, write to the Free Software
17   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18   USA */

19
20 package org.objectweb.jac.core.translators;
21
22 import java.lang.reflect.Modifier JavaDoc;
23 import java.util.Arrays JavaDoc;
24 import java.util.Collection JavaDoc;
25 import java.util.HashMap JavaDoc;
26 import java.util.Iterator JavaDoc;
27 import java.util.LinkedList JavaDoc;
28 import java.util.List JavaDoc;
29 import java.util.Map JavaDoc;
30 import java.util.Vector JavaDoc;
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     /**
53      * Translator initializator. */

54
55     public WrappeeTranslator_BCEL(LoadtimeRTTI rtti) {
56         this.rtti = rtti;
57     }
58
59     private static final String JavaDoc nextWrapper_signature =
60     "(Lorg/objectweb/jac/core/Interaction;)Ljava/lang/Object;";
61
62     private static final String JavaDoc 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 JavaDoc getWrappingChain_signature =
68     "(Lorg/objectweb/jac/core/Wrappee;Lorg/objectweb/jac/core/rtti/AbstractMethodItem;)Lorg/objectweb/jac/core/WrappingChain;";
69
70     private String JavaDoc 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 JavaDoc 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 JavaDoc gSNewName,
115                                     int staticFieldIndex,
116                                     List JavaDoc staticFieldIndexes,
117                                     int wrappingChainIndex,
118                                     List JavaDoc 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 JavaDoc)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 JavaDoc 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 JavaDoc[] {},
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 JavaDoc 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 JavaDoc 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 JavaDoc renameMethod(ClassGen classGen, ConstantPoolGen constPool,
532                                 Method method, String JavaDoc 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 JavaDoc className = classGen.getClassName();
568         String JavaDoc methodName = method.getName();
569         MethodGen methodGen = new MethodGen(method,className,constPool);
570         Iterator JavaDoc instructions = methodGen.getInstructionList().iterator();
571         String JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc invokedClass = invoke.getClassName(constPool);
654                 String JavaDoc invokedMethodName = invoke.getMethodName(constPool);
655                 int numArgs = invoke.getArgumentTypes(constPool).length;
656                 Object JavaDoc 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 JavaDoc signature =
667                         nameAndType.getSignature(constPool.getConstantPool());
668                     String JavaDoc 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 JavaDoc.class)) ||
689                          invoke.getClassType(constPool).isCastableTo(Type.getType(Map JavaDoc.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 JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc type = Type.getType(field.getSignature()).toString();
830         String JavaDoc translatedType = (String JavaDoc)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 JavaDoc 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 JavaDoc staticFieldIndexes,
868                                  int wrappingChainIndex,
869                                  List JavaDoc wrappingChainIndexes)
870     {
871         logger.debug("Translating method "+
872                      method.getName()+"("+method.getNameIndex()+")");
873         // get all methods
874
String JavaDoc 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 JavaDoc newName = null;
880         InstructionList callSuper;
881         String JavaDoc 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 JavaDoc className,Method method) {
928         String JavaDoc 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 JavaDoc 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 JavaDoc methods = (List JavaDoc)wrappableMethods.get(className);
953         Iterator JavaDoc it = methods.iterator();
954         while(it.hasNext()) {
955             String JavaDoc cur = (String JavaDoc)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 JavaDoc 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 JavaDoc 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 JavaDoc getMethodFullName(Method method) {
1056        String JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc fieldName;
1160        public String JavaDoc methodName;
1161        public int fieldIndex;
1162        public StaticField(String JavaDoc fieldName, String JavaDoc 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 JavaDoc aClass) throws Exception JavaDoc
1175    {
1176        JavaClass originalClass = Repository.lookupClass(aClass);
1177        if (originalClass==null) {
1178            logger.info("CLASS NOT FOUND "+aClass);
1179            throw new ClassNotFoundException JavaDoc("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 JavaDoc staticFields = new LinkedList JavaDoc();
1227            List JavaDoc staticFieldIndexes = new Vector JavaDoc();
1228            List JavaDoc wrappingChainIndexes = new Vector JavaDoc();
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 JavaDoc(
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 JavaDoc)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 JavaDoc)staticFieldIndexes.get(i)).intValue()));
1265                    } catch(Exception JavaDoc 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 JavaDoc aClass) throws Exception JavaDoc
1325    {
1326        JavaClass originalClass = Repository.lookupClass(aClass);
1327        if (originalClass==null) {
1328            logger.info("CLASS NOT FOUND "+aClass);
1329            throw new ClassNotFoundException JavaDoc("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 JavaDoc 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 JavaDoc collectionTypes = new HashMap JavaDoc();
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