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 ---