1 /* 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.nashorn.internal.runtime; 27 28 import static jdk.nashorn.internal.codegen.CompilerConstants.RUN_SCRIPT; 29 import static jdk.nashorn.internal.codegen.CompilerConstants.STRICT_MODE; 30 import static jdk.nashorn.internal.lookup.Lookup.MH; 31 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; 32 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; 33 34 import java.io.File; 35 import java.io.IOException; 36 import java.io.PrintWriter; 37 import java.lang.invoke.MethodHandle; 38 import java.lang.invoke.MethodHandles; 39 import java.lang.reflect.Modifier; 40 import java.util.concurrent.atomic.AtomicLong; 41 import java.net.MalformedURLException; 42 import java.net.URL; 43 import java.security.AccessControlContext; 44 import java.security.AccessController; 45 import java.security.CodeSigner; 46 import java.security.CodeSource; 47 import java.security.Permissions; 48 import java.security.PrivilegedAction; 49 import java.security.ProtectionDomain; 50 import java.util.Map; 51 52 import jdk.internal.org.objectweb.asm.ClassReader; 53 import jdk.internal.org.objectweb.asm.util.CheckClassAdapter; 54 import jdk.nashorn.api.scripting.ScriptObjectMirror; 55 import jdk.nashorn.internal.codegen.Compiler; 56 import jdk.nashorn.internal.codegen.ObjectClassGenerator; 57 import jdk.nashorn.internal.ir.FunctionNode; 58 import jdk.nashorn.internal.ir.debug.ASTWriter; 59 import jdk.nashorn.internal.ir.debug.PrintVisitor; 60 import jdk.nashorn.internal.objects.Global; 61 import jdk.nashorn.internal.parser.Parser; 62 import jdk.nashorn.internal.runtime.options.Options; 63 64 /** 65 * This class manages the global state of execution. Context is immutable. 66 */ 67 public final class Context { 68 // nashorn specific security runtime access permission names 69 /** 70 * Permission needed to pass arbitrary nashorn command line options when creating Context. 71 */ 72 public static final String NASHORN_SET_CONFIG = "nashorn.setConfig"; 73 74 /** 75 * Permission needed to create Nashorn Context instance. 76 */ 77 public static final String NASHORN_CREATE_CONTEXT = "nashorn.createContext"; 78 79 /** 80 * Permission needed to create Nashorn Global instance. 81 */ 82 public static final String NASHORN_CREATE_GLOBAL = "nashorn.createGlobal"; 83 84 /** 85 * Permission to get current Nashorn Context from thread local storage. 86 */ 87 public static final String NASHORN_GET_CONTEXT = "nashorn.getContext"; 88 89 /** 90 * Permission to use Java reflection/jsr292 from script code. 91 */ 92 public static final String NASHORN_JAVA_REFLECTION = "nashorn.JavaReflection"; 93 94 /* Force DebuggerSupport to be loaded. */ 95 static { 96 DebuggerSupport.FORCELOAD = true; 97 } 98 99 /** 100 * ContextCodeInstaller that has the privilege of installing classes in the Context. 101 * Can only be instantiated from inside the context and is opaque to other classes 102 */ 103 public static class ContextCodeInstaller implements CodeInstaller<ScriptEnvironment> { 104 private final Context context; 105 private final ScriptLoader loader; 106 private final CodeSource codeSource; 107 108 private ContextCodeInstaller(final Context context, final ScriptLoader loader, final CodeSource codeSource) { 109 this.context = context; 110 this.loader = loader; 111 this.codeSource = codeSource; 112 } 113 114 /** 115 * Return the context for this installer 116 * @return ScriptEnvironment 117 */ 118 @Override 119 public ScriptEnvironment getOwner() { 120 return context.env; 121 } 122 123 @Override 124 public Class<?> install(final String className, final byte[] bytecode) { 125 return loader.installClass(className, bytecode, codeSource); 126 } 127 128 @Override 129 public void verify(final byte[] code) { 130 context.verify(code); 131 } 132 133 @Override 134 public long getUniqueScriptId() { 135 return context.getUniqueScriptId(); 136 } 137 } 138 139 /** Is Context global debug mode enabled ? */ 140 public static final boolean DEBUG = Options.getBooleanProperty("nashorn.debug"); 141 142 private static final ThreadLocal<ScriptObject> currentGlobal = new ThreadLocal<>(); 143 144 /** 145 * Get the current global scope 146 * @return the current global scope 147 */ 148 public static ScriptObject getGlobal() { 149 // This class in a package.access protected package. 150 // Trusted code only can call this method. 151 return getGlobalTrusted(); 152 } 153 154 /** 155 * Set the current global scope 156 * @param global the global scope 157 */ 158 public static void setGlobal(final ScriptObject global) { 159 if (global != null && !(global instanceof Global)) { 160 throw new IllegalArgumentException("global is not an instance of Global!"); 161 } 162 163 setGlobalTrusted(global); 164 } 165 166 /** 167 * Get context of the current global 168 * @return current global scope's context. 169 */ 170 public static Context getContext() { 171 final SecurityManager sm = System.getSecurityManager(); 172 if (sm != null) { 173 sm.checkPermission(new RuntimePermission(NASHORN_GET_CONTEXT)); 174 } 175 return getContextTrusted(); 176 } 177 178 /** 179 * Get current context's error writer 180 * 181 * @return error writer of the current context 182 */ 183 public static PrintWriter getCurrentErr() { 184 final ScriptObject global = getGlobalTrusted(); 185 return (global != null)? global.getContext().getErr() : new PrintWriter(System.err); 186 } 187 188 /** 189 * Output text to this Context's error stream 190 * @param str text to write 191 */ 192 public static void err(final String str) { 193 err(str, true); 194 } 195 196 /** 197 * Output text to this Context's error stream, optionally with 198 * a newline afterwards 199 * 200 * @param str text to write 201 * @param crlf write a carriage return/new line after text 202 */ 203 @SuppressWarnings("resource") 204 public static void err(final String str, final boolean crlf) { 205 final PrintWriter err = Context.getCurrentErr(); 206 if (err != null) { 207 if (crlf) { 208 err.println(str); 209 } else { 210 err.print(str); 211 } 212 } 213 } 214 215 /** Current environment. */ 216 private final ScriptEnvironment env; 217 218 /** is this context in strict mode? Cached from env. as this is used heavily. */ 219 final boolean _strict; 220 221 /** class loader to resolve classes from script. */ 222 private final ClassLoader appLoader; 223 224 /** Class loader to load classes from -classpath option, if set. */ 225 private final ClassLoader classPathLoader; 226 227 /** Class loader to load classes compiled from scripts. */ 228 private final ScriptLoader scriptLoader; 229 230 /** Current error manager. */ 231 private final ErrorManager errors; 232 233 /** Unique id for script. Used only when --loader-per-compile=false */ 234 private final AtomicLong uniqueScriptId; 235 236 private static final ClassLoader myLoader = Context.class.getClassLoader(); 237 private static final StructureLoader sharedLoader; 238 239 private static AccessControlContext createNoPermAccCtxt() { 240 return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, new Permissions()) }); 241 } 242 243 private static AccessControlContext createPermAccCtxt(final String permName) { 244 final Permissions perms = new Permissions(); 245 perms.add(new RuntimePermission(permName)); 246 return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, perms) }); 247 } 248 249 private static final AccessControlContext NO_PERMISSIONS_ACC_CTXT = createNoPermAccCtxt(); 250 private static final AccessControlContext CREATE_LOADER_ACC_CTXT = createPermAccCtxt("createClassLoader"); 251 private static final AccessControlContext CREATE_GLOBAL_ACC_CTXT = createPermAccCtxt(NASHORN_CREATE_GLOBAL); 252 253 static { 254 sharedLoader = AccessController.doPrivileged(new PrivilegedAction<StructureLoader>() { 255 @Override 256 public StructureLoader run() { 257 return new StructureLoader(myLoader, null); 258 } 259 }, CREATE_LOADER_ACC_CTXT); 260 } 261 262 /** 263 * ThrowErrorManager that throws ParserException upon error conditions. 264 */ 265 public static class ThrowErrorManager extends ErrorManager { 266 @Override 267 public void error(final String message) { 268 throw new ParserException(message); 269 } 270 271 @Override 272 public void error(final ParserException e) { 273 throw e; 274 } 275 } 276 277 /** 278 * Constructor 279 * 280 * @param options options from command line or Context creator 281 * @param errors error manger 282 * @param appLoader application class loader 283 */ 284 public Context(final Options options, final ErrorManager errors, final ClassLoader appLoader) { 285 this(options, errors, new PrintWriter(System.out, true), new PrintWriter(System.err, true), appLoader); 286 } 287 288 /** 289 * Constructor 290 * 291 * @param options options from command line or Context creator 292 * @param errors error manger 293 * @param out output writer for this Context 294 * @param err error writer for this Context 295 * @param appLoader application class loader 296 */ 297 public Context(final Options options, final ErrorManager errors, final PrintWriter out, final PrintWriter err, final ClassLoader appLoader) { 298 final SecurityManager sm = System.getSecurityManager(); 299 if (sm != null) { 300 sm.checkPermission(new RuntimePermission(NASHORN_CREATE_CONTEXT)); 301 } 302 303 this.env = new ScriptEnvironment(options, out, err); 304 this._strict = env._strict; 305 this.appLoader = appLoader; 306 if (env._loader_per_compile) { 307 this.scriptLoader = null; 308 this.uniqueScriptId = null; 309 } else { 310 this.scriptLoader = createNewLoader(); 311 this.uniqueScriptId = new AtomicLong(); 312 } 313 this.errors = errors; 314 315 // if user passed -classpath option, make a class loader with that and set it as 316 // thread context class loader so that script can access classes from that path. 317 final String classPath = options.getString("classpath"); 318 if (! env._compile_only && classPath != null && !classPath.isEmpty()) { 319 // make sure that caller can create a class loader. 320 if (sm != null) { 321 sm.checkPermission(new RuntimePermission("createClassLoader")); 322 } 323 this.classPathLoader = NashornLoader.createClassLoader(classPath); 324 } else { 325 this.classPathLoader = null; 326 } 327 328 // print version info if asked. 329 if (env._version) { 330 getErr().println("nashorn " + Version.version()); 331 } 332 333 if (env._fullversion) { 334 getErr().println("nashorn full version " + Version.fullVersion()); 335 } 336 } 337 338 /** 339 * Get the error manager for this context 340 * @return error manger 341 */ 342 public ErrorManager getErrorManager() { 343 return errors; 344 } 345 346 /** 347 * Get the script environment for this context 348 * @return script environment 349 */ 350 public ScriptEnvironment getEnv() { 351 return env; 352 } 353 354 /** 355 * Get the output stream for this context 356 * @return output print writer 357 */ 358 public PrintWriter getOut() { 359 return env.getOut(); 360 } 361 362 /** 363 * Get the error stream for this context 364 * @return error print writer 365 */ 366 public PrintWriter getErr() { 367 return env.getErr(); 368 } 369 370 /** 371 * Get the PropertyMap of the current global scope 372 * @return the property map of the current global scope 373 */ 374 public static PropertyMap getGlobalMap() { 375 return Context.getGlobalTrusted().getMap(); 376 } 377 378 /** 379 * Compile a top level script. 380 * 381 * @param source the source 382 * @param scope the scope 383 * 384 * @return top level function for script 385 */ 386 public ScriptFunction compileScript(final Source source, final ScriptObject scope) { 387 return compileScript(source, scope, this.errors); 388 } 389 390 /** 391 * Entry point for {@code eval} 392 * 393 * @param initialScope The scope of this eval call 394 * @param string Evaluated code as a String 395 * @param callThis "this" to be passed to the evaluated code 396 * @param location location of the eval call 397 * @param strict is this {@code eval} call from a strict mode code? 398 * 399 * @return the return value of the {@code eval} 400 */ 401 public Object eval(final ScriptObject initialScope, final String string, final Object callThis, final Object location, final boolean strict) { 402 final String file = (location == UNDEFINED || location == null) ? "<eval>" : location.toString(); 403 final Source source = new Source(file, string); 404 final boolean directEval = location != UNDEFINED; // is this direct 'eval' call or indirectly invoked eval? 405 final ScriptObject global = Context.getGlobalTrusted(); 406 407 ScriptObject scope = initialScope; 408 409 // ECMA section 10.1.1 point 2 says eval code is strict if it begins 410 // with "use strict" directive or eval direct call itself is made 411 // from from strict mode code. We are passed with caller's strict mode. 412 boolean strictFlag = directEval && strict; 413 414 Class<?> clazz = null; 415 try { 416 clazz = compile(source, new ThrowErrorManager(), strictFlag); 417 } catch (final ParserException e) { 418 e.throwAsEcmaException(global); 419 return null; 420 } 421 422 if (!strictFlag) { 423 // We need to get strict mode flag from compiled class. This is 424 // because eval code may start with "use strict" directive. 425 try { 426 strictFlag = clazz.getField(STRICT_MODE.symbolName()).getBoolean(null); 427 } catch (final NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { 428 //ignored 429 strictFlag = false; 430 } 431 } 432 433 // In strict mode, eval does not instantiate variables and functions 434 // in the caller's environment. A new environment is created! 435 if (strictFlag) { 436 // Create a new scope object 437 final ScriptObject strictEvalScope = ((GlobalObject)global).newObject(); 438 439 // bless it as a "scope" 440 strictEvalScope.setIsScope(); 441 442 // set given scope to be it's proto so that eval can still 443 // access caller environment vars in the new environment. 444 strictEvalScope.setProto(scope); 445 scope = strictEvalScope; 446 } 447 448 ScriptFunction func = getRunScriptFunction(clazz, scope); 449 Object evalThis; 450 if (directEval) { 451 evalThis = (callThis instanceof ScriptObject || strictFlag) ? callThis : global; 452 } else { 453 evalThis = global; 454 } 455 456 return ScriptRuntime.apply(func, evalThis); 457 } 458 459 private static Source loadInternal(final String srcStr, final String prefix, final String resourcePath) { 460 if (srcStr.startsWith(prefix)) { 461 final String resource = resourcePath + srcStr.substring(prefix.length()); 462 // NOTE: even sandbox scripts should be able to load scripts in nashorn: scheme 463 // These scripts are always available and are loaded from nashorn.jar's resources. 464 return AccessController.doPrivileged( 465 new PrivilegedAction<Source>() { 466 @Override 467 public Source run() { 468 try { 469 final URL resURL = Context.class.getResource(resource); 470 return (resURL != null)? new Source(srcStr, resURL) : null; 471 } catch (final IOException exp) { 472 return null; 473 } 474 } 475 }); 476 } 477 478 return null; 479 } 480 481 /** 482 * Implementation of {@code load} Nashorn extension. Load a script file from a source 483 * expression 484 * 485 * @param scope the scope 486 * @param from source expression for script 487 * 488 * @return return value for load call (undefined) 489 * 490 * @throws IOException if source cannot be found or loaded 491 */ 492 public Object load(final ScriptObject scope, final Object from) throws IOException { 493 final Object src = (from instanceof ConsString)? from.toString() : from; 494 Source source = null; 495 496 // load accepts a String (which could be a URL or a file name), a File, a URL 497 // or a ScriptObject that has "name" and "source" (string valued) properties. 498 if (src instanceof String) { 499 final String srcStr = (String)src; 500 final File file = new File(srcStr); 501 if (srcStr.indexOf(':') != -1) { 502 if ((source = loadInternal(srcStr, "nashorn:", "resources/")) == null && 503 (source = loadInternal(srcStr, "fx:", "resources/fx/")) == null) { 504 URL url; 505 try { 506 //check for malformed url. if malformed, it may still be a valid file 507 url = new URL(srcStr); 508 } catch (final MalformedURLException e) { 509 url = file.toURI().toURL(); 510 } 511 source = new Source(url.toString(), url); 512 } 513 } else if (file.isFile()) { 514 source = new Source(srcStr, file); 515 } 516 } else if (src instanceof File && ((File)src).isFile()) { 517 final File file = (File)src; 518 source = new Source(file.getName(), file); 519 } else if (src instanceof URL) { 520 final URL url = (URL)src; 521 source = new Source(url.toString(), url); 522 } else if (src instanceof ScriptObject) { 523 final ScriptObject sobj = (ScriptObject)src; 524 if (sobj.has("script") && sobj.has("name")) { 525 final String script = JSType.toString(sobj.get("script")); 526 final String name = JSType.toString(sobj.get("name")); 527 source = new Source(name, script); 528 } 529 } else if (src instanceof Map) { 530 final Map<?,?> map = (Map<?,?>)src; 531 if (map.containsKey("script") && map.containsKey("name")) { 532 final String script = JSType.toString(map.get("script")); 533 final String name = JSType.toString(map.get("name")); 534 source = new Source(name, script); 535 } 536 } 537 538 if (source != null) { 539 return evaluateSource(source, scope, scope); 540 } 541 542 throw typeError("cant.load.script", ScriptRuntime.safeToString(from)); 543 } 544 545 /** 546 * Implementation of {@code loadWithNewGlobal} Nashorn extension. Load a script file from a source 547 * expression, after creating a new global scope. 548 * 549 * @param from source expression for script 550 * @param args (optional) arguments to be passed to the loaded script 551 * 552 * @return return value for load call (undefined) 553 * 554 * @throws IOException if source cannot be found or loaded 555 */ 556 public Object loadWithNewGlobal(final Object from, final Object...args) throws IOException { 557 final ScriptObject oldGlobal = getGlobalTrusted(); 558 final ScriptObject newGlobal = AccessController.doPrivileged(new PrivilegedAction<ScriptObject>() { 559 @Override 560 public ScriptObject run() { 561 try { 562 return newGlobal(); 563 } catch (final RuntimeException e) { 564 if (Context.DEBUG) { 565 e.printStackTrace(); 566 } 567 throw e; 568 } 569 } 570 }, CREATE_GLOBAL_ACC_CTXT); 571 // initialize newly created Global instance 572 initGlobal(newGlobal); 573 setGlobalTrusted(newGlobal); 574 575 final Object[] wrapped = args == null? ScriptRuntime.EMPTY_ARRAY : ScriptObjectMirror.wrapArray(args, oldGlobal); 576 newGlobal.put("arguments", ((GlobalObject)newGlobal).wrapAsObject(wrapped)); 577 578 try { 579 // wrap objects from newGlobal's world as mirrors - but if result 580 // is from oldGlobal's world, unwrap it! 581 return ScriptObjectMirror.unwrap(ScriptObjectMirror.wrap(load(newGlobal, from), newGlobal), oldGlobal); 582 } finally { 583 setGlobalTrusted(oldGlobal); 584 } 585 } 586 587 /** 588 * Load or get a structure class. Structure class names are based on the number of parameter fields 589 * and {@link AccessorProperty} fields in them. Structure classes are used to represent ScriptObjects 590 * 591 * @see ObjectClassGenerator 592 * @see AccessorProperty 593 * @see ScriptObject 594 * 595 * @param fullName full name of class, e.g. jdk.nashorn.internal.objects.JO2P1 contains 2 fields and 1 parameter. 596 * 597 * @return the {@code Class<?>} for this structure 598 * 599 * @throws ClassNotFoundException if structure class cannot be resolved 600 */ 601 public static Class<?> forStructureClass(final String fullName) throws ClassNotFoundException { 602 if (System.getSecurityManager() != null && !NashornLoader.isStructureClass(fullName)) { 603 throw new ClassNotFoundException(fullName); 604 } 605 return Class.forName(fullName, true, sharedLoader); 606 } 607 608 /** 609 * Checks that the given package can be accessed from no permissions context. 610 * 611 * @param fullName fully qualified package name 612 * @throw SecurityException if not accessible 613 */ 614 public static void checkPackageAccess(final String fullName) { 615 final int index = fullName.lastIndexOf('.'); 616 if (index != -1) { 617 final SecurityManager sm = System.getSecurityManager(); 618 if (sm != null) { 619 AccessController.doPrivileged(new PrivilegedAction<Void>() { 620 @Override 621 public Void run() { 622 sm.checkPackageAccess(fullName.substring(0, index)); 623 return null; 624 } 625 }, NO_PERMISSIONS_ACC_CTXT); 626 } 627 } 628 } 629 630 /** 631 * Checks that the given package can be accessed from no permissions context. 632 * 633 * @param fullName fully qualified package name 634 * @return true if package is accessible, false otherwise 635 */ 636 public static boolean isAccessiblePackage(final String fullName) { 637 try { 638 checkPackageAccess(fullName); 639 return true; 640 } catch (final SecurityException se) { 641 return false; 642 } 643 } 644 645 /** 646 * Checks that the given Class is public and it can be accessed from no permissions context. 647 * 648 * @param clazz Class object to check 649 * @return true if Class is accessible, false otherwise 650 */ 651 public static boolean isAccessibleClass(final Class<?> clazz) { 652 return Modifier.isPublic(clazz.getModifiers()) && Context.isAccessiblePackage(clazz.getName()); 653 } 654 655 /** 656 * Lookup a Java class. This is used for JSR-223 stuff linking in from 657 * {@code jdk.nashorn.internal.objects.NativeJava} and {@code jdk.nashorn.internal.runtime.NativeJavaPackage} 658 * 659 * @param fullName full name of class to load 660 * 661 * @return the {@code Class<?>} for the name 662 * 663 * @throws ClassNotFoundException if class cannot be resolved 664 */ 665 public Class<?> findClass(final String fullName) throws ClassNotFoundException { 666 // check package access as soon as possible! 667 checkPackageAccess(fullName); 668 669 // try the script -classpath loader, if that is set 670 if (classPathLoader != null) { 671 try { 672 return Class.forName(fullName, true, classPathLoader); 673 } catch (final ClassNotFoundException ignored) { 674 // ignore, continue search 675 } 676 } 677 678 // Try finding using the "app" loader. 679 return Class.forName(fullName, true, appLoader); 680 } 681 682 /** 683 * Hook to print stack trace for a {@link Throwable} that occurred during 684 * execution 685 * 686 * @param t throwable for which to dump stack 687 */ 688 public static void printStackTrace(final Throwable t) { 689 if (Context.DEBUG) { 690 t.printStackTrace(Context.getCurrentErr()); 691 } 692 } 693 694 /** 695 * Verify generated bytecode before emission. This is called back from the 696 * {@link ObjectClassGenerator} or the {@link Compiler}. If the "--verify-code" parameter 697 * hasn't been given, this is a nop 698 * 699 * Note that verification may load classes -- we don't want to do that unless 700 * user specified verify option. We check it here even though caller 701 * may have already checked that flag 702 * 703 * @param bytecode bytecode to verify 704 */ 705 public void verify(final byte[] bytecode) { 706 if (env._verify_code) { 707 // No verification when security manager is around as verifier 708 // may load further classes - which should be avoided. 709 if (System.getSecurityManager() == null) { 710 CheckClassAdapter.verify(new ClassReader(bytecode), sharedLoader, false, new PrintWriter(System.err, true)); 711 } 712 } 713 } 714 715 /** 716 * Create and initialize a new global scope object. 717 * 718 * @return the initialized global scope object. 719 */ 720 public ScriptObject createGlobal() { 721 return initGlobal(newGlobal()); 722 } 723 724 /** 725 * Create a new uninitialized global scope object 726 * @return the global script object 727 */ 728 public ScriptObject newGlobal() { 729 return new Global(this); 730 } 731 732 /** 733 * Initialize given global scope object. 734 * 735 * @param global the global 736 * @return the initialized global scope object. 737 */ 738 public ScriptObject initGlobal(final ScriptObject global) { 739 if (! (global instanceof GlobalObject)) { 740 throw new IllegalArgumentException("not a global object!"); 741 } 742 743 // Need only minimal global object, if we are just compiling. 744 if (!env._compile_only) { 745 final ScriptObject oldGlobal = Context.getGlobalTrusted(); 746 try { 747 Context.setGlobalTrusted(global); 748 // initialize global scope with builtin global objects 749 ((GlobalObject)global).initBuiltinObjects(); 750 } finally { 751 Context.setGlobalTrusted(oldGlobal); 752 } 753 } 754 755 return global; 756 } 757 758 /** 759 * Trusted variants - package-private 760 */ 761 762 /** 763 * Return the current global scope 764 * @return current global scope 765 */ 766 static ScriptObject getGlobalTrusted() { 767 return currentGlobal.get(); 768 } 769 770 /** 771 * Set the current global scope 772 */ 773 static void setGlobalTrusted(ScriptObject global) { 774 currentGlobal.set(global); 775 } 776 777 /** 778 * Return the current global's context 779 * @return current global's context 780 */ 781 static Context getContextTrusted() { 782 return Context.getGlobalTrusted().getContext(); 783 } 784 785 /** 786 * Try to infer Context instance from the Class. If we cannot, 787 * then get it from the thread local variable. 788 * 789 * @param clazz the class 790 * @return context 791 */ 792 static Context fromClass(final Class<?> clazz) { 793 final ClassLoader loader = clazz.getClassLoader(); 794 795 Context context = null; 796 if (loader instanceof NashornLoader) { 797 context = ((NashornLoader)loader).getContext(); 798 } 799 800 return (context != null) ? context : Context.getContextTrusted(); 801 } 802 803 private Object evaluateSource(final Source source, final ScriptObject scope, final ScriptObject thiz) { 804 ScriptFunction script = null; 805 806 try { 807 script = compileScript(source, scope, new Context.ThrowErrorManager()); 808 } catch (final ParserException e) { 809 e.throwAsEcmaException(); 810 } 811 812 return ScriptRuntime.apply(script, thiz); 813 } 814 815 private static ScriptFunction getRunScriptFunction(final Class<?> script, final ScriptObject scope) { 816 if (script == null) { 817 return null; 818 } 819 820 // Get run method - the entry point to the script 821 final MethodHandle runMethodHandle = 822 MH.findStatic( 823 MethodHandles.lookup(), 824 script, 825 RUN_SCRIPT.symbolName(), 826 MH.type( 827 Object.class, 828 ScriptFunction.class, 829 Object.class)); 830 831 boolean strict; 832 833 try { 834 strict = script.getField(STRICT_MODE.symbolName()).getBoolean(null); 835 } catch (final NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { 836 strict = false; 837 } 838 839 // Package as a JavaScript function and pass function back to shell. 840 return ((GlobalObject)Context.getGlobalTrusted()).newScriptFunction(RUN_SCRIPT.symbolName(), runMethodHandle, scope, strict); 841 } 842 843 private ScriptFunction compileScript(final Source source, final ScriptObject scope, final ErrorManager errMan) { 844 return getRunScriptFunction(compile(source, errMan, this._strict), scope); 845 } 846 847 private synchronized Class<?> compile(final Source source, final ErrorManager errMan, final boolean strict) { 848 // start with no errors, no warnings. 849 errMan.reset(); 850 851 GlobalObject global = null; 852 Class<?> script; 853 854 if (env._class_cache_size > 0) { 855 global = (GlobalObject)Context.getGlobalTrusted(); 856 script = global.findCachedClass(source); 857 if (script != null) { 858 Compiler.LOG.fine("Code cache hit for ", source, " avoiding recompile."); 859 return script; 860 } 861 } 862 863 final FunctionNode functionNode = new Parser(env, source, errMan, strict).parse(); 864 if (errors.hasErrors()) { 865 return null; 866 } 867 868 if (env._print_ast) { 869 getErr().println(new ASTWriter(functionNode)); 870 } 871 872 if (env._print_parse) { 873 getErr().println(new PrintVisitor(functionNode)); 874 } 875 876 if (env._parse_only) { 877 return null; 878 } 879 880 final URL url = source.getURL(); 881 final ScriptLoader loader = env._loader_per_compile ? createNewLoader() : scriptLoader; 882 final CodeSource cs = url == null ? null : new CodeSource(url, (CodeSigner[])null); 883 final CodeInstaller<ScriptEnvironment> installer = new ContextCodeInstaller(this, loader, cs); 884 885 final Compiler compiler = new Compiler(installer, strict); 886 887 final FunctionNode newFunctionNode = compiler.compile(functionNode); 888 script = compiler.install(newFunctionNode); 889 890 if (global != null) { 891 global.cacheClass(source, script); 892 } 893 894 return script; 895 } 896 897 private ScriptLoader createNewLoader() { 898 return AccessController.doPrivileged( 899 new PrivilegedAction<ScriptLoader>() { 900 @Override 901 public ScriptLoader run() { 902 return new ScriptLoader(sharedLoader, Context.this); 903 } 904 }, CREATE_LOADER_ACC_CTXT); 905 } 906 907 private long getUniqueScriptId() { 908 return uniqueScriptId.getAndIncrement(); 909 } 910 }