]> source.dussan.org Git - aspectj.git/commitdiff
Completed: Improve ajc memory usage
authoracolyer <acolyer>
Fri, 24 Feb 2006 12:35:43 +0000 (12:35 +0000)
committeracolyer <acolyer>
Fri, 24 Feb 2006 12:35:43 +0000 (12:35 +0000)
the last of the big memory hog in AjState is now removed.

org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildManager.java
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjState.java
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/StatefulNameEnvironment.java

index 1ef198bf2474bd488d9b40603b450084eb6a70f0..4f6c664c79e7644b81cabd7f92f917ee47d05571 100644 (file)
@@ -234,6 +234,7 @@ public class AjBuildManager implements IOutputClassFileNameProvider,IBinarySourc
                 }
                 binarySourcesForTheNextCompile = state.getBinaryFilesToCompile(true);
                 performCompilation(buildConfig.getFiles());
+                state.clearBinarySourceFiles(); // we don't want these hanging around...
                 if (handler.hasErrors()) {
                        CompilationAndWeavingContext.leavingPhase(ct);
                     return false;
@@ -815,8 +816,8 @@ public class AjBuildManager implements IOutputClassFileNameProvider,IBinarySourc
                //System.out.println("compiling");
                environment = getLibraryAccess(classpaths, filenames);
                
-               if (!state.getClassNameToUCFMap().isEmpty()) {
-                       environment = new StatefulNameEnvironment(environment, state.getClassNameToUCFMap());
+               if (!state.getClassNameToFileMap().isEmpty()) {
+                       environment = new StatefulNameEnvironment(environment, state.getClassNameToFileMap());
                }
                
                org.aspectj.ajdt.internal.compiler.CompilerAdapter.setCompilerAdapterFactory(this);
index e47215ace7c7ce63a85109c6468719e2df10f68b..e901f057efa55deb773095e07668b465ba0947dd 100644 (file)
@@ -23,6 +23,7 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Hashtable;
 import java.util.Iterator;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -36,11 +37,19 @@ import org.aspectj.bridge.SourceLocation;
 import org.aspectj.org.eclipse.jdt.internal.compiler.CompilationResult;
 import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
 import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
+import org.aspectj.org.eclipse.jdt.internal.compiler.env.IBinaryField;
+import org.aspectj.org.eclipse.jdt.internal.compiler.env.IBinaryMethod;
+import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.CompilerModifiers;
 import org.aspectj.org.eclipse.jdt.internal.core.builder.ReferenceCollection;
 import org.aspectj.org.eclipse.jdt.internal.core.builder.StringSet;
+import org.aspectj.org.eclipse.jdt.internal.core.util.Util;
 import org.aspectj.util.FileUtil;
 import org.aspectj.weaver.IWeaver;
+import org.aspectj.weaver.ReferenceType;
+import org.aspectj.weaver.ReferenceTypeDelegate;
+import org.aspectj.weaver.ResolvedMember;
 import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.UnresolvedType;
 import org.aspectj.weaver.bcel.BcelWeaver;
 import org.aspectj.weaver.bcel.BcelWorld;
 import org.aspectj.weaver.bcel.UnwovenClassFile;
@@ -71,7 +80,8 @@ public class AjState {
        /**
         * Keeps a list of (FQN,Filename) pairs (as ClassFile objects)
         * for types that resulted from the compilation of the given
-        * File.
+        * File. Note :- the ClassFile objects contain no byte code, 
+        * they are simply a Filename,typename pair.
         * 
         * Populated in noteResult and used in addDependentsOf(File)
         * 
@@ -86,7 +96,7 @@ public class AjState {
         * 
         * Added by AMC during state refactoring, 1Q06.
         */
-       private Set sourceFilesDefiningAspects = new HashSet();
+       private Set/*<File>*/ sourceFilesDefiningAspects = new HashSet();
        
        /**
         * Populated in noteResult to record the set of types that should be recompiled if
@@ -99,7 +109,9 @@ public class AjState {
        /**
         * Holds UnwovenClassFiles (byte[]s) originating from the given file source. This
         * could be a jar file, a directory, or an individual .class file. This is an 
-        * *expensive* map we would like to release much earlier if possible.
+        * *expensive* map. It is cleared immediately following a batch build, and the
+        * cheaper inputClassFilesBySource map is kept for processing of any subsequent
+        * incremental builds.
         * 
         * Populated during AjBuildManager.initBcelWorld().
         * 
@@ -116,11 +128,24 @@ public class AjState {
         * 
         */
        private Map/*File, List<UnwovenClassFile>*/ binarySourceFiles = new HashMap();
+
+       /**
+        * Initially a duplicate of the information held in binarySourceFiles, with the
+        * key difference that the values are ClassFiles (type name, File) not UnwovenClassFiles
+        * (which also have all the byte code in them). After a batch build, binarySourceFiles
+        * is cleared, leaving just this much lighter weight map to use in processing 
+        * subsequent incremental builds.
+        */
+       private Map/*<File,List<ClassFile>*/ inputClassFilesBySource = new HashMap();
+       
+       /**
+        * Holds structure information on types as they were at the end of the last
+        * build. It would be nice to get rid of this too, but can't see an easy way to do
+        * that right now. 
+        */
+       private Map/*FQN,CompactStructureRepresentation*/ resolvedTypeStructuresFromLastBuild = new HashMap();
        
        /**
-        * The third of the three expensive collections of state held by AjState to support
-        * incremental compilation. FQN -> UCF.
-        * 
         * Populated in noteResult to record the set of UnwovenClassFiles (intermediate results)
         * that originated from compilation of the class with the given fully-qualified name.
         * 
@@ -129,7 +154,7 @@ public class AjState {
         * Passed into StatefulNameEnvironment during incremental compilation to support 
         * findType lookups.
         */
-       private Map/*<String, UnwovenClassFile>*/ classesFromName = new HashMap();
+       private Map/*<String, File>*/ classesFromName = new HashMap();
        
        
        private List/*File*/ compiledSourceFiles = new ArrayList();
@@ -319,7 +344,7 @@ public class AjState {
         * lastSBT is the last build time for the state asking the question
         */
        private boolean hasStructuralChangedSince(File file,long lastSuccessfulBuildTime) {
-               long lastModTime = file.lastModified();
+               //long lastModTime = file.lastModified();
                Long l = (Long)structuralChangesSinceLastFullBuild.get(file.getAbsolutePath());
                long strucModTime = -1;
                if (l!=null) strucModTime = l.longValue();
@@ -426,6 +451,9 @@ public class AjState {
                                ucfs.add(ucf);
                                addDependentsOf(ucf.getClassName());
                                binarySourceFiles.put(bsf.binSrc.getPath(),ucfs);
+                               List cfs = new ArrayList(1);
+                               cfs.add(getClassFileFor(ucf));
+                               this.inputClassFilesBySource.put(bsf.binSrc.getPath(), cfs);
                                toWeave.put(bsf.binSrc.getPath(),ucfs);
                        }
                        deleteBinaryClassFiles();
@@ -441,20 +469,16 @@ public class AjState {
         */
        private void removeAllResultsOfLastBuild() {
            // remove all binarySourceFiles, and all classesFromName...
-           for (Iterator iter = binarySourceFiles.values().iterator(); iter.hasNext();) {
-            List ucfs = (List) iter.next();
-            for (Iterator iterator = ucfs.iterator(); iterator.hasNext();) {
-                UnwovenClassFile ucf = (UnwovenClassFile) iterator.next();
-                try {
-                    ucf.deleteRealFile();
-                } catch (IOException ex) { /* we did our best here */ } 
+           for (Iterator iter = this.inputClassFilesBySource.values().iterator(); iter.hasNext();) {
+            List cfs = (List) iter.next();
+            for (Iterator iterator = cfs.iterator(); iterator.hasNext();) {
+                ClassFile cf = (ClassFile) iterator.next();
+                cf.deleteFromFileSystem();
             }
         }
            for (Iterator iterator = classesFromName.values().iterator(); iterator.hasNext();) {
-            UnwovenClassFile ucf = (UnwovenClassFile) iterator.next();
-            try {
-                ucf.deleteRealFile();
-            } catch (IOException ex) { /* we did our best here */ }  
+            File f = (File) iterator.next();
+            new ClassFile("",f).deleteFromFileSystem();
         }
            for (Iterator iter = resources.iterator(); iter.hasNext();) {
             String resource = (String) iter.next();
@@ -484,15 +508,11 @@ public class AjState {
                // range of bsf is ucfs, domain is files (.class and jars) in inpath/jars
                for (Iterator iter = deletedBinaryFiles.iterator(); iter.hasNext();) {
                        AjBuildConfig.BinarySourceFile deletedFile = (AjBuildConfig.BinarySourceFile) iter.next();
-                       List ucfs = (List) binarySourceFiles.get(deletedFile.binSrc.getPath());
-                       binarySourceFiles.remove(deletedFile.binSrc.getPath());
-
-                       // AMC temp during refactoring
-                       UnwovenClassFile ucf = (UnwovenClassFile) ucfs.get(0);
-                       ClassFile cf = new ClassFile(ucf.getClassName(),new File(ucf.getFilename()));
-                       // end temp
-                       
-                       deleteClassFile(cf);
+                       List cfs = (List) this.inputClassFilesBySource.get(deletedFile.binSrc.getPath());
+                       for (Iterator iterator = cfs.iterator(); iterator.hasNext();) {
+                               deleteClassFile((ClassFile)iterator.next());                            
+                       }
+                       this.inputClassFilesBySource.remove(deletedFile.binSrc.getPath());
                }
        }
        
@@ -584,9 +604,9 @@ public class AjState {
 
                UnwovenClassFile[] unwovenClassFiles = result.unwovenClassFiles();
                for (int i = 0; i < unwovenClassFiles.length; i++) {
-                       UnwovenClassFile lastTimeRound = (UnwovenClassFile) classesFromName.get(unwovenClassFiles[i].getClassName()); 
+                       File lastTimeRound = (File) classesFromName.get(unwovenClassFiles[i].getClassName()); 
                        recordClassFile(unwovenClassFiles[i],lastTimeRound);
-                       classesFromName.put(unwovenClassFiles[i].getClassName(),unwovenClassFiles[i]);
+                       classesFromName.put(unwovenClassFiles[i].getClassName(),new File(unwovenClassFiles[i].getFilename()));
                }
 
                // need to do this before types are deleted from the World...
@@ -713,111 +733,176 @@ public class AjState {
                return null;
        }
        
-       private void recordClassFile(UnwovenClassFile thisTime, UnwovenClassFile lastTime) {
-               if (simpleStrings == null) return; // batch build
+       private void recordClassFile(UnwovenClassFile thisTime, File lastTime) {
+               if (simpleStrings == null) {
+                       // batch build
+                       // record resolved type for structural comparisions in future increments
+                       // this records a second reference to a structure already held in memory
+                       // by the world.
+                       ResolvedType rType = world.resolve(thisTime.getClassName());
+                       if (!rType.isMissing()) {
+                               this.resolvedTypeStructuresFromLastBuild.put(thisTime.getClassName(),new CompactStructureRepresentation(rType));
+                       }
+                       return;
+               }
 
+               CompactStructureRepresentation existingStructure = (CompactStructureRepresentation) this.resolvedTypeStructuresFromLastBuild.get(thisTime.getClassName());
+               ReferenceType newResolvedType = (ReferenceType) world.resolve(thisTime.getClassName());
+               if (!newResolvedType.isMissing()) {
+                       this.resolvedTypeStructuresFromLastBuild.put(thisTime.getClassName(),new CompactStructureRepresentation(newResolvedType));
+               }
+               
                if (lastTime == null) {
                        addDependentsOf(thisTime.getClassName());
                        return;
                }
 
-               byte[] newBytes = thisTime.getBytes();
-               byte[] oldBytes = lastTime.getBytes();
-               boolean bytesEqual = (newBytes.length == oldBytes.length);
-               for (int i = 0; (i < oldBytes.length) && bytesEqual; i++) {
-                       if (newBytes[i] != oldBytes[i]) bytesEqual = false;
+               if (newResolvedType.isMissing()) {
+                       return;
                }
-               if (!bytesEqual) {
-                       try {
-                               ClassFileReader reader = new ClassFileReader(oldBytes, lastTime.getFilename().toCharArray());
-                               // ignore local types since they're only visible inside a single method
-                               if (!(reader.isLocal() || reader.isAnonymous()) && 
-                                               reader.hasStructuralChanges(newBytes)) {
+
+               byte[] newBytes = thisTime.getBytes();
+               try {
+                       ClassFileReader reader = new ClassFileReader(newBytes, lastTime.getAbsolutePath().toCharArray());
+                       // ignore local types since they're only visible inside a single method
+                       if (!(reader.isLocal() || reader.isAnonymous())) {
+                               if (hasStructuralChanges(reader,existingStructure)) {
                                        structuralChangesSinceLastFullBuild.put(thisTime.getFilename(),new Long(currentBuildTime));
-                                       addDependentsOf(lastTime.getClassName());
+                                       addDependentsOf(new String(reader.getName()).replace('/','.'));
                                }
-                       } catch (ClassFormatException e) {
-                               addDependentsOf(lastTime.getClassName());
-                       }                       
-               }
+                       }
+               } catch (ClassFormatException e) {
+                       addDependentsOf(thisTime.getClassName());
+               }                                                       
        }
        
+       
+       /**
+        * Compare the class structure of the new intermediate (unwoven) class with the
+        * existingResolvedType of the same class that we have in the world, looking for
+        * any structural differences (and ignoring aj members resulting from weaving....)
+        * 
+        * Warning : long but boring method implementation... 
+        * @param reader
+        * @param existingType
+        * @return
+        */
+       private boolean hasStructuralChanges(ClassFileReader reader, CompactStructureRepresentation existingType) {
+               // mirrors the checks in ClassFileReader.hasStructuralChanges, but compares against
+               // ref type delegate instead of old bytes
+               if (existingType == null) {
+                       return true;
+               }
+               
+               // modifiers
+               if (!modifiersEqual(reader.getModifiers(),existingType.modifiers)) {
+                       return true;
+               }
+               
+               // generic signature
+               if (!equal(reader.getGenericSignature(),existingType.genericSignature)) {
+                       return true;
+               }
+               
+               // superclass name
+               if (!equal(reader.getSuperclassName(),existingType.superclassName)) {
+                       return true;
+               }
+               
+               // interfaces
+               char[][] existingIfs = existingType.interfaces;
+               char[][] newIfsAsChars = reader.getInterfaceNames();
+               if (newIfsAsChars == null) { newIfsAsChars = new char[0][]; }
+               char[][] newIfs = new char[newIfsAsChars.length][];
+               if (existingIfs.length != newIfs.length) {
+                       return true;
+               }
+               new_interface_loop: for (int i = 0; i < newIfs.length; i++) {
+                       for (int j = 0; j < existingIfs.length; j++) {
+                               if (equal(existingIfs[j],newIfs[i])) {
+                                       continue new_interface_loop;
+                               }
+                       }
+                       return true;
+               }
+               
+               // fields
+               MemberStructure[] existingFields = existingType.fields;
+               IBinaryField[] newFields = reader.getFields();
+               if (newFields == null) { newFields = new IBinaryField[0]; }
+               if (newFields.length != existingFields.length) {
+                       return true;
+               }
+               new_field_loop: for (int i = 0; i < newFields.length; i++) {
+                       char[] fieldName = newFields[i].getName();
+                       for (int j = 0; j < existingFields.length; j++) {
+                               if (equal(existingFields[j].name,fieldName)) {
+                                       if (!modifiersEqual(newFields[i].getModifiers(),existingFields[j].modifiers)) {
+                                               return true;
+                                       }
+                                       if (!equal(existingFields[j].signature,newFields[i].getTypeName())) {
+                                               return true;
+                                       }
+                                       continue new_field_loop;
+                               }
+                       }
+                       return true;
+               }
+               
+               // methods
+               MemberStructure[] existingMethods = existingType.methods;
+               IBinaryMethod[] newMethods = reader.getMethods();
+               if (newMethods == null) { newMethods = new IBinaryMethod[0]; }
+               if (newMethods.length != existingMethods.length) {
+                       return true;
+               }
+               new_method_loop: for (int i = 0; i < newMethods.length; i++) {
+                       char[] methodName = newMethods[i].getSelector();
+                       for (int j = 0; j < existingMethods.length; j++) {
+                               if (equal(existingMethods[j].name,methodName)) {
+                                       // candidate match
+                                       if (!equal(newMethods[i].getMethodDescriptor(),existingMethods[j].signature)) {
+                                               continue; // might be overloading
+                                       } 
+                                       else {
+                                               // matching sigs
+                                               if (!modifiersEqual(newMethods[i].getModifiers(),existingMethods[j].modifiers)) {
+                                                       return true;
+                                               }
+                                               continue new_method_loop;
+                                       }
+                               }
+                       }
+                       return true; // (no match found)
+               }
+               
+               return false;
+       }
 
-//     public void noteClassesFromFile(CompilationResult result, String sourceFileName, List unwovenClassFiles) {
-//             File sourceFile = new File(sourceFileName);
-//             
-//             if (result != null) {
-//                     references.put(sourceFile, new ReferenceCollection(result.qualifiedReferences, result.simpleNameReferences));
-//             }
-//             
-//             List previous = (List)classesFromFile.get(sourceFile);
-//             List newClassFiles = new ArrayList();
-//             for (Iterator i = unwovenClassFiles.iterator(); i.hasNext();) {
-//                     UnwovenClassFile cf = (UnwovenClassFile) i.next();
-//                     cf = writeClassFile(cf, findAndRemoveClassFile(cf.getClassName(), previous));
-//                     newClassFiles.add(cf);
-//                     classesFromName.put(cf.getClassName(), cf);
-//             }
-//             
-//             if (previous != null && !previous.isEmpty()) {
-//                     for (Iterator i = previous.iterator(); i.hasNext();) {
-//                             UnwovenClassFile cf = (UnwovenClassFile) i.next();
-//                             deleteClassFile(cf);
-//                     }
-//             }
-//
-//             classesFromFile.put(sourceFile, newClassFiles);
-//             resultsFromFile.put(sourceFile, result);
-//     }
-//
-//     private UnwovenClassFile findAndRemoveClassFile(String name, List previous) {
-//             if (previous == null) return null;
-//             for (Iterator i = previous.iterator(); i.hasNext();) {
-//                     UnwovenClassFile cf = (UnwovenClassFile) i.next();
-//                     if (cf.getClassName().equals(name)) {
-//                             i.remove();
-//                             return cf;
-//                     } 
-//             }
-//             return null;
-//     }
-//
-//     private UnwovenClassFile writeClassFile(UnwovenClassFile cf, UnwovenClassFile previous) {
-//             if (simpleStrings == null) { // batch build
-//                     addedClassFiles.add(cf);
-//                     return cf;
-//             }
-//             
-//             try {
-//                     if (previous == null) {
-//                             addedClassFiles.add(cf);
-//                             addDependentsOf(cf.getClassName());
-//                             return cf;
-//                     } 
-//                     
-//                     byte[] oldBytes = previous.getBytes();
-//                     byte[] newBytes = cf.getBytes();
-//                     //if (this.compileLoop > 1) { // only optimize files which were recompiled during the dependent pass, see 33990
-//                             notEqual : if (newBytes.length == oldBytes.length) {
-//                                     for (int i = newBytes.length; --i >= 0;) {
-//                                             if (newBytes[i] != oldBytes[i]) break notEqual;
-//                                     }
-//                                     //addedClassFiles.add(previous); //!!! performance wasting
-//                                     buildManager.bcelWorld.addSourceObjectType(previous.getJavaClass());
-//                                     return previous; // bytes are identical so skip them
-//                             }
-//                     //}
-//                     ClassFileReader reader = new ClassFileReader(oldBytes, previous.getFilename().toCharArray());
-//                     // ignore local types since they're only visible inside a single method
-//                     if (!(reader.isLocal() || reader.isAnonymous()) && reader.hasStructuralChanges(newBytes)) {
-//                             addDependentsOf(cf.getClassName());
-//                     }
-//             } catch (ClassFormatException e) {
-//                     addDependentsOf(cf.getClassName());
-//             }
-//             addedClassFiles.add(cf);
-//             return cf;
-//     }
+       private boolean modifiersEqual(int eclipseModifiers, int resolvedTypeModifiers) {
+               resolvedTypeModifiers = resolvedTypeModifiers & CompilerModifiers.AccJustFlag;
+               eclipseModifiers = eclipseModifiers & CompilerModifiers.AccJustFlag;
+               if ((eclipseModifiers & CompilerModifiers.AccSuper) != 0) {
+                       eclipseModifiers -= CompilerModifiers.AccSuper;
+               }
+               return (eclipseModifiers == resolvedTypeModifiers);
+       }
+       
+       private boolean equal(char[] c1, char[] c2) {
+               if (c1 == null && c2 == null) {
+                       return true;
+               }
+               if (c1 == null || c2 == null) {
+                       return false;
+               }
+               if (c1.length != c2.length) {
+                       return false;
+               }
+               for (int i = 0; i < c1.length; i++) {
+                       if (c1[i] != c2[i]) return false;
+               }
+               return true;
+       }
        
        private static StringSet makeStringSet(List strings) {
                StringSet ret = new StringSet(strings.size());
@@ -943,13 +1028,28 @@ public class AjState {
        
        public void recordBinarySource(String fromPathName, List unwovenClassFiles) {
                this.binarySourceFiles.put(fromPathName,unwovenClassFiles);
+               List simpleClassFiles = new LinkedList();
+               for (Iterator iter = unwovenClassFiles.iterator(); iter.hasNext();) {
+                       UnwovenClassFile ucf = (UnwovenClassFile) iter.next();
+                       ClassFile cf = getClassFileFor(ucf);
+                       simpleClassFiles.add(cf);
+               }
+               this.inputClassFilesBySource.put(fromPathName,simpleClassFiles);
+       }
+
+       /**
+        * @param ucf
+        * @return
+        */
+       private ClassFile getClassFileFor(UnwovenClassFile ucf) {
+               return new ClassFile(ucf.getClassName(),new File(ucf.getFilename()));
        }
        
        public Map getBinarySourceMap() {
                return this.binarySourceFiles;
        }
        
-       public Map getClassNameToUCFMap() {
+       public Map getClassNameToFileMap() {
                return this.classesFromName;
        }
        
@@ -1012,4 +1112,59 @@ public class AjState {
                }
        }
 
+       private static class CompactStructureRepresentation {
+               
+               public CompactStructureRepresentation(ResolvedType forType) {
+                       this.className = forType.getName().replace('.','/').toCharArray();
+                       this.modifiers = forType.getModifiers();
+                       this.genericSignature = forType.getGenericSignature().toCharArray();
+                       if (this.genericSignature.length == 0) {
+                               this.genericSignature = null;
+                       }
+                       this.superclassName = forType.getSuperclass().getName().replace('.','/').toCharArray();
+                       ResolvedType[] rTypes = forType.getDeclaredInterfaces();
+                       this.interfaces = new char[rTypes.length][];
+                       for (int i = 0; i < rTypes.length; i++) {
+                               this.interfaces[i] = rTypes[i].getName().replace('.','/').toCharArray();
+                       }
+                       ResolvedMember[] rFields = forType.getDeclaredFields();
+                       this.fields = new MemberStructure[rFields.length];
+                       for (int i = 0; i < rFields.length; i++) {
+                               this.fields[i] = new MemberStructure();
+                               this.fields[i].name = rFields[i].getName().toCharArray();
+                               this.fields[i].modifiers = rFields[i].getModifiers();
+                               this.fields[i].signature = rFields[i].getReturnType().getSignature().toCharArray();
+                       }
+                       ResolvedMember[] rMethods = forType.getDeclaredMethods();
+                       this.methods = new MemberStructure[rMethods.length];
+                       for (int i = 0; i < rMethods.length; i++) {
+                               this.methods[i] = new MemberStructure();
+                               this.methods[i].name = rMethods[i].getName().toCharArray();
+                               this.methods[i].modifiers = rMethods[i].getModifiers();
+                               StringBuffer sig = new StringBuffer();
+                               sig.append("(");
+                               UnresolvedType[] pTypes = rMethods[i].getParameterTypes();
+                               for (int j = 0; j < pTypes.length; j++) {
+                                       sig.append(pTypes[j].getSignature());
+                               }
+                               sig.append(")");
+                               sig.append(rMethods[i].getReturnType().getSignature());
+                               this.methods[i].signature = sig.toString().toCharArray();
+                       }
+               }
+               
+               char[] className;
+               int modifiers;
+               char[] genericSignature;
+               char[] superclassName;
+               char[][] interfaces;
+               MemberStructure[] fields;
+               MemberStructure[] methods;
+       }
+       
+       private static class MemberStructure {
+               char[] name;
+               int modifiers;
+               char[] signature;
+       }
 }
index 8d00916d87aada89a21b2e9e11880aa0c138462b..11524e9e8465fa08d9f90834fc6dae5c7feb8c5a 100644 (file)
 package org.aspectj.ajdt.internal.core.builder;
 
 //import java.util.HashMap;
+import java.io.File;
+import java.io.IOException;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
 
-import org.aspectj.weaver.bcel.UnwovenClassFile;
 import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation;
 import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
 import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
 import org.aspectj.org.eclipse.jdt.internal.compiler.env.INameEnvironment;
 import org.aspectj.org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
+import org.aspectj.util.FileUtil;
 
 
 public class StatefulNameEnvironment implements INameEnvironment {
        private Map classesFromName;
+       private Map inflatedClassFilesCache;
        private Set packageNames;
        private INameEnvironment baseEnvironment;
        
        public StatefulNameEnvironment(INameEnvironment baseEnvironment, Map classesFromName) {
                this.classesFromName = classesFromName;
+               this.inflatedClassFilesCache = new HashMap();
                this.baseEnvironment = baseEnvironment;
                
                packageNames = new HashSet();
@@ -60,18 +65,29 @@ public class StatefulNameEnvironment implements INameEnvironment {
        }
 
        private NameEnvironmentAnswer findType(String name) {
-               UnwovenClassFile cf = (UnwovenClassFile)classesFromName.get(name);
-               //System.err.println("find: " + name + " found: " + cf);
-               
-               if (cf == null) return null;
-
-               try {
-                       //System.out.println("from cache: " + name);
-                       return new NameEnvironmentAnswer(
-                                       new ClassFileReader(cf.getBytes(), cf.getFilename().toCharArray()),
-                                       null /* no access restriction */);
-               } catch (ClassFormatException e) {
-                       return null; //!!! seems to match FileSystem behavior
+               if (this.inflatedClassFilesCache.containsKey(name)) {
+                       return (NameEnvironmentAnswer) this.inflatedClassFilesCache.get(name);
+               }
+               else {
+                       File fileOnDisk = (File)classesFromName.get(name);
+                       //System.err.println("find: " + name + " found: " + cf);
+                       
+                       if (fileOnDisk == null) return null;
+       
+                       try {
+                               //System.out.println("from cache: " + name);
+                               byte[] bytes = FileUtil.readAsByteArray(fileOnDisk);
+                               NameEnvironmentAnswer ret = 
+                                       new NameEnvironmentAnswer(
+                                               new ClassFileReader(bytes, fileOnDisk.getAbsolutePath().toCharArray()),
+                                               null /* no access restriction */);
+                               this.inflatedClassFilesCache.put(name,ret);
+                               return ret;
+                       } catch (ClassFormatException e) {
+                               return null; //!!! seems to match FileSystem behavior
+                       } catch (IOException ex) {
+                               return null; // see above...
+                       }
                }
        }