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