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