001: // Copyright (C) 2002, 2003, 2004 Per M.A. Bothner.
002: // This is free software; for terms and warranty disclaimer see ./COPYING.
003:
004: package gnu.mapping;
005:
006: import gnu.math.*;
007: import gnu.lists.*;
008:
009: /** A procedure activation stack (when compiled with explicit stacks). */
010:
011: public class CallContext // implements Runnable
012: // extends ValueStack ??? FIXME
013: {
014: /* #ifdef JAVA2 */
015: static ThreadLocal currentContext = new ThreadLocal();
016: /* #else */
017: // static java.util.Hashtable threadMap = new java.util.Hashtable(50);
018: /* #endif */
019: Thread currentThread;
020:
021: Environment curEnvironment;
022:
023: public final Environment getEnvironmentRaw() {
024: return curEnvironment;
025: }
026:
027: public final void setEnvironmentRaw(Environment env) {
028: curEnvironment = env;
029: }
030:
031: public final Environment getEnvironment() {
032: if (curEnvironment == null) {
033: Environment env = Environment.make(currentThread.getName(),
034: Environment.global);
035: env.flags |= Environment.THREAD_SAFE;
036: curEnvironment = env;
037: }
038: return curEnvironment;
039: }
040:
041: public static void setInstance(CallContext ctx) {
042: Thread thread = Thread.currentThread();
043: ctx.currentThread = thread;
044: /* #ifdef JAVA2 */
045: currentContext.set(ctx);
046: /* #else */
047: // if (thread instanceof Future)
048: // ((Future) thread).closure.context = ctx;
049: // else
050: // threadMap.put(thread, ctx);
051: /* #endif */
052: }
053:
054: /** Get but don't create a CallContext for the current thread. */
055: public static CallContext getOnlyInstance() {
056: /* #ifdef JAVA2 */
057: return (CallContext) currentContext.get();
058: /* #else */
059: // Thread thread = Thread.currentThread();
060: // if (thread instanceof Future)
061: // return ((Future) thread).getCallContext();
062: // return (CallContext) threadMap.get(thread);
063: /* #endif */
064: }
065:
066: /** Get or create a CallContext for the current thread. */
067: public static CallContext getInstance() {
068: CallContext ctx = getOnlyInstance();
069: if (ctx == null) {
070: ctx = new CallContext();
071: setInstance(ctx);
072: }
073: return ctx;
074: }
075:
076: public Procedure proc;
077:
078: /** The program location in the current procedure.
079: * This a selector that only has meaning to the proc's Procedure.*/
080: public int pc;
081:
082: /* CPS:
083: CallFrame frame;
084: */
085:
086: /** Default place for function results.
087: * In the future, function arguments will also use vstack. */
088: public ValueStack vstack = new ValueStack(); // ?? super
089: /** Function results are written to this Consumer.
090: * This may point to vstack - or some other Consumer. */
091: public Consumer consumer = vstack;
092:
093: /** Used for passing parameters. (Will be replaced by vstack.) */
094: public Object value1;
095: public Object value2;
096: public Object value3;
097: public Object value4;
098: public Object[] values;
099: public int ivalue1;
100: public int ivalue2;
101:
102: /** Number of actual arguments. */
103: public int count;
104:
105: /** Index of next argument.
106: * This is used by methods like getNextArg, used by callees. */
107: public int next;
108:
109: /** Encoding of where the arguments are.
110: * Each argument uses 4 bits.
111: * Arguments beyond 8 are implicitly ARG_IN_VALUES_ARRAY.
112: */
113: public int where;
114: public final static int ARG_IN_VALUES_ARRAY = 0;
115: public final static int ARG_IN_VALUE1 = 1;
116: public final static int ARG_IN_VALUE2 = 2;
117: public final static int ARG_IN_VALUE3 = 3;
118: public final static int ARG_IN_VALUE4 = 4;
119: public final static int ARG_IN_IVALUE1 = 5;
120: public final static int ARG_IN_IVALUE2 = 6;
121:
122: Object getArgAsObject(int i) {
123: if (i < 8) {
124: switch ((this .where >> (4 * i)) & 15) {
125: case ARG_IN_VALUE1:
126: return value1;
127: case ARG_IN_VALUE2:
128: return value2;
129: case ARG_IN_VALUE3:
130: return value3;
131: case ARG_IN_VALUE4:
132: return value4;
133: case ARG_IN_IVALUE1:
134: return IntNum.make(ivalue1);
135: case ARG_IN_IVALUE2:
136: return IntNum.make(ivalue2);
137: }
138: }
139: return values[i];
140: }
141:
142: /** Get the next incoming argument.
143: * Throw WrongArguments if there are no more arguments.
144: * FIXME: This and following methods don't really fit until the
145: * current match/apply-based API, at least as currently implemented.
146: * We probably need to pass in (or make this a method of) the Procedure.
147: */
148: public Object getNextArg() {
149: if (next >= count)
150: throw new WrongArguments(null, count);
151: return getArgAsObject(next++);
152: }
153:
154: public int getNextIntArg() {
155: if (next >= count)
156: throw new WrongArguments(null, count);
157: Object arg = getArgAsObject(next++);
158: return ((Number) arg).intValue();
159: }
160:
161: /** Get the next incoming argument.
162: * Return defaultValue if there are no more arguments.
163: */
164: public Object getNextArg(Object defaultValue) {
165: if (next >= count)
166: return defaultValue;
167: return getArgAsObject(next++);
168: }
169:
170: public int getNextIntArg(int defaultValue) {
171: if (next >= count)
172: return defaultValue;
173: return ((Number) getArgAsObject(next++)).intValue();
174: }
175:
176: /** Get remaining arguments as an array. */
177: public final Object[] getRestArgsArray(int next) {
178: Object[] args = new Object[count - next];
179: int i = 0;
180: while (next < count) {
181: args[i++] = getArgAsObject(next++);
182: }
183: return args;
184: }
185:
186: /** Get remaining arguments as a list.
187: * Used for Scheme and Lisp rest args. */
188: public final LList getRestArgsList(int next) {
189: LList nil = LList.Empty;
190: LList list = nil;
191: Pair last = null;
192: while (next < count) {
193: Pair pair = new Pair(getArgAsObject(next++), nil);
194: if (last == null)
195: list = pair;
196: else
197: last.cdr = pair;
198: last = pair;
199: }
200: return list;
201: }
202:
203: /** Note that we are done with the input arguments.
204: * Throw WrongArguments if there are unprocessed arguments.
205: */
206: public void lastArg() {
207: if (next < count)
208: throw new WrongArguments(null, count);
209: values = null;
210: }
211:
212: public Object[] getArgs() {
213: if (where == 0)
214: return values;
215: else {
216: int n = count;
217: next = 0;
218: Object[] args = new Object[n];
219: for (int i = 0; i < n; i++)
220: args[i] = getNextArg();
221: return args;
222: }
223: }
224:
225: public void runUntilDone() throws Throwable {
226: for (;;) {
227: Procedure proc = this .proc;
228: if (proc == null) {
229: /* CPS:
230: CallFrame fr = frame;
231: if (fr == null)
232: break;
233: proc = fr.proc;
234: frame = fr.previous;
235: if (proc == null)
236: */
237: break;
238: }
239: this .proc = null;
240: proc.apply(this );
241: }
242: }
243:
244: /** Setup routine before calling a method that takes a CallContext.
245: * The compiler emits a call to this before a call to a method that takes
246: * a CallContext, when it wants the function result as an Object.
247: * It pushes the CallContest state so it can uses the vstack for a
248: * temporary, After the method, getFromContext extract the method's result
249: * from the vstack and restores the state.
250: */
251: public final int startFromContext() {
252: ValueStack vst = vstack;
253: int oindex = vst.find(consumer);
254: vst.ensureSpace(3);
255: int gapStart = vst.gapStart;
256: vst.data[gapStart++] = TreeList.INT_FOLLOWS;
257: vst.setIntN(gapStart, oindex);
258: gapStart += 2;
259: consumer = vst;
260: vst.gapStart = gapStart;
261: return gapStart;
262: }
263:
264: /** Routine to extract result and restore state after startFromContext.
265: */
266: public final Object getFromContext(int oldIndex) throws Throwable {
267: runUntilDone();
268: ValueStack vst = vstack;
269: Object result = Values.make(vst, oldIndex, vst.gapStart);
270: cleanupFromContext(oldIndex);
271: return result;
272: }
273:
274: /** Cleanup-only part of getFromContext.
275: * This can be in an exception handler as an alternative
276: * to getFromContext, which is called in the non-exception case.
277: * (Alternatively, the compiler could call cleanupFromContext
278: * from a finally clause but that is less efficient, partly
279: * because the JVM stack must be empty before a finally subroutine.)
280: */
281: public final void cleanupFromContext(int oldIndex) throws Throwable {
282: ValueStack vst = vstack;
283: char[] data = vst.data;
284: int oindex = (data[oldIndex - 2] << 16)
285: | (data[oldIndex - 1] & 0xFFFF);
286: consumer = (Consumer) vst.objects[oindex];
287: vst.objects[oindex] = null;
288: vst.oindex = oindex;
289: vst.gapStart = oldIndex - 3;
290: }
291:
292: /** Run until no more continuations, returning final result. */
293: public final Object runUntilValue() throws Throwable {
294: Consumer consumerSave = consumer;
295: ValueStack vst = vstack;
296: consumer = vst;
297: int dindexSave = vst.gapStart;
298: int oindexSave = vst.oindex;
299: try {
300: runUntilDone();
301: return Values.make(vst, dindexSave, vst.gapStart);
302: } finally {
303: consumer = consumerSave;
304: vst.gapStart = dindexSave;
305: vst.oindex = oindexSave;
306: }
307: }
308:
309: /** Run until no more continuations, sending result to a COnsumer. */
310: public final void runUntilValue(Consumer out) throws Throwable {
311: Consumer consumerSave = consumer;
312: consumer = out;
313: try {
314: runUntilDone();
315: } finally {
316: consumer = consumerSave;
317: }
318: }
319:
320: /** Write values (of function result) to current consumer. */
321: public void writeValue(Object value) {
322: Values.writeValues(value, consumer);
323: }
324:
325: /** A stack of currently re-bound fluids variables.
326: * There is one for each active fluids-let or parameterize variable. */
327: Location[] pushedFluids;
328: /** The number of active elements of the pushedFluids array. */
329: int pushedFluidsCount;
330:
331: public final void pushFluid(Location loc) {
332: Location[] fluids = pushedFluids;
333: int count = pushedFluidsCount;
334: if (fluids == null) {
335: pushedFluids = fluids = new Location[10];
336: } else if (count == fluids.length) {
337: Location[] newFluids = new Location[2 * count];
338: System.arraycopy(fluids, 0, newFluids, 0, count);
339: pushedFluids = fluids = newFluids;
340: }
341: fluids[count] = loc;
342: pushedFluidsCount = count + 1;
343: }
344:
345: public final void popFluid() {
346: pushedFluids[--pushedFluidsCount] = null;
347: }
348:
349: /** Current stack of evaluation frames for interpreter. */
350: public Object[][] evalFrames;
351: }
352:
353: /* CPS:
354: class CallFrame
355: {
356: Procedure proc;
357: CallFrame previous;
358: int saveVstackLen;
359:
360: // Should probably be in sub-classes of ClassFrame:
361: Object[] values;
362: }
363: */
|