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