diff options
author | aclement <aclement> | 2006-05-11 07:29:59 +0000 |
---|---|---|
committer | aclement <aclement> | 2006-05-11 07:29:59 +0000 |
commit | ac4db735b6f4d5b7d17f0b8d093b63b910c704bd (patch) | |
tree | f1e4e90cc55710c448de163f2d1c2c9e18fffee4 /asm/src | |
parent | c010978b54cf6f95d913ae6dc7b1107ea8f24647 (diff) | |
download | aspectj-ac4db735b6f4d5b7d17f0b8d093b63b910c704bd.tar.gz aspectj-ac4db735b6f4d5b7d17f0b8d093b63b910c704bd.zip |
134471 - incremental structure model repair code overhaul - different strategy for tidying up relationships.
Diffstat (limited to 'asm/src')
-rw-r--r-- | asm/src/org/aspectj/asm/AsmManager.java | 483 |
1 files changed, 370 insertions, 113 deletions
diff --git a/asm/src/org/aspectj/asm/AsmManager.java b/asm/src/org/aspectj/asm/AsmManager.java index bc63e881b..cd4051915 100644 --- a/asm/src/org/aspectj/asm/AsmManager.java +++ b/asm/src/org/aspectj/asm/AsmManager.java @@ -466,6 +466,28 @@ public class AsmManager { } } + private void dumprelsStderr(String key) { + System.err.println("Relationships dump follows: "+key); + IRelationshipMap irm = AsmManager.getDefault().getRelationshipMap(); + int ctr = 1; + Set entries = irm.getEntries(); + for (Iterator iter = entries.iterator(); iter.hasNext();) { + String hid = (String) iter.next(); + List rels = irm.get(hid); + for (Iterator iterator = rels.iterator(); iterator.hasNext();) { + IRelationship ir = (IRelationship) iterator.next(); + List targets = ir.getTargets(); + for (Iterator iterator2 = targets.iterator(); + iterator2.hasNext(); + ) { + String thid = (String) iterator2.next(); + System.err.println("Hid:"+(ctr++)+":(targets="+targets.size()+") "+hid+" ("+ir.getName()+") "+thid); + } + } + } + System.err.println("End of relationships dump for: "+key); + } + //===================== DELTA PROCESSING CODE ============== start ==========// // XXX shouldn't be aware of the delimiter @@ -473,6 +495,42 @@ public class AsmManager { return hid.substring(0,hid.indexOf("|")); } + /** + * Removes the hierarchy structure for the specified files from the structure model. + * Returns true if it deleted anything + */ + public boolean removeStructureModelForFiles(Writer fw,Collection files) throws IOException { + + IHierarchy model = AsmManager.getDefault().getHierarchy(); + + boolean modelModified = false; + + Set deletedNodes = new HashSet(); + for (Iterator iter = files.iterator(); iter.hasNext();) { + File fileForCompilation = (File) iter.next(); + String correctedPath = AsmManager.getDefault().getCanonicalFilePath(fileForCompilation); + IProgramElement progElem = (IProgramElement)model.findInFileMap(correctedPath); + if (progElem!=null) { + // Found it, let's remove it + if (dumpDeltaProcessing) { + fw.write("Deleting "+progElem+" node for file "+fileForCompilation+"\n"); + } + removeNode(progElem); + deletedNodes.add(getFilename(progElem.getHandleIdentifier())); + if (!model.removeFromFileMap(correctedPath.toString())) + throw new RuntimeException("Whilst repairing model, couldn't remove entry for file: "+correctedPath.toString()+" from the filemap"); + modelModified = true; + } + } + if (modelModified) model.updateHandleMap(deletedNodes); + return modelModified; + } + + private void flushModelCache() { + IHierarchy model = AsmManager.getDefault().getHierarchy(); + model.flushTypeMap(); + } + // This code is *SLOW* but it isnt worth fixing until we address the // bugs in binary weaving. public void fixupStructureModel(Writer fw,List filesToBeCompiled,Set files_added,Set files_deleted) throws IOException { @@ -512,7 +570,8 @@ public class AsmManager { } } - public void processDelta(List filesToBeCompiled,Set files_added,Set files_deleted) { + + public void processDelta(List files_tobecompiled,Set files_added,Set files_deleted) { try { Writer fw = null; @@ -522,148 +581,346 @@ public class AsmManager { FileWriter filew = new FileWriter(dumpFilename,true); fw = new BufferedWriter(filew); fw.write("=== Processing delta changes for the model ===\n"); - fw.write("Files for compilation:#"+filesToBeCompiled.size()+":"+filesToBeCompiled+"\n"); + fw.write("Files for compilation:#"+files_tobecompiled.size()+":"+files_tobecompiled+"\n"); fw.write("Files added :#"+files_added.size()+":"+files_added+"\n"); fw.write("Files deleted :#"+files_deleted.size()+":"+files_deleted+"\n"); } long stime = System.currentTimeMillis(); - fixupStructureModel(fw,filesToBeCompiled,files_added,files_deleted); + boolean modificationOccurred = false; + //fixupStructureModel(fw,filesToBeCompiled,files_added,files_deleted); + // Let's remove all the files that are deleted on this compile + modificationOccurred = + removeStructureModelForFiles(fw,files_deleted) | + modificationOccurred; long etime1 = System.currentTimeMillis(); // etime1-stime = time to fix up the model - IHierarchy model = AsmManager.getDefault().getHierarchy(); + repairRelationships(fw); + long etime2 = System.currentTimeMillis(); // etime2-stime = time to repair the relationship map + + modificationOccurred = + removeStructureModelForFiles(fw,files_tobecompiled) | + modificationOccurred; + + if (dumpDeltaProcessing) { + fw.write("===== Delta Processing timing ==========\n"); + fw.write("Hierarchy="+(etime1-stime)+"ms Relationshipmap="+(etime2-etime1)+"ms\n"); + fw.write("===== Traversal ========================\n"); +// fw.write("Source handles processed="+srchandlecounter+"\n"); +// fw.write("Target handles processed="+tgthandlecounter+"\n"); + fw.write("========================================\n"); + fw.flush();fw.close(); - // Some of this code relies on the fact that relationships are always in pairs, so you know - // if you are the target of a relationship because you are also the source of a relationship - // This seems a valid assumption for now... + } + reportModelInfo("After delta processing"); + } catch (IOException e) { + e.printStackTrace(); + } + + } + + /** + * two kinds of relationships + * + * A affects B + * B affectedBy A + * + * Both of these relationships are added when 'B' is modified. Concrete examples are + * 'advises/advisedby' or 'annotates/annotatedby'. + * + * What we need to do is when 'B' is going to be woven, remove all relationships that may + * reoccur when it is woven. + * So - remove 'affects' relationships where the target is 'B', remove all 'affectedBy' + * relationships where the source is 'B'. + * + */ + public void removeRelationshipsTargettingThisType(String typename) { + boolean debug=false; + if (debug) System.err.println(">>removeRelationshipsTargettingThisType "+typename); + String pkg = null; + String type= typename; + int lastSep = typename.lastIndexOf('.'); + if (lastSep != -1) { + pkg = typename.substring(0,lastSep); + type= typename.substring(lastSep+1); + } + boolean didsomething=false; + IProgramElement typeNode = hierarchy.findElementForType(pkg,type); - //TODO Speed this code up by making this assumption: - // the only piece of the handle that is interesting is the file name. We are working at file granularity, if the - // file does not exist (i.e. its not in the filemap) then any handle inside that file cannot exist. - if (dumpDeltaProcessing) fw.write("Repairing relationships map:\n"); + // Reasons for that being null: + // 1. the file has fundamental errors and so doesn't exist in the model (-proceedOnError probably forced us to weave) + if (typeNode == null) return; + + Set sourcesToRemove = new HashSet(); + + // Iterate over the source handles in the relationships map, the aim here is to remove any 'affected by' + // relationships where the source of the relationship is the specified type (since it will be readded + // when the type is woven) + Set sourcehandlesSet = mapper.getEntries(); + List relationshipsToRemove = new ArrayList(); + for (Iterator keyiter = sourcehandlesSet.iterator(); keyiter.hasNext();) { + String hid = (String) keyiter.next(); + IProgramElement sourceElement = hierarchy.getElement(hid); + if (sourceElement == null || sameType(hid,sourceElement,typeNode)) { + // worth continuing as there may be a relationship to remove + relationshipsToRemove.clear(); + List relationships = mapper.get(hid); + for (Iterator reliter = relationships.iterator();reliter.hasNext();) { + IRelationship rel = (IRelationship) reliter.next(); + if (rel.getKind()==IRelationship.Kind.USES_POINTCUT) continue; // these relationships are added at compile time, argh + if (rel.isAffects()) continue; // we want 'affected by' relationships - (e.g. advised by) + relationshipsToRemove.add(rel); // all the relationships can be removed, regardless of the target(s) + } + // Now, were any relationships emptied during that processing and so need removing for this source handle + if (relationshipsToRemove.size()>0) { + didsomething=true; + if (relationshipsToRemove.size() == relationships.size()) sourcesToRemove.add(hid); + else { + for (int i = 0 ;i<relationshipsToRemove.size();i++) + relationships.remove(relationshipsToRemove.get(i)); + } + } + } + } +// Remove sources that have no valid relationships any more + for (Iterator srciter = sourcesToRemove.iterator(); srciter.hasNext();) { + String hid = (String) srciter.next(); +// System.err.println(" source handle: all relationships have gone for "+hid); + mapper.removeAll(hid); + IProgramElement ipe = hierarchy.getElement(hid); + if (ipe!=null) { + // If the relationship was hanging off a 'code' node, delete it. + if (ipe.getKind().equals(IProgramElement.Kind.CODE)) { + if (debug) System.err.println(" source handle: it was code node, removing that as well... code="+ipe+" parent="+ipe.getParent()); + removeSingleNode(ipe); + } + } + } - // Now sort out the relationships map - IRelationshipMap irm = AsmManager.getDefault().getRelationshipMap(); - Set sourcesToRemove = new HashSet(); - Set nonExistingHandles = new HashSet(); // Cache of handles that we *know* are invalid - int srchandlecounter = 0; - int tgthandlecounter = 0; - + if (debug) dumprelsStderr("after processing 'affectedby'"); + if (didsomething) { // did we do anything? + sourcesToRemove.clear(); + // removing 'affects' relationships + if (debug) dumprelsStderr("before processing 'affects'"); // Iterate over the source handles in the relationships map - Set keyset = irm.getEntries(); // These are source handles - for (Iterator keyiter = keyset.iterator(); keyiter.hasNext();) { - String hid = (String) keyiter.next(); - srchandlecounter++; - - // Do we already know this handle points to nowhere? - if (nonExistingHandles.contains(hid)) { - sourcesToRemove.add(hid); - } else { - // We better check if it actually exists - IProgramElement existingElement = model.getElement(hid); - if (dumpDeltaProcessing) fw.write("Looking for handle ["+hid+"] in model, found: "+existingElement+"\n"); - - // Did we find it? - if (existingElement == null) { - // No, so delete this relationship - sourcesToRemove.add(hid); - nonExistingHandles.add(hid); // Speed up a bit you swine - } else { - // Ok, so the source is valid, what about the targets? - List relationships = irm.get(hid); - List relationshipsToRemove = new ArrayList(); - // Iterate through the relationships against this source handle - for (Iterator reliter = relationships.iterator();reliter.hasNext();) { - IRelationship rel = (IRelationship) reliter.next(); - List targets = rel.getTargets(); - List targetsToRemove = new ArrayList(); + sourcehandlesSet = mapper.getEntries(); + for (Iterator keyiter = sourcehandlesSet.iterator(); keyiter.hasNext();) { + String hid = (String) keyiter.next(); + IProgramElement sourceElement = hierarchy.getElement(hid); + + relationshipsToRemove.clear(); + List relationships = mapper.get(hid); + for (Iterator reliter = relationships.iterator();reliter.hasNext();) { + IRelationship rel = (IRelationship) reliter.next(); + if (rel.getKind()==IRelationship.Kind.USES_POINTCUT) continue; // these relationships are added at compile time, argh + if (!rel.isAffects()) continue; + List targets = rel.getTargets(); + List targetsToRemove = new ArrayList(); - // Iterate through the targets for this relationship - for (Iterator targetIter = targets.iterator();targetIter.hasNext();) { - String targethid = (String) targetIter.next(); - tgthandlecounter++; - // Do we already know it doesn't exist? - if (nonExistingHandles.contains(targethid)) { - if (dumpDeltaProcessing) fw.write("Target handle ["+targethid+"] for srchid["+hid+"]rel["+rel.getName()+"] does not exist\n"); - targetsToRemove.add(targethid); - } else { - // We better check - IProgramElement existingTarget = model.getElement(targethid); - if (existingTarget == null) { - if (dumpDeltaProcessing) fw.write("Target handle ["+targethid+"] for srchid["+hid+"]rel["+rel.getName()+"] does not exist\n"); - targetsToRemove.add(targethid); - nonExistingHandles.add(targethid); - } - } - } - - // Do we have some targets that need removing? - if (targetsToRemove.size()!=0) { - // Are we removing *all* of the targets for this relationship (i.e. removing the relationship) - if (targetsToRemove.size()==targets.size()) { - if (dumpDeltaProcessing) fw.write("No targets remain for srchid["+hid+"] rel["+rel.getName()+"]: removing it\n"); - relationshipsToRemove.add(rel); - } else { - // Remove all the targets that are no longer valid - for (Iterator targsIter = targetsToRemove.iterator();targsIter.hasNext();) { - String togo = (String) targsIter.next(); - targets.remove(togo); - } - // Should have already been caught above, but lets double check ... - if (targets.size()==0) { - if (dumpDeltaProcessing) fw.write("No targets remain for srchid["+hid+"] rel["+rel.getName()+"]: removing it\n"); - relationshipsToRemove.add(rel); // TODO Should only remove this relationship for the srchid? - } - } - } - } - // Now, were any relationships emptied during that processing and so need removing for this source handle - if (relationshipsToRemove.size()>0) { - // Are we removing *all* of the relationships for this source handle? - if (relationshipsToRemove.size() == relationships.size()) { - // We know they are all going to go, so just delete the source handle. - sourcesToRemove.add(hid); - } else { - for (int i = 0 ;i<relationshipsToRemove.size();i++) { - IRelationship irel = (IRelationship)relationshipsToRemove.get(i); - verifyAssumption(irm.remove(hid,irel),"Failed to remove relationship "+irel.getName()+" for shid "+hid); - } - List rels = irm.get(hid); - if (rels==null || rels.size()==0) sourcesToRemove.add(hid); - } + // find targets that target the type we are interested in, they need removing + for (Iterator targetsIter = targets.iterator(); targetsIter.hasNext();) { + String targethid = (String) targetsIter.next(); + // Does this point to the same type? + IProgramElement existingTarget = hierarchy.getElement(targethid); + if (existingTarget == null || sameType(targethid,existingTarget,typeNode)) targetsToRemove.add(targethid); + } + + if (targetsToRemove.size()!=0) { + if (targetsToRemove.size()==targets.size()) relationshipsToRemove.add(rel); + else { + // Remove all the targets that are no longer valid + for (Iterator targsIter = targetsToRemove.iterator();targsIter.hasNext();) { + String togo = (String) targsIter.next(); + targets.remove(togo); + } } } } + // Now, were any relationships emptied during that processing and so need removing for this source handle + if (relationshipsToRemove.size()>0) { + // Are we removing *all* of the relationships for this source handle? + if (relationshipsToRemove.size() == relationships.size()) sourcesToRemove.add(hid); + else { + for (int i = 0 ;i<relationshipsToRemove.size();i++) + relationships.remove(relationshipsToRemove.get(i)); + } + } } // Remove sources that have no valid relationships any more for (Iterator srciter = sourcesToRemove.iterator(); srciter.hasNext();) { String hid = (String) srciter.next(); - irm.removeAll(hid); - IProgramElement ipe = model.getElement(hid); + // System.err.println(" source handle: all relationships have gone for "+hid); + mapper.removeAll(hid); + IProgramElement ipe = hierarchy.getElement(hid); if (ipe!=null) { // If the relationship was hanging off a 'code' node, delete it. if (ipe.getKind().equals(IProgramElement.Kind.CODE)) { + if (debug) System.err.println(" source handle: it was code node, removing that as well... code="+ipe+" parent="+ipe.getParent()); removeSingleNode(ipe); } } } - long etime2 = System.currentTimeMillis(); // etime2-stime = time to repair the relationship map - if (dumpDeltaProcessing) { - fw.write("===== Delta Processing timing ==========\n"); - fw.write("Hierarchy="+(etime1-stime)+"ms Relationshipmap="+(etime2-etime1)+"ms\n"); - fw.write("===== Traversal ========================\n"); - fw.write("Source handles processed="+srchandlecounter+"\n"); - fw.write("Target handles processed="+tgthandlecounter+"\n"); - fw.write("========================================\n"); - fw.flush();fw.close(); - } - reportModelInfo("After delta processing"); - } catch (IOException e) { - e.printStackTrace(); + if (debug) dumprelsStderr("after processing 'affects'"); + } + + if (debug) System.err.println("<<removeRelationshipsTargettingThisFile"); + } + + /** + * Return true if the target element is in the type specified. + */ + private boolean sameType(String hid,IProgramElement target, IProgramElement type) { + IProgramElement containingType = target; + if (target==null) + throw new RuntimeException("target can't be null!"); + if (type==null) + throw new RuntimeException("type can't be null!"); + if (target.getKind().isSourceFile()) { + // @AJ aspect with broken relationship endpoint - we couldn't find the real + // endpoint (the declare parents or ITD or similar) so defaulted to the + // first line of the source file... + + // FRAGILE + // Let's assume the worst, and that it is the same type if the source files + // are the same. This will break for multiple top level types in a file... + if (target.getSourceLocation()==null) return false; // these four possibilities should really be FIXED so we don't have this situation + if (type.getSourceLocation()==null) return false; + if (target.getSourceLocation().getSourceFile()==null) return false; + if (type.getSourceLocation().getSourceFile()==null) return false; + return (target.getSourceLocation().getSourceFile().equals(type.getSourceLocation().getSourceFile())); } + while (!containingType.getKind().isType()) { +// System.err.println("Checked: "+containingType.getKind()+" "+containingType); + containingType = containingType.getParent(); + } + return (type.equals(containingType)); + } + /** + * Go through all the relationships in the model, if any endpoints no longer exist (the node it + * points to has been deleted from the model) then delete the relationship. + */ + private void repairRelationships(Writer fw) { + try { + IHierarchy model = AsmManager.getDefault().getHierarchy(); + //TODO Speed this code up by making this assumption: + // the only piece of the handle that is interesting is the file name. We are working at file granularity, if the + // file does not exist (i.e. its not in the filemap) then any handle inside that file cannot exist. + if (dumpDeltaProcessing) fw.write("Repairing relationships map:\n"); + + // Now sort out the relationships map + IRelationshipMap irm = AsmManager.getDefault().getRelationshipMap(); + Set sourcesToRemove = new HashSet(); + Set nonExistingHandles = new HashSet(); // Cache of handles that we *know* are invalid + int srchandlecounter = 0; + int tgthandlecounter = 0; + + // Iterate over the source handles in the relationships map + Set keyset = irm.getEntries(); // These are source handles + for (Iterator keyiter = keyset.iterator(); keyiter.hasNext();) { + String hid = (String) keyiter.next(); + srchandlecounter++; + + // Do we already know this handle points to nowhere? + if (nonExistingHandles.contains(hid)) { + sourcesToRemove.add(hid); + } else { + // We better check if it actually exists + IProgramElement existingElement = model.getElement(hid); + if (dumpDeltaProcessing) fw.write("Looking for handle ["+hid+"] in model, found: "+existingElement+"\n"); + + // Did we find it? + if (existingElement == null) { + // No, so delete this relationship + sourcesToRemove.add(hid); + nonExistingHandles.add(hid); // Speed up a bit you swine + } else { + // Ok, so the source is valid, what about the targets? + List relationships = irm.get(hid); + List relationshipsToRemove = new ArrayList(); + // Iterate through the relationships against this source handle + for (Iterator reliter = relationships.iterator();reliter.hasNext();) { + IRelationship rel = (IRelationship) reliter.next(); + List targets = rel.getTargets(); + List targetsToRemove = new ArrayList(); + + // Iterate through the targets for this relationship + for (Iterator targetIter = targets.iterator();targetIter.hasNext();) { + String targethid = (String) targetIter.next(); + tgthandlecounter++; + // Do we already know it doesn't exist? + if (nonExistingHandles.contains(targethid)) { + if (dumpDeltaProcessing) fw.write("Target handle ["+targethid+"] for srchid["+hid+"]rel["+rel.getName()+"] does not exist\n"); + targetsToRemove.add(targethid); + } else { + // We better check + IProgramElement existingTarget = model.getElement(targethid); + if (existingTarget == null) { + if (dumpDeltaProcessing) fw.write("Target handle ["+targethid+"] for srchid["+hid+"]rel["+rel.getName()+"] does not exist\n"); + targetsToRemove.add(targethid); + nonExistingHandles.add(targethid); + } + } + } + + // Do we have some targets that need removing? + if (targetsToRemove.size()!=0) { + // Are we removing *all* of the targets for this relationship (i.e. removing the relationship) + if (targetsToRemove.size()==targets.size()) { + if (dumpDeltaProcessing) fw.write("No targets remain for srchid["+hid+"] rel["+rel.getName()+"]: removing it\n"); + relationshipsToRemove.add(rel); + } else { + // Remove all the targets that are no longer valid + for (Iterator targsIter = targetsToRemove.iterator();targsIter.hasNext();) { + String togo = (String) targsIter.next(); + targets.remove(togo); + } + // Should have already been caught above, but lets double check ... + if (targets.size()==0) { + if (dumpDeltaProcessing) fw.write("No targets remain for srchid["+hid+"] rel["+rel.getName()+"]: removing it\n"); + relationshipsToRemove.add(rel); // TODO Should only remove this relationship for the srchid? + } + } + } + } + // Now, were any relationships emptied during that processing and so need removing for this source handle + if (relationshipsToRemove.size()>0) { + // Are we removing *all* of the relationships for this source handle? + if (relationshipsToRemove.size() == relationships.size()) { + // We know they are all going to go, so just delete the source handle. + sourcesToRemove.add(hid); + } else { + // MEMORY LEAK - we don't remove the relationships !! + for (int i = 0 ;i<relationshipsToRemove.size();i++) { + IRelationship irel = (IRelationship)relationshipsToRemove.get(i); + verifyAssumption(irm.remove(hid,irel),"Failed to remove relationship "+irel.getName()+" for shid "+hid); + } + List rels = irm.get(hid); + if (rels==null || rels.size()==0) sourcesToRemove.add(hid); + } + } + } + } + } + // Remove sources that have no valid relationships any more + for (Iterator srciter = sourcesToRemove.iterator(); srciter.hasNext();) { + String hid = (String) srciter.next(); + irm.removeAll(hid); + IProgramElement ipe = model.getElement(hid); + if (ipe!=null) { + // If the relationship was hanging off a 'code' node, delete it. + if (ipe.getKind().equals(IProgramElement.Kind.CODE)) { + //System.err.println("Deleting code node"); + removeSingleNode(ipe); + } + } + } + } catch (IOException ioe) { + System.err.println("Failed to repair relationships:"); + ioe.printStackTrace(); + } } /** |