/* * Javolution - Java(TM) Solution for Real-Time and Embedded Systems * Copyright (C) 2006 - Javolution (http://javolution.org/) * All rights reserved. * * Permission to use, copy, modify, and distribute this software is * freely granted, provided that this notice is preserved. */ package javolution.context; import java.lang.ThreadLocal; import javolution.lang.Configurable; import javolution.util.FastMap; import javolution.util.FastTable; /** * <p> This class represents a stack {@link AllocatorContext allocator context}; * (using thread-local pools or RTSJ <code>ScopedMemory</code>).</p> * * <p> Stacks allocations reduce heap memory allocation and often result in * faster execution time for almost all objects but the smallest one.</p> * * <p> Stack allocated objects should never be assigned to static members * (see {@link ImmortalContext}). Also, methods entering/exiting stack * contexts should ensure that stack allocated objects do not escape from * their context scope. If necessary, stack objects can be exported using * {@link #outerExecute} or {@link #outerCopy}:[code] * public class LargeInteger implements ValueType, Realtime { * public LargeInteger sqrt() { * StackContext.enter(); * try { * LargeInteger result = ZERO; * LargeInteger k = this.shiftRight(this.bitLength() / 2)); // First approximation. * while (true) { // Newton Iteration. * result = (k.plus(this.divide(k))).shiftRight(1); * if (result.equals(k)) return StackContext.outerCopy(result); // Exports result. * k = result; * } * } finally { * StackContext.exit(); * } * } * }[/code]</p> * * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a> * @version 5.2, August 19, 2007 */ public abstract class StackContext extends AllocatorContext { /** * Holds the default implementation. This implementation uses thread-local * pools. RTSJ alternative implementations could use * <code>ScopedMemory</code> for their stack allocations. * Users may also disable stack allocation by providing a class allocating * on the heap. */ public static final Configurable <Class<? extends StackContext>> DEFAULT = new Configurable(Default.class) {}; /** * Enters the {@link #DEFAULT} stack context. */ public static void enter() { Context.enter((Class) DEFAULT.get()); } /** * Enters a stack context only if the specified condition is verified. * * @param condition <code>true</code> to enter a stack context; * <code>false</code> otherwise. */ public static void enter(boolean condition) { if (condition) { StackContext.enter(); } } /** * Exits the current stack context. * * @throws ClassCastException if the context is not a stack context. */ public static void exit() { Context.exit(StackContext.class); } /** * Exits a stack context only if the specified condition is verified. * * @param condition <code>true</code> to exit a stack context; * <code>false</code> otherwise. */ public static void exit(boolean condition) { if (condition) { StackContext.exit(); } } /** * Default implementation. */ private static final class Default extends StackContext { private final ThreadLocal _factoryToAllocator = new ThreadLocal() { protected Object initialValue() { return new FastMap(); } }; private final ThreadLocal _activeAllocators = new ThreadLocal() { protected Object initialValue() { return new FastTable(); } }; // All allocators which have been used by the owner // (no synchronization required). private final FastTable _ownerUsedAllocators = new FastTable(); // All allocators which have been used by the concurrent threads // (synchronization required). private final FastTable _nonOwnerUsedAllocators = new FastTable(); protected void deactivate() { FastTable allocators = (FastTable) _activeAllocators.get(); for (int i = 0, n = allocators.size(); i < n;) { ((Allocator) allocators.get(i++)).user = null; } allocators.clear(); } protected Allocator getAllocator(ObjectFactory factory) { FastMap factoryToAllocator = (FastMap) _factoryToAllocator.get(); StackAllocator allocator = (StackAllocator) factoryToAllocator.get(factory); if (allocator == null) { allocator = new StackAllocator(factory); factoryToAllocator.put(factory, allocator); } if (allocator.user == null) { // Activate. allocator.user = Thread.currentThread(); FastTable activeAllocators = (FastTable) _activeAllocators.get(); activeAllocators.add(allocator); } if (!allocator._inUse) { // Add to lists of allocators used. allocator._inUse = true; if (Thread.currentThread() == getOwner()) _ownerUsedAllocators.add(allocator); else synchronized (_nonOwnerUsedAllocators) { _nonOwnerUsedAllocators.add(allocator); } } return allocator; } protected void enterAction() { getOuter().getAllocatorContext().deactivate(); } protected void exitAction() { this.deactivate(); // Resets all allocators used. for (int i = 0; i < _ownerUsedAllocators.size(); i++) { StackAllocator allocator = (StackAllocator) _ownerUsedAllocators.get(i); allocator.reset(); } _ownerUsedAllocators.clear(); for (int i = 0; i < _nonOwnerUsedAllocators.size(); i++) { StackAllocator allocator = (StackAllocator) _nonOwnerUsedAllocators.get(i); allocator.reset(); } _nonOwnerUsedAllocators.clear(); } } // Holds stack allocator implementation. private static final class StackAllocator extends Allocator { private final ObjectFactory _factory; private boolean _inUse; private int _queueLimit; public StackAllocator(ObjectFactory factory) { this._factory = factory; } protected Object allocate() { if (_queueLimit >= queue.length) resize(); Object obj = _factory.create(); queue[_queueLimit++] = obj; return obj; } protected void recycle(Object object) { if (_factory.doCleanup()) _factory.cleanup(object); for (int i = queueSize; i < _queueLimit; i++) { if (queue[i] == object) { // Found it. queue[i] = queue[queueSize]; queue[queueSize++] = object; return; } } throw new java.lang.UnsupportedOperationException( "Cannot recycle to the stack an object " + "which has not been allocated from the stack"); } protected void reset() { _inUse = false; while (_factory.doCleanup() && (queueSize != _queueLimit)) { Object obj = queue[queueSize++]; _factory.cleanup(obj); } queueSize = _queueLimit; } public String toString() { return "Stack allocator for " + _factory.getClass(); } } // Allows instances of private classes to be factory produced. static { ObjectFactory.setInstance(new ObjectFactory() { protected Object create() { return new Default(); } }, Default.class); } }