1 /* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  *
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 // API class
8 
9 package org.mozilla.javascript;
10 
11 import java.beans.PropertyChangeEvent;
12 import java.beans.PropertyChangeListener;
13 import java.io.CharArrayWriter;
14 import java.io.IOException;
15 import java.io.PrintWriter;
16 import java.io.Reader;
17 import java.io.StringWriter;
18 import java.io.Writer;
19 import java.lang.reflect.InvocationTargetException;
20 import java.lang.reflect.Method;
21 import java.util.Map;
22 import java.util.HashMap;
23 import java.util.Set;
24 import java.util.HashSet;
25 import java.util.Locale;
26 
27 import org.mozilla.javascript.ast.AstRoot;
28 import org.mozilla.javascript.ast.ScriptNode;
29 import org.mozilla.javascript.debug.DebuggableScript;
30 import org.mozilla.javascript.debug.Debugger;
31 import org.mozilla.javascript.xml.XMLLib;
32 
33 /**
34  * This class represents the runtime context of an executing script.
35  *
36  * Before executing a script, an instance of Context must be created
37  * and associated with the thread that will be executing the script.
38  * The Context will be used to store information about the executing
39  * of the script such as the call stack. Contexts are associated with
40  * the current thread  using the {@link #call(ContextAction)}
41  * or {@link #enter()} methods.<p>
42  *
43  * Different forms of script execution are supported. Scripts may be
44  * evaluated from the source directly, or first compiled and then later
45  * executed. Interactive execution is also supported.<p>
46  *
47  * Some aspects of script execution, such as type conversions and
48  * object creation, may be accessed directly through methods of
49  * Context.
50  *
51  * @see Scriptable
52  * @author Norris Boyd
53  * @author Brendan Eich
54  */
55 
56 public class Context
57 {
58     /**
59      * Language versions.
60      *
61      * All integral values are reserved for future version numbers.
62      */
63 
64     /**
65      * The unknown version.
66      */
67     public static final int VERSION_UNKNOWN =   -1;
68 
69     /**
70      * The default version.
71      */
72     public static final int VERSION_DEFAULT =    0;
73 
74     /**
75      * JavaScript 1.0
76      */
77     public static final int VERSION_1_0 =      100;
78 
79     /**
80      * JavaScript 1.1
81      */
82     public static final int VERSION_1_1 =      110;
83 
84     /**
85      * JavaScript 1.2
86      */
87     public static final int VERSION_1_2 =      120;
88 
89     /**
90      * JavaScript 1.3
91      */
92     public static final int VERSION_1_3 =      130;
93 
94     /**
95      * JavaScript 1.4
96      */
97     public static final int VERSION_1_4 =      140;
98 
99     /**
100      * JavaScript 1.5
101      */
102     public static final int VERSION_1_5 =      150;
103 
104     /**
105      * JavaScript 1.6
106      */
107     public static final int VERSION_1_6 =      160;
108 
109     /**
110      * JavaScript 1.7
111      */
112     public static final int VERSION_1_7 =      170;
113 
114     /**
115      * JavaScript 1.8
116      */
117     public static final int VERSION_1_8 =      180;
118 
119     /**
120      * Controls behaviour of <tt>Date.prototype.getYear()</tt>.
121      * If <tt>hasFeature(FEATURE_NON_ECMA_GET_YEAR)</tt> returns true,
122      * Date.prototype.getYear subtructs 1900 only if 1900 <= date < 2000.
123      * The default behavior of {@link #hasFeature(int)} is always to subtruct
124      * 1900 as rquired by ECMAScript B.2.4.
125      */
126     public static final int FEATURE_NON_ECMA_GET_YEAR = 1;
127 
128     /**
129      * Control if member expression as function name extension is available.
130      * If <tt>hasFeature(FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME)</tt> returns
131      * true, allow <tt>function memberExpression(args) { body }</tt> to be
132      * syntax sugar for <tt>memberExpression = function(args) { body }</tt>,
133      * when memberExpression is not a simple identifier.
134      * See ECMAScript-262, section 11.2 for definition of memberExpression.
135      * By default {@link #hasFeature(int)} returns false.
136      */
137     public static final int FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME = 2;
138 
139     /**
140      * Control if reserved keywords are treated as identifiers.
141      * If <tt>hasFeature(RESERVED_KEYWORD_AS_IDENTIFIER)</tt> returns true,
142      * treat future reserved keyword (see  Ecma-262, section 7.5.3) as ordinary
143      * identifiers but warn about this usage.
144      *
145      * By default {@link #hasFeature(int)} returns false.
146      */
147     public static final int FEATURE_RESERVED_KEYWORD_AS_IDENTIFIER = 3;
148 
149     /**
150      * Control if <tt>toString()</tt> should returns the same result
151      * as  <tt>toSource()</tt> when applied to objects and arrays.
152      * If <tt>hasFeature(FEATURE_TO_STRING_AS_SOURCE)</tt> returns true,
153      * calling <tt>toString()</tt> on JS objects gives the same result as
154      * calling <tt>toSource()</tt>. That is it returns JS source with code
155      * to create an object with all enumeratable fields of the original object
156      * instead of printing <tt>[object <i>result of
157      * {@link Scriptable#getClassName()}</i>]</tt>.
158      * <p>
159      * By default {@link #hasFeature(int)} returns true only if
160      * the current JS version is set to {@link #VERSION_1_2}.
161      */
162     public static final int FEATURE_TO_STRING_AS_SOURCE = 4;
163 
164     /**
165      * Control if properties <tt>__proto__</tt> and <tt>__parent__</tt>
166      * are treated specially.
167      * If <tt>hasFeature(FEATURE_PARENT_PROTO_PROPERTIES)</tt> returns true,
168      * treat <tt>__parent__</tt> and <tt>__proto__</tt> as special properties.
169      * <p>
170      * The properties allow to query and set scope and prototype chains for the
171      * objects. The special meaning of the properties is available
172      * only when they are used as the right hand side of the dot operator.
173      * For example, while <tt>x.__proto__ = y</tt> changes the prototype
174      * chain of the object <tt>x</tt> to point to <tt>y</tt>,
175      * <tt>x["__proto__"] = y</tt> simply assigns a new value to the property
176      * <tt>__proto__</tt> in <tt>x</tt> even when the feature is on.
177      *
178      * By default {@link #hasFeature(int)} returns true.
179      */
180     public static final int FEATURE_PARENT_PROTO_PROPERTIES = 5;
181 
182         /**
183          * @deprecated In previous releases, this name was given to
184          * FEATURE_PARENT_PROTO_PROPERTIES.
185          */
186     public static final int FEATURE_PARENT_PROTO_PROPRTIES = 5;
187 
188     /**
189      * Control if support for E4X(ECMAScript for XML) extension is available.
190      * If hasFeature(FEATURE_E4X) returns true, the XML syntax is available.
191      * <p>
192      * By default {@link #hasFeature(int)} returns true if
193      * the current JS version is set to {@link #VERSION_DEFAULT}
194      * or is at least {@link #VERSION_1_6}.
195      * @since 1.6 Release 1
196      */
197     public static final int FEATURE_E4X = 6;
198 
199     /**
200      * Control if dynamic scope should be used for name access.
201      * If hasFeature(FEATURE_DYNAMIC_SCOPE) returns true, then the name lookup
202      * during name resolution will use the top scope of the script or function
203      * which is at the top of JS execution stack instead of the top scope of the
204      * script or function from the current stack frame if the top scope of
205      * the top stack frame contains the top scope of the current stack frame
206      * on its prototype chain.
207      * <p>
208      * This is useful to define shared scope containing functions that can
209      * be called from scripts and functions using private scopes.
210      * <p>
211      * By default {@link #hasFeature(int)} returns false.
212      * @since 1.6 Release 1
213      */
214     public static final int FEATURE_DYNAMIC_SCOPE = 7;
215 
216     /**
217      * Control if strict variable mode is enabled.
218      * When the feature is on Rhino reports runtime errors if assignment
219      * to a global variable that does not exist is executed. When the feature
220      * is off such assignments create a new variable in the global scope as
221      * required by ECMA 262.
222      * <p>
223      * By default {@link #hasFeature(int)} returns false.
224      * @since 1.6 Release 1
225      */
226     public static final int FEATURE_STRICT_VARS = 8;
227 
228     /**
229      * Control if strict eval mode is enabled.
230      * When the feature is on Rhino reports runtime errors if non-string
231      * argument is passed to the eval function. When the feature is off
232      * eval simply return non-string argument as is without performing any
233      * evaluation as required by ECMA 262.
234      * <p>
235      * By default {@link #hasFeature(int)} returns false.
236      * @since 1.6 Release 1
237      */
238     public static final int FEATURE_STRICT_EVAL = 9;
239 
240     /**
241      * When the feature is on Rhino will add a "fileName" and "lineNumber"
242      * properties to Error objects automatically. When the feature is off, you
243      * have to explicitly pass them as the second and third argument to the
244      * Error constructor. Note that neither behavior is fully ECMA 262
245      * compliant (as 262 doesn't specify a three-arg constructor), but keeping
246      * the feature off results in Error objects that don't have
247      * additional non-ECMA properties when constructed using the ECMA-defined
248      * single-arg constructor and is thus desirable if a stricter ECMA
249      * compliance is desired, specifically adherence to the point 15.11.5. of
250      * the standard.
251      * <p>
252      * By default {@link #hasFeature(int)} returns false.
253      * @since 1.6 Release 6
254      */
255     public static final int FEATURE_LOCATION_INFORMATION_IN_ERROR = 10;
256 
257     /**
258      * Controls whether JS 1.5 'strict mode' is enabled.
259      * When the feature is on, Rhino reports more than a dozen different
260      * warnings.  When the feature is off, these warnings are not generated.
261      * FEATURE_STRICT_MODE implies FEATURE_STRICT_VARS and FEATURE_STRICT_EVAL.
262      * <p>
263      * By default {@link #hasFeature(int)} returns false.
264      * @since 1.6 Release 6
265      */
266     public static final int FEATURE_STRICT_MODE = 11;
267 
268     /**
269      * Controls whether a warning should be treated as an error.
270      * @since 1.6 Release 6
271      */
272     public static final int FEATURE_WARNING_AS_ERROR = 12;
273 
274     /**
275      * Enables enhanced access to Java.
276      * Specifically, controls whether private and protected members can be
277      * accessed, and whether scripts can catch all Java exceptions.
278      * <p>
279      * Note that this feature should only be enabled for trusted scripts.
280      * <p>
281      * By default {@link #hasFeature(int)} returns false.
282      * @since 1.7 Release 1
283      */
284     public static final int FEATURE_ENHANCED_JAVA_ACCESS = 13;
285 
286     public static final String languageVersionProperty = "language version";
287     public static final String errorReporterProperty   = "error reporter";
288 
289     /**
290      * Convenient value to use as zero-length array of objects.
291      */
292     public static final Object[] emptyArgs = ScriptRuntime.emptyArgs;
293 
294     /**
295      * Creates a new Context. The context will be associated with the {@link
296      * ContextFactory#getGlobal() global context factory}.
297      *
298      * Note that the Context must be associated with a thread before
299      * it can be used to execute a script.
300      * @deprecated this constructor is deprecated because it creates a
301      * dependency on a static singleton context factory. Use
302      * {@link ContextFactory#enter()} or
303      * {@link ContextFactory#call(ContextAction)} instead. If you subclass
304      * this class, consider using {@link #Context(ContextFactory)} constructor
305      * instead in the subclasses' constructors.
306      */
Context()307     public Context()
308     {
309         this(ContextFactory.getGlobal());
310     }
311 
312     /**
313      * Creates a new context. Provided as a preferred super constructor for
314      * subclasses in place of the deprecated default public constructor.
315      * @param factory the context factory associated with this context (most
316      * likely, the one that created the context). Can not be null. The context
317      * features are inherited from the factory, and the context will also
318      * otherwise use its factory's services.
319      * @throws IllegalArgumentException if factory parameter is null.
320      */
Context(ContextFactory factory)321     protected Context(ContextFactory factory)
322     {
323         if(factory == null) {
324             throw new IllegalArgumentException("factory == null");
325         }
326         this.factory = factory;
327         version = VERSION_DEFAULT;
328         optimizationLevel = codegenClass != null ? 0 : -1;
329         maximumInterpreterStackDepth = Integer.MAX_VALUE;
330     }
331 
332     /**
333      * Get the current Context.
334      *
335      * The current Context is per-thread; this method looks up
336      * the Context associated with the current thread. <p>
337      *
338      * @return the Context associated with the current thread, or
339      *         null if no context is associated with the current
340      *         thread.
341      * @see ContextFactory#enterContext()
342      * @see ContextFactory#call(ContextAction)
343      */
getCurrentContext()344     public static Context getCurrentContext()
345     {
346         Object helper = VMBridge.instance.getThreadContextHelper();
347         return VMBridge.instance.getContext(helper);
348     }
349 
350     /**
351      * Same as calling {@link ContextFactory#enterContext()} on the global
352      * ContextFactory instance.
353      * @return a Context associated with the current thread
354      * @see #getCurrentContext()
355      * @see #exit()
356      * @see #call(ContextAction)
357      */
enter()358     public static Context enter()
359     {
360         return enter(null);
361     }
362 
363     /**
364      * Get a Context associated with the current thread, using
365      * the given Context if need be.
366      * <p>
367      * The same as <code>enter()</code> except that <code>cx</code>
368      * is associated with the current thread and returned if
369      * the current thread has no associated context and <code>cx</code>
370      * is not associated with any other thread.
371      * @param cx a Context to associate with the thread if possible
372      * @return a Context associated with the current thread
373      * @deprecated use {@link ContextFactory#enterContext(Context)} instead as
374      * this method relies on usage of a static singleton "global" ContextFactory.
375      * @see ContextFactory#enterContext(Context)
376      * @see ContextFactory#call(ContextAction)
377      */
enter(Context cx)378     public static Context enter(Context cx)
379     {
380         return enter(cx, ContextFactory.getGlobal());
381     }
382 
enter(Context cx, ContextFactory factory)383     static final Context enter(Context cx, ContextFactory factory)
384     {
385         Object helper = VMBridge.instance.getThreadContextHelper();
386         Context old = VMBridge.instance.getContext(helper);
387         if (old != null) {
388             cx = old;
389         } else {
390             if (cx == null) {
391                 cx = factory.makeContext();
392                 if (cx.enterCount != 0) {
393                     throw new IllegalStateException("factory.makeContext() returned Context instance already associated with some thread");
394                 }
395                 factory.onContextCreated(cx);
396                 if (factory.isSealed() && !cx.isSealed()) {
397                     cx.seal(null);
398                 }
399             } else {
400                 if (cx.enterCount != 0) {
401                     throw new IllegalStateException("can not use Context instance already associated with some thread");
402                 }
403             }
404             VMBridge.instance.setContext(helper, cx);
405         }
406         ++cx.enterCount;
407         return cx;
408      }
409 
410     /**
411      * Exit a block of code requiring a Context.
412      *
413      * Calling <code>exit()</code> will remove the association between
414      * the current thread and a Context if the prior call to
415      * {@link ContextFactory#enterContext()} on this thread newly associated a
416      * Context with this thread. Once the current thread no longer has an
417      * associated Context, it cannot be used to execute JavaScript until it is
418      * again associated with a Context.
419      * @see ContextFactory#enterContext()
420      */
exit()421     public static void exit()
422     {
423         Object helper = VMBridge.instance.getThreadContextHelper();
424         Context cx = VMBridge.instance.getContext(helper);
425         if (cx == null) {
426             throw new IllegalStateException(
427                 "Calling Context.exit without previous Context.enter");
428         }
429         if (cx.enterCount < 1) Kit.codeBug();
430         if (--cx.enterCount == 0) {
431             VMBridge.instance.setContext(helper, null);
432             cx.factory.onContextReleased(cx);
433         }
434     }
435 
436     /**
437      * Call {@link ContextAction#run(Context cx)}
438      * using the Context instance associated with the current thread.
439      * If no Context is associated with the thread, then
440      * <tt>ContextFactory.getGlobal().makeContext()</tt> will be called to
441      * construct new Context instance. The instance will be temporary
442      * associated with the thread during call to
443      * {@link ContextAction#run(Context)}.
444      * @deprecated use {@link ContextFactory#call(ContextAction)} instead as
445      * this method relies on usage of a static singleton "global"
446      * ContextFactory.
447      * @return The result of {@link ContextAction#run(Context)}.
448      */
call(ContextAction action)449     public static Object call(ContextAction action)
450     {
451         return call(ContextFactory.getGlobal(), action);
452     }
453 
454     /**
455      * Call {@link
456      * Callable#call(Context cx, Scriptable scope, Scriptable thisObj,
457      *               Object[] args)}
458      * using the Context instance associated with the current thread.
459      * If no Context is associated with the thread, then
460      * {@link ContextFactory#makeContext()} will be called to construct
461      * new Context instance. The instance will be temporary associated
462      * with the thread during call to {@link ContextAction#run(Context)}.
463      * <p>
464      * It is allowed but not advisable to use null for <tt>factory</tt>
465      * argument in which case the global static singleton ContextFactory
466      * instance will be used to create new context instances.
467      * @see ContextFactory#call(ContextAction)
468      */
call(ContextFactory factory, final Callable callable, final Scriptable scope, final Scriptable thisObj, final Object[] args)469     public static Object call(ContextFactory factory, final Callable callable,
470                               final Scriptable scope, final Scriptable thisObj,
471                               final Object[] args)
472     {
473         if(factory == null) {
474             factory = ContextFactory.getGlobal();
475         }
476         return call(factory, new ContextAction() {
477             public Object run(Context cx) {
478                 return callable.call(cx, scope, thisObj, args);
479             }
480         });
481     }
482 
483     /**
484      * The method implements {@link ContextFactory#call(ContextAction)} logic.
485      */
486     static Object call(ContextFactory factory, ContextAction action) {
487         Context cx = enter(null, factory);
488         try {
489             return action.run(cx);
490         }
491         finally {
492             exit();
493         }
494     }
495 
496     /**
497      * @deprecated
498      * @see ContextFactory#addListener(org.mozilla.javascript.ContextFactory.Listener)
499      * @see ContextFactory#getGlobal()
500      */
501     public static void addContextListener(ContextListener listener)
502     {
503         // Special workaround for the debugger
504         String DBG = "org.mozilla.javascript.tools.debugger.Main";
505         if (DBG.equals(listener.getClass().getName())) {
506             Class<?> cl = listener.getClass();
507             Class<?> factoryClass = Kit.classOrNull(
508                 "org.mozilla.javascript.ContextFactory");
509             Class<?>[] sig = { factoryClass };
510             Object[] args = { ContextFactory.getGlobal() };
511             try {
512                 Method m = cl.getMethod("attachTo", sig);
513                 m.invoke(listener, args);
514             } catch (Exception ex) {
515                 RuntimeException rex = new RuntimeException();
516                 Kit.initCause(rex, ex);
517                 throw rex;
518             }
519             return;
520         }
521 
522         ContextFactory.getGlobal().addListener(listener);
523     }
524 
525     /**
526      * @deprecated
527      * @see ContextFactory#removeListener(org.mozilla.javascript.ContextFactory.Listener)
528      * @see ContextFactory#getGlobal()
529      */
530     public static void removeContextListener(ContextListener listener)
531     {
532         ContextFactory.getGlobal().addListener(listener);
533     }
534 
535     /**
536      * Return {@link ContextFactory} instance used to create this Context.
537      */
538     public final ContextFactory getFactory()
539     {
540         return factory;
541     }
542 
543     /**
544      * Checks if this is a sealed Context. A sealed Context instance does not
545      * allow to modify any of its properties and will throw an exception
546      * on any such attempt.
547      * @see #seal(Object sealKey)
548      */
549     public final boolean isSealed()
550     {
551         return sealed;
552     }
553 
554     /**
555      * Seal this Context object so any attempt to modify any of its properties
556      * including calling {@link #enter()} and {@link #exit()} methods will
557      * throw an exception.
558      * <p>
559      * If <tt>sealKey</tt> is not null, calling
560      * {@link #unseal(Object sealKey)} with the same key unseals
561      * the object. If <tt>sealKey</tt> is null, unsealing is no longer possible.
562      *
563      * @see #isSealed()
564      * @see #unseal(Object)
565      */
566     public final void seal(Object sealKey)
567     {
568         if (sealed) onSealedMutation();
569         sealed = true;
570         this.sealKey = sealKey;
571     }
572 
573     /**
574      * Unseal previously sealed Context object.
575      * The <tt>sealKey</tt> argument should not be null and should match
576      * <tt>sealKey</tt> suplied with the last call to
577      * {@link #seal(Object)} or an exception will be thrown.
578      *
579      * @see #isSealed()
580      * @see #seal(Object sealKey)
581      */
582     public final void unseal(Object sealKey)
583     {
584         if (sealKey == null) throw new IllegalArgumentException();
585         if (this.sealKey != sealKey) throw new IllegalArgumentException();
586         if (!sealed) throw new IllegalStateException();
587         sealed = false;
588         this.sealKey = null;
589     }
590 
591     static void onSealedMutation()
592     {
593         throw new IllegalStateException();
594     }
595 
596     /**
597      * Get the current language version.
598      * <p>
599      * The language version number affects JavaScript semantics as detailed
600      * in the overview documentation.
601      *
602      * @return an integer that is one of VERSION_1_0, VERSION_1_1, etc.
603      */
604     public final int getLanguageVersion()
605     {
606        return version;
607     }
608 
609     /**
610      * Set the language version.
611      *
612      * <p>
613      * Setting the language version will affect functions and scripts compiled
614      * subsequently. See the overview documentation for version-specific
615      * behavior.
616      *
617      * @param version the version as specified by VERSION_1_0, VERSION_1_1, etc.
618      */
619     public void setLanguageVersion(int version)
620     {
621         if (sealed) onSealedMutation();
622         checkLanguageVersion(version);
623         Object listeners = propertyListeners;
624         if (listeners != null && version != this.version) {
625             firePropertyChangeImpl(listeners, languageVersionProperty,
626                                Integer.valueOf(this.version),
627                                Integer.valueOf(version));
628         }
629         this.version = version;
630     }
631 
632     public static boolean isValidLanguageVersion(int version)
633     {
634         switch (version) {
635             case VERSION_DEFAULT:
636             case VERSION_1_0:
637             case VERSION_1_1:
638             case VERSION_1_2:
639             case VERSION_1_3:
640             case VERSION_1_4:
641             case VERSION_1_5:
642             case VERSION_1_6:
643             case VERSION_1_7:
644             case VERSION_1_8:
645                 return true;
646         }
647         return false;
648     }
649 
650     public static void checkLanguageVersion(int version)
651     {
652         if (isValidLanguageVersion(version)) {
653             return;
654         }
655         throw new IllegalArgumentException("Bad language version: "+version);
656     }
657 
658     /**
659      * Get the implementation version.
660      *
661      * <p>
662      * The implementation version is of the form
663      * <pre>
664      *    "<i>name langVer</i> <code>release</code> <i>relNum date</i>"
665      * </pre>
666      * where <i>name</i> is the name of the product, <i>langVer</i> is
667      * the language version, <i>relNum</i> is the release number, and
668      * <i>date</i> is the release date for that specific
669      * release in the form "yyyy mm dd".
670      *
671      * @return a string that encodes the product, language version, release
672      *         number, and date.
673      */
674     public final String getImplementationVersion()
675     {
676         // XXX Probably it would be better to embed this directly into source
677         // with special build preprocessing but that would require some ant
678         // tweaking and then replacing token in resource files was simpler
679         if (implementationVersion == null) {
680             implementationVersion
681                 = ScriptRuntime.getMessage0("implementation.version");
682         }
683         return implementationVersion;
684     }
685 
686     /**
687      * Get the current error reporter.
688      *
689      * @see org.mozilla.javascript.ErrorReporter
690      */
691     public final ErrorReporter getErrorReporter()
692     {
693         if (errorReporter == null) {
694             return DefaultErrorReporter.instance;
695         }
696         return errorReporter;
697     }
698 
699     /**
700      * Change the current error reporter.
701      *
702      * @return the previous error reporter
703      * @see org.mozilla.javascript.ErrorReporter
704      */
705     public final ErrorReporter setErrorReporter(ErrorReporter reporter)
706     {
707         if (sealed) onSealedMutation();
708         if (reporter == null) throw new IllegalArgumentException();
709         ErrorReporter old = getErrorReporter();
710         if (reporter == old) {
711             return old;
712         }
713         Object listeners = propertyListeners;
714         if (listeners != null) {
715             firePropertyChangeImpl(listeners, errorReporterProperty,
716                                    old, reporter);
717         }
718         this.errorReporter = reporter;
719         return old;
720     }
721 
722     /**
723      * Get the current locale.  Returns the default locale if none has
724      * been set.
725      *
726      * @see java.util.Locale
727      */
728 
729     public final Locale getLocale()
730     {
731         if (locale == null)
732             locale = Locale.getDefault();
733         return locale;
734     }
735 
736     /**
737      * Set the current locale.
738      *
739      * @see java.util.Locale
740      */
741     public final Locale setLocale(Locale loc)
742     {
743         if (sealed) onSealedMutation();
744         Locale result = locale;
745         locale = loc;
746         return result;
747     }
748 
749     /**
750      * Register an object to receive notifications when a bound property
751      * has changed
752      * @see java.beans.PropertyChangeEvent
753      * @see #removePropertyChangeListener(java.beans.PropertyChangeListener)
754      * @param l the listener
755      */
756     public final void addPropertyChangeListener(PropertyChangeListener l)
757     {
758         if (sealed) onSealedMutation();
759         propertyListeners = Kit.addListener(propertyListeners, l);
760     }
761 
762     /**
763      * Remove an object from the list of objects registered to receive
764      * notification of changes to a bounded property
765      * @see java.beans.PropertyChangeEvent
766      * @see #addPropertyChangeListener(java.beans.PropertyChangeListener)
767      * @param l the listener
768      */
769     public final void removePropertyChangeListener(PropertyChangeListener l)
770     {
771         if (sealed) onSealedMutation();
772         propertyListeners = Kit.removeListener(propertyListeners, l);
773     }
774 
775     /**
776      * Notify any registered listeners that a bounded property has changed
777      * @see #addPropertyChangeListener(java.beans.PropertyChangeListener)
778      * @see #removePropertyChangeListener(java.beans.PropertyChangeListener)
779      * @see java.beans.PropertyChangeListener
780      * @see java.beans.PropertyChangeEvent
781      * @param  property  the bound property
782      * @param  oldValue  the old value
783      * @param  newValue   the new value
784      */
785     final void firePropertyChange(String property, Object oldValue,
786                                   Object newValue)
787     {
788         Object listeners = propertyListeners;
789         if (listeners != null) {
790             firePropertyChangeImpl(listeners, property, oldValue, newValue);
791         }
792     }
793 
794     private void firePropertyChangeImpl(Object listeners, String property,
795                                         Object oldValue, Object newValue)
796     {
797         for (int i = 0; ; ++i) {
798             Object l = Kit.getListener(listeners, i);
799             if (l == null)
800                 break;
801             if (l instanceof PropertyChangeListener) {
802                 PropertyChangeListener pcl = (PropertyChangeListener)l;
803                 pcl.propertyChange(new PropertyChangeEvent(
804                     this, property, oldValue, newValue));
805             }
806         }
807     }
808 
809     /**
810      * Report a warning using the error reporter for the current thread.
811      *
812      * @param message the warning message to report
813      * @param sourceName a string describing the source, such as a filename
814      * @param lineno the starting line number
815      * @param lineSource the text of the line (may be null)
816      * @param lineOffset the offset into lineSource where problem was detected
817      * @see org.mozilla.javascript.ErrorReporter
818      */
819     public static void reportWarning(String message, String sourceName,
820                                      int lineno, String lineSource,
821                                      int lineOffset)
822     {
823         Context cx = Context.getContext();
824         if (cx.hasFeature(FEATURE_WARNING_AS_ERROR))
825             reportError(message, sourceName, lineno, lineSource, lineOffset);
826         else
827             cx.getErrorReporter().warning(message, sourceName, lineno,
828                                           lineSource, lineOffset);
829     }
830 
831     /**
832      * Report a warning using the error reporter for the current thread.
833      *
834      * @param message the warning message to report
835      * @see org.mozilla.javascript.ErrorReporter
836      */
837     public static void reportWarning(String message)
838     {
839         int[] linep = { 0 };
840         String filename = getSourcePositionFromStack(linep);
841         Context.reportWarning(message, filename, linep[0], null, 0);
842     }
843 
844     public static void reportWarning(String message, Throwable t)
845     {
846         int[] linep = { 0 };
847         String filename = getSourcePositionFromStack(linep);
848         Writer sw = new StringWriter();
849         PrintWriter pw = new PrintWriter(sw);
850         pw.println(message);
851         t.printStackTrace(pw);
852         pw.flush();
853         Context.reportWarning(sw.toString(), filename, linep[0], null, 0);
854     }
855 
856     /**
857      * Report an error using the error reporter for the current thread.
858      *
859      * @param message the error message to report
860      * @param sourceName a string describing the source, such as a filename
861      * @param lineno the starting line number
862      * @param lineSource the text of the line (may be null)
863      * @param lineOffset the offset into lineSource where problem was detected
864      * @see org.mozilla.javascript.ErrorReporter
865      */
866     public static void reportError(String message, String sourceName,
867                                    int lineno, String lineSource,
868                                    int lineOffset)
869     {
870         Context cx = getCurrentContext();
871         if (cx != null) {
872             cx.getErrorReporter().error(message, sourceName, lineno,
873                                         lineSource, lineOffset);
874         } else {
875             throw new EvaluatorException(message, sourceName, lineno,
876                                          lineSource, lineOffset);
877         }
878     }
879 
880     /**
881      * Report an error using the error reporter for the current thread.
882      *
883      * @param message the error message to report
884      * @see org.mozilla.javascript.ErrorReporter
885      */
886     public static void reportError(String message)
887     {
888         int[] linep = { 0 };
889         String filename = getSourcePositionFromStack(linep);
890         Context.reportError(message, filename, linep[0], null, 0);
891     }
892 
893     /**
894      * Report a runtime error using the error reporter for the current thread.
895      *
896      * @param message the error message to report
897      * @param sourceName a string describing the source, such as a filename
898      * @param lineno the starting line number
899      * @param lineSource the text of the line (may be null)
900      * @param lineOffset the offset into lineSource where problem was detected
901      * @return a runtime exception that will be thrown to terminate the
902      *         execution of the script
903      * @see org.mozilla.javascript.ErrorReporter
904      */
905     public static EvaluatorException reportRuntimeError(String message,
906                                                         String sourceName,
907                                                         int lineno,
908                                                         String lineSource,
909                                                         int lineOffset)
910     {
911         Context cx = getCurrentContext();
912         if (cx != null) {
913             return cx.getErrorReporter().
914                             runtimeError(message, sourceName, lineno,
915                                          lineSource, lineOffset);
916         } else {
917             throw new EvaluatorException(message, sourceName, lineno,
918                                          lineSource, lineOffset);
919         }
920     }
921 
922     static EvaluatorException reportRuntimeError0(String messageId)
923     {
924         String msg = ScriptRuntime.getMessage0(messageId);
925         return reportRuntimeError(msg);
926     }
927 
928     static EvaluatorException reportRuntimeError1(String messageId,
929                                                   Object arg1)
930     {
931         String msg = ScriptRuntime.getMessage1(messageId, arg1);
932         return reportRuntimeError(msg);
933     }
934 
935     static EvaluatorException reportRuntimeError2(String messageId,
936                                                   Object arg1, Object arg2)
937     {
938         String msg = ScriptRuntime.getMessage2(messageId, arg1, arg2);
939         return reportRuntimeError(msg);
940     }
941 
942     static EvaluatorException reportRuntimeError3(String messageId,
943                                                   Object arg1, Object arg2,
944                                                   Object arg3)
945     {
946         String msg = ScriptRuntime.getMessage3(messageId, arg1, arg2, arg3);
947         return reportRuntimeError(msg);
948     }
949 
950     static EvaluatorException reportRuntimeError4(String messageId,
951                                                   Object arg1, Object arg2,
952                                                   Object arg3, Object arg4)
953     {
954         String msg
955             = ScriptRuntime.getMessage4(messageId, arg1, arg2, arg3, arg4);
956         return reportRuntimeError(msg);
957     }
958 
959     /**
960      * Report a runtime error using the error reporter for the current thread.
961      *
962      * @param message the error message to report
963      * @see org.mozilla.javascript.ErrorReporter
964      */
965     public static EvaluatorException reportRuntimeError(String message)
966     {
967         int[] linep = { 0 };
968         String filename = getSourcePositionFromStack(linep);
969         return Context.reportRuntimeError(message, filename, linep[0], null, 0);
970     }
971 
972     /**
973      * Initialize the standard objects.
974      *
975      * Creates instances of the standard objects and their constructors
976      * (Object, String, Number, Date, etc.), setting up 'scope' to act
977      * as a global object as in ECMA 15.1.<p>
978      *
979      * This method must be called to initialize a scope before scripts
980      * can be evaluated in that scope.<p>
981      *
982      * This method does not affect the Context it is called upon.
983      *
984      * @return the initialized scope
985      */
986     public final ScriptableObject initStandardObjects()
987     {
988         return initStandardObjects(null, false);
989     }
990 
991     /**
992      * Initialize the standard objects.
993      *
994      * Creates instances of the standard objects and their constructors
995      * (Object, String, Number, Date, etc.), setting up 'scope' to act
996      * as a global object as in ECMA 15.1.<p>
997      *
998      * This method must be called to initialize a scope before scripts
999      * can be evaluated in that scope.<p>
1000      *
1001      * This method does not affect the Context it is called upon.
1002      *
1003      * @param scope the scope to initialize, or null, in which case a new
1004      *        object will be created to serve as the scope
1005      * @return the initialized scope. The method returns the value of the scope
1006      *         argument if it is not null or newly allocated scope object which
1007      *         is an instance {@link ScriptableObject}.
1008      */
1009     public final Scriptable initStandardObjects(ScriptableObject scope)
1010     {
1011         return initStandardObjects(scope, false);
1012     }
1013 
1014     /**
1015      * Initialize the standard objects.
1016      *
1017      * Creates instances of the standard objects and their constructors
1018      * (Object, String, Number, Date, etc.), setting up 'scope' to act
1019      * as a global object as in ECMA 15.1.<p>
1020      *
1021      * This method must be called to initialize a scope before scripts
1022      * can be evaluated in that scope.<p>
1023      *
1024      * This method does not affect the Context it is called upon.<p>
1025      *
1026      * This form of the method also allows for creating "sealed" standard
1027      * objects. An object that is sealed cannot have properties added, changed,
1028      * or removed. This is useful to create a "superglobal" that can be shared
1029      * among several top-level objects. Note that sealing is not allowed in
1030      * the current ECMA/ISO language specification, but is likely for
1031      * the next version.
1032      *
1033      * @param scope the scope to initialize, or null, in which case a new
1034      *        object will be created to serve as the scope
1035      * @param sealed whether or not to create sealed standard objects that
1036      *        cannot be modified.
1037      * @return the initialized scope. The method returns the value of the scope
1038      *         argument if it is not null or newly allocated scope object.
1039      * @since 1.4R3
1040      */
1041     public ScriptableObject initStandardObjects(ScriptableObject scope,
1042                                                 boolean sealed)
1043     {
1044         return ScriptRuntime.initStandardObjects(this, scope, sealed);
1045     }
1046 
1047     /**
1048      * Get the singleton object that represents the JavaScript Undefined value.
1049      */
1050     public static Object getUndefinedValue()
1051     {
1052         return Undefined.instance;
1053     }
1054 
1055     /**
1056      * Evaluate a JavaScript source string.
1057      *
1058      * The provided source name and line number are used for error messages
1059      * and for producing debug information.
1060      *
1061      * @param scope the scope to execute in
1062      * @param source the JavaScript source
1063      * @param sourceName a string describing the source, such as a filename
1064      * @param lineno the starting line number
1065      * @param securityDomain an arbitrary object that specifies security
1066      *        information about the origin or owner of the script. For
1067      *        implementations that don't care about security, this value
1068      *        may be null.
1069      * @return the result of evaluating the string
1070      * @see org.mozilla.javascript.SecurityController
1071      */
1072     public final Object evaluateString(Scriptable scope, String source,
1073                                        String sourceName, int lineno,
1074                                        Object securityDomain)
1075     {
1076         Script script = compileString(source, sourceName, lineno,
1077                                       securityDomain);
1078         if (script != null) {
1079             return script.exec(this, scope);
1080         } else {
1081             return null;
1082         }
1083     }
1084 
1085     /**
1086      * Evaluate a reader as JavaScript source.
1087      *
1088      * All characters of the reader are consumed.
1089      *
1090      * @param scope the scope to execute in
1091      * @param in the Reader to get JavaScript source from
1092      * @param sourceName a string describing the source, such as a filename
1093      * @param lineno the starting line number
1094      * @param securityDomain an arbitrary object that specifies security
1095      *        information about the origin or owner of the script. For
1096      *        implementations that don't care about security, this value
1097      *        may be null.
1098      * @return the result of evaluating the source
1099      *
1100      * @exception IOException if an IOException was generated by the Reader
1101      */
1102     public final Object evaluateReader(Scriptable scope, Reader in,
1103                                        String sourceName, int lineno,
1104                                        Object securityDomain)
1105         throws IOException
1106     {
1107         Script script = compileReader(scope, in, sourceName, lineno,
1108                                       securityDomain);
1109         if (script != null) {
1110             return script.exec(this, scope);
1111         } else {
1112             return null;
1113         }
1114     }
1115 
1116     /**
1117      * Execute script that may pause execution by capturing a continuation.
1118      * Caller must be prepared to catch a ContinuationPending exception
1119      * and resume execution by calling
1120      * {@link #resumeContinuation(Object, Scriptable, Object)}.
1121      * @param script The script to execute. Script must have been compiled
1122      *      with interpreted mode (optimization level -1)
1123      * @param scope The scope to execute the script against
1124      * @throws ContinuationPending if the script calls a function that results
1125      *      in a call to {@link #captureContinuation()}
1126      * @since 1.7 Release 2
1127      */
1128     public Object executeScriptWithContinuations(Script script,
1129             Scriptable scope)
1130         throws ContinuationPending
1131     {
1132         if (!(script instanceof InterpretedFunction) ||
1133             !((InterpretedFunction)script).isScript())
1134         {
1135             // Can only be applied to scripts
1136             throw new IllegalArgumentException("Script argument was not" +
1137                     " a script or was not created by interpreted mode ");
1138         }
1139         return callFunctionWithContinuations((InterpretedFunction) script,
1140                 scope, ScriptRuntime.emptyArgs);
1141     }
1142 
1143     /**
1144      * Call function that may pause execution by capturing a continuation.
1145      * Caller must be prepared to catch a ContinuationPending exception
1146      * and resume execution by calling
1147      * {@link #resumeContinuation(Object, Scriptable, Object)}.
1148      * @param function The function to call. The function must have been
1149      *      compiled with interpreted mode (optimization level -1)
1150      * @param scope The scope to execute the script against
1151      * @param args The arguments for the function
1152      * @throws ContinuationPending if the script calls a function that results
1153      *      in a call to {@link #captureContinuation()}
1154      * @since 1.7 Release 2
1155      */
1156     public Object callFunctionWithContinuations(Callable function,
1157             Scriptable scope, Object[] args)
1158         throws ContinuationPending
1159     {
1160         if (!(function instanceof InterpretedFunction)) {
1161             // Can only be applied to scripts
1162             throw new IllegalArgumentException("Function argument was not" +
1163                     " created by interpreted mode ");
1164         }
1165         if (ScriptRuntime.hasTopCall(this)) {
1166             throw new IllegalStateException("Cannot have any pending top " +
1167                     "calls when executing a script with continuations");
1168         }
1169         // Annotate so we can check later to ensure no java code in
1170         // intervening frames
1171         isContinuationsTopCall = true;
1172         return ScriptRuntime.doTopCall(function, this, scope, scope, args);
1173     }
1174 
1175     /**
1176      * Capture a continuation from the current execution. The execution must
1177      * have been started via a call to
1178      * {@link #executeScriptWithContinuations(Script, Scriptable)} or
1179      * {@link #callFunctionWithContinuations(Callable, Scriptable, Object[])}.
1180      * This implies that the code calling
1181      * this method must have been called as a function from the
1182      * JavaScript script. Also, there cannot be any non-JavaScript code
1183      * between the JavaScript frames (e.g., a call to eval()). The
1184      * ContinuationPending exception returned must be thrown.
1185      * @return A ContinuationPending exception that must be thrown
1186      * @since 1.7 Release 2
1187      */
1188     public ContinuationPending captureContinuation() {
1189         return new ContinuationPending(
1190                 Interpreter.captureContinuation(this));
1191     }
1192 
1193     /**
1194      * Restarts execution of the JavaScript suspended at the call
1195      * to {@link #captureContinuation()}. Execution of the code will resume
1196      * with the functionResult as the result of the call that captured the
1197      * continuation.
1198      * Execution of the script will either conclude normally and the
1199      * result returned, another continuation will be captured and
1200      * thrown, or the script will terminate abnormally and throw an exception.
1201      * @param continuation The value returned by
1202      * {@link ContinuationPending#getContinuation()}
1203      * @param functionResult This value will appear to the code being resumed
1204      *      as the result of the function that captured the continuation
1205      * @throws ContinuationPending if another continuation is captured before
1206      *      the code terminates
1207      * @since 1.7 Release 2
1208      */
1209     public Object resumeContinuation(Object continuation,
1210             Scriptable scope, Object functionResult)
1211             throws ContinuationPending
1212     {
1213         Object[] args = { functionResult };
1214         return Interpreter.restartContinuation(
1215                 (org.mozilla.javascript.NativeContinuation) continuation,
1216                 this, scope, args);
1217     }
1218 
1219     /**
1220      * Check whether a string is ready to be compiled.
1221      * <p>
1222      * stringIsCompilableUnit is intended to support interactive compilation of
1223      * JavaScript.  If compiling the string would result in an error
1224      * that might be fixed by appending more source, this method
1225      * returns false.  In every other case, it returns true.
1226      * <p>
1227      * Interactive shells may accumulate source lines, using this
1228      * method after each new line is appended to check whether the
1229      * statement being entered is complete.
1230      *
1231      * @param source the source buffer to check
1232      * @return whether the source is ready for compilation
1233      * @since 1.4 Release 2
1234      */
1235     public final boolean stringIsCompilableUnit(String source)
1236     {
1237         boolean errorseen = false;
1238         CompilerEnvirons compilerEnv = new CompilerEnvirons();
1239         compilerEnv.initFromContext(this);
1240         // no source name or source text manager, because we're just
1241         // going to throw away the result.
1242         compilerEnv.setGeneratingSource(false);
1243         Parser p = new Parser(compilerEnv, DefaultErrorReporter.instance);
1244         try {
1245             p.parse(source, null, 1);
1246         } catch (EvaluatorException ee) {
1247             errorseen = true;
1248         }
1249         // Return false only if an error occurred as a result of reading past
1250         // the end of the file, i.e. if the source could be fixed by
1251         // appending more source.
1252         if (errorseen && p.eof())
1253             return false;
1254         else
1255             return true;
1256     }
1257 
1258     /**
1259      * @deprecated
1260      * @see #compileReader(Reader in, String sourceName, int lineno,
1261      *                     Object securityDomain)
1262      */
1263     public final Script compileReader(Scriptable scope, Reader in,
1264                                       String sourceName, int lineno,
1265                                       Object securityDomain)
1266         throws IOException
1267     {
1268         return compileReader(in, sourceName, lineno, securityDomain);
1269     }
1270 
1271     /**
1272      * Compiles the source in the given reader.
1273      * <p>
1274      * Returns a script that may later be executed.
1275      * Will consume all the source in the reader.
1276      *
1277      * @param in the input reader
1278      * @param sourceName a string describing the source, such as a filename
1279      * @param lineno the starting line number for reporting errors
1280      * @param securityDomain an arbitrary object that specifies security
1281      *        information about the origin or owner of the script. For
1282      *        implementations that don't care about security, this value
1283      *        may be null.
1284      * @return a script that may later be executed
1285      * @exception IOException if an IOException was generated by the Reader
1286      * @see org.mozilla.javascript.Script
1287      */
1288     public final Script compileReader(Reader in, String sourceName,
1289                                       int lineno, Object securityDomain)
1290         throws IOException
1291     {
1292         if (lineno < 0) {
1293             // For compatibility IllegalArgumentException can not be thrown here
1294             lineno = 0;
1295         }
1296         return (Script) compileImpl(null, in, null, sourceName, lineno,
1297                                     securityDomain, false, null, null);
1298     }
1299 
1300     /**
1301      * Compiles the source in the given string.
1302      * <p>
1303      * Returns a script that may later be executed.
1304      *
1305      * @param source the source string
1306      * @param sourceName a string describing the source, such as a filename
1307      * @param lineno the starting line number for reporting errors. Use
1308      *        0 if the line number is unknown.
1309      * @param securityDomain an arbitrary object that specifies security
1310      *        information about the origin or owner of the script. For
1311      *        implementations that don't care about security, this value
1312      *        may be null.
1313      * @return a script that may later be executed
1314      * @see org.mozilla.javascript.Script
1315      */
1316     public final Script compileString(String source,
1317                                       String sourceName, int lineno,
1318                                       Object securityDomain)
1319     {
1320         if (lineno < 0) {
1321             // For compatibility IllegalArgumentException can not be thrown here
1322             lineno = 0;
1323         }
1324         return compileString(source, null, null, sourceName, lineno,
1325                              securityDomain);
1326     }
1327 
1328     final Script compileString(String source,
1329                                Evaluator compiler,
1330                                ErrorReporter compilationErrorReporter,
1331                                String sourceName, int lineno,
1332                                Object securityDomain)
1333     {
1334         try {
1335             return (Script) compileImpl(null, null, source, sourceName, lineno,
1336                                         securityDomain, false,
1337                                         compiler, compilationErrorReporter);
1338         } catch (IOException ex) {
1339             // Should not happen when dealing with source as string
1340             throw new RuntimeException();
1341         }
1342     }
1343 
1344     /**
1345      * Compile a JavaScript function.
1346      * <p>
1347      * The function source must be a function definition as defined by
1348      * ECMA (e.g., "function f(a) { return a; }").
1349      *
1350      * @param scope the scope to compile relative to
1351      * @param source the function definition source
1352      * @param sourceName a string describing the source, such as a filename
1353      * @param lineno the starting line number
1354      * @param securityDomain an arbitrary object that specifies security
1355      *        information about the origin or owner of the script. For
1356      *        implementations that don't care about security, this value
1357      *        may be null.
1358      * @return a Function that may later be called
1359      * @see org.mozilla.javascript.Function
1360      */
1361     public final Function compileFunction(Scriptable scope, String source,
1362                                           String sourceName, int lineno,
1363                                           Object securityDomain)
1364     {
1365         return compileFunction(scope, source, null, null, sourceName, lineno,
1366                                securityDomain);
1367     }
1368 
1369     final Function compileFunction(Scriptable scope, String source,
1370                                    Evaluator compiler,
1371                                    ErrorReporter compilationErrorReporter,
1372                                    String sourceName, int lineno,
1373                                    Object securityDomain)
1374     {
1375         try {
1376             return (Function) compileImpl(scope, null, source, sourceName,
1377                                           lineno, securityDomain, true,
1378                                           compiler, compilationErrorReporter);
1379         }
1380         catch (IOException ioe) {
1381             // Should never happen because we just made the reader
1382             // from a String
1383             throw new RuntimeException();
1384         }
1385     }
1386 
1387     /**
1388      * Decompile the script.
1389      * <p>
1390      * The canonical source of the script is returned.
1391      *
1392      * @param script the script to decompile
1393      * @param indent the number of spaces to indent the result
1394      * @return a string representing the script source
1395      */
1396     public final String decompileScript(Script script, int indent)
1397     {
1398         NativeFunction scriptImpl = (NativeFunction) script;
1399         return scriptImpl.decompile(indent, 0);
1400     }
1401 
1402     /**
1403      * Decompile a JavaScript Function.
1404      * <p>
1405      * Decompiles a previously compiled JavaScript function object to
1406      * canonical source.
1407      * <p>
1408      * Returns function body of '[native code]' if no decompilation
1409      * information is available.
1410      *
1411      * @param fun the JavaScript function to decompile
1412      * @param indent the number of spaces to indent the result
1413      * @return a string representing the function source
1414      */
1415     public final String decompileFunction(Function fun, int indent)
1416     {
1417         if (fun instanceof BaseFunction)
1418             return ((BaseFunction)fun).decompile(indent, 0);
1419         else
1420             return "function " + fun.getClassName() +
1421                    "() {\n\t[native code]\n}\n";
1422     }
1423 
1424     /**
1425      * Decompile the body of a JavaScript Function.
1426      * <p>
1427      * Decompiles the body a previously compiled JavaScript Function
1428      * object to canonical source, omitting the function header and
1429      * trailing brace.
1430      *
1431      * Returns '[native code]' if no decompilation information is available.
1432      *
1433      * @param fun the JavaScript function to decompile
1434      * @param indent the number of spaces to indent the result
1435      * @return a string representing the function body source.
1436      */
1437     public final String decompileFunctionBody(Function fun, int indent)
1438     {
1439         if (fun instanceof BaseFunction) {
1440             BaseFunction bf = (BaseFunction)fun;
1441             return bf.decompile(indent, Decompiler.ONLY_BODY_FLAG);
1442         }
1443         // ALERT: not sure what the right response here is.
1444         return "[native code]\n";
1445     }
1446 
1447     /**
1448      * Create a new JavaScript object.
1449      *
1450      * Equivalent to evaluating "new Object()".
1451      * @param scope the scope to search for the constructor and to evaluate
1452      *              against
1453      * @return the new object
1454      */
1455     public Scriptable newObject(Scriptable scope)
1456     {
1457         NativeObject result = new NativeObject();
1458         ScriptRuntime.setBuiltinProtoAndParent(result, scope,
1459                 TopLevel.Builtins.Object);
1460         return result;
1461     }
1462 
1463     /**
1464      * Create a new JavaScript object by executing the named constructor.
1465      *
1466      * The call <code>newObject(scope, "Foo")</code> is equivalent to
1467      * evaluating "new Foo()".
1468      *
1469      * @param scope the scope to search for the constructor and to evaluate against
1470      * @param constructorName the name of the constructor to call
1471      * @return the new object
1472      */
1473     public Scriptable newObject(Scriptable scope, String constructorName)
1474     {
1475         return newObject(scope, constructorName, ScriptRuntime.emptyArgs);
1476     }
1477 
1478     /**
1479      * Creates a new JavaScript object by executing the named constructor.
1480      *
1481      * Searches <code>scope</code> for the named constructor, calls it with
1482      * the given arguments, and returns the result.<p>
1483      *
1484      * The code
1485      * <pre>
1486      * Object[] args = { "a", "b" };
1487      * newObject(scope, "Foo", args)</pre>
1488      * is equivalent to evaluating "new Foo('a', 'b')", assuming that the Foo
1489      * constructor has been defined in <code>scope</code>.
1490      *
1491      * @param scope The scope to search for the constructor and to evaluate
1492      *              against
1493      * @param constructorName the name of the constructor to call
1494      * @param args the array of arguments for the constructor
1495      * @return the new object
1496      */
1497     public Scriptable newObject(Scriptable scope, String constructorName,
1498                                 Object[] args)
1499     {
1500         scope = ScriptableObject.getTopLevelScope(scope);
1501         Function ctor = ScriptRuntime.getExistingCtor(this, scope,
1502                                                       constructorName);
1503         if (args == null) { args = ScriptRuntime.emptyArgs; }
1504         return ctor.construct(this, scope, args);
1505     }
1506 
1507     /**
1508      * Create an array with a specified initial length.
1509      * <p>
1510      * @param scope the scope to create the object in
1511      * @param length the initial length (JavaScript arrays may have
1512      *               additional properties added dynamically).
1513      * @return the new array object
1514      */
1515     public Scriptable newArray(Scriptable scope, int length)
1516     {
1517         NativeArray result = new NativeArray(length);
1518         ScriptRuntime.setBuiltinProtoAndParent(result, scope,
1519                 TopLevel.Builtins.Array);
1520         return result;
1521     }
1522 
1523     /**
1524      * Create an array with a set of initial elements.
1525      *
1526      * @param scope the scope to create the object in.
1527      * @param elements the initial elements. Each object in this array
1528      *                 must be an acceptable JavaScript type and type
1529      *                 of array should be exactly Object[], not
1530      *                 SomeObjectSubclass[].
1531      * @return the new array object.
1532      */
1533     public Scriptable newArray(Scriptable scope, Object[] elements)
1534     {
1535         if (elements.getClass().getComponentType() != ScriptRuntime.ObjectClass)
1536             throw new IllegalArgumentException();
1537         NativeArray result = new NativeArray(elements);
1538         ScriptRuntime.setBuiltinProtoAndParent(result, scope,
1539                 TopLevel.Builtins.Array);
1540         return result;
1541     }
1542 
1543     /**
1544      * Get the elements of a JavaScript array.
1545      * <p>
1546      * If the object defines a length property convertible to double number,
1547      * then the number is converted Uint32 value as defined in Ecma 9.6
1548      * and Java array of that size is allocated.
1549      * The array is initialized with the values obtained by
1550      * calling get() on object for each value of i in [0,length-1]. If
1551      * there is not a defined value for a property the Undefined value
1552      * is used to initialize the corresponding element in the array. The
1553      * Java array is then returned.
1554      * If the object doesn't define a length property or it is not a number,
1555      * empty array is returned.
1556      * @param object the JavaScript array or array-like object
1557      * @return a Java array of objects
1558      * @since 1.4 release 2
1559      */
1560     public final Object[] getElements(Scriptable object)
1561     {
1562         return ScriptRuntime.getArrayElements(object);
1563     }
1564 
1565     /**
1566      * Convert the value to a JavaScript boolean value.
1567      * <p>
1568      * See ECMA 9.2.
1569      *
1570      * @param value a JavaScript value
1571      * @return the corresponding boolean value converted using
1572      *         the ECMA rules
1573      */
1574     public static boolean toBoolean(Object value)
1575     {
1576         return ScriptRuntime.toBoolean(value);
1577     }
1578 
1579     /**
1580      * Convert the value to a JavaScript Number value.
1581      * <p>
1582      * Returns a Java double for the JavaScript Number.
1583      * <p>
1584      * See ECMA 9.3.
1585      *
1586      * @param value a JavaScript value
1587      * @return the corresponding double value converted using
1588      *         the ECMA rules
1589      */
1590     public static double toNumber(Object value)
1591     {
1592         return ScriptRuntime.toNumber(value);
1593     }
1594 
1595     /**
1596      * Convert the value to a JavaScript String value.
1597      * <p>
1598      * See ECMA 9.8.
1599      * <p>
1600      * @param value a JavaScript value
1601      * @return the corresponding String value converted using
1602      *         the ECMA rules
1603      */
1604     public static String toString(Object value)
1605     {
1606         return ScriptRuntime.toString(value);
1607     }
1608 
1609     /**
1610      * Convert the value to an JavaScript object value.
1611      * <p>
1612      * Note that a scope must be provided to look up the constructors
1613      * for Number, Boolean, and String.
1614      * <p>
1615      * See ECMA 9.9.
1616      * <p>
1617      * Additionally, arbitrary Java objects and classes will be
1618      * wrapped in a Scriptable object with its Java fields and methods
1619      * reflected as JavaScript properties of the object.
1620      *
1621      * @param value any Java object
1622      * @param scope global scope containing constructors for Number,
1623      *              Boolean, and String
1624      * @return new JavaScript object
1625      */
1626     public static Scriptable toObject(Object value, Scriptable scope)
1627     {
1628         return ScriptRuntime.toObject(scope, value);
1629     }
1630 
1631     /**
1632      * @deprecated
1633      * @see #toObject(Object, Scriptable)
1634      */
1635     public static Scriptable toObject(Object value, Scriptable scope,
1636                                       Class<?> staticType)
1637     {
1638         return ScriptRuntime.toObject(scope, value);
1639     }
1640 
1641     /**
1642      * Convenient method to convert java value to its closest representation
1643      * in JavaScript.
1644      * <p>
1645      * If value is an instance of String, Number, Boolean, Function or
1646      * Scriptable, it is returned as it and will be treated as the corresponding
1647      * JavaScript type of string, number, boolean, function and object.
1648      * <p>
1649      * Note that for Number instances during any arithmetic operation in
1650      * JavaScript the engine will always use the result of
1651      * <tt>Number.doubleValue()</tt> resulting in a precision loss if
1652      * the number can not fit into double.
1653      * <p>
1654      * If value is an instance of Character, it will be converted to string of
1655      * length 1 and its JavaScript type will be string.
1656      * <p>
1657      * The rest of values will be wrapped as LiveConnect objects
1658      * by calling {@link WrapFactory#wrap(Context cx, Scriptable scope,
1659      * Object obj, Class staticType)} as in:
1660      * <pre>
1661      *    Context cx = Context.getCurrentContext();
1662      *    return cx.getWrapFactory().wrap(cx, scope, value, null);
1663      * </pre>
1664      *
1665      * @param value any Java object
1666      * @param scope top scope object
1667      * @return value suitable to pass to any API that takes JavaScript values.
1668      */
1669     public static Object javaToJS(Object value, Scriptable scope)
1670     {
1671         if (value instanceof String || value instanceof Number
1672             || value instanceof Boolean || value instanceof Scriptable)
1673         {
1674             return value;
1675         } else if (value instanceof Character) {
1676             return String.valueOf(((Character)value).charValue());
1677         } else {
1678             Context cx = Context.getContext();
1679             return cx.getWrapFactory().wrap(cx, scope, value, null);
1680         }
1681     }
1682 
1683     /**
1684      * Convert a JavaScript value into the desired type.
1685      * Uses the semantics defined with LiveConnect3 and throws an
1686      * Illegal argument exception if the conversion cannot be performed.
1687      * @param value the JavaScript value to convert
1688      * @param desiredType the Java type to convert to. Primitive Java
1689      *        types are represented using the TYPE fields in the corresponding
1690      *        wrapper class in java.lang.
1691      * @return the converted value
1692      * @throws EvaluatorException if the conversion cannot be performed
1693      */
1694     public static Object jsToJava(Object value, Class<?> desiredType)
1695         throws EvaluatorException
1696     {
1697         return NativeJavaObject.coerceTypeImpl(desiredType, value);
1698     }
1699 
1700     /**
1701      * @deprecated
1702      * @see #jsToJava(Object, Class)
1703      * @throws IllegalArgumentException if the conversion cannot be performed.
1704      *         Note that {@link #jsToJava(Object, Class)} throws
1705      *         {@link EvaluatorException} instead.
1706      */
1707     public static Object toType(Object value, Class<?> desiredType)
1708         throws IllegalArgumentException
1709     {
1710         try {
1711             return jsToJava(value, desiredType);
1712         } catch (EvaluatorException ex) {
1713             IllegalArgumentException
1714                 ex2 = new IllegalArgumentException(ex.getMessage());
1715             Kit.initCause(ex2, ex);
1716             throw ex2;
1717         }
1718     }
1719 
1720     /**
1721      * Rethrow the exception wrapping it as the script runtime exception.
1722      * Unless the exception is instance of {@link EcmaError} or
1723      * {@link EvaluatorException} it will be wrapped as
1724      * {@link WrappedException}, a subclass of {@link EvaluatorException}.
1725      * The resulting exception object always contains
1726      * source name and line number of script that triggered exception.
1727      * <p>
1728      * This method always throws an exception, its return value is provided
1729      * only for convenience to allow a usage like:
1730      * <pre>
1731      * throw Context.throwAsScriptRuntimeEx(ex);
1732      * </pre>
1733      * to indicate that code after the method is unreachable.
1734      * @throws EvaluatorException
1735      * @throws EcmaError
1736      */
1737     public static RuntimeException throwAsScriptRuntimeEx(Throwable e)
1738     {
1739         while ((e instanceof InvocationTargetException)) {
1740             e = ((InvocationTargetException) e).getTargetException();
1741         }
1742         // special handling of Error so scripts would not catch them
1743         if (e instanceof Error) {
1744             Context cx = getContext();
1745             if (cx == null ||
1746                 !cx.hasFeature(Context.FEATURE_ENHANCED_JAVA_ACCESS))
1747             {
1748                 throw (Error)e;
1749             }
1750         }
1751         if (e instanceof RhinoException) {
1752             throw (RhinoException)e;
1753         }
1754         throw new WrappedException(e);
1755     }
1756 
1757     /**
1758      * Tell whether debug information is being generated.
1759      * @since 1.3
1760      */
1761     public final boolean isGeneratingDebug()
1762     {
1763         return generatingDebug;
1764     }
1765 
1766     /**
1767      * Specify whether or not debug information should be generated.
1768      * <p>
1769      * Setting the generation of debug information on will set the
1770      * optimization level to zero.
1771      * @since 1.3
1772      */
1773     public final void setGeneratingDebug(boolean generatingDebug)
1774     {
1775         if (sealed) onSealedMutation();
1776         generatingDebugChanged = true;
1777         if (generatingDebug && getOptimizationLevel() > 0)
1778             setOptimizationLevel(0);
1779         this.generatingDebug = generatingDebug;
1780     }
1781 
1782     /**
1783      * Tell whether source information is being generated.
1784      * @since 1.3
1785      */
1786     public final boolean isGeneratingSource()
1787     {
1788         return generatingSource;
1789     }
1790 
1791     /**
1792      * Specify whether or not source information should be generated.
1793      * <p>
1794      * Without source information, evaluating the "toString" method
1795      * on JavaScript functions produces only "[native code]" for
1796      * the body of the function.
1797      * Note that code generated without source is not fully ECMA
1798      * conformant.
1799      * @since 1.3
1800      */
1801     public final void setGeneratingSource(boolean generatingSource)
1802     {
1803         if (sealed) onSealedMutation();
1804         this.generatingSource = generatingSource;
1805     }
1806 
1807     /**
1808      * Get the current optimization level.
1809      * <p>
1810      * The optimization level is expressed as an integer between -1 and
1811      * 9.
1812      * @since 1.3
1813      *
1814      */
1815     public final int getOptimizationLevel()
1816     {
1817         return optimizationLevel;
1818     }
1819 
1820     /**
1821      * Set the current optimization level.
1822      * <p>
1823      * The optimization level is expected to be an integer between -1 and
1824      * 9. Any negative values will be interpreted as -1, and any values
1825      * greater than 9 will be interpreted as 9.
1826      * An optimization level of -1 indicates that interpretive mode will
1827      * always be used. Levels 0 through 9 indicate that class files may
1828      * be generated. Higher optimization levels trade off compile time
1829      * performance for runtime performance.
1830      * The optimizer level can't be set greater than -1 if the optimizer
1831      * package doesn't exist at run time.
1832      * @param optimizationLevel an integer indicating the level of
1833      *        optimization to perform
1834      * @since 1.3
1835      *
1836      */
1837     public final void setOptimizationLevel(int optimizationLevel)
1838     {
1839         if (sealed) onSealedMutation();
1840         if (optimizationLevel == -2) {
1841             // To be compatible with Cocoon fork
1842             optimizationLevel = -1;
1843         }
1844         checkOptimizationLevel(optimizationLevel);
1845         if (codegenClass == null)
1846             optimizationLevel = -1;
1847         this.optimizationLevel = optimizationLevel;
1848     }
1849 
1850     public static boolean isValidOptimizationLevel(int optimizationLevel)
1851     {
1852         return -1 <= optimizationLevel && optimizationLevel <= 9;
1853     }
1854 
1855     public static void checkOptimizationLevel(int optimizationLevel)
1856     {
1857         if (isValidOptimizationLevel(optimizationLevel)) {
1858             return;
1859         }
1860         throw new IllegalArgumentException(
1861             "Optimization level outside [-1..9]: "+optimizationLevel);
1862     }
1863 
1864     /**
1865      * Returns the maximum stack depth (in terms of number of call frames)
1866      * allowed in a single invocation of interpreter. If the set depth would be
1867      * exceeded, the interpreter will throw an EvaluatorException in the script.
1868      * Defaults to Integer.MAX_VALUE. The setting only has effect for
1869      * interpreted functions (those compiled with optimization level set to -1).
1870      * As the interpreter doesn't use the Java stack but rather manages its own
1871      * stack in the heap memory, a runaway recursion in interpreted code would
1872      * eventually consume all available memory and cause OutOfMemoryError
1873      * instead of a StackOverflowError limited to only a single thread. This
1874      * setting helps prevent such situations.
1875      *
1876      * @return The current maximum interpreter stack depth.
1877      */
1878     public final int getMaximumInterpreterStackDepth()
1879     {
1880         return maximumInterpreterStackDepth;
1881     }
1882 
1883     /**
1884      * Sets the maximum stack depth (in terms of number of call frames)
1885      * allowed in a single invocation of interpreter. If the set depth would be
1886      * exceeded, the interpreter will throw an EvaluatorException in the script.
1887      * Defaults to Integer.MAX_VALUE. The setting only has effect for
1888      * interpreted functions (those compiled with optimization level set to -1).
1889      * As the interpreter doesn't use the Java stack but rather manages its own
1890      * stack in the heap memory, a runaway recursion in interpreted code would
1891      * eventually consume all available memory and cause OutOfMemoryError
1892      * instead of a StackOverflowError limited to only a single thread. This
1893      * setting helps prevent such situations.
1894      *
1895      * @param max the new maximum interpreter stack depth
1896      * @throws IllegalStateException if this context's optimization level is not
1897      * -1
1898      * @throws IllegalArgumentException if the new depth is not at least 1
1899      */
1900     public final void setMaximumInterpreterStackDepth(int max)
1901     {
1902         if(sealed) onSealedMutation();
1903         if(optimizationLevel != -1) {
1904             throw new IllegalStateException("Cannot set maximumInterpreterStackDepth when optimizationLevel != -1");
1905         }
1906         if(max < 1) {
1907             throw new IllegalArgumentException("Cannot set maximumInterpreterStackDepth to less than 1");
1908         }
1909         maximumInterpreterStackDepth = max;
1910     }
1911 
1912     /**
1913      * Set the security controller for this context.
1914      * <p> SecurityController may only be set if it is currently null
1915      * and {@link SecurityController#hasGlobal()} is <tt>false</tt>.
1916      * Otherwise a SecurityException is thrown.
1917      * @param controller a SecurityController object
1918      * @throws SecurityException if there is already a SecurityController
1919      *         object for this Context or globally installed.
1920      * @see SecurityController#initGlobal(SecurityController controller)
1921      * @see SecurityController#hasGlobal()
1922      */
1923     public final void setSecurityController(SecurityController controller)
1924     {
1925         if (sealed) onSealedMutation();
1926         if (controller == null) throw new IllegalArgumentException();
1927         if (securityController != null) {
1928             throw new SecurityException("Can not overwrite existing SecurityController object");
1929         }
1930         if (SecurityController.hasGlobal()) {
1931             throw new SecurityException("Can not overwrite existing global SecurityController object");
1932         }
1933         securityController = controller;
1934     }
1935 
1936     /**
1937      * Set the LiveConnect access filter for this context.
1938      * <p> {@link ClassShutter} may only be set if it is currently null.
1939      * Otherwise a SecurityException is thrown.
1940      * @param shutter a ClassShutter object
1941      * @throws SecurityException if there is already a ClassShutter
1942      *         object for this Context
1943      */
1944     public synchronized final void setClassShutter(ClassShutter shutter)
1945     {
1946         if (sealed) onSealedMutation();
1947         if (shutter == null) throw new IllegalArgumentException();
1948         if (hasClassShutter) {
1949             throw new SecurityException("Cannot overwrite existing " +
1950                                         "ClassShutter object");
1951         }
1952         classShutter = shutter;
1953         hasClassShutter = true;
1954     }
1955 
1956     final synchronized ClassShutter getClassShutter()
1957     {
1958         return classShutter;
1959     }
1960 
1961     public interface ClassShutterSetter {
1962         public void setClassShutter(ClassShutter shutter);
1963         public ClassShutter getClassShutter();
1964     }
1965 
1966     public final synchronized ClassShutterSetter getClassShutterSetter() {
1967         if (hasClassShutter)
1968             return null;
1969         hasClassShutter = true;
1970         return new ClassShutterSetter() {
1971             public void setClassShutter(ClassShutter shutter) {
1972                 classShutter = shutter;
1973             }
1974             public ClassShutter getClassShutter() {
1975                 return classShutter;
1976             }
1977         };
1978     }
1979 
1980     /**
1981      * Get a value corresponding to a key.
1982      * <p>
1983      * Since the Context is associated with a thread it can be
1984      * used to maintain values that can be later retrieved using
1985      * the current thread.
1986      * <p>
1987      * Note that the values are maintained with the Context, so
1988      * if the Context is disassociated from the thread the values
1989      * cannot be retrieved. Also, if private data is to be maintained
1990      * in this manner the key should be a java.lang.Object
1991      * whose reference is not divulged to untrusted code.
1992      * @param key the key used to lookup the value
1993      * @return a value previously stored using putThreadLocal.
1994      */
1995     public final Object getThreadLocal(Object key)
1996     {
1997         if (threadLocalMap == null)
1998             return null;
1999         return threadLocalMap.get(key);
2000     }
2001 
2002     /**
2003      * Put a value that can later be retrieved using a given key.
2004      * <p>
2005      * @param key the key used to index the value
2006      * @param value the value to save
2007      */
2008     public synchronized final void putThreadLocal(Object key, Object value)
2009     {
2010         if (sealed) onSealedMutation();
2011         if (threadLocalMap == null)
2012             threadLocalMap = new HashMap<Object,Object>();
2013         threadLocalMap.put(key, value);
2014     }
2015 
2016     /**
2017      * Remove values from thread-local storage.
2018      * @param key the key for the entry to remove.
2019      * @since 1.5 release 2
2020      */
2021     public final void removeThreadLocal(Object key)
2022     {
2023         if (sealed) onSealedMutation();
2024         if (threadLocalMap == null)
2025             return;
2026         threadLocalMap.remove(key);
2027     }
2028 
2029     /**
2030      * @deprecated
2031      * @see ClassCache#get(Scriptable)
2032      * @see ClassCache#setCachingEnabled(boolean)
2033      */
2034     public static void setCachingEnabled(boolean cachingEnabled)
2035     {
2036     }
2037 
2038     /**
2039      * Set a WrapFactory for this Context.
2040      * <p>
2041      * The WrapFactory allows custom object wrapping behavior for
2042      * Java object manipulated with JavaScript.
2043      * @see WrapFactory
2044      * @since 1.5 Release 4
2045      */
2046     public final void setWrapFactory(WrapFactory wrapFactory)
2047     {
2048         if (sealed) onSealedMutation();
2049         if (wrapFactory == null) throw new IllegalArgumentException();
2050         this.wrapFactory = wrapFactory;
2051     }
2052 
2053     /**
2054      * Return the current WrapFactory, or null if none is defined.
2055      * @see WrapFactory
2056      * @since 1.5 Release 4
2057      */
2058     public final WrapFactory getWrapFactory()
2059     {
2060         if (wrapFactory == null) {
2061             wrapFactory = new WrapFactory();
2062         }
2063         return wrapFactory;
2064     }
2065 
2066     /**
2067      * Return the current debugger.
2068      * @return the debugger, or null if none is attached.
2069      */
2070     public final Debugger getDebugger()
2071     {
2072         return debugger;
2073     }
2074 
2075     /**
2076      * Return the debugger context data associated with current context.
2077      * @return the debugger data, or null if debugger is not attached
2078      */
2079     public final Object getDebuggerContextData()
2080     {
2081         return debuggerData;
2082     }
2083 
2084     /**
2085      * Set the associated debugger.
2086      * @param debugger the debugger to be used on callbacks from
2087      * the engine.
2088      * @param contextData arbitrary object that debugger can use to store
2089      *        per Context data.
2090      */
2091     public final void setDebugger(Debugger debugger, Object contextData)
2092     {
2093         if (sealed) onSealedMutation();
2094         this.debugger = debugger;
2095         debuggerData = contextData;
2096     }
2097 
2098     /**
2099      * Return DebuggableScript instance if any associated with the script.
2100      * If callable supports DebuggableScript implementation, the method
2101      * returns it. Otherwise null is returned.
2102      */
2103     public static DebuggableScript getDebuggableView(Script script)
2104     {
2105         if (script instanceof NativeFunction) {
2106             return ((NativeFunction)script).getDebuggableView();
2107         }
2108         return null;
2109     }
2110 
2111     /**
2112      * Controls certain aspects of script semantics.
2113      * Should be overwritten to alter default behavior.
2114      * <p>
2115      * The default implementation calls
2116      * {@link ContextFactory#hasFeature(Context cx, int featureIndex)}
2117      * that allows to customize Context behavior without introducing
2118      * Context subclasses.  {@link ContextFactory} documentation gives
2119      * an example of hasFeature implementation.
2120      *
2121      * @param featureIndex feature index to check
2122      * @return true if the <code>featureIndex</code> feature is turned on
2123      * @see #FEATURE_NON_ECMA_GET_YEAR
2124      * @see #FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME
2125      * @see #FEATURE_RESERVED_KEYWORD_AS_IDENTIFIER
2126      * @see #FEATURE_TO_STRING_AS_SOURCE
2127      * @see #FEATURE_PARENT_PROTO_PROPRTIES
2128      * @see #FEATURE_E4X
2129      * @see #FEATURE_DYNAMIC_SCOPE
2130      * @see #FEATURE_STRICT_VARS
2131      * @see #FEATURE_STRICT_EVAL
2132      * @see #FEATURE_LOCATION_INFORMATION_IN_ERROR
2133      * @see #FEATURE_STRICT_MODE
2134      * @see #FEATURE_WARNING_AS_ERROR
2135      * @see #FEATURE_ENHANCED_JAVA_ACCESS
2136      */
2137     public boolean hasFeature(int featureIndex)
2138     {
2139         ContextFactory f = getFactory();
2140         return f.hasFeature(this, featureIndex);
2141     }
2142 
2143     /**
2144      * Returns an object which specifies an E4X implementation to use within
2145      * this <code>Context</code>. Note that the XMLLib.Factory interface should
2146      * be considered experimental.
2147      *
2148      * The default implementation uses the implementation provided by this
2149      * <code>Context</code>'s {@link ContextFactory}.
2150      *
2151      * @return An XMLLib.Factory. Should not return <code>null</code> if
2152      *         {@link #FEATURE_E4X} is enabled. See {@link #hasFeature}.
2153      */
2154     public XMLLib.Factory getE4xImplementationFactory() {
2155         return getFactory().getE4xImplementationFactory();
2156     }
2157 
2158     /**
2159      * Get threshold of executed instructions counter that triggers call to
2160      * <code>observeInstructionCount()</code>.
2161      * When the threshold is zero, instruction counting is disabled,
2162      * otherwise each time the run-time executes at least the threshold value
2163      * of script instructions, <code>observeInstructionCount()</code> will
2164      * be called.
2165      */
2166     public final int getInstructionObserverThreshold()
2167     {
2168         return instructionThreshold;
2169     }
2170 
2171     /**
2172      * Set threshold of executed instructions counter that triggers call to
2173      * <code>observeInstructionCount()</code>.
2174      * When the threshold is zero, instruction counting is disabled,
2175      * otherwise each time the run-time executes at least the threshold value
2176      * of script instructions, <code>observeInstructionCount()</code> will
2177      * be called.<p/>
2178      * Note that the meaning of "instruction" is not guaranteed to be
2179      * consistent between compiled and interpretive modes: executing a given
2180      * script or function in the different modes will result in different
2181      * instruction counts against the threshold.
2182      * {@link #setGenerateObserverCount} is called with true if
2183      * <code>threshold</code> is greater than zero, false otherwise.
2184      * @param threshold The instruction threshold
2185      */
2186     public final void setInstructionObserverThreshold(int threshold)
2187     {
2188         if (sealed) onSealedMutation();
2189         if (threshold < 0) throw new IllegalArgumentException();
2190         instructionThreshold = threshold;
2191         setGenerateObserverCount(threshold > 0);
2192     }
2193 
2194     /**
2195      * Turn on or off generation of code with callbacks to
2196      * track the count of executed instructions.
2197      * Currently only affects JVM byte code generation: this slows down the
2198      * generated code, but code generated without the callbacks will not
2199      * be counted toward instruction thresholds. Rhino's interpretive
2200      * mode does instruction counting without inserting callbacks, so
2201      * there is no requirement to compile code differently.
2202      * @param generateObserverCount if true, generated code will contain
2203      * calls to accumulate an estimate of the instructions executed.
2204      */
2205     public void setGenerateObserverCount(boolean generateObserverCount) {
2206         this.generateObserverCount = generateObserverCount;
2207     }
2208 
2209     /**
2210      * Allow application to monitor counter of executed script instructions
2211      * in Context subclasses.
2212      * Run-time calls this when instruction counting is enabled and the counter
2213      * reaches limit set by <code>setInstructionObserverThreshold()</code>.
2214      * The method is useful to observe long running scripts and if necessary
2215      * to terminate them.
2216      * <p>
2217      * The default implementation calls
2218      * {@link ContextFactory#observeInstructionCount(Context cx,
2219      *                                               int instructionCount)}
2220      * that allows to customize Context behavior without introducing
2221      * Context subclasses.
2222      *
2223      * @param instructionCount amount of script instruction executed since
2224      * last call to <code>observeInstructionCount</code>
2225      * @throws Error to terminate the script
2226      * @see #setOptimizationLevel(int)
2227      */
2228     protected void observeInstructionCount(int instructionCount)
2229     {
2230         ContextFactory f = getFactory();
2231         f.observeInstructionCount(this, instructionCount);
2232     }
2233 
2234     /**
2235      * Create class loader for generated classes.
2236      * The method calls {@link ContextFactory#createClassLoader(ClassLoader)}
2237      * using the result of {@link #getFactory()}.
2238      */
2239     public GeneratedClassLoader createClassLoader(ClassLoader parent)
2240     {
2241         ContextFactory f = getFactory();
2242         return f.createClassLoader(parent);
2243     }
2244 
2245     public final ClassLoader getApplicationClassLoader()
2246     {
2247         if (applicationClassLoader == null) {
2248             ContextFactory f = getFactory();
2249             ClassLoader loader = f.getApplicationClassLoader();
2250             if (loader == null) {
2251                 ClassLoader threadLoader
2252                     = VMBridge.instance.getCurrentThreadClassLoader();
2253                 if (threadLoader != null
2254                     && Kit.testIfCanLoadRhinoClasses(threadLoader))
2255                 {
2256                     // Thread.getContextClassLoader is not cached since
2257                     // its caching prevents it from GC which may lead to
2258                     // a memory leak and hides updates to
2259                     // Thread.getContextClassLoader
2260                     return threadLoader;
2261                 }
2262                 // Thread.getContextClassLoader can not load Rhino classes,
2263                 // try to use the loader of ContextFactory or Context
2264                 // subclasses.
2265                 Class<?> fClass = f.getClass();
2266                 if (fClass != ScriptRuntime.ContextFactoryClass) {
2267                     loader = fClass.getClassLoader();
2268                 } else {
2269                     loader = getClass().getClassLoader();
2270                 }
2271             }
2272             applicationClassLoader = loader;
2273         }
2274         return applicationClassLoader;
2275     }
2276 
2277     public final void setApplicationClassLoader(ClassLoader loader)
2278     {
2279         if (sealed) onSealedMutation();
2280         if (loader == null) {
2281             // restore default behaviour
2282             applicationClassLoader = null;
2283             return;
2284         }
2285         if (!Kit.testIfCanLoadRhinoClasses(loader)) {
2286             throw new IllegalArgumentException(
2287                 "Loader can not resolve Rhino classes");
2288         }
2289         applicationClassLoader = loader;
2290     }
2291 
2292     /********** end of API **********/
2293 
2294     /**
2295      * Internal method that reports an error for missing calls to
2296      * enter().
2297      */
2298     static Context getContext()
2299     {
2300         Context cx = getCurrentContext();
2301         if (cx == null) {
2302             throw new RuntimeException(
2303                 "No Context associated with current Thread");
2304         }
2305         return cx;
2306     }
2307 
2308     private Object compileImpl(Scriptable scope,
2309                                Reader sourceReader, String sourceString,
2310                                String sourceName, int lineno,
2311                                Object securityDomain, boolean returnFunction,
2312                                Evaluator compiler,
2313                                ErrorReporter compilationErrorReporter)
2314         throws IOException
2315     {
2316         if(sourceName == null) {
2317             sourceName = "unnamed script";
2318         }
2319         if (securityDomain != null && getSecurityController() == null) {
2320             throw new IllegalArgumentException(
2321                 "securityDomain should be null if setSecurityController() was never called");
2322         }
2323 
2324         // One of sourceReader or sourceString has to be null
2325         if (!(sourceReader == null ^ sourceString == null)) Kit.codeBug();
2326         // scope should be given if and only if compiling function
2327         if (!(scope == null ^ returnFunction)) Kit.codeBug();
2328 
2329         CompilerEnvirons compilerEnv = new CompilerEnvirons();
2330         compilerEnv.initFromContext(this);
2331         if (compilationErrorReporter == null) {
2332             compilationErrorReporter = compilerEnv.getErrorReporter();
2333         }
2334 
2335         if (debugger != null) {
2336             if (sourceReader != null) {
2337                 sourceString = Kit.readReader(sourceReader);
2338                 sourceReader = null;
2339             }
2340         }
2341 
2342         Parser p = new Parser(compilerEnv, compilationErrorReporter);
2343         if (returnFunction) {
2344             p.calledByCompileFunction = true;
2345         }
2346         AstRoot ast;
2347         if (sourceString != null) {
2348             ast = p.parse(sourceString, sourceName, lineno);
2349         } else {
2350             ast = p.parse(sourceReader, sourceName, lineno);
2351         }
2352         if (returnFunction) {
2353             // parser no longer adds function to script node
2354             if (!(ast.getFirstChild() != null
2355                   && ast.getFirstChild().getType() == Token.FUNCTION))
2356             {
2357                 // XXX: the check just looks for the first child
2358                 // and allows for more nodes after it for compatibility
2359                 // with sources like function() {};;;
2360                 throw new IllegalArgumentException(
2361                     "compileFunction only accepts source with single JS function: "+sourceString);
2362             }
2363         }
2364 
2365         IRFactory irf = new IRFactory(compilerEnv, compilationErrorReporter);
2366         ScriptNode tree = irf.transformTree(ast);
2367 
2368         // discard everything but the IR tree
2369         p = null;
2370         ast = null;
2371         irf = null;
2372 
2373         if (compiler == null) {
2374             compiler = createCompiler();
2375         }
2376 
2377         Object bytecode = compiler.compile(compilerEnv,
2378                                            tree, tree.getEncodedSource(),
2379                                            returnFunction);
2380         if (debugger != null) {
2381             if (sourceString == null) Kit.codeBug();
2382             if (bytecode instanceof DebuggableScript) {
2383                 DebuggableScript dscript = (DebuggableScript)bytecode;
2384                 notifyDebugger_r(this, dscript, sourceString);
2385             } else {
2386                 throw new RuntimeException("NOT SUPPORTED");
2387             }
2388         }
2389 
2390         Object result;
2391         if (returnFunction) {
2392             result = compiler.createFunctionObject(this, scope, bytecode, securityDomain);
2393         } else {
2394             result = compiler.createScriptObject(bytecode, securityDomain);
2395         }
2396 
2397         return result;
2398     }
2399 
2400     private static void notifyDebugger_r(Context cx, DebuggableScript dscript,
2401                                          String debugSource)
2402     {
2403         cx.debugger.handleCompilationDone(cx, dscript, debugSource);
2404         for (int i = 0; i != dscript.getFunctionCount(); ++i) {
2405             notifyDebugger_r(cx, dscript.getFunction(i), debugSource);
2406         }
2407     }
2408 
2409     private static Class<?> codegenClass = Kit.classOrNull(
2410                              "org.mozilla.javascript.optimizer.Codegen");
2411     private static Class<?> interpreterClass = Kit.classOrNull(
2412                              "org.mozilla.javascript.Interpreter");
2413 
2414     private Evaluator createCompiler()
2415     {
2416         Evaluator result = null;
2417         if (optimizationLevel >= 0 && codegenClass != null) {
2418             result = (Evaluator)Kit.newInstanceOrNull(codegenClass);
2419         }
2420         if (result == null) {
2421             result = createInterpreter();
2422         }
2423         return result;
2424     }
2425 
2426     static Evaluator createInterpreter()
2427     {
2428         return (Evaluator)Kit.newInstanceOrNull(interpreterClass);
2429     }
2430 
2431     static String getSourcePositionFromStack(int[] linep)
2432     {
2433         Context cx = getCurrentContext();
2434         if (cx == null)
2435             return null;
2436         if (cx.lastInterpreterFrame != null) {
2437             Evaluator evaluator = createInterpreter();
2438             if (evaluator != null)
2439                 return evaluator.getSourcePositionFromStack(cx, linep);
2440         }
2441         /**
2442          * A bit of a hack, but the only way to get filename and line
2443          * number from an enclosing frame.
2444          */
2445         CharArrayWriter writer = new CharArrayWriter();
2446         RuntimeException re = new RuntimeException();
2447         re.printStackTrace(new PrintWriter(writer));
2448         String s = writer.toString();
2449         int open = -1;
2450         int close = -1;
2451         int colon = -1;
2452         for (int i=0; i < s.length(); i++) {
2453             char c = s.charAt(i);
2454             if (c == ':')
2455                 colon = i;
2456             else if (c == '(')
2457                 open = i;
2458             else if (c == ')')
2459                 close = i;
2460             else if (c == '\n' && open != -1 && close != -1 && colon != -1 &&
2461                      open < colon && colon < close)
2462             {
2463                 String fileStr = s.substring(open + 1, colon);
2464                 if (!fileStr.endsWith(".java")) {
2465                     String lineStr = s.substring(colon + 1, close);
2466                     try {
2467                         linep[0] = Integer.parseInt(lineStr);
2468                         if (linep[0] < 0) {
2469                             linep[0] = 0;
2470                         }
2471                         return fileStr;
2472                     }
2473                     catch (NumberFormatException e) {
2474                         // fall through
2475                     }
2476                 }
2477                 open = close = colon = -1;
2478             }
2479         }
2480 
2481         return null;
2482     }
2483 
2484     RegExpProxy getRegExpProxy()
2485     {
2486         if (regExpProxy == null) {
2487             Class<?> cl = Kit.classOrNull(
2488                           "org.mozilla.javascript.regexp.RegExpImpl");
2489             if (cl != null) {
2490                 regExpProxy = (RegExpProxy)Kit.newInstanceOrNull(cl);
2491             }
2492         }
2493         return regExpProxy;
2494     }
2495 
2496     final boolean isVersionECMA1()
2497     {
2498         return version == VERSION_DEFAULT || version >= VERSION_1_3;
2499     }
2500 
2501 // The method must NOT be public or protected
2502     SecurityController getSecurityController()
2503     {
2504         SecurityController global = SecurityController.global();
2505         if (global != null) {
2506             return global;
2507         }
2508         return securityController;
2509     }
2510 
2511     public final boolean isGeneratingDebugChanged()
2512     {
2513         return generatingDebugChanged;
2514     }
2515 
2516     /**
2517      * Add a name to the list of names forcing the creation of real
2518      * activation objects for functions.
2519      *
2520      * @param name the name of the object to add to the list
2521      */
2522     public void addActivationName(String name)
2523     {
2524         if (sealed) onSealedMutation();
2525         if (activationNames == null)
2526             activationNames = new HashSet<String>();
2527         activationNames.add(name);
2528     }
2529 
2530     /**
2531      * Check whether the name is in the list of names of objects
2532      * forcing the creation of activation objects.
2533      *
2534      * @param name the name of the object to test
2535      *
2536      * @return true if an function activation object is needed.
2537      */
2538     public final boolean isActivationNeeded(String name)
2539     {
2540         return activationNames != null && activationNames.contains(name);
2541     }
2542 
2543     /**
2544      * Remove a name from the list of names forcing the creation of real
2545      * activation objects for functions.
2546      *
2547      * @param name the name of the object to remove from the list
2548      */
2549     public void removeActivationName(String name)
2550     {
2551         if (sealed) onSealedMutation();
2552         if (activationNames != null)
2553             activationNames.remove(name);
2554     }
2555 
2556     private static String implementationVersion;
2557 
2558     private final ContextFactory factory;
2559     private boolean sealed;
2560     private Object sealKey;
2561 
2562     Scriptable topCallScope;
2563     boolean isContinuationsTopCall;
2564     NativeCall currentActivationCall;
2565     XMLLib cachedXMLLib;
2566 
2567     // for Objects, Arrays to tag themselves as being printed out,
2568     // so they don't print themselves out recursively.
2569     // Use ObjToIntMap instead of java.util.HashSet for JDK 1.1 compatibility
2570     ObjToIntMap iterating;
2571 
2572     Object interpreterSecurityDomain;
2573 
2574     int version;
2575 
2576     private SecurityController securityController;
2577     private boolean hasClassShutter;
2578     private ClassShutter classShutter;
2579     private ErrorReporter errorReporter;
2580     RegExpProxy regExpProxy;
2581     private Locale locale;
2582     private boolean generatingDebug;
2583     private boolean generatingDebugChanged;
2584     private boolean generatingSource=true;
2585     boolean useDynamicScope;
2586     private int optimizationLevel;
2587     private int maximumInterpreterStackDepth;
2588     private WrapFactory wrapFactory;
2589     Debugger debugger;
2590     private Object debuggerData;
2591     private int enterCount;
2592     private Object propertyListeners;
2593     private Map<Object,Object> threadLocalMap;
2594     private ClassLoader applicationClassLoader;
2595 
2596     /**
2597      * This is the list of names of objects forcing the creation of
2598      * function activation records.
2599      */
2600     Set<String> activationNames;
2601 
2602     // For the interpreter to store the last frame for error reports etc.
2603     Object lastInterpreterFrame;
2604 
2605     // For the interpreter to store information about previous invocations
2606     // interpreter invocations
2607     ObjArray previousInterpreterInvocations;
2608 
2609     // For instruction counting (interpreter only)
2610     int instructionCount;
2611     int instructionThreshold;
2612 
2613     // It can be used to return the second index-like result from function
2614     int scratchIndex;
2615 
2616     // It can be used to return the second uint32 result from function
2617     long scratchUint32;
2618 
2619     // It can be used to return the second Scriptable result from function
2620     Scriptable scratchScriptable;
2621 
2622     // Generate an observer count on compiled code
2623     public boolean generateObserverCount = false;
2624 }
2625