2003/11/13 05:04:22
[org.ibex.core.git] / src / org / xwt / js / JSContext.java
1 package org.xwt.js;
2 import java.util.*;
3 import org.xwt.util.*;
4
5 /** encapsulates the state of a JavaScript "thread" (no relation to Java threads) */
6 public class JSContext {
7
8     // Statics //////////////////////////////////////////////////////////////////////
9     private int getLine_() { return current().f == null || (pc < 0 || pc >= f.size) ? -1 : f.line[pc]; }
10     public static int getLine() { return current().getLine_(); }
11     public static String getSourceName() { return current().f == null ? null : current().f.sourceName; } 
12     
13     /** fetches the currently-executing javascript function */
14     private static JSContext current() { return (JSContext)threadToJSContext.get(Thread.currentThread()); }
15     private static Hashtable threadToJSContext = new Hashtable();
16     
17     // Instance members and methods //////////////////////////////////////////////////////////////////////
18     
19     /**
20      *  the number of times this context has been paused; used by
21      *  Function.eval() to make sure it behaves properly even if the
22      *  pause Callback is invoked *before* control is returned to
23      *  eval()
24      */
25     int pausecount = 0;
26
27     JSFunction f = null;          ///< the currently-executing JSFunction
28     JSScope scope = null;
29     Vec stack = new Vec();        ///< the object stack
30     int pc = 0;                   ///< the program counter
31     boolean pauseable;
32
33     public static void invokePauseable(JSFunction function) { new JSContext(f, true).invoke(new JSArray()); }
34
35     JSContext(JSFunction f, boolean pauseable) {
36         this.pauseable = pauseable;
37         this.f = f;
38         scope = new JSScope(function.parentJSScope);
39     }
40
41     void invoke(JSArray args) {
42         stack.push(new JSFunction.CallMarker(cx));
43         stack.push(args);
44         resume();
45     }
46     
47     /** returns a callback which will restart the context, or null if this context is not pauseable */
48     public static Callback pause() { return current().pause_(); }
49     private Callback pause_() {
50         if (!pauseable) return null;
51         pausecount++;
52         return new Callback() { public Object call(Object o) {
53             paused = false;
54             stack.push(o);
55             resume();
56             return null;
57         } };
58     }
59     
60     private void resume() {
61         Thread t = Thread.currentThread();
62         JSContext old = (JSContext)threadToJSContext.get(t);
63         threadToJSContext.put(t, this);
64         try {
65             JSFunction.eval(this);
66         } finally {
67             if (old == null) threadToJSContext.remove(t);
68             else threadToJSContext.put(t, old);
69         }
70     }
71 }