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