Skip to content
Snippets Groups Projects
Commit 3cdf9a92 authored by Emma Söderberg's avatar Emma Söderberg
Browse files

Removes double-linked DDG edges and adds DDG cleanup methods to incremental/param.

When removing the double-linked DDG edges, to only keep tracking of dependants, some
dependant sets will contain references to EMPTY or GARBAGE handlers. These entries
where previously cleaned up via the double-linked edges. The two added cleanup methods
allows for clean up of such remaining dependants for a node or a tree.

Tested on default tests and incremental/param.
parent 3f2c1fdb
No related branches found
No related tags found
No related merge requests found
...@@ -36,6 +36,25 @@ aspect IncrementalDDG { ...@@ -36,6 +36,25 @@ aspect IncrementalDDG {
tt.expand("Grammar.emitDDGNode", out); 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. * Generate DDG nodes for storage that needs dependency tracking in an AST node.
* The number of DDG nodes needed depend on the incremental configuration: * The number of DDG nodes needed depend on the incremental configuration:
...@@ -120,6 +139,57 @@ aspect IncrementalDDG { ...@@ -120,6 +139,57 @@ aspect IncrementalDDG {
tt.expand("ASTDecl.incrementalCopyHandlerMethod", out); 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. * Emit string for copying of token DDG nodes in a node.
*/ */
......
...@@ -48,6 +48,7 @@ aspect IncrementalEval { ...@@ -48,6 +48,7 @@ aspect IncrementalEval {
genIncrementalNotification(out); genIncrementalNotification(out);
genIncrementalState(out); genIncrementalState(out);
genIncrementalRegions(out); genIncrementalRegions(out);
genIncrementalCleanup(out);
genIncrementalDebug(out); genIncrementalDebug(out);
} }
......
...@@ -185,7 +185,6 @@ $endif ...@@ -185,7 +185,6 @@ $endif
// Dependency management // Dependency management
public java.util.HashSet<$DDGNodeName> fListenerSet = new java.util.HashSet<$DDGNodeName>(4); 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() { public boolean hasDependants() {
return !fListenerSet.isEmpty(); return !fListenerSet.isEmpty();
...@@ -193,33 +192,24 @@ $endif ...@@ -193,33 +192,24 @@ $endif
public void addDependant($DDGNodeName node) { public void addDependant($DDGNodeName node) {
fListenerSet.add(node); fListenerSet.add(node);
node.addDependency(this);
} }
public void removeDependant($DDGNodeName node) { public void removeDependant($DDGNodeName node) {
fListenerSet.remove(node); fListenerSet.remove(node);
} }
public void clearDependants() { public void cleanupDependants() {
for ($DDGNodeName node : fListenerSet) { java.util.Iterator<$DDGNodeName> itr = fListenerSet.iterator();
node.removeDependency(this); while (itr.hasNext()) {
} $DDGNodeName node = itr.next();
fListenerSet.clear(); if (node.isEmpty() || node.isGarbage()) {
} itr.remove();
public void clearDependencies() {
for ($DDGNodeName node : fDependencySet) {
node.removeDependant(this);
} }
fDependencySet.clear();
} }
public void addDependency($DDGNodeName node) {
fDependencySet.add(node);
} }
public void removeDependency($DDGNodeName node) { public void clearDependants() {
fDependencySet.remove(node); fListenerSet.clear();
} }
/* /*
...@@ -233,26 +223,10 @@ $endif ...@@ -233,26 +223,10 @@ $endif
this.addDependant(l); this.addDependant(l);
} }
} }
node.clearDependencies();
node.clearDependants(); node.clearDependants();
node.throwAway(); 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 // Notification
private boolean visited = false; private boolean visited = false;
...@@ -267,7 +241,6 @@ $endif ...@@ -267,7 +241,6 @@ $endif
if (!node.isGarbage()) { if (!node.isGarbage()) {
node.dependencyChanged(); node.dependencyChanged();
} }
node.removeDependency(this);
} }
visited = false; visited = false;
} }
...@@ -287,15 +260,7 @@ $if (IncrementalPropLimit) ...@@ -287,15 +260,7 @@ $if (IncrementalPropLimit)
if (noCacheRead && !fNode.inc_valueAffected(fAttrID, fParams)) { if (noCacheRead && !fNode.inc_valueAffected(fAttrID, fParams)) {
} else { } else {
$endif $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) $if (IncrementalPropLimit)
} }
$endif $endif
...@@ -361,6 +326,10 @@ $endif ...@@ -361,6 +326,10 @@ $endif
return fState == $ASTNode.inc_COMPUTED; return fState == $ASTNode.inc_COMPUTED;
} }
public boolean isEmpty() {
return fState == $ASTNode.inc_EMPTY;
}
$if (IncrementalDebug) $if (IncrementalDebug)
// Debugging // Debugging
...@@ -555,3 +524,111 @@ $if (IncrementalLevelParam) ...@@ -555,3 +524,111 @@ $if (IncrementalLevelParam)
getChild_handler = new $DDGNodeName[children.length]; getChild_handler = new $DDGNodeName[children.length];
$endif $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
]]
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment