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