diff --git a/ChangeLog b/ChangeLog index ec11c757d91f1bf84542ce4121cf10a37cdc4aca..de5ad71ae2c9c2d1f69589659d4dea06da837d35 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,12 @@ 2018-04-04 Jesper Öqvist <jesper.oqvist@cs.lth.se> * Fixed aliasing issue for parameterized NTAs in concurrent mode. + * Fixed race conditions for grammar-declared NTAs in concurrent mode. + See issue 291 and 292 on the issue tracker. + * Grammar-declared NTAs have been moved out of the child vector in + concurrent mode. + * Added a new internal helper method to ASTNode: + getChildNoTransformBase(). 2018-03-22 Jesper Öqvist <jesper.oqvist@cs.lth.se> diff --git a/src/jastadd/ast/JaddCodeGen.jrag b/src/jastadd/ast/JaddCodeGen.jrag index 96d09f14ba338e9631dc9f9c7dbfedef3162dae9..2f5a72f09506f475083fdb2610434ea334341244 100644 --- a/src/jastadd/ast/JaddCodeGen.jrag +++ b/src/jastadd/ast/JaddCodeGen.jrag @@ -105,6 +105,43 @@ aspect JaddCodeGen { return i; } + public void ASTDecl.emitConcurrentGetChild(PrintWriter out) { + // Build list of NTA indices. + String getNta = ""; + int numNta = 0; + int i = 0; + for (Component c : components()) { + if (c instanceof TokenComponent) { + // Tokens are not stored in the child array. + continue; + } + + String attrName = null; + if (c instanceof ListComponentNTA) { + attrName = "get" + c.name() + "List"; + } else if (c instanceof OptionalComponentNTA) { + attrName = "get" + c.name() + "Opt"; + } else if (c instanceof AggregateComponentNTA) { + attrName = "get" + c.name(); + } + + if (attrName != null) { + getNta += "case " + i + ":\n"; + getNta += " _value = " + attrName + "_value.get();\n"; + getNta += " break;\n"; + numNta += 1; + } + i += 1; + } + TemplateContext tt = templateContext(); + if (numNta > 0) { + tt.bind("GetNTAs", getNta); + tt.expand("ASTDecl.getChildNoTransform:concurrent", out); + } else { + tt.expand("ASTDecl.getChildNoTransform:concurrent:empty", out); + } + } + /** * Default constructor: creates list and opt nodes for * all list and opt children. Initializes NTAs. @@ -558,6 +595,14 @@ aspect JaddCodeGen { emitCopyNode(out); emitFullCopy(out); emitIsEqualMethods(out); + + if (config().concurrentEval() + && !isASTNodeDecl() + && !isOptDecl() + && !isListDecl()) { + emitConcurrentGetChild(out); + } + genIncremental(out); } diff --git a/src/jastadd/ast/JragCodeGen.jrag b/src/jastadd/ast/JragCodeGen.jrag index 4264d3aea553c503868e53cb608ad8ec4fa3add3..5f9e369a66619a7d4feac4996878fee1f9bda59e 100644 --- a/src/jastadd/ast/JragCodeGen.jrag +++ b/src/jastadd/ast/JragCodeGen.jrag @@ -731,7 +731,8 @@ aspect JragCodeGen { || attrName.equals(comp.name() + "Opt") && comp instanceof OptionalComponentNTA || attrName.equals(comp.name() + "List") && comp instanceof ListComponentNTA) { if (config().concurrentEval()) { - return "setChild(_result, get" + attrName + "ChildPosition());\n"; + // Only link result with parent. Child vector is not used for NTAs in concurrent mode. + return "_result.setParent(this);\n"; } else { return "setChild(" + signature() + "_value, get" + attrName + "ChildPosition());\n"; } diff --git a/src/template/ast/ASTNode.tt b/src/template/ast/ASTNode.tt index d687c5f230d056b4ed50bc58d21e3718df01261e..8a7037396672df0e655e5c74c6bc3e034d4c9a52 100644 --- a/src/template/ast/ASTNode.tt +++ b/src/template/ast/ASTNode.tt @@ -495,15 +495,18 @@ $endif ASTNode.getChildNoTransform [[ /** - * <p><em>This method does not invoke AST transformations.</em></p> + * Gets a child without triggering rewrites. * @apilevel low-level */ - $if(IncrementalEnabled) public T $ASTNode.getChildNoTransform(int i) { - // Must be able to override get child methods for incremental evaluation - $else - public final T $ASTNode.getChildNoTransform(int i) { - $endif + return getChildNoTransformBase(i); + } + + /** + * Directly accesses the child vector. + * @apilevel internal + */ + public T $ASTNode.getChildNoTransformBase(int i) { if (children == null) { return null; } diff --git a/src/template/concurrent/Attributes.tt b/src/template/concurrent/Attributes.tt index 849c98c9511daa937907e6771efef4463b831579..51905a5db0b67123f6699ef74262c9bd76f23f8f 100644 --- a/src/template/concurrent/Attributes.tt +++ b/src/template/concurrent/Attributes.tt @@ -1,4 +1,4 @@ -# Copyright (c) 2013-2017, The JastAdd Team +# Copyright (c) 2013-2018, The JastAdd Team # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -209,8 +209,17 @@ if (#(signature)_computed) { $else Object cached_value = #(signature)_value.get(); if (cached_value != AttributeValue.NONE) { - #boxedType _value = (#boxedType) cached_value; $include(AttrDecl.traceCacheRead) + #boxedType _value = (#boxedType) cached_value; + $if(#isAttrNTA)$if(RewriteEnabled) + if (_value != null && _value.mayHaveRewrite()) { + $ASTNode rewritten = _value.rewrittenNode(); + if (rewritten != _value) { + rewritten.setParent(this); + _value = (#boxedType) rewritten; + } + } + $endif$endif return _value; $endif $endif @@ -339,3 +348,24 @@ if (state.inCircle()) { $endif $endif ]] + +# Delegates child lookups to corresponding higher-order attributes. +ASTDecl.getChildNoTransform:concurrent [[ + public $ASTNode #name.getChildNoTransform(int i) { + Object _value = AttributeValue.NONE; + switch (i) { + $GetNTAs + } + if (_value != AttributeValue.NONE) { + return ($ASTNode) _value; + } + return super.getChildNoTransformBase(i); + } +]] + +ASTDecl.getChildNoTransform:concurrent:empty [[ + public $ASTNode #name.getChildNoTransform(int i) { + return super.getChildNoTransformBase(i); + } +]] +