src/jdk/nashorn/internal/runtime/Context.java

Tue, 07 May 2013 14:43:17 +0200

author
lagergren
date
Tue, 07 May 2013 14:43:17 +0200
changeset 253
fb1d7ea3e1b6
parent 248
829b06307fb2
child 317
08a8fda6c0bf
permissions
-rw-r--r--

8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
Reviewed-by: jlaskey, attila

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

mercurial