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 {
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.
*/
......
......@@ -48,6 +48,7 @@ aspect IncrementalEval {
genIncrementalNotification(out);
genIncrementalState(out);
genIncrementalRegions(out);
genIncrementalCleanup(out);
genIncrementalDebug(out);
}
......
......@@ -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);
}
$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
]]
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment