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