1 /* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
\r
3 * The contents of this file are subject to the Netscape Public
\r
4 * License Version 1.1 (the "License"); you may not use this file
\r
5 * except in compliance with the License. You may obtain a copy of
\r
6 * the License at http://www.mozilla.org/NPL/
\r
8 * Software distributed under the License is distributed on an "AS
\r
9 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
\r
10 * implied. See the License for the specific language governing
\r
11 * rights and limitations under the License.
\r
13 * The Original Code is Rhino code, released
\r
16 * The Initial Developer of the Original Code is Netscape
\r
17 * Communications Corporation. Portions created by Netscape are
\r
18 * Copyright (C) 1997-2000 Netscape Communications Corporation. All
\r
33 * Alternatively, the contents of this file may be used under the
\r
34 * terms of the GNU Public License (the "GPL"), in which case the
\r
35 * provisions of the GPL are applicable instead of those above.
\r
36 * If you wish to allow use of your version of this file only
\r
37 * under the terms of the GPL and not to allow others to use your
\r
38 * version of this file under the NPL, indicate your decision by
\r
39 * deleting the provisions above and replace them with the notice
\r
40 * and other provisions required by the GPL. If you do not delete
\r
41 * the provisions above, a recipient may use your version of this
\r
42 * file under either the NPL or the GPL.
\r
47 package org.mozilla.javascript;
\r
49 import java.beans.*;
\r
51 import java.util.Vector;
\r
52 import java.util.Enumeration;
\r
53 import java.util.Hashtable;
\r
54 import java.util.Locale;
\r
55 import java.util.ResourceBundle;
\r
56 import java.util.ListResourceBundle;
\r
57 import java.text.MessageFormat;
\r
58 import java.lang.reflect.*;
\r
59 import org.mozilla.javascript.debug.*;
\r
62 * This class represents the runtime context of an executing script.
\r
64 * Before executing a script, an instance of Context must be created
\r
65 * and associated with the thread that will be executing the script.
\r
66 * The Context will be used to store information about the executing
\r
67 * of the script such as the call stack. Contexts are associated with
\r
68 * the current thread using the <a href="#enter()">enter()</a> method.<p>
\r
70 * The behavior of the execution engine may be altered through methods
\r
71 * such as <a href="#setLanguageVersion>setLanguageVersion</a> and
\r
72 * <a href="#setErrorReporter>setErrorReporter</a>.<p>
\r
74 * Different forms of script execution are supported. Scripts may be
\r
75 * evaluated from the source directly, or first compiled and then later
\r
76 * executed. Interactive execution is also supported.<p>
\r
78 * Some aspects of script execution, such as type conversions and
\r
79 * object creation, may be accessed directly through methods of
\r
83 * @author Norris Boyd
\r
84 * @author Brendan Eich
\r
87 public class Context {
\r
88 public static final String languageVersionProperty = "language version";
\r
89 public static final String errorReporterProperty = "error reporter";
\r
92 * Create a new Context.
\r
94 * Note that the Context must be associated with a thread before
\r
95 * it can be used to execute a script.
\r
97 * @see org.mozilla.javascript.Context#enter
\r
104 * Create a new context with the associated security support.
\r
106 * @param securitySupport an encapsulation of the functionality
\r
107 * needed to support security for scripts.
\r
108 * @see org.mozilla.javascript.SecuritySupport
\r
110 public Context(SecuritySupport securitySupport) {
\r
111 this.securitySupport = securitySupport;
\r
115 private void init() {
\r
116 setLanguageVersion(VERSION_DEFAULT);
\r
117 optimizationLevel = codegenClass != null ? 0 : -1;
\r
118 Object[] array = contextListeners;
\r
119 if (array != null) {
\r
120 for (int i = array.length; i-- != 0;) {
\r
121 ((ContextListener)array[i]).contextCreated(this);
\r
127 * Get a context associated with the current thread, creating
\r
130 * The Context stores the execution state of the JavaScript
\r
131 * engine, so it is required that the context be entered
\r
132 * before execution may begin. Once a thread has entered
\r
133 * a Context, then getCurrentContext() may be called to find
\r
134 * the context that is associated with the current thread.
\r
136 * Calling <code>enter()</code> will
\r
137 * return either the Context currently associated with the
\r
138 * thread, or will create a new context and associate it
\r
139 * with the current thread. Each call to <code>enter()</code>
\r
140 * must have a matching call to <code>exit()</code>. For example,
\r
142 * Context cx = Context.enter();
\r
144 * cx.evaluateString(...);
\r
147 * @return a Context associated with the current thread
\r
148 * @see org.mozilla.javascript.Context#getCurrentContext
\r
149 * @see org.mozilla.javascript.Context#exit
\r
151 public static Context enter() {
\r
152 return enter(null);
\r
156 * Get a Context associated with the current thread, using
\r
157 * the given Context if need be.
\r
159 * The same as <code>enter()</code> except that <code>cx</code>
\r
160 * is associated with the current thread and returned if
\r
161 * the current thread has no associated context and <code>cx</code>
\r
162 * is not associated with any other thread.
\r
163 * @param cx a Context to associate with the thread if possible
\r
164 * @return a Context associated with the current thread
\r
166 public static Context enter(Context cx) {
\r
167 // There's some duplication of code in this method to avoid
\r
168 // unnecessary synchronizations.
\r
169 Thread t = Thread.currentThread();
\r
170 Context current = (Context) threadContexts.get(t);
\r
171 if (current != null) {
\r
172 synchronized (current) {
\r
173 current.enterCount++;
\r
176 else if (cx != null) {
\r
177 synchronized (cx) {
\r
178 if (cx.currentThread == null) {
\r
179 cx.currentThread = t;
\r
180 threadContexts.put(t, cx);
\r
187 current = new Context();
\r
188 current.currentThread = t;
\r
189 threadContexts.put(t, current);
\r
190 current.enterCount = 1;
\r
192 Object[] array = contextListeners;
\r
193 if (array != null) {
\r
194 for (int i = array.length; i-- != 0;) {
\r
195 ((ContextListener)array[i]).contextEntered(current);
\r
202 * Exit a block of code requiring a Context.
\r
204 * Calling <code>exit()</code> will remove the association between
\r
205 * the current thread and a Context if the prior call to
\r
206 * <code>enter()</code> on this thread newly associated a Context
\r
207 * with this thread.
\r
208 * Once the current thread no longer has an associated Context,
\r
209 * it cannot be used to execute JavaScript until it is again associated
\r
212 * @see org.mozilla.javascript.Context#enter
\r
214 public static void exit() {
\r
215 Context cx = getCurrentContext();
\r
216 boolean released = false;
\r
218 synchronized (cx) {
\r
219 if (--cx.enterCount == 0) {
\r
220 threadContexts.remove(cx.currentThread);
\r
221 cx.currentThread = null;
\r
225 Object[] array = contextListeners;
\r
226 if (array != null) {
\r
227 for (int i = array.length; i-- != 0;) {
\r
228 ContextListener l = (ContextListener)array[i];
\r
229 l.contextExited(cx);
\r
230 if (released) { l.contextReleased(cx); }
\r
237 * Get the current Context.
\r
239 * The current Context is per-thread; this method looks up
\r
240 * the Context associated with the current thread. <p>
\r
242 * @return the Context associated with the current thread, or
\r
243 * null if no context is associated with the current
\r
245 * @see org.mozilla.javascript.Context#enter
\r
246 * @see org.mozilla.javascript.Context#exit
\r
248 public static Context getCurrentContext() {
\r
249 Thread t = Thread.currentThread();
\r
250 return (Context) threadContexts.get(t);
\r
253 public static Context getContextForThread(Thread t) {
\r
254 Context ret = (Context) threadContexts.get(t);
\r
255 return ret == null ? Context.enter() : ret;
\r
259 * Language versions
\r
261 * All integral values are reserved for future version numbers.
\r
265 * The unknown version.
\r
267 public static final int VERSION_UNKNOWN = -1;
\r
270 * The default version.
\r
272 public static final int VERSION_DEFAULT = 0;
\r
277 public static final int VERSION_1_0 = 100;
\r
282 public static final int VERSION_1_1 = 110;
\r
287 public static final int VERSION_1_2 = 120;
\r
292 public static final int VERSION_1_3 = 130;
\r
297 public static final int VERSION_1_4 = 140;
\r
302 public static final int VERSION_1_5 = 150;
\r
305 * Get the current language version.
\r
307 * The language version number affects JavaScript semantics as detailed
\r
308 * in the overview documentation.
\r
310 * @return an integer that is one of VERSION_1_0, VERSION_1_1, etc.
\r
312 public int getLanguageVersion() {
\r
317 * Set the language version.
\r
320 * Setting the language version will affect functions and scripts compiled
\r
321 * subsequently. See the overview documentation for version-specific
\r
324 * @param version the version as specified by VERSION_1_0, VERSION_1_1, etc.
\r
326 public void setLanguageVersion(int version) {
\r
327 Object[] array = listeners;
\r
328 if (array != null && version != this.version) {
\r
329 firePropertyChangeImpl(array, languageVersionProperty,
\r
330 new Integer(this.version),
\r
331 new Integer(version));
\r
333 this.version = version;
\r
337 * Get the implementation version.
\r
340 * The implementation version is of the form
\r
342 * "<i>name langVer</i> <code>release</code> <i>relNum date</i>"
\r
344 * where <i>name</i> is the name of the product, <i>langVer</i> is
\r
345 * the language version, <i>relNum</i> is the release number, and
\r
346 * <i>date</i> is the release date for that specific
\r
347 * release in the form "yyyy mm dd".
\r
349 * @return a string that encodes the product, language version, release
\r
350 * number, and date.
\r
352 public String getImplementationVersion() {
\r
353 return "Rhino 1.5 release 2 2001 07 27";
\r
357 * Get the current error reporter.
\r
359 * @see org.mozilla.javascript.ErrorReporter
\r
361 public ErrorReporter getErrorReporter() {
\r
362 if (errorReporter == null) {
\r
363 errorReporter = new DefaultErrorReporter();
\r
365 return errorReporter;
\r
369 * Change the current error reporter.
\r
371 * @return the previous error reporter
\r
372 * @see org.mozilla.javascript.ErrorReporter
\r
374 public ErrorReporter setErrorReporter(ErrorReporter reporter) {
\r
375 ErrorReporter result = errorReporter;
\r
376 Object[] array = listeners;
\r
377 if (array != null && errorReporter != reporter) {
\r
378 firePropertyChangeImpl(array, errorReporterProperty,
\r
379 errorReporter, reporter);
\r
381 errorReporter = reporter;
\r
386 * Get the current locale. Returns the default locale if none has
\r
389 * @see java.util.Locale
\r
392 public Locale getLocale() {
\r
393 if (locale == null)
\r
394 locale = Locale.getDefault();
\r
399 * Set the current locale.
\r
401 * @see java.util.Locale
\r
403 public Locale setLocale(Locale loc) {
\r
404 Locale result = locale;
\r
410 * Register an object to receive notifications when a bound property
\r
412 * @see java.beans.PropertyChangeEvent
\r
413 * @see #removePropertyChangeListener(java.beans.PropertyChangeListener)
\r
414 * @param listener the listener
\r
416 public void addPropertyChangeListener(PropertyChangeListener listener) {
\r
417 synchronized (this) {
\r
418 listeners = ListenerArray.add(listeners, listener);
\r
423 * Remove an object from the list of objects registered to receive
\r
424 * notification of changes to a bounded property
\r
425 * @see java.beans.PropertyChangeEvent
\r
426 * @see #addPropertyChangeListener(java.beans.PropertyChangeListener)
\r
427 * @param listener the listener
\r
429 public void removePropertyChangeListener(PropertyChangeListener listener) {
\r
430 synchronized (this) {
\r
431 listeners = ListenerArray.remove(listeners, listener);
\r
436 * Notify any registered listeners that a bounded property has changed
\r
437 * @see #addPropertyChangeListener(java.beans.PropertyChangeListener)
\r
438 * @see #removePropertyChangeListener(java.beans.PropertyChangeListener)
\r
439 * @see java.beans.PropertyChangeListener
\r
440 * @see java.beans.PropertyChangeEvent
\r
441 * @param property the bound property
\r
442 * @param oldValue the old value
\r
443 * @param newVale the new value
\r
445 void firePropertyChange(String property, Object oldValue,
\r
448 Object[] array = listeners;
\r
449 if (array != null) {
\r
450 firePropertyChangeImpl(array, property, oldValue, newValue);
\r
454 private void firePropertyChangeImpl(Object[] array, String property,
\r
455 Object oldValue, Object newValue)
\r
457 for (int i = array.length; i-- != 0;) {
\r
458 Object obj = array[i];
\r
459 if (obj instanceof PropertyChangeListener) {
\r
460 PropertyChangeListener l = (PropertyChangeListener)obj;
\r
461 l.propertyChange(new PropertyChangeEvent(
\r
462 this, property, oldValue, newValue));
\r
468 * Report a warning using the error reporter for the current thread.
\r
470 * @param message the warning message to report
\r
471 * @param sourceName a string describing the source, such as a filename
\r
472 * @param lineno the starting line number
\r
473 * @param lineSource the text of the line (may be null)
\r
474 * @param lineOffset the offset into lineSource where problem was detected
\r
475 * @see org.mozilla.javascript.ErrorReporter
\r
477 public static void reportWarning(String message, String sourceName,
\r
478 int lineno, String lineSource,
\r
481 Context cx = Context.getContext();
\r
482 cx.getErrorReporter().warning(message, sourceName, lineno,
\r
483 lineSource, lineOffset);
\r
487 * Report a warning using the error reporter for the current thread.
\r
489 * @param message the warning message to report
\r
490 * @see org.mozilla.javascript.ErrorReporter
\r
492 public static void reportWarning(String message) {
\r
493 int[] linep = { 0 };
\r
494 String filename = getSourcePositionFromStack(linep);
\r
495 Context.reportWarning(message, filename, linep[0], null, 0);
\r
499 * Report an error using the error reporter for the current thread.
\r
501 * @param message the error message to report
\r
502 * @param sourceName a string describing the source, such as a filename
\r
503 * @param lineno the starting line number
\r
504 * @param lineSource the text of the line (may be null)
\r
505 * @param lineOffset the offset into lineSource where problem was detected
\r
506 * @see org.mozilla.javascript.ErrorReporter
\r
508 public static void reportError(String message, String sourceName,
\r
509 int lineno, String lineSource,
\r
512 Context cx = getCurrentContext();
\r
515 cx.getErrorReporter().error(message, sourceName, lineno,
\r
516 lineSource, lineOffset);
\r
518 throw new EvaluatorException(message);
\r
523 * Report an error using the error reporter for the current thread.
\r
525 * @param message the error message to report
\r
526 * @see org.mozilla.javascript.ErrorReporter
\r
528 public static void reportError(String message) {
\r
529 int[] linep = { 0 };
\r
530 String filename = getSourcePositionFromStack(linep);
\r
531 Context.reportError(message, filename, linep[0], null, 0);
\r
535 * Report a runtime error using the error reporter for the current thread.
\r
537 * @param message the error message to report
\r
538 * @param sourceName a string describing the source, such as a filename
\r
539 * @param lineno the starting line number
\r
540 * @param lineSource the text of the line (may be null)
\r
541 * @param lineOffset the offset into lineSource where problem was detected
\r
542 * @return a runtime exception that will be thrown to terminate the
\r
543 * execution of the script
\r
544 * @see org.mozilla.javascript.ErrorReporter
\r
546 public static EvaluatorException reportRuntimeError(String message,
\r
552 Context cx = getCurrentContext();
\r
555 return cx.getErrorReporter().
\r
556 runtimeError(message, sourceName, lineno,
\r
557 lineSource, lineOffset);
\r
559 throw new EvaluatorException(message);
\r
563 static EvaluatorException reportRuntimeError0(String messageId) {
\r
564 return reportRuntimeError(getMessage0(messageId));
\r
567 static EvaluatorException reportRuntimeError1
\r
568 (String messageId, Object arg1)
\r
570 return reportRuntimeError(getMessage1(messageId, arg1));
\r
573 static EvaluatorException reportRuntimeError2
\r
574 (String messageId, Object arg1, Object arg2)
\r
576 return reportRuntimeError(getMessage2(messageId, arg1, arg2));
\r
579 static EvaluatorException reportRuntimeError3
\r
580 (String messageId, Object arg1, Object arg2, Object arg3)
\r
582 return reportRuntimeError(getMessage3(messageId, arg1, arg2, arg3));
\r
586 * Report a runtime error using the error reporter for the current thread.
\r
588 * @param message the error message to report
\r
589 * @see org.mozilla.javascript.ErrorReporter
\r
591 public static EvaluatorException reportRuntimeError(String message) {
\r
592 int[] linep = { 0 };
\r
593 String filename = getSourcePositionFromStack(linep);
\r
594 return Context.reportRuntimeError(message, filename, linep[0], null, 0);
\r
598 * Initialize the standard objects.
\r
600 * Creates instances of the standard objects and their constructors
\r
601 * (Object, String, Number, Date, etc.), setting up 'scope' to act
\r
602 * as a global object as in ECMA 15.1.<p>
\r
604 * This method must be called to initialize a scope before scripts
\r
605 * can be evaluated in that scope.
\r
607 * @param scope the scope to initialize, or null, in which case a new
\r
608 * object will be created to serve as the scope
\r
609 * @return the initialized scope
\r
611 public Scriptable initStandardObjects(ScriptableObject scope) {
\r
612 return initStandardObjects(scope, false);
\r
616 * Initialize the standard objects.
\r
618 * Creates instances of the standard objects and their constructors
\r
619 * (Object, String, Number, Date, etc.), setting up 'scope' to act
\r
620 * as a global object as in ECMA 15.1.<p>
\r
622 * This method must be called to initialize a scope before scripts
\r
623 * can be evaluated in that scope.<p>
\r
625 * This form of the method also allows for creating "sealed" standard
\r
626 * objects. An object that is sealed cannot have properties added or
\r
627 * removed. This is useful to create a "superglobal" that can be shared
\r
628 * among several top-level objects. Note that sealing is not allowed in
\r
629 * the current ECMA/ISO language specification, but is likely for
\r
630 * the next version.
\r
632 * @param scope the scope to initialize, or null, in which case a new
\r
633 * object will be created to serve as the scope
\r
634 * @param sealed whether or not to create sealed standard objects that
\r
635 * cannot be modified.
\r
636 * @return the initialized scope
\r
639 public ScriptableObject initStandardObjects(ScriptableObject scope,
\r
643 scope = new NativeObject();
\r
645 BaseFunction.init(this, scope, sealed);
\r
646 NativeObject.init(this, scope, sealed);
\r
648 Scriptable objectProto = ScriptableObject.getObjectPrototype(scope);
\r
650 // Function.prototype.__proto__ should be Object.prototype
\r
651 Scriptable functionProto = ScriptableObject.getFunctionPrototype(scope);
\r
652 functionProto.setPrototype(objectProto);
\r
654 // Set the prototype of the object passed in if need be
\r
655 if (scope.getPrototype() == null)
\r
656 scope.setPrototype(objectProto);
\r
658 // must precede NativeGlobal since it's needed therein
\r
659 NativeError.init(this, scope, sealed);
\r
660 NativeGlobal.init(this, scope, sealed);
\r
662 NativeArray.init(this, scope, sealed);
\r
663 NativeString.init(this, scope, sealed);
\r
664 NativeBoolean.init(this, scope, sealed);
\r
665 NativeNumber.init(this, scope, sealed);
\r
666 NativeDate.init(this, scope, sealed);
\r
667 NativeMath.init(this, scope, sealed);
\r
669 NativeWith.init(this, scope, sealed);
\r
670 NativeCall.init(this, scope, sealed);
\r
671 NativeScript.init(this, scope, sealed);
\r
673 new LazilyLoadedCtor(scope,
\r
675 "org.mozilla.javascript.regexp.NativeRegExp",
\r
678 // This creates the Packages and java package roots.
\r
679 new LazilyLoadedCtor(scope,
\r
681 "org.mozilla.javascript.NativeJavaPackage",
\r
683 new LazilyLoadedCtor(scope,
\r
685 "org.mozilla.javascript.NativeJavaPackage",
\r
687 new LazilyLoadedCtor(scope,
\r
689 "org.mozilla.javascript.NativeJavaPackage",
\r
692 // Define the JavaAdapter class, allowing it to be overridden.
\r
693 String adapterClass = "org.mozilla.javascript.JavaAdapter";
\r
694 String adapterProperty = "JavaAdapter";
\r
696 adapterClass = System.getProperty(adapterClass, adapterClass);
\r
697 adapterProperty = System.getProperty
\r
698 ("org.mozilla.javascript.JavaAdapterClassName",
\r
701 catch (SecurityException e) {
\r
702 // We may not be allowed to get system properties. Just
\r
703 // use the default adapter in that case.
\r
706 new LazilyLoadedCtor(scope, adapterProperty, adapterClass, sealed);
\r
712 * Get the singleton object that represents the JavaScript Undefined value.
\r
714 public static Object getUndefinedValue() {
\r
715 return Undefined.instance;
\r
719 * Evaluate a JavaScript source string.
\r
721 * The provided source name and line number are used for error messages
\r
722 * and for producing debug information.
\r
724 * @param scope the scope to execute in
\r
725 * @param source the JavaScript source
\r
726 * @param sourceName a string describing the source, such as a filename
\r
727 * @param lineno the starting line number
\r
728 * @param securityDomain an arbitrary object that specifies security
\r
729 * information about the origin or owner of the script. For
\r
730 * implementations that don't care about security, this value
\r
732 * @return the result of evaluating the string
\r
733 * @exception JavaScriptException if an uncaught JavaScript exception
\r
734 * occurred while evaluating the source string
\r
735 * @see org.mozilla.javascript.SecuritySupport
\r
737 public Object evaluateString(Scriptable scope, String source,
\r
738 String sourceName, int lineno,
\r
739 Object securityDomain)
\r
740 throws JavaScriptException
\r
743 Reader in = new StringReader(source);
\r
744 return evaluateReader(scope, in, sourceName, lineno,
\r
747 catch (IOException ioe) {
\r
748 // Should never occur because we just made the reader from a String
\r
749 throw new RuntimeException();
\r
754 * Evaluate a reader as JavaScript source.
\r
756 * All characters of the reader are consumed.
\r
758 * @param scope the scope to execute in
\r
759 * @param in the Reader to get JavaScript source from
\r
760 * @param sourceName a string describing the source, such as a filename
\r
761 * @param lineno the starting line number
\r
762 * @param securityDomain an arbitrary object that specifies security
\r
763 * information about the origin or owner of the script. For
\r
764 * implementations that don't care about security, this value
\r
766 * @return the result of evaluating the source
\r
768 * @exception IOException if an IOException was generated by the Reader
\r
769 * @exception JavaScriptException if an uncaught JavaScript exception
\r
770 * occurred while evaluating the Reader
\r
772 public Object evaluateReader(Scriptable scope, Reader in,
\r
773 String sourceName, int lineno,
\r
774 Object securityDomain)
\r
775 throws IOException, JavaScriptException
\r
777 Script script = compileReader(scope, in, sourceName, lineno,
\r
779 if (script != null)
\r
780 return script.exec(this, scope);
\r
786 * Check whether a string is ready to be compiled.
\r
788 * stringIsCompilableUnit is intended to support interactive compilation of
\r
789 * javascript. If compiling the string would result in an error
\r
790 * that might be fixed by appending more source, this method
\r
791 * returns false. In every other case, it returns true.
\r
793 * Interactive shells may accumulate source lines, using this
\r
794 * method after each new line is appended to check whether the
\r
795 * statement being entered is complete.
\r
797 * @param source the source buffer to check
\r
798 * @return whether the source is ready for compilation
\r
799 * @since 1.4 Release 2
\r
801 synchronized public boolean stringIsCompilableUnit(String source)
\r
803 Reader in = new StringReader(source);
\r
804 // no source name or source text manager, because we're just
\r
805 // going to throw away the result.
\r
806 TokenStream ts = new TokenStream(in, null, null, 1);
\r
808 // Temporarily set error reporter to always be the exception-throwing
\r
809 // DefaultErrorReporter. (This is why the method is synchronized...)
\r
810 ErrorReporter currentReporter =
\r
811 setErrorReporter(new DefaultErrorReporter());
\r
813 boolean errorseen = false;
\r
815 IRFactory irf = new IRFactory(ts, null);
\r
816 Parser p = new Parser(irf);
\r
818 } catch (IOException ioe) {
\r
820 } catch (EvaluatorException ee) {
\r
823 // Restore the old error reporter.
\r
824 setErrorReporter(currentReporter);
\r
826 // Return false only if an error occurred as a result of reading past
\r
827 // the end of the file, i.e. if the source could be fixed by
\r
828 // appending more source.
\r
829 if (errorseen && ts.eof())
\r
836 * Compiles the source in the given reader.
\r
838 * Returns a script that may later be executed.
\r
839 * Will consume all the source in the reader.
\r
841 * @param scope if nonnull, will be the scope in which the script object
\r
842 * is created. The script object will be a valid JavaScript object
\r
843 * as if it were created using the JavaScript1.3 Script constructor
\r
844 * @param in the input reader
\r
845 * @param sourceName a string describing the source, such as a filename
\r
846 * @param lineno the starting line number for reporting errors
\r
847 * @param securityDomain an arbitrary object that specifies security
\r
848 * information about the origin or owner of the script. For
\r
849 * implementations that don't care about security, this value
\r
851 * @return a script that may later be executed
\r
852 * @see org.mozilla.javascript.Script#exec
\r
853 * @exception IOException if an IOException was generated by the Reader
\r
855 public Script compileReader(Scriptable scope, Reader in, String sourceName,
\r
856 int lineno, Object securityDomain)
\r
859 return (Script) compile(scope, in, sourceName, lineno, securityDomain,
\r
865 * Compile a JavaScript function.
\r
867 * The function source must be a function definition as defined by
\r
868 * ECMA (e.g., "function f(a) { return a; }").
\r
870 * @param scope the scope to compile relative to
\r
871 * @param source the function definition source
\r
872 * @param sourceName a string describing the source, such as a filename
\r
873 * @param lineno the starting line number
\r
874 * @param securityDomain an arbitrary object that specifies security
\r
875 * information about the origin or owner of the script. For
\r
876 * implementations that don't care about security, this value
\r
878 * @return a Function that may later be called
\r
879 * @see org.mozilla.javascript.Function
\r
881 public Function compileFunction(Scriptable scope, String source,
\r
882 String sourceName, int lineno,
\r
883 Object securityDomain)
\r
885 Reader in = new StringReader(source);
\r
887 return (Function) compile(scope, in, sourceName, lineno,
\r
888 securityDomain, true);
\r
890 catch (IOException ioe) {
\r
891 // Should never happen because we just made the reader
\r
893 throw new RuntimeException();
\r
898 * Decompile the script.
\r
900 * The canonical source of the script is returned.
\r
902 * @param script the script to decompile
\r
903 * @param scope the scope under which to decompile
\r
904 * @param indent the number of spaces to indent the result
\r
905 * @return a string representing the script source
\r
907 public String decompileScript(Script script, Scriptable scope,
\r
910 NativeScript ns = (NativeScript) script;
\r
911 ns.initScript(scope);
\r
912 return ns.decompile(this, indent, false);
\r
916 * Decompile a JavaScript Function.
\r
918 * Decompiles a previously compiled JavaScript function object to
\r
919 * canonical source.
\r
921 * Returns function body of '[native code]' if no decompilation
\r
922 * information is available.
\r
924 * @param fun the JavaScript function to decompile
\r
925 * @param indent the number of spaces to indent the result
\r
926 * @return a string representing the function source
\r
928 public String decompileFunction(Function fun, int indent) {
\r
929 if (fun instanceof BaseFunction)
\r
930 return ((BaseFunction)fun).decompile(this, indent, false);
\r
932 return "function " + fun.getClassName() +
\r
933 "() {\n\t[native code]\n}\n";
\r
937 * Decompile the body of a JavaScript Function.
\r
939 * Decompiles the body a previously compiled JavaScript Function
\r
940 * object to canonical source, omitting the function header and
\r
943 * Returns '[native code]' if no decompilation information is available.
\r
945 * @param fun the JavaScript function to decompile
\r
946 * @param indent the number of spaces to indent the result
\r
947 * @return a string representing the function body source.
\r
949 public String decompileFunctionBody(Function fun, int indent) {
\r
950 if (fun instanceof BaseFunction)
\r
951 return ((BaseFunction)fun).decompile(this, indent, true);
\r
953 // not sure what the right response here is. JSRef currently
\r
955 return "[native code]\n";
\r
959 * Create a new JavaScript object.
\r
961 * Equivalent to evaluating "new Object()".
\r
962 * @param scope the scope to search for the constructor and to evaluate
\r
964 * @return the new object
\r
965 * @exception PropertyException if "Object" cannot be found in
\r
967 * @exception NotAFunctionException if the "Object" found in the scope
\r
968 * is not a function
\r
969 * @exception JavaScriptException if an uncaught JavaScript exception
\r
970 * occurred while creating the object
\r
972 public Scriptable newObject(Scriptable scope)
\r
973 throws PropertyException,
\r
974 NotAFunctionException,
\r
975 JavaScriptException
\r
977 return newObject(scope, "Object", null);
\r
981 * Create a new JavaScript object by executing the named constructor.
\r
983 * The call <code>newObject(scope, "Foo")</code> is equivalent to
\r
984 * evaluating "new Foo()".
\r
986 * @param scope the scope to search for the constructor and to evaluate against
\r
987 * @param constructorName the name of the constructor to call
\r
988 * @return the new object
\r
989 * @exception PropertyException if a property with the constructor
\r
990 * name cannot be found in the scope
\r
991 * @exception NotAFunctionException if the property found in the scope
\r
992 * is not a function
\r
993 * @exception JavaScriptException if an uncaught JavaScript exception
\r
994 * occurred while creating the object
\r
996 public Scriptable newObject(Scriptable scope, String constructorName)
\r
997 throws PropertyException,
\r
998 NotAFunctionException,
\r
999 JavaScriptException
\r
1001 return newObject(scope, constructorName, null);
\r
1005 * Creates a new JavaScript object by executing the named constructor.
\r
1007 * Searches <code>scope</code> for the named constructor, calls it with
\r
1008 * the given arguments, and returns the result.<p>
\r
1012 * Object[] args = { "a", "b" };
\r
1013 * newObject(scope, "Foo", args)</pre>
\r
1014 * is equivalent to evaluating "new Foo('a', 'b')", assuming that the Foo
\r
1015 * constructor has been defined in <code>scope</code>.
\r
1017 * @param scope The scope to search for the constructor and to evaluate
\r
1019 * @param constructorName the name of the constructor to call
\r
1020 * @param args the array of arguments for the constructor
\r
1021 * @return the new object
\r
1022 * @exception PropertyException if a property with the constructor
\r
1023 * name cannot be found in the scope
\r
1024 * @exception NotAFunctionException if the property found in the scope
\r
1025 * is not a function
\r
1026 * @exception JavaScriptException if an uncaught JavaScript exception
\r
1027 * occurs while creating the object
\r
1029 public Scriptable newObject(Scriptable scope, String constructorName,
\r
1031 throws PropertyException,
\r
1032 NotAFunctionException,
\r
1033 JavaScriptException
\r
1035 Object ctorVal = ScriptRuntime.getTopLevelProp(scope, constructorName);
\r
1036 if (ctorVal == Scriptable.NOT_FOUND) {
\r
1037 String message = getMessage1("msg.ctor.not.found", constructorName);
\r
1038 throw new PropertyException(message);
\r
1040 if (!(ctorVal instanceof Function)) {
\r
1041 String message = getMessage1("msg.not.ctor", constructorName);
\r
1042 throw new NotAFunctionException(message);
\r
1044 Function ctor = (Function) ctorVal;
\r
1045 return ctor.construct(this, ctor.getParentScope(),
\r
1046 (args == null) ? ScriptRuntime.emptyArgs : args);
\r
1050 * Create an array with a specified initial length.
\r
1052 * @param scope the scope to create the object in
\r
1053 * @param length the initial length (JavaScript arrays may have
\r
1054 * additional properties added dynamically).
\r
1055 * @return the new array object
\r
1057 public Scriptable newArray(Scriptable scope, int length) {
\r
1058 Scriptable result = new NativeArray(length);
\r
1059 newArrayHelper(scope, result);
\r
1064 * Create an array with a set of initial elements.
\r
1066 * @param scope the scope to create the object in
\r
1067 * @param elements the initial elements. Each object in this array
\r
1068 * must be an acceptable JavaScript type.
\r
1069 * @return the new array object
\r
1071 public Scriptable newArray(Scriptable scope, Object[] elements) {
\r
1072 Scriptable result = new NativeArray(elements);
\r
1073 newArrayHelper(scope, result);
\r
1078 * Get the elements of a JavaScript array.
\r
1080 * If the object defines a length property, a Java array with that
\r
1081 * length is created and initialized with the values obtained by
\r
1082 * calling get() on object for each value of i in [0,length-1]. If
\r
1083 * there is not a defined value for a property the Undefined value
\r
1084 * is used to initialize the corresponding element in the array. The
\r
1085 * Java array is then returned.
\r
1086 * If the object doesn't define a length property, null is returned.
\r
1087 * @param object the JavaScript array or array-like object
\r
1088 * @return a Java array of objects
\r
1089 * @since 1.4 release 2
\r
1091 public Object[] getElements(Scriptable object) {
\r
1092 double doubleLen = NativeArray.getLengthProperty(object);
\r
1093 if (doubleLen != doubleLen)
\r
1095 int len = (int) doubleLen;
\r
1096 Object[] result = new Object[len];
\r
1097 for (int i=0; i < len; i++) {
\r
1098 Object elem = object.get(i, object);
\r
1099 result[i] = elem == Scriptable.NOT_FOUND ? Undefined.instance
\r
1106 * Convert the value to a JavaScript boolean value.
\r
1110 * @param value a JavaScript value
\r
1111 * @return the corresponding boolean value converted using
\r
1114 public static boolean toBoolean(Object value) {
\r
1115 return ScriptRuntime.toBoolean(value);
\r
1119 * Convert the value to a JavaScript Number value.
\r
1121 * Returns a Java double for the JavaScript Number.
\r
1125 * @param value a JavaScript value
\r
1126 * @return the corresponding double value converted using
\r
1129 public static double toNumber(Object value) {
\r
1130 return ScriptRuntime.toNumber(value);
\r
1134 * Convert the value to a JavaScript String value.
\r
1138 * @param value a JavaScript value
\r
1139 * @return the corresponding String value converted using
\r
1142 public static String toString(Object value) {
\r
1143 return ScriptRuntime.toString(value);
\r
1147 * Convert the value to an JavaScript object value.
\r
1149 * Note that a scope must be provided to look up the constructors
\r
1150 * for Number, Boolean, and String.
\r
1154 * Additionally, arbitrary Java objects and classes will be
\r
1155 * wrapped in a Scriptable object with its Java fields and methods
\r
1156 * reflected as JavaScript properties of the object.
\r
1158 * @param value any Java object
\r
1159 * @param scope global scope containing constructors for Number,
\r
1160 * Boolean, and String
\r
1161 * @return new JavaScript object
\r
1163 public static Scriptable toObject(Object value, Scriptable scope) {
\r
1164 return ScriptRuntime.toObject(scope, value, null);
\r
1168 * Convert the value to an JavaScript object value.
\r
1170 * Note that a scope must be provided to look up the constructors
\r
1171 * for Number, Boolean, and String.
\r
1175 * Additionally, arbitrary Java objects and classes will be
\r
1176 * wrapped in a Scriptable object with its Java fields and methods
\r
1177 * reflected as JavaScript properties of the object. If the
\r
1178 * "staticType" parameter is provided, it will be used as the static
\r
1179 * type of the Java value to create.
\r
1181 * @param value any Java object
\r
1182 * @param scope global scope containing constructors for Number,
\r
1183 * Boolean, and String
\r
1184 * @param staticType the static type of the Java value to create
\r
1185 * @return new JavaScript object
\r
1187 public static Scriptable toObject(Object value, Scriptable scope,
\r
1188 Class staticType) {
\r
1189 if (value == null && staticType != null)
\r
1191 return ScriptRuntime.toObject(scope, value, staticType);
\r
1195 * Tell whether debug information is being generated.
\r
1198 public boolean isGeneratingDebug() {
\r
1199 return generatingDebug;
\r
1203 * Specify whether or not debug information should be generated.
\r
1205 * Setting the generation of debug information on will set the
\r
1206 * optimization level to zero.
\r
1209 public void setGeneratingDebug(boolean generatingDebug) {
\r
1210 generatingDebugChanged = true;
\r
1211 if (generatingDebug)
\r
1212 setOptimizationLevel(0);
\r
1213 this.generatingDebug = generatingDebug;
\r
1217 * Tell whether source information is being generated.
\r
1220 public boolean isGeneratingSource() {
\r
1221 return generatingSource;
\r
1225 * Specify whether or not source information should be generated.
\r
1227 * Without source information, evaluating the "toString" method
\r
1228 * on JavaScript functions produces only "[native code]" for
\r
1229 * the body of the function.
\r
1230 * Note that code generated without source is not fully ECMA
\r
1234 public void setGeneratingSource(boolean generatingSource) {
\r
1235 this.generatingSource = generatingSource;
\r
1239 * Get the current optimization level.
\r
1241 * The optimization level is expressed as an integer between -1 and
\r
1246 public int getOptimizationLevel() {
\r
1247 return optimizationLevel;
\r
1251 * Set the current optimization level.
\r
1253 * The optimization level is expected to be an integer between -1 and
\r
1254 * 9. Any negative values will be interpreted as -1, and any values
\r
1255 * greater than 9 will be interpreted as 9.
\r
1256 * An optimization level of -1 indicates that interpretive mode will
\r
1257 * always be used. Levels 0 through 9 indicate that class files may
\r
1258 * be generated. Higher optimization levels trade off compile time
\r
1259 * performance for runtime performance.
\r
1260 * The optimizer level can't be set greater than -1 if the optimizer
\r
1261 * package doesn't exist at run time.
\r
1262 * @param optimizationLevel an integer indicating the level of
\r
1263 * optimization to perform
\r
1267 public void setOptimizationLevel(int optimizationLevel) {
\r
1268 if (optimizationLevel < 0) {
\r
1269 optimizationLevel = -1;
\r
1270 } else if (optimizationLevel > 9) {
\r
1271 optimizationLevel = 9;
\r
1273 if (codegenClass == null)
\r
1274 optimizationLevel = -1;
\r
1275 this.optimizationLevel = optimizationLevel;
\r
1279 * Get the current target class file name.
\r
1281 * If nonnull, requests to compile source will result in one or
\r
1282 * more class files being generated.
\r
1285 public String getTargetClassFileName() {
\r
1286 return nameHelper == null
\r
1288 : nameHelper.getTargetClassFileName();
\r
1292 * Set the current target class file name.
\r
1294 * If nonnull, requests to compile source will result in one or
\r
1295 * more class files being generated. If null, classes will only
\r
1296 * be generated in memory.
\r
1300 public void setTargetClassFileName(String classFileName) {
\r
1301 if (nameHelper != null)
\r
1302 nameHelper.setTargetClassFileName(classFileName);
\r
1306 * Get the current package to generate classes into.
\r
1310 public String getTargetPackage() {
\r
1311 return (nameHelper == null) ? null : nameHelper.getTargetPackage();
\r
1315 * Set the package to generate classes into.
\r
1319 public void setTargetPackage(String targetPackage) {
\r
1320 if (nameHelper != null)
\r
1321 nameHelper.setTargetPackage(targetPackage);
\r
1325 * Get the current interface to write class bytes into.
\r
1327 * @see ClassOutput
\r
1328 * @since 1.5 Release 2
\r
1330 public ClassOutput getClassOutput() {
\r
1331 return nameHelper == null ? null : nameHelper.getClassOutput();
\r
1335 * Set the interface to write class bytes into.
\r
1336 * Unless setTargetClassFileName() has been called classOutput will be
\r
1337 * used each time the javascript compiler has generated the bytecode for a
\r
1340 * @see ClassOutput
\r
1341 * @since 1.5 Release 2
\r
1343 public void setClassOutput(ClassOutput classOutput) {
\r
1344 if (nameHelper != null)
\r
1345 nameHelper.setClassOutput(classOutput);
\r
1349 * Add a Context listener.
\r
1351 public static void addContextListener(ContextListener listener) {
\r
1352 synchronized (staticDataLock) {
\r
1353 contextListeners = ListenerArray.add(contextListeners, listener);
\r
1358 * Remove a Context listener.
\r
1359 * @param listener the listener to remove.
\r
1361 public static void removeContextListener(ContextListener listener) {
\r
1362 synchronized (staticDataLock) {
\r
1363 contextListeners = ListenerArray.remove(contextListeners, listener);
\r
1368 * Set the security support for this context.
\r
1369 * <p> SecuritySupport may only be set if it is currently null.
\r
1370 * Otherwise a SecurityException is thrown.
\r
1371 * @param supportObj a SecuritySupport object
\r
1372 * @throws SecurityException if there is already a SecuritySupport
\r
1373 * object for this Context
\r
1375 public synchronized void setSecuritySupport(SecuritySupport supportObj) {
\r
1376 if (securitySupport != null) {
\r
1377 throw new SecurityException("Cannot overwrite existing " +
\r
1378 "SecuritySupport object");
\r
1380 securitySupport = supportObj;
\r
1384 * Return true if a security domain is required on calls to
\r
1385 * compile and evaluate scripts.
\r
1387 * @since 1.4 Release 2
\r
1389 public static boolean isSecurityDomainRequired() {
\r
1390 return requireSecurityDomain;
\r
1394 * Returns the security context associated with the innermost
\r
1395 * script or function being executed by the interpreter.
\r
1396 * @since 1.4 release 2
\r
1398 public Object getInterpreterSecurityDomain() {
\r
1399 return interpreterSecurityDomain;
\r
1403 * Returns true if the class parameter is a class in the
\r
1404 * interpreter. Typically used by embeddings that get a class
\r
1405 * context to check security. These embeddings must know
\r
1406 * whether to get the security context associated with the
\r
1407 * interpreter or not.
\r
1409 * @param cl a class to test whether or not it is an interpreter
\r
1411 * @return true if cl is an interpreter class
\r
1412 * @since 1.4 release 2
\r
1414 public boolean isInterpreterClass(Class cl) {
\r
1415 return cl == Interpreter.class;
\r
1419 * Set the class that the generated target will extend.
\r
1421 * @param extendsClass the class it extends
\r
1423 public void setTargetExtends(Class extendsClass) {
\r
1424 if (nameHelper != null) {
\r
1425 nameHelper.setTargetExtends(extendsClass);
\r
1430 * Set the interfaces that the generated target will implement.
\r
1432 * @param implementsClasses an array of Class objects, one for each
\r
1433 * interface the target will extend
\r
1435 public void setTargetImplements(Class[] implementsClasses) {
\r
1436 if (nameHelper != null) {
\r
1437 nameHelper.setTargetImplements(implementsClasses);
\r
1442 * Get a value corresponding to a key.
\r
1444 * Since the Context is associated with a thread it can be
\r
1445 * used to maintain values that can be later retrieved using
\r
1446 * the current thread.
\r
1448 * Note that the values are maintained with the Context, so
\r
1449 * if the Context is disassociated from the thread the values
\r
1450 * cannot be retreived. Also, if private data is to be maintained
\r
1451 * in this manner the key should be a java.lang.Object
\r
1452 * whose reference is not divulged to untrusted code.
\r
1453 * @param key the key used to lookup the value
\r
1454 * @return a value previously stored using putThreadLocal.
\r
1456 public Object getThreadLocal(Object key) {
\r
1457 if (hashtable == null)
\r
1459 return hashtable.get(key);
\r
1463 * Put a value that can later be retrieved using a given key.
\r
1465 * @param key the key used to index the value
\r
1466 * @param value the value to save
\r
1468 public void putThreadLocal(Object key, Object value) {
\r
1469 if (hashtable == null)
\r
1470 hashtable = new Hashtable();
\r
1471 hashtable.put(key, value);
\r
1475 * Remove values from thread-local storage.
\r
1476 * @param key the key for the entry to remove.
\r
1477 * @since 1.5 release 2
\r
1479 public void removeThreadLocal(Object key) {
\r
1480 if (hashtable == null)
\r
1482 hashtable.remove(key);
\r
1486 * Return whether functions are compiled by this context using
\r
1489 * If functions are compiled with dynamic scope, then they execute
\r
1490 * in the scope of their caller, rather than in their parent scope.
\r
1491 * This is useful for sharing functions across multiple scopes.
\r
1492 * @since 1.5 Release 1
\r
1494 public boolean hasCompileFunctionsWithDynamicScope() {
\r
1495 return compileFunctionsWithDynamicScopeFlag;
\r
1499 * Set whether functions compiled by this context should use
\r
1502 * @param flag if true, compile functions with dynamic scope
\r
1503 * @since 1.5 Release 1
\r
1505 public void setCompileFunctionsWithDynamicScope(boolean flag) {
\r
1506 compileFunctionsWithDynamicScopeFlag = flag;
\r
1510 * Set whether to cache some values statically.
\r
1512 * By default, the engine will cache some values statically
\r
1513 * (reflected Java classes, for instance). This can speed
\r
1514 * execution dramatically, but increases the memory footprint.
\r
1515 * Also, with caching enabled, references may be held to
\r
1516 * objects past the lifetime of any real usage.
\r
1518 * If caching is enabled and this method is called with a
\r
1519 * <code>false</code> argument, the caches will be emptied.
\r
1520 * So one strategy could be to clear the caches at times
\r
1521 * appropriate to the application.
\r
1523 * Caching is enabled by default.
\r
1525 * @param cachingEnabled if true, caching is enabled
\r
1526 * @since 1.5 Release 1
\r
1528 public static void setCachingEnabled(boolean cachingEnabled) {
\r
1529 if (isCachingEnabled && !cachingEnabled) {
\r
1530 // Caching is being turned off. Empty caches.
\r
1531 JavaMembers.classTable = new Hashtable();
\r
1532 nameHelper.reset();
\r
1534 isCachingEnabled = cachingEnabled;
\r
1535 FunctionObject.setCachingEnabled(cachingEnabled);
\r
1539 * Set a WrapHandler for this Context.
\r
1541 * The WrapHandler allows custom object wrapping behavior for
\r
1542 * Java object manipulated with JavaScript.
\r
1543 * @see org.mozilla.javascript.WrapHandler
\r
1544 * @since 1.5 Release 2
\r
1546 public void setWrapHandler(WrapHandler wrapHandler) {
\r
1547 this.wrapHandler = wrapHandler;
\r
1551 * Return the current WrapHandler, or null if none is defined.
\r
1552 * @see org.mozilla.javascript.WrapHandler
\r
1553 * @since 1.5 Release 2
\r
1555 public WrapHandler getWrapHandler() {
\r
1556 return wrapHandler;
\r
1559 public DebuggableEngine getDebuggableEngine() {
\r
1560 if (debuggableEngine == null)
\r
1561 debuggableEngine = new DebuggableEngineImpl(this);
\r
1562 return debuggableEngine;
\r
1567 * if hasFeature(FEATURE_NON_ECMA_GET_YEAR) returns true,
\r
1568 * Date.prototype.getYear subtructs 1900 only if 1900 <= date < 2000
\r
1569 * in deviation with Ecma B.2.4
\r
1571 public static final int FEATURE_NON_ECMA_GET_YEAR = 1;
\r
1574 * Controls certain aspects of script semantics.
\r
1575 * Should be overwritten to alter default behavior.
\r
1576 * @param featureIndex feature index to check
\r
1577 * @return true if the <code>featureIndex</code> feature is turned on
\r
1578 * @see #FEATURE_NON_ECMA_GET_YEAR
\r
1580 public boolean hasFeature(int featureIndex) {
\r
1581 if (featureIndex == FEATURE_NON_ECMA_GET_YEAR) {
\r
1583 * During the great date rewrite of 1.3, we tried to track the
\r
1584 * evolving ECMA standard, which then had a definition of
\r
1585 * getYear which always subtracted 1900. Which we
\r
1586 * implemented, not realizing that it was incompatible with
\r
1587 * the old behavior... now, rather than thrash the behavior
\r
1588 * yet again, we've decided to leave it with the - 1900
\r
1589 * behavior and point people to the getFullYear method. But
\r
1590 * we try to protect existing scripts that have specified a
\r
1593 return (version == Context.VERSION_1_0
\r
1594 || version == Context.VERSION_1_1
\r
1595 || version == Context.VERSION_1_2);
\r
1597 throw new RuntimeException("Bad feature index: " + featureIndex);
\r
1601 * Get/Set threshold of executed instructions counter that triggers call to
\r
1602 * <code>observeInstructionCount()</code>.
\r
1603 * When the threshold is zero, instruction counting is disabled,
\r
1604 * otherwise each time the run-time executes at least the threshold value
\r
1605 * of script instructions, <code>observeInstructionCount()</code> will
\r
1608 public int getInstructionObserverThreshold() {
\r
1609 return instructionThreshold;
\r
1612 public void setInstructionObserverThreshold(int threshold) {
\r
1613 instructionThreshold = threshold;
\r
1617 * Allow application to monitor counter of executed script instructions
\r
1618 * in Context subclasses.
\r
1619 * Run-time calls this when instruction counting is enabled and the counter
\r
1620 * reaches limit set by <code>setInstructionObserverThreshold()</code>.
\r
1621 * The method is useful to observe long running scripts and if necessary
\r
1622 * to terminate them.
\r
1623 * @param instructionCount amount of script instruction executed since
\r
1624 * last call to <code>observeInstructionCount</code>
\r
1625 * @throws Error to terminate the script
\r
1627 protected void observeInstructionCount(int instructionCount) {}
\r
1629 /********** end of API **********/
\r
1631 void pushFrame(DebugFrame frame) {
\r
1632 if (frameStack == null)
\r
1633 frameStack = new java.util.Stack();
\r
1634 frameStack.push(frame);
\r
1643 static String getMessage0(String messageId) {
\r
1644 return getMessage(messageId, null);
\r
1647 static String getMessage1(String messageId, Object arg1) {
\r
1648 Object[] arguments = {arg1};
\r
1649 return getMessage(messageId, arguments);
\r
1652 static String getMessage2(String messageId, Object arg1, Object arg2) {
\r
1653 Object[] arguments = {arg1, arg2};
\r
1654 return getMessage(messageId, arguments);
\r
1657 static String getMessage3
\r
1658 (String messageId, Object arg1, Object arg2, Object arg3) {
\r
1659 Object[] arguments = {arg1, arg2, arg3};
\r
1660 return getMessage(messageId, arguments);
\r
1663 * Internal method that reports an error for missing calls to
\r
1666 static Context getContext() {
\r
1667 Thread t = Thread.currentThread();
\r
1668 Context cx = (Context) threadContexts.get(t);
\r
1670 throw new RuntimeException(
\r
1671 "No Context associated with current Thread");
\r
1676 /** GCJ doesn't have an easy way to bundle up .properties files, so we do this */
\r
1677 static class HardCodedResourceBundle extends ListResourceBundle {
\r
1678 public Object[][] getContents() { return contents; }
\r
1679 static final Object[][] contents = {
\r
1680 { "msg.dup.parms", "Duplicate parameter name \"{0}\"." },
\r
1681 { "msg.ctor.not.found", "Constructor for \"{0}\" not found." },
\r
1682 { "msg.not.ctor", "\"{0}\" is not a constructor." },
\r
1683 { "msg.varargs.ctor", "Method or constructor \"{0}\" must be static with the signature \"(Context cx, Object[] args, Function ctorObj, boolean inNewExpr)\" to define a variable arguments constructor." },
\r
1684 { "msg.varargs.fun", "Method \"{0}\" must be static with the signature \"(Context cx, Scriptable thisObj, Object[] args, Function funObj)\" to define a variable arguments function." },
\r
1685 { "msg.incompat.call", "Method \"{0}\" called on incompatible object." },
\r
1686 { "msg.bad.parms", "Bad method parameters for \"{0}\"." },
\r
1687 { "msg.no.overload", "Method \"{0}\" occurs multiple times in class \"{1}\"." },
\r
1688 { "msg.method.not.found", "Method \"{0}\" not found in \"{1}\"." },
\r
1689 { "msg.bad.for.in.lhs", "Invalid left-hand side of for..in loop." },
\r
1690 { "msg.bad.lhs.assign", "Invalid assignment left-hand side." },
\r
1691 { "msg.mult.index", "Only one variable allowed in for..in loop." },
\r
1692 { "msg.cant.convert", "Can''t convert to type \"{0}\"." },
\r
1693 { "msg.cant.call.indirect", "Function \"{0}\" must be called directly, and not by way of a function of another name." },
\r
1694 { "msg.eval.nonstring", "Calling eval() with anything other than a primitive string value will simply return the value. Is this what you intended?" },
\r
1695 { "msg.only.from.new", "\"{0}\" may only be invoked from a \"new\" expression." },
\r
1696 { "msg.deprec.ctor", "The \"{0}\" constructor is deprecated." },
\r
1697 { "msg.no.function.ref.found.in", "no source found in {1} to decompile function reference {0}" },
\r
1698 { "msg.no.function.ref.found", "no source found to decompile function reference {0}" },
\r
1699 { "msg.arg.isnt.array", "second argument to Function.prototype.apply must be an array" },
\r
1700 { "msg.bad.esc.mask", "invalid string escape mask" },
\r
1701 { "msg.cant.instantiate", "error instantiating ({0}): class {1} is interface or abstract" },
\r
1702 { "msg.bad.ctor.sig", "Found constructor with wrong signature: {0} calling {1} with signature {2}" },
\r
1703 { "msg.not.java.obj", "Expected argument to getClass() to be a Java object." },
\r
1704 { "msg.no.java.ctor", "Java constructor for \"{0}\" with arguments \"{1}\" not found." },
\r
1705 { "msg.method.ambiguous", "The choice of Java method {0}.{1} matching JavaScript argument types ({2}) is ambiguous; candidate methods are: {3}" },
\r
1706 { "msg.constructor.ambiguous", "The choice of Java constructor {0} matching JavaScript argument types ({1}) is ambiguous; candidate constructors are: {2}" },
\r
1707 { "msg.conversion.not.allowed", "Cannot convert {0} to {1}" },
\r
1708 { "msg.bad.quant", "Invalid quantifier {0}" },
\r
1709 { "msg.overlarge.max", "Overly large maximum {0}" },
\r
1710 { "msg.zero.quant", "Zero quantifier {0}" },
\r
1711 { "msg.max.lt.min", "Maximum {0} less than minimum" },
\r
1712 { "msg.unterm.quant", "Unterminated quantifier {0}" },
\r
1713 { "msg.unterm.paren", "Unterminated parenthetical {0}" },
\r
1714 { "msg.unterm.class", "Unterminated character class {0}" },
\r
1715 { "msg.bad.range", "Invalid range in character class." },
\r
1716 { "msg.trail.backslash", "Trailing \\ in regular expression." },
\r
1717 { "msg.no.regexp", "Regular expressions are not available." },
\r
1718 { "msg.bad.backref", "back-reference exceeds number of capturing parentheses." },
\r
1719 { "msg.dup.label", "Duplicate label {0}." },
\r
1720 { "msg.undef.label", "Undefined label {0}." },
\r
1721 { "msg.bad.break", "Unlabelled break must be inside loop or switch." },
\r
1722 { "msg.continue.outside", "continue must be inside loop." },
\r
1723 { "msg.continue.nonloop", "Can only continue to labeled iteration statement." },
\r
1724 { "msg.fn.redecl", "Function \"{0}\" redeclared; prior definition will be ignored." },
\r
1725 { "msg.no.paren.parms", "missing ( before function parameters" },
\r
1726 { "msg.no.parm", "missing formal parameter" },
\r
1727 { "msg.no.paren.after.parms", "missing ) after formal parameters" },
\r
1728 { "msg.no.brace.body", "missing '{' before function body" },
\r
1729 { "msg.no.brace.after.body", "missing } after function body" },
\r
1730 { "msg.no.paren.cond", "missing ( before condition" },
\r
1731 { "msg.no.paren.after.cond", "missing ) after condition" },
\r
1732 { "msg.no.semi.stmt", "missing ; before statement" },
\r
1733 { "msg.no.name.after.dot", "missing name after . operator" },
\r
1734 { "msg.no.bracket.index", "missing ] in index expression" },
\r
1735 { "msg.no.paren.switch", "missing ( before switch expression" },
\r
1736 { "msg.no.paren.after.switch", "missing ) after switch expression" },
\r
1737 { "msg.no.brace.switch", "missing '{' before switch body" },
\r
1738 { "msg.bad.switch", "invalid switch statement" },
\r
1739 { "msg.no.colon.case", "missing : after case expression" },
\r
1740 { "msg.no.while.do", "missing while after do-loop body" },
\r
1741 { "msg.no.paren.for", "missing ( after for" },
\r
1742 { "msg.no.semi.for", "missing ; after for-loop initializer" },
\r
1743 { "msg.no.semi.for.cond", "missing ; after for-loop condition" },
\r
1744 { "msg.no.paren.for.ctrl", "missing ) after for-loop control" },
\r
1745 { "msg.no.paren.with", "missing ( before with-statement object" },
\r
1746 { "msg.no.paren.after.with", "missing ) after with-statement object" },
\r
1747 { "msg.bad.return", "invalid return" },
\r
1748 { "msg.no.brace.block", "missing } in compound statement" },
\r
1749 { "msg.bad.label", "invalid label" },
\r
1750 { "msg.bad.var", "missing variable name" },
\r
1751 { "msg.bad.var.init", "invalid variable initialization" },
\r
1752 { "msg.no.colon.cond", "missing : in conditional expression" },
\r
1753 { "msg.no.paren.arg", "missing ) after argument list" },
\r
1754 { "msg.no.bracket.arg", "missing ] after element list" },
\r
1755 { "msg.bad.prop", "invalid property id" },
\r
1756 { "msg.no.colon.prop", "missing : after property id" },
\r
1757 { "msg.no.brace.prop", "missing } after property list" },
\r
1758 { "msg.no.paren", "missing ) in parenthetical" },
\r
1759 { "msg.reserved.id", "identifier is a reserved word" },
\r
1760 { "msg.no.paren.catch", "missing ( before catch-block condition" },
\r
1761 { "msg.bad.catchcond", "invalid catch block condition" },
\r
1762 { "msg.catch.unreachable", "any catch clauses following an unqualified catch are unreachable" },
\r
1763 { "msg.no.brace.catchblock", "missing '{' before catch-block body" },
\r
1764 { "msg.try.no.catchfinally", "''try'' without ''catch'' or ''finally''" },
\r
1765 { "msg.syntax", "syntax error" },
\r
1766 { "msg.assn.create", "Assignment to undefined \"{0}\" will create a new variable. Add a variable statement at the top level scope to remove this warning." },
\r
1767 { "msg.prop.not.found", "Property not found." },
\r
1768 { "msg.invalid.type", "Invalid JavaScript value of type {0}" },
\r
1769 { "msg.primitive.expected", "Primitive type expected (had {0} instead)" },
\r
1770 { "msg.null.to.object", "Cannot convert null to an object." },
\r
1771 { "msg.undef.to.object", "Cannot convert undefined to an object." },
\r
1772 { "msg.cyclic.value", "Cyclic {0} value not allowed." },
\r
1773 { "msg.is.not.defined", "\"{0}\" is not defined." },
\r
1774 { "msg.isnt.function", "{0} is not a function." },
\r
1775 { "msg.bad.default.value", "Object''s getDefaultValue() method returned an object." },
\r
1776 { "msg.instanceof.not.object", " Can''t use instanceof on a non-object." },
\r
1777 { "msg.instanceof.bad.prototype", " ''prototype'' property of {0} is not an object." },
\r
1778 { "msg.bad.radix", " illegal radix {0}." },
\r
1779 { "msg.default.value", "Cannot find default value for object." },
\r
1780 { "msg.zero.arg.ctor", "Cannot load class \"{0}\" which has no zero-parameter constructor." },
\r
1781 { "msg.multiple.ctors", "Cannot have more than one constructor method, but found both {0} and {1}." },
\r
1782 { "msg.ctor.multiple.parms", "Can''t define constructor or class {0} since more than one constructor has multiple parameters." },
\r
1783 { "msg.extend.scriptable", "{0} must extend ScriptableObject in order to define property {1}." },
\r
1784 { "msg.bad.getter.parms", "In order to define a property, getter {0} must have zero parameters or a single ScriptableObject parameter." },
\r
1785 { "msg.obj.getter.parms", "Expected static or delegated getter {0} to take a ScriptableObject parameter." },
\r
1786 { "msg.getter.static", "Getter and setter must both be static or neither be static." },
\r
1787 { "msg.setter2.parms", "Two-parameter setter must take a ScriptableObject as its first parameter." },
\r
1788 { "msg.setter1.parms", "Expected single parameter setter for {0}" },
\r
1789 { "msg.setter2.expected", "Expected static or delegated setter {0} to take two parameters." },
\r
1790 { "msg.setter.parms", "Expected either one or two parameters for setter." },
\r
1791 { "msg.add.sealed", "Cannot add a property to a sealed object." },
\r
1792 { "msg.remove.sealed", "Cannot remove a property from a sealed object." },
\r
1793 { "msg.token.replaces.pushback", "ungot token {0} replaces pushback token {1}" },
\r
1794 { "msg.missing.exponent", "missing exponent" },
\r
1795 { "msg.caught.nfe", "number format error: {0}" },
\r
1796 { "msg.unterminated.string.lit", "unterminated string literal" },
\r
1797 { "msg.oct.esc.too.large", "octal escape too large" },
\r
1798 { "msg.nested.comment", "nested comment" },
\r
1799 { "msg.unterminated.comment", "unterminated comment" },
\r
1800 { "msg.unterminated.re.lit", "unterminated regular expression literal" },
\r
1801 { "msg.invalid.re.flag", "invalid flag after regular expression" },
\r
1802 { "msg.no.re.input.for", "no input for {0}" },
\r
1803 { "msg.illegal.character", "illegal character" },
\r
1804 { "msg.invalid.escape", "invalid Unicode escape sequence" },
\r
1805 { "msg.bad.octal.literal", "illegal octal literal digit {0}; interpreting it as a decimal digit" },
\r
1806 { "msg.undefined", "The undefined value has no properties." },
\r
1807 { "msg.java.internal.field.type", "Internal error: type conversion of {0} to assign to {1} on {2} failed." },
\r
1808 { "msg.java.conversion.implicit_method", "Can''t find converter method \"{0}\" on class {1}." },
\r
1809 { "msg.java.method.assign", "Java method \"{0}\" cannot be assigned to." },
\r
1810 { "msg.java.internal.private", "Internal error: attempt to access private/protected field \"{0}\"." },
\r
1811 { "msg.java.no_such_method", "Can''t find method {0}." },
\r
1812 { "msg.script.is.not.constructor", "Script objects are not constructors." },
\r
1813 { "msg.nonjava.method", "Java method \"{0}\" was invoked with a ''this'' value that was not a Java object." },
\r
1814 { "msg.java.member.not.found", "Java class \"{0}\" has no public instance field or method named \"{1}\"." },
\r
1815 { "msg.pkg.int", "Java package names may not be numbers." },
\r
1816 { "msg.ambig.import", "Ambiguous import: \"{0}\" and and \"{1}\"." },
\r
1817 { "msg.not.pkg", "Function importPackage must be called with a package; had \"{0}\" instead." },
\r
1818 { "msg.not.class", "Function importClass must be called with a class; had \"{0}\" instead." },
\r
1819 { "msg.prop.defined", "Cannot import \"{0}\" since a property by that name is already defined." },
\r
1820 { "msg.arraylength.bad", "Inappropriate array length." },
\r
1821 { "msg.bad.uri", "Malformed URI sequence." },
\r
1822 { "msg.bad.precision", "Precision {0} out of range." }
\r
1826 static final ResourceBundle myresources = new HardCodedResourceBundle();
\r
1828 /* OPT there's a noticable delay for the first error! Maybe it'd
\r
1829 * make sense to use a ListResourceBundle instead of a properties
\r
1830 * file to avoid (synchronized) text parsing.
\r
1832 static String getMessage(String messageId, Object[] arguments) {
\r
1833 Context cx = getCurrentContext();
\r
1834 Locale locale = cx != null ? cx.getLocale() : Locale.getDefault();
\r
1836 // ResourceBundle does cacheing.
\r
1837 ResourceBundle rb = myresources;
\r
1839 String formatString;
\r
1841 formatString = rb.getString(messageId);
\r
1842 } catch (java.util.MissingResourceException mre) {
\r
1843 throw new RuntimeException
\r
1844 ("no message resource found for message property "+ messageId);
\r
1848 * It's OK to format the string, even if 'arguments' is null;
\r
1849 * we need to format it anyway, to make double ''s collapse to
\r
1852 // TODO: MessageFormat is not available on pJava
\r
1853 MessageFormat formatter = new MessageFormat(formatString);
\r
1854 return formatter.format(arguments);
\r
1858 static final boolean printTrees = false;
\r
1861 * Compile a script.
\r
1863 * Reads script source from the reader and compiles it, returning
\r
1864 * a class for either the script or the function depending on the
\r
1865 * value of <code>returnFunction</code>.
\r
1867 * @param scope the scope to compile relative to
\r
1868 * @param in the Reader to read source from
\r
1869 * @param sourceName the name of the origin of the source (usually
\r
1871 * @param lineno the line number of the start of the source
\r
1872 * @param securityDomain an arbitrary object that specifies security
\r
1873 * information about the origin or owner of the script. For
\r
1874 * implementations that don't care about security, this value
\r
1876 * @param returnFunction if true, will expect the source to contain
\r
1877 * a function; return value is assumed to
\r
1878 * then be a org.mozilla.javascript.Function
\r
1879 * @return a class for the script or function
\r
1880 * @see org.mozilla.javascript.Context#compileReader
\r
1882 private Object compile(Scriptable scope, Reader in, String sourceName,
\r
1883 int lineno, Object securityDomain,
\r
1884 boolean returnFunction)
\r
1885 throws IOException
\r
1887 if (debugger != null && in != null) {
\r
1888 in = new DebugReader(in);
\r
1890 TokenStream ts = new TokenStream(in, scope, sourceName, lineno);
\r
1891 return compile(scope, ts, securityDomain, in, returnFunction);
\r
1894 private static Class codegenClass = null;
\r
1895 private static ClassNameHelper nameHelper = null;
\r
1899 codegenClass = Class.forName(
\r
1900 "org.mozilla.javascript.optimizer.Codegen");
\r
1901 Class nameHelperClass = Class.forName(
\r
1902 "org.mozilla.javascript.optimizer.OptClassNameHelper");
\r
1903 nameHelper = (ClassNameHelper)nameHelperClass.newInstance();
\r
1904 } catch (ClassNotFoundException x) {
\r
1905 // ...must be running lite, that's ok
\r
1906 codegenClass = null;
\r
1907 } catch (IllegalAccessException x) {
\r
1908 codegenClass = null;
\r
1909 } catch (InstantiationException x) {
\r
1910 codegenClass = null;
\r
1915 private Interpreter getCompiler() {
\r
1916 if (codegenClass != null) {
\r
1918 return (Interpreter) codegenClass.newInstance();
\r
1920 catch (SecurityException x) {
\r
1922 catch (IllegalArgumentException x) {
\r
1924 catch (InstantiationException x) {
\r
1926 catch (IllegalAccessException x) {
\r
1930 return new Interpreter();
\r
1933 private Object compile(Scriptable scope, TokenStream ts,
\r
1934 Object securityDomain, Reader in,
\r
1935 boolean returnFunction)
\r
1936 throws IOException
\r
1938 Interpreter compiler = optimizationLevel == -1
\r
1939 ? new Interpreter()
\r
1943 IRFactory irf = compiler.createIRFactory(ts, nameHelper, scope);
\r
1944 Parser p = new Parser(irf);
\r
1945 Node tree = (Node) p.parse(ts);
\r
1946 if (tree == null)
\r
1949 tree = compiler.transform(tree, ts, scope);
\r
1952 System.out.println(tree.toStringTree());
\r
1954 if (returnFunction) {
\r
1955 Node first = tree.getFirstChild();
\r
1956 if (first == null)
\r
1958 tree = (Node) first.getProp(Node.FUNCTION_PROP);
\r
1963 if (in instanceof DebugReader) {
\r
1964 DebugReader dr = (DebugReader) in;
\r
1965 tree.putProp(Node.DEBUGSOURCE_PROP, dr.getSaved());
\r
1968 Object result = compiler.compile(this, scope, tree, securityDomain,
\r
1969 securitySupport, nameHelper);
\r
1971 return errorCount == 0 ? result : null;
\r
1974 static String getSourcePositionFromStack(int[] linep) {
\r
1975 Context cx = getCurrentContext();
\r
1978 if (cx.interpreterLine > 0 && cx.interpreterSourceFile != null) {
\r
1979 linep[0] = cx.interpreterLine;
\r
1980 return cx.interpreterSourceFile;
\r
1983 * A bit of a hack, but the only way to get filename and line
\r
1984 * number from an enclosing frame.
\r
1986 CharArrayWriter writer = new CharArrayWriter();
\r
1987 RuntimeException re = new RuntimeException();
\r
1988 re.printStackTrace(new PrintWriter(writer));
\r
1989 String s = writer.toString();
\r
1993 for (int i=0; i < s.length(); i++) {
\r
1994 char c = s.charAt(i);
\r
1997 else if (c == '(')
\r
1999 else if (c == ')')
\r
2001 else if (c == '\n' && open != -1 && close != -1 && colon != -1 &&
\r
2002 open < colon && colon < close)
\r
2004 String fileStr = s.substring(open + 1, colon);
\r
2005 if (fileStr.endsWith(".js")) {
\r
2006 String lineStr = s.substring(colon + 1, close);
\r
2008 linep[0] = Integer.parseInt(lineStr);
\r
2011 catch (NumberFormatException e) {
\r
2015 open = close = colon = -1;
\r
2022 RegExpProxy getRegExpProxy() {
\r
2023 if (regExpProxy == null) {
\r
2025 Class c = Class.forName(
\r
2026 "org.mozilla.javascript.regexp.RegExpImpl");
\r
2027 regExpProxy = (RegExpProxy) c.newInstance();
\r
2028 return regExpProxy;
\r
2029 } catch (ClassNotFoundException e) {
\r
2030 } catch (InstantiationException e) {
\r
2031 } catch (IllegalAccessException e) {
\r
2034 return regExpProxy;
\r
2037 private void newArrayHelper(Scriptable scope, Scriptable array) {
\r
2038 array.setParentScope(scope);
\r
2039 Object ctor = ScriptRuntime.getTopLevelProp(scope, "Array");
\r
2040 if (ctor != null && ctor instanceof Scriptable) {
\r
2041 Scriptable s = (Scriptable) ctor;
\r
2042 array.setPrototype((Scriptable) s.get("prototype", s));
\r
2046 final boolean isVersionECMA1() {
\r
2047 return version == VERSION_DEFAULT || version >= VERSION_1_3;
\r
2051 * Get the security context from the given class.
\r
2053 * When some form of security check needs to be done, the class context
\r
2054 * must retrieved from the security manager to determine what class is
\r
2055 * requesting some form of privileged access.
\r
2056 * @since 1.4 release 2
\r
2058 Object getSecurityDomainFromClass(Class cl) {
\r
2059 if (cl == Interpreter.class)
\r
2060 return interpreterSecurityDomain;
\r
2061 return securitySupport.getSecurityDomain(cl);
\r
2064 SecuritySupport getSecuritySupport() {
\r
2065 return securitySupport;
\r
2068 Object getSecurityDomainForStackDepth(int depth) {
\r
2069 Object result = null;
\r
2070 if (securitySupport != null) {
\r
2071 Class[] classes = securitySupport.getClassContext();
\r
2072 if (classes != null) {
\r
2073 if (depth != -1) {
\r
2074 int depth1 = depth + 1;
\r
2075 result = getSecurityDomainFromClass(classes[depth1]);
\r
2077 for (int i=1; i < classes.length; i++) {
\r
2078 result = getSecurityDomainFromClass(classes[i]);
\r
2079 if (result != null)
\r
2085 if (result != null)
\r
2087 if (requireSecurityDomain)
\r
2088 checkSecurityDomainRequired();
\r
2092 private static boolean requireSecurityDomain = false;
\r
2093 private static boolean resourceMissing = false;
\r
2095 final static String securityResourceName = "org.mozilla.javascript.resources.Security";
\r
2097 final public static void checkSecurityDomainRequired() { }
\r
2099 public boolean isGeneratingDebugChanged() {
\r
2100 return generatingDebugChanged;
\r
2105 * Add a name to the list of names forcing the creation of real
\r
2106 * activation objects for functions.
\r
2108 * @param name the name of the object to add to the list
\r
2110 public void addActivationName(String name) {
\r
2111 if (activationNames == null)
\r
2112 activationNames = new Hashtable(5);
\r
2113 activationNames.put(name, name);
\r
2117 * Check whether the name is in the list of names of objects
\r
2118 * forcing the creation of activation objects.
\r
2120 * @param name the name of the object to test
\r
2122 * @return true if an function activation object is needed.
\r
2124 public boolean isActivationNeeded(String name) {
\r
2125 if ("arguments".equals(name))
\r
2127 return activationNames != null && activationNames.containsKey(name);
\r
2131 * Remove a name from the list of names forcing the creation of real
\r
2132 * activation objects for functions.
\r
2134 * @param name the name of the object to remove from the list
\r
2136 public void removeActivationName(String name) {
\r
2137 if (activationNames != null)
\r
2138 activationNames.remove(name);
\r
2142 static final boolean useJSObject = false;
\r
2145 * The activation of the currently executing function or script.
\r
2147 NativeCall currentActivation;
\r
2149 // for Objects, Arrays to tag themselves as being printed out,
\r
2150 // so they don't print themselves out recursively.
\r
2151 Hashtable iterating;
\r
2153 Object interpreterSecurityDomain;
\r
2157 static boolean isCachingEnabled = true;
\r
2159 private SecuritySupport securitySupport;
\r
2160 private ErrorReporter errorReporter;
\r
2161 private Thread currentThread;
\r
2162 private static Hashtable threadContexts = new Hashtable(11);
\r
2163 private RegExpProxy regExpProxy;
\r
2164 private Locale locale;
\r
2165 private boolean generatingDebug;
\r
2166 private boolean generatingDebugChanged;
\r
2167 private boolean generatingSource=true;
\r
2168 private boolean compileFunctionsWithDynamicScopeFlag;
\r
2169 private int optimizationLevel;
\r
2170 WrapHandler wrapHandler;
\r
2171 Debugger debugger;
\r
2172 DebuggableEngine debuggableEngine;
\r
2173 boolean inLineStepMode;
\r
2174 java.util.Stack frameStack;
\r
2175 private int enterCount;
\r
2176 private Object[] listeners;
\r
2177 private Hashtable hashtable;
\r
2180 * This is the list of names of objects forcing the creation of
\r
2181 * function activation records.
\r
2183 private Hashtable activationNames;
\r
2185 // Private lock for static fields to avoid a possibility of denial
\r
2186 // of service via synchronized (Context.class) { while (true) {} }
\r
2187 private static final Object staticDataLock = new Object();
\r
2188 private static Object[] contextListeners;
\r
2189 public Function currentFunction;
\r
2190 Vector arrayCache = new Vector(10);
\r
2192 // For the interpreter to indicate line/source for error reports.
\r
2193 public int interpreterLine;
\r
2194 public String interpreterSourceFile;
\r
2196 public int stackDepth = 0;
\r
2198 // For instruction counting (interpreter only)
\r
2199 int instructionCount;
\r
2200 int instructionThreshold;
\r