diff --git a/src/jastadd/incremental/IncrementalDDG.jadd b/src/jastadd/incremental/IncrementalDDG.jadd index 1470b385c6aafe42773569ca4789cf43a8143c26..86ef22b24c8891b0306a47e9093cf371e8d1f4e9 100644 --- a/src/jastadd/incremental/IncrementalDDG.jadd +++ b/src/jastadd/incremental/IncrementalDDG.jadd @@ -36,6 +36,25 @@ aspect IncrementalDDG { tt.expand("Grammar.emitDDGNode", out); } + /** + * Generate DDG cleanup methods, + * + * Methods: cleanupDependants, cleanupDependantsInTree + * + * After introducing single direction edges in the DDG flushed (emptied) + * dependants (or listeners) may remain in the DDG. The purpose of these + * methods is to clean up such dependants. + */ + public void ASTDecl.genIncrementalCleanup(PrintWriter out) { + if (!config().incremental()) return; + TemplateContext tt = templateContext(); + tt.bind("CleanupTokenDependants", genCleanupTokenDependantsString()); + tt.bind("CleanupAttributeDependants", genCleanupAttributeDependantsString()); + tt.expand("ASTDecl.cleanupDependantsMethod", out); + tt.bind("CleanupDependantsInNTAs", genCleanupDependantsInNTAsString()); + tt.expand("ASTDecl.cleanupDependantsInTreeMethod", out); + } + /** * Generate DDG nodes for storage that needs dependency tracking in an AST node. * The number of DDG nodes needed depend on the incremental configuration: @@ -120,6 +139,57 @@ aspect IncrementalDDG { tt.expand("ASTDecl.incrementalCopyHandlerMethod", out); } + /** + * Generate string with code for cleaning up dependants in NTAs. + */ + public String ASTDecl.genCleanupDependantsInNTAsString() { + StringBuffer res = new StringBuffer(); + TemplateContext tt = templateContext(); + for (AttrDecl attr : listOfCachedAttributes()) { + if ((attr.isNTA() || attr.getNTA()) && !attr.isPrimitive() && + !(attr.type().equals("String") || attr.type().equals("java.lang.String"))) { + tt.bind("IsParameterized", attr.getNumParameter() > 0); + tt.bind("AttrSign", attr.signature()); + res.append(tt.expand("ASTDecl.checkAndCleanupNTADependants")); + } + } + return res.toString(); + } + + /** + * Generate string with code for cleaning up dependants. + */ + public String ASTDecl.genCleanupAttributeDependantsString() { + StringBuffer res = new StringBuffer(); + TemplateContext tt = templateContext(); + // Add dump string for each attribute + for (AttrDecl attr : listOfCachedAttributes()) { + tt.bind("IsParameterized", attr.getNumParameter() > 0); + tt.bind("IsNTA", (attr.isNTA() || attr.getNTA()) && !attr.isPrimitive() && + !(attr.type().equals("String") || attr.type().equals("java.lang.String"))); + tt.bind("AttrSign", attr.signature()); + res.append(tt.expand("ASTDecl.checkAndCleanupAttributeDependants")); + } + return res.toString(); + } + + /** + * Generate string with code for cleaning up token dependants. + */ + public String ASTDecl.genCleanupTokenDependantsString() { + StringBuffer res = new StringBuffer(); + TemplateContext tt = templateContext(); + if (config().incrementalLevelParam() || config().incrementalLevelAttr()) { + for (Component c : components()) { + if (c instanceof TokenComponent && !c.isNTA()) { + tt.bind("Id", ((TokenComponent)c).getTokenId().getID()); + res.append(tt.expand("ASTDecl.checkAndCleanupTokenDependants")); + } + } + } + return res.toString(); + } + /** * Emit string for copying of token DDG nodes in a node. */ diff --git a/src/jastadd/incremental/IncrementalEval.jadd b/src/jastadd/incremental/IncrementalEval.jadd index 53ad4e55f7c41213b26047c13138ba3f1c21d5a7..be4e8845476621c4e9d3b858281ca1a774d0aee8 100644 --- a/src/jastadd/incremental/IncrementalEval.jadd +++ b/src/jastadd/incremental/IncrementalEval.jadd @@ -48,6 +48,7 @@ aspect IncrementalEval { genIncrementalNotification(out); genIncrementalState(out); genIncrementalRegions(out); + genIncrementalCleanup(out); genIncrementalDebug(out); } diff --git a/src/template/incremental/DDGNode.tt b/src/template/incremental/DDGNode.tt index 94781fe1d5f5ce4491058e26e26e956f98eae356..e2d8fdd1a6fcde630c5e7e49353ad678dbba41d1 100644 --- a/src/template/incremental/DDGNode.tt +++ b/src/template/incremental/DDGNode.tt @@ -185,7 +185,6 @@ $endif // Dependency management public java.util.HashSet<$DDGNodeName> fListenerSet = new java.util.HashSet<$DDGNodeName>(4); - public java.util.HashSet<$DDGNodeName> fDependencySet = new java.util.HashSet<$DDGNodeName>(4); public boolean hasDependants() { return !fListenerSet.isEmpty(); @@ -193,33 +192,24 @@ $endif public void addDependant($DDGNodeName node) { fListenerSet.add(node); - node.addDependency(this); } public void removeDependant($DDGNodeName node) { fListenerSet.remove(node); } - public void clearDependants() { - for ($DDGNodeName node : fListenerSet) { - node.removeDependency(this); - } - fListenerSet.clear(); - } - - public void clearDependencies() { - for ($DDGNodeName node : fDependencySet) { - node.removeDependant(this); + public void cleanupDependants() { + java.util.Iterator<$DDGNodeName> itr = fListenerSet.iterator(); + while (itr.hasNext()) { + $DDGNodeName node = itr.next(); + if (node.isEmpty() || node.isGarbage()) { + itr.remove(); + } } - fDependencySet.clear(); - } - - public void addDependency($DDGNodeName node) { - fDependencySet.add(node); } - public void removeDependency($DDGNodeName node) { - fDependencySet.remove(node); + public void clearDependants() { + fListenerSet.clear(); } /* @@ -233,26 +223,10 @@ $endif this.addDependant(l); } } - node.clearDependencies(); node.clearDependants(); node.throwAway(); } - /* - * Transfers dependencies from another handler, used in rewrites. - */ - public void transferDependenciesFrom($DDGNodeName node) { - if (node == null || this == node) - return; - for ($DDGNodeName l : node.fDependencySet) { - l.addDependant(this); - } -$if (IncrementalPropLimit) - setCacheInDependent(node.cacheInDependent); -$endif - node.clearDependencies(); - } - // Notification private boolean visited = false; @@ -267,7 +241,6 @@ $endif if (!node.isGarbage()) { node.dependencyChanged(); } - node.removeDependency(this); } visited = false; } @@ -287,15 +260,7 @@ $if (IncrementalPropLimit) if (noCacheRead && !fNode.inc_valueAffected(fAttrID, fParams)) { } else { $endif - if (!fDependencySet.isEmpty()) { - // Remove dependencies - java.util.HashSet<$DDGNodeName> k = fDependencySet; - fDependencySet = new java.util.HashSet<$DDGNodeName>(4); - for ($DDGNodeName node : k) { - node.removeDependant(this); - } - fNode.reactToDependencyChange(fAttrID, fParams); - } + fNode.reactToDependencyChange(fAttrID, fParams); $if (IncrementalPropLimit) } $endif @@ -361,6 +326,10 @@ $endif return fState == $ASTNode.inc_COMPUTED; } + public boolean isEmpty() { + return fState == $ASTNode.inc_EMPTY; + } + $if (IncrementalDebug) // Debugging @@ -555,3 +524,111 @@ $if (IncrementalLevelParam) getChild_handler = new $DDGNodeName[children.length]; $endif ]] + +# Generate code for cleanup dependants method. +ASTDecl.cleanupDependantsMethod = [[ +private boolean #name.inc_cleanupDependants_visited = false; +public void #name.cleanupDependants() { + if (inc_cleanupDependants_visited) { + return; + } + inc_cleanupDependants_visited = true; +$if (#isASTNodeDecl) +$if (IncrementalLevelParam) + getParent_handler.cleanupDependants(); + numChildren_handler.cleanupDependants(); + for (int k = 0; getChild_handler != null && k < getChild_handler.length; k++) { + if (getChild_handler[k] != null) { + getChild_handler[k].cleanupDependants(); + } + } +$endif +$endif +$if (IncrementalLevelRegion) +$if (IsRegionRoot) + handler.cleanupDependants(); +$endif +$endif + $CleanupTokenDependants + $CleanupAttributeDependants +$if (!#isASTNodeDecl) +$if (IncrementalLevelRegion) +$if (!IsRegionRoot) + super.cleanupDependants(); +$endif +$else + super.cleanupDependants(); +$endif +$endif + inc_cleanupDependants_visited = false; +} +]] + +# Generate code for checking token handler and cleaning up dependants. +ASTDecl.checkAndCleanupTokenDependants = [[ +if (get$(Id)_handler != null) { + get$(Id)_handler.cleanupDependants(); +} +]] + +# Generate code for checking attribute handler and cleaning up dependants. +ASTDecl.checkAndCleanupAttributeDependants = [[ +$if (IncrementalLevelParam) +$if (IsParameterized) +for (java.util.Iterator itr = $(AttrSign)_handler.values().iterator(); itr.hasNext();) { + $DDGNodeName handler = ($DDGNodeName)itr.next(); + handler.cleanupDependants(); +} +$else +if ($(AttrSign)_handler != null) { + $(AttrSign)_handler.cleanupDependants(); +} +$endif +$if (IsNTA) +$if (IsParameterized) +if ($(AttrSign)_proxy != null) { + $(AttrSign)_proxy.cleanupDependants(); +} +$else +if ($(AttrSign)_computed && ($(AttrSign)_value instanceof $ASTNode)) { + $(AttrSign)_value.cleanupDependants(); +} +$endif +$endif +$endif +]] + +# Generate code for method cleanupDependantsInTree. +ASTDecl.cleanupDependantsInTreeMethod = [[ +private boolean #name.inc_cleanupDependantsInTree_visited = false; +public void #name.cleanupDependantsInTree() { + if (inc_cleanupDependantsInTree_visited) { + return; + } + inc_cleanupDependantsInTree_visited = true; + cleanupDependants(); + for (int i = 0; children != null && i < children.length; i++) { + $ASTNode child = children[i]; + if (child == null) { + continue; + } + child.cleanupDependantsInTree(); + } + $CleanupDependantsInNTAs + inc_cleanupDependantsInTree_visited = false; +} +]] + +# Generate string with code for cleaning up dependants in NTAs. +ASTDecl.checkAndCleanupNTADependants = [[ +$if (IsParameterized) +if ($(AttrSign)_proxy != null) { + $(AttrSign)_proxy.cleanupDependantsInTree(); +} +$else +if ($(AttrSign)_computed && ($(AttrSign)_value instanceof $ASTNode)) { + $(AttrSign)_value.cleanupDependantsInTree(); +} +$endif +]] +