All Downloads are FREE. Search and download functionalities are using the official Maven repository.

template.ast.State.tt Maven / Gradle / Ivy

There is a newer version: 2.3.6
Show newest version
# Copyright (c) 2013-2016, The JastAdd Team
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
#     * Redistributions of source code must retain the above copyright notice,
#       this list of conditions and the following disclaimer.
#     * Redistributions in binary form must reproduce the above copyright
#       notice, this list of conditions and the following disclaimer in the
#       documentation and/or other materials provided with the distribution.
#     * Neither the name of the Lund University nor the names of its
#       contributors may be used to endorse or promote products derived from
#       this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

ASTState = [[
/** Wrapper class for storing nullable attribute values. */
public class AttributeValue {
  /**
   * This singleton object is an illegal, unused, attribute value.
   * It represents that an attribute has not been memoized, or that
   * a circular attribute approximation has not been initialized.
   */
  public static final Object NONE = new Object();

  public final T value;

  public AttributeValue(T value) {
    this.value = value;
  }

  public static  boolean equals(AttributeValue v1, AttributeValue v2) {
    if (v1 == null || v2 == null) {
      return v1 == v2;
    } else {
      return equals(v1.value, v2.value);
    }
  }

  public static  boolean equals(V v1, V v2) {
    if (v1 == null || v2 == null) {
      return v1 == v2;
    } else {
      return v1 == v2 || v1.equals(v2);
    }
  }
}

$if(Concurrent)
/**
 * Tuple for storing attribute value and done flag.
 * 

Used in concurrent circular attribute evaluation. */ public class CircularAttributeValue { public volatile boolean done; public final AtomicReference value; public CircularAttributeValue() { this.value = new AtomicReference(AttributeValue.NONE); } public CircularAttributeValue(Object value) { this.value = new AtomicReference(value); } public boolean compareAndSet(Object expected, Object next) { return value.compareAndSet(expected, next); } public Object get() { return value.get(); } } $endif /** @apilevel internal */ public class $StateClass { /** * This class stores an attribute value tagged with an iteration ID for * a circular evaluation. * * @apilevel internal */ protected static class CircularValue { Object value; Cycle cycle; } /** * Instances of this class are used to uniquely identify circular evaluation iterations. * These iteration ID objects are created for each new fixed-point iteration in * a circular evaluation. * * @apilevel internal */ protected static class Cycle { } /** * The iteration ID used outside of circular evaluation. * *

This is the iteration ID when no circular evaluation is ongoing. */ public static final Cycle NON_CYCLE = new Cycle(); /** * Tracks the state of the current circular evaluation. This class defines a * stack structure where the next element on the stack is pointed to by the * {@code next} field. * * @apilevel internal */ protected static class CircleState { final CircleState next; $if(LegacyRewrite) boolean resetCycle = false; $endif boolean change = false; /** Evaluation depth of lazy attributes. */ int lazyAttribute = 0; $if(CacheCycle) boolean lastCycle = false; $endif $if(ComponentCheck) boolean completed = false; // Whether the circular evaluation has completed. $endif /** Cycle ID of the latest cycle in this circular evaluation. */ Cycle cycle = NON_CYCLE; $if(Concurrent) /** * Tracks attribute value observations during circular evaluation. * *

The purpose of this map is a little different when evaluating * a circular attribute and when evaluating a non-circular attribute * during a fixed-point evaluation. * For a circularly evaluated attribute, this map is only used to track * iteration IDs. For a non-circularly evaluated attribute, the map * stores thread-local attribute approximations. */ final java.util.Map observations; $endif protected CircleState(CircleState next) { this.next = next; $if(Concurrent) if (next != null) { observations = new java.util.IdentityHashMap(); } else { // The bottom observation map is immutable. // This makes it easier to detect if something breaks the rule of // not storing observations in the bottom state. observations = java.util.Collections.emptyMap(); } $endif } } $if(Concurrent) class Observation { public final Object value; public final Cycle cycle; public Observation(Object value, Cycle cycle) { this.value = value; this.cycle = cycle; } } $endif /** Sentinel circle state representing non-circular evaluation. */ private static final CircleState CIRCLE_BOTTOM = new CircleState(null); /** * Current circular state. * @apilevel internal */ private CircleState circle = CIRCLE_BOTTOM; /** @apilevel internal */ protected boolean inCircle() { return circle != CIRCLE_BOTTOM; } /** @apilevel internal */ protected boolean calledByLazyAttribute() { return circle.lazyAttribute > 0; } /** @apilevel internal */ protected void enterLazyAttribute() { circle.lazyAttribute += 1; } /** @apilevel internal */ protected void leaveLazyAttribute() { circle.lazyAttribute -= 1; } /** @apilevel internal */ protected void enterCircle() { CircleState next = new CircleState(circle); circle = next; } $if(Concurrent) /** * Store an attribute value and iteration index for an attribute. * *

This is used by memoized attributes during circular evaluation to store the thread-local * approximation tagged with the current iteration ID. */ public void observe(Object attributeId, Object value) { circle.observations.put(attributeId, new Observation(value, circle.cycle)); } /** * Update iteration ID for circular attribute. * *

Because circular attributes don't use the observed value, the observation value is * set to NONE. */ public void updateIteration(Object attributeId) { circle.observations.put(attributeId, new Observation(AttributeValue.NONE, circle.cycle)); } /** * Check if the stored iteration ID for the attribute is equal to the * current iteration id. * * @return {@code true} if the attribute was observed on the current cycle. */ public boolean observedInCycle(Object attributeId) { Observation observation = circle.observations.get(attributeId); return observation != null && observation.cycle == circle.cycle; } /** * Used by non-circularly evaluated attributes during fixed-point computation * to get the most recent approximation for the attribute. * * @return the last observed attribute value for the given attribute. */ public T lastObservedValue(Object attributeId) { Observation observation = circle.observations.get(attributeId); return observation == null ? null : (T) observation.value; } $endif /** * Maps circular attribute to last evaluated cycle index. * @apilevel internal */ private java.util.Map visited = new java.util.IdentityHashMap(); /** * Check if attribute was already visited during the current cycle. * @apilevel internal * @return {@code true} if the attribute was already visited. */ protected boolean checkAndSetVisited(Object attribute, int cycle) { boolean result = visited.containsKey(attribute) && visited.get(attribute) == cycle; visited.put(attribute, cycle); return result; } /** * Reset visited cycle tracking for this thread. * @apilevel internal */ protected void clearVisited() { visited.clear(); } // TODO(joqvist): may not be necessary. /** * Reset visit tracker for a single attribute. * @apilevel internal */ protected void resetVisited(Object attribute) { visited.remove(attribute); } /** @apilevel internal */ protected void leaveCircle() { $if(ComponentCheck) circle.completed = true; $endif circle = circle.next; } /** @apilevel internal */ protected Cycle nextCycle() { Cycle cycle = new Cycle(); circle.cycle = cycle; return cycle; } /** @apilevel internal */ protected Cycle cycle() { return circle.cycle; } /** @apilevel internal */ protected CircleState currentCircle() { return circle; } $if(ComponentCheck) /** * Throws a RuntimeException if called on a different circular evaluation * than the given circle state. * @apilevel internal */ protected void assertSameCircle(CircleState prev, String attribute) { if (prev != null && !prev.completed && prev != currentCircle()) { throw new RuntimeException(String.format("Circular definition of attribute %s.", attribute)); } } $endif /** @apilevel internal */ protected void setChangeInCycle() { circle.change = true; } /** @apilevel internal */ protected boolean testAndClearChangeInCycle() { boolean change = circle.change; circle.change = false; return change; } /** @apilevel internal */ protected boolean changeInCycle() { return circle.change; } $if(CacheCycle) /** @apilevel internal */ protected boolean lastCycle() { return circle.lastCycle; } /** @apilevel internal */ protected void startLastCycle() { circle.lastCycle = true; } $endif $if(LegacyRewrite) /** @apilevel internal */ protected void startResetCycle() { circle.resetCycle = true; } /** @apilevel internal */ protected boolean resetCycle() { return circle.resetCycle; } $endif protected $StateClass() { $if(ComponentCheck) circle.completed = true; $endif $if(LegacyRewrite) stack = new int[64]; pos = 0; $endif } $if(LegacyRewrite) /** @apilevel internal */ public static final int REWRITE_CHANGE = 1; /** @apilevel internal */ public static final int REWRITE_NOCHANGE = 2; /** @apilevel internal */ public static final int REWRITE_INTERRUPT = 3; public int boundariesCrossed = 0; // state code private int[] stack; private int pos; private void ensureSize(int size) { if (size < stack.length) { return; } int[] newStack = new int[stack.length * 2]; System.arraycopy(stack, 0, newStack, 0, stack.length); stack = newStack; } public void push(int i) { ensureSize(pos+1); stack[pos++] = i; } public int pop() { return stack[--pos]; } public int peek() { return stack[pos - 1]; } $endif $include(State.incHook) $if(TracingEnabled) public interface ReceiverFactory { Trace.Receiver build(); } public static ReceiverFactory receiverFactory = new ReceiverFactory() { public Trace.Receiver build() { return new Trace.Receiver() { public void accept($StateClass.Trace.Event event, $ASTNode node, String attribute, Object params, Object value) { } }; } }; private Trace trace = null; /** @return the tracer instance used for tracing attribute evaluation in this AST. */ public Trace trace() { if (trace == null) { trace = new Trace(receiverFactory.build()); } return trace; } $include(TraceClass) $endif $if(Concurrent) public static int NUM_THREADS = $NumThreads; /** State-global thread pool. */ private java.util.concurrent.ExecutorService threadPool = null; public synchronized java.util.concurrent.ExecutorService threadPool() { if (threadPool != null) { return threadPool; } else { threadPool = newDaemonThreadPool(NUM_THREADS); return threadPool; } } /** * Worker threads will shut down when the JVM stops, but this method can be called * to force them to stop prematurely. */ public synchronized void stopWorkers() { threadPool.shutdown(); threadPool = null; } /** Global thread pool. */ private static java.util.concurrent.ExecutorService globalThreadPool = null; public static java.util.concurrent.ExecutorService globalThreadPool() { synchronized ($StateClass.class) { if (globalThreadPool != null) { return globalThreadPool; } else { globalThreadPool = newDaemonThreadPool(NUM_THREADS); return globalThreadPool; } } } /** * Starts a thread pool with worker threads. The .shutdown() method should * be called once the work is finished, otherwise the worker threads prevent * Java VM from shutting down. */ public static java.util.concurrent.ExecutorService newThreadPool(int numThreads) { return java.util.concurrent.Executors.newFixedThreadPool(numThreads); } /** * Starts a thread pool with daemon worker threads. Daemon threads do not * prevent the Java VM from shutting down. */ public static java.util.concurrent.ExecutorService newDaemonThreadPool(int numThreads) { final java.util.concurrent.ThreadFactory threadFactory = java.util.concurrent.Executors.defaultThreadFactory(); return java.util.concurrent.Executors.newFixedThreadPool(numThreads, new java.util.concurrent.ThreadFactory() { @Override public Thread newThread(Runnable r) { Thread thread = threadFactory.newThread(r); thread.setDaemon(true); return thread; } }); } $endif } ]] ASTState.reset [[ /** @apilevel internal */ public void $StateClass.reset() { $SynchBegin // Reset circular evaluation state. circle = CIRCLE_BOTTOM; $if(LegacyRewrite) boundariesCrossed = 0; $endif $SynchEnd } ]]





© 2015 - 2024 Weber Informatics LLC | Privacy Policy