001: /*
002: * Javolution - Java(TM) Solution for Real-Time and Embedded Systems
003: * Copyright (C) 2006 - Javolution (http://javolution.org/)
004: * All rights reserved.
005: *
006: * Permission to use, copy, modify, and distribute this software is
007: * freely granted, provided that this notice is preserved.
008: */
009: package javolution.context;
010:
011: import j2me.lang.ThreadLocal;
012: import javolution.lang.Configurable;
013: import javolution.lang.ValueType;
014: import javolution.util.FastMap;
015: import javolution.util.FastTable;
016:
017: /**
018: * <p> This class represents a stack {@link AllocatorContext allocator context};
019: * (using thread-local pools or RTSJ <code>ScopedMemory</code>).</p>
020: *
021: * <p> Stacks allocations reduce heap memory allocation and often result in
022: * faster execution time for almost all objects but the smallest one.</p>
023: *
024: * <p> Stack allocated objects should never be assigned to static members
025: * (see {@link ImmortalContext}). Also, methods entering/exiting stack
026: * contexts should ensure that stack allocated objects do not escape from
027: * their context scope. If necessary, stack objects can be exported using
028: * {@link #outerExecute} or {@link #outerCopy}:[code]
029: * public class LargeInteger implements ValueType, Realtime {
030: * public LargeInteger sqrt() {
031: * StackContext.enter();
032: * try {
033: * LargeInteger result = ZERO;
034: * LargeInteger k = this.shiftRight(this.bitLength() / 2)); // First approximation.
035: * while (true) { // Newton Iteration.
036: * result = (k.plus(this.divide(k))).shiftRight(1);
037: * if (result.equals(k)) return StackContext.outerCopy(result); // Exports result.
038: * k = result;
039: * }
040: * } finally {
041: * StackContext.exit();
042: * }
043: * }
044: * }[/code]</p>
045: *
046: * <p> It should be noted that future versions of the JVM may provide some
047: * limited support for stack allocation through escape analysis.
048: * Users can always {@link #DISABLED turn-off} stack allocation to
049: * revert to standard heap allocation.</p>
050: *
051: * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
052: * @version 5.2, August 19, 2007
053: */
054: public abstract class StackContext extends AllocatorContext {
055:
056: /**
057: * Holds the default implementation. This implementation uses thread-local
058: * pools. RTSJ alternative implementations could use
059: * <code>ScopedMemory</code> for their stack allocations.
060: */
061: public static final Configurable/*<Class<? extends StackContext>>*/DEFAULT = new Configurable(
062: Default.CLASS);
063:
064: /**
065: * Indicates if stack allocations are globally disabled.
066: */
067: public static final Configurable/*<Boolean>*/DISABLED = new Configurable/*<Boolean>*/(
068: new Boolean(false));
069:
070: /**
071: * Indicates if this stack context is disabled.
072: */
073: private boolean _isDisabled = false;
074:
075: /**
076: * Enters the {@link #DEFAULT} stack context.
077: *
078: * @return the statck context being entered.
079: */
080: public static StackContext enter() {
081: StackContext ctx = (StackContext) Context.enter((Class) DEFAULT
082: .get());
083: ctx._isDisabled = ((Boolean) DISABLED.get()).booleanValue();
084: return ctx;
085: }
086:
087: /**
088: * Exits the current stack context.
089: *
090: * @return the stack context being exited.
091: * @throws ClassCastException if the context is not a stack context.
092: */
093: public static/*StackContext*/Context exit() {
094: return (StackContext) Context.exit();
095: }
096:
097: /**
098: * Performs a copy of the specified value allocated outside of the
099: * current stack context.
100: *
101: * @param value the value to be copied.
102: * @return a copy allocated using the outer allocator.
103: */
104: public static/*<T extends ValueType>*/ValueType/*{T}*/outerCopy(
105: ValueType/*{T}*/value) {
106: StackContext ctx = (StackContext) AllocatorContext.getCurrent();
107: boolean isDisabled = ctx.isDisabled();
108: ctx.setDisabled(true);
109: Object copy = value.copy();
110: ctx.setDisabled(isDisabled);
111: return (ValueType/*{T}*/) copy;
112: }
113:
114: /**
115: * Executes the specified logic outside of the current stack context.
116: *
117: * @param logic the logic to be executed outside of the current stack
118: * context.
119: */
120: public static void outerExecute(Runnable logic) {
121: StackContext ctx = (StackContext) AllocatorContext.getCurrent();
122: boolean isDisabled = ctx.isDisabled();
123: ctx.setDisabled(true);
124: logic.run();
125: ctx.setDisabled(isDisabled);
126: }
127:
128: /**
129: * Indicates if this stack context is disabled. When disabled, allocation
130: * are performed using the outer {@link AllocatorContext}.
131: */
132: public final boolean isDisabled() {
133: return _isDisabled;
134: }
135:
136: /**
137: * Enables/disables this stack context.
138: *
139: * @param isDisabled <code>true</code> if disabled; <code>false</code>
140: * otherwise.
141: */
142: public final void setDisabled(boolean isDisabled) {
143: if (isDisabled == _isDisabled)
144: return; // No change.
145: if (isDisabled) {
146: deactivate();
147: } else {
148: getOuter().getAllocatorContext().deactivate();
149: }
150: _isDisabled = isDisabled;
151: }
152:
153: /**
154: * Default implementation.
155: */
156: private static final class Default extends StackContext {
157:
158: private static final Class CLASS = new Default().getClass();
159:
160: private final ThreadLocal _factoryToAllocator = new ThreadLocal() {
161: protected Object initialValue() {
162: return new FastMap();
163: }
164: };
165:
166: private final ThreadLocal _activeAllocators = new ThreadLocal() {
167: protected Object initialValue() {
168: return new FastTable();
169: }
170: };
171:
172: // All allocators which have been used by the owner
173: // (no synchronization required).
174: private final FastTable _ownerUsedAllocators = new FastTable();
175:
176: // All allocators which have been used by the concurrent threads
177: // (synchronization required).
178: private final FastTable _nonOwnerUsedAllocators = new FastTable();
179:
180: protected void deactivate() {
181: FastTable allocators = (FastTable) _activeAllocators.get();
182: for (int i = 0, n = allocators.size(); i < n;) {
183: ((Allocator) allocators.get(i++)).user = null;
184: }
185: allocators.clear();
186: }
187:
188: protected Allocator getAllocator(ObjectFactory factory) {
189: if (isDisabled()) // Forwards to outer.
190: return getOuter().getAllocatorContext().getAllocator(
191: factory);
192:
193: FastMap factoryToAllocator = (FastMap) _factoryToAllocator
194: .get();
195: StackAllocator allocator = (StackAllocator) factoryToAllocator
196: .get(factory);
197: if (allocator == null) {
198: allocator = new StackAllocator(factory);
199: factoryToAllocator.put(factory, allocator);
200: }
201: if (allocator.user == null) { // Activate.
202: allocator.user = Thread.currentThread();
203: FastTable activeAllocators = (FastTable) _activeAllocators
204: .get();
205: activeAllocators.add(allocator);
206: }
207: if (!allocator._inUse) { // Add to lists of allocators used.
208: allocator._inUse = true;
209: if (Thread.currentThread() == getOwner()) {
210: _ownerUsedAllocators.add(allocator);
211: } else {
212: synchronized (_nonOwnerUsedAllocators) {
213: _nonOwnerUsedAllocators.add(allocator);
214: }
215: }
216: }
217: return allocator;
218: }
219:
220: protected void enterAction() {
221: getOuter().getAllocatorContext().deactivate();
222: }
223:
224: protected void exitAction() {
225: this .deactivate();
226:
227: // Resets all allocators used.
228: for (int i = 0; i < _ownerUsedAllocators.size(); i++) {
229: StackAllocator allocator = (StackAllocator) _ownerUsedAllocators
230: .get(i);
231: allocator.reset();
232: }
233: _ownerUsedAllocators.clear();
234: for (int i = 0; i < _nonOwnerUsedAllocators.size(); i++) {
235: StackAllocator allocator = (StackAllocator) _nonOwnerUsedAllocators
236: .get(i);
237: allocator.reset();
238: }
239: _nonOwnerUsedAllocators.clear();
240: }
241: }
242:
243: // Holds stack allocator implementation.
244: private static final class StackAllocator extends Allocator {
245:
246: private final ObjectFactory _factory;
247:
248: private boolean _inUse;
249:
250: private int _queueLimit;
251:
252: public StackAllocator(ObjectFactory factory) {
253: this ._factory = factory;
254: keepInQueue = true;
255: }
256:
257: protected Object allocate() {
258: if (_queueLimit >= queue.length)
259: resize();
260: Object obj = _factory.create();
261: queue[_queueLimit++] = obj;
262: return obj;
263: }
264:
265: protected void recycle(Object object) {
266: if (_factory.doCleanup()) {
267: _factory.cleanup(object);
268: }
269: for (int i = queueSize; i < _queueLimit; i++) {
270: if (queue[i] == object) { // Found it.
271: queue[i] = queue[queueSize];
272: queue[queueSize++] = object;
273: return;
274: }
275: }
276: throw new j2me.lang.UnsupportedOperationException(
277: "Cannot recycle to the stack an object "
278: + "which has not been allocated from the stack");
279: }
280:
281: protected void reset() {
282: _inUse = false;
283: while (_factory.doCleanup() && (queueSize != _queueLimit)) {
284: Object obj = queue[queueSize++];
285: _factory.cleanup(obj);
286: }
287: queueSize = _queueLimit;
288: }
289:
290: public String toString() {
291: return "Stack allocator for " + _factory.getClass();
292: }
293: }
294:
295: // Allows instances of private classes to be factory produced.
296: static {
297: ObjectFactory.setInstance(new ObjectFactory() {
298: protected Object create() {
299: return new Default();
300: }
301: }, Default.CLASS);
302: }
303: }
|