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