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

Print this page




  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package jdk.nashorn.internal.runtime;
  27 
  28 import static jdk.nashorn.internal.codegen.CompilerConstants.RUN_SCRIPT;
  29 import static jdk.nashorn.internal.codegen.CompilerConstants.STRICT_MODE;
  30 import static jdk.nashorn.internal.lookup.Lookup.MH;
  31 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
  32 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
  33 
  34 import java.io.File;
  35 import java.io.IOException;
  36 import java.io.PrintWriter;
  37 import java.lang.invoke.MethodHandle;
  38 import java.lang.invoke.MethodHandles;


  39 import java.lang.reflect.Modifier;
  40 import java.net.MalformedURLException;
  41 import java.net.URL;
  42 import java.security.AccessControlContext;
  43 import java.security.AccessController;
  44 import java.security.CodeSigner;
  45 import java.security.CodeSource;
  46 import java.security.Permissions;
  47 import java.security.PrivilegedAction;
  48 import java.security.ProtectionDomain;

  49 import java.util.Map;
  50 import java.util.concurrent.atomic.AtomicLong;
  51 import jdk.internal.org.objectweb.asm.ClassReader;
  52 import jdk.internal.org.objectweb.asm.util.CheckClassAdapter;
  53 import jdk.nashorn.api.scripting.ScriptObjectMirror;
  54 import jdk.nashorn.internal.codegen.Compiler;
  55 import jdk.nashorn.internal.codegen.ObjectClassGenerator;
  56 import jdk.nashorn.internal.ir.FunctionNode;
  57 import jdk.nashorn.internal.ir.debug.ASTWriter;
  58 import jdk.nashorn.internal.ir.debug.PrintVisitor;
  59 import jdk.nashorn.internal.objects.Global;
  60 import jdk.nashorn.internal.parser.Parser;
  61 import jdk.nashorn.internal.runtime.options.Options;
  62 
  63 /**
  64  * This class manages the global state of execution. Context is immutable.
  65  */
  66 public final class Context {
  67     // nashorn specific security runtime access permission names
  68     /**


 138         public void verify(final byte[] code) {
 139             context.verify(code);
 140         }
 141 
 142         @Override
 143         public long getUniqueScriptId() {
 144             return context.getUniqueScriptId();
 145         }
 146 
 147         @Override
 148         public long getUniqueEvalId() {
 149             return context.getUniqueEvalId();
 150         }
 151     }
 152 
 153     /** Is Context global debug mode enabled ? */
 154     public static final boolean DEBUG = Options.getBooleanProperty("nashorn.debug");
 155 
 156     private static final ThreadLocal<ScriptObject> currentGlobal = new ThreadLocal<>();
 157 



 158     /**
 159      * Get the current global scope
 160      * @return the current global scope
 161      */
 162     public static ScriptObject getGlobal() {
 163         // This class in a package.access protected package.
 164         // Trusted code only can call this method.
 165         return getGlobalTrusted();
 166     }
 167 
 168     /**
 169      * Set the current global scope
 170      * @param global the global scope
 171      */
 172     public static void setGlobal(final ScriptObject global) {
 173         if (global != null && !(global instanceof Global)) {
 174             throw new IllegalArgumentException("global is not an instance of Global!");
 175         }
 176 
 177         setGlobalTrusted(global);


 331         } else {
 332             this.scriptLoader = createNewLoader();
 333             this.uniqueScriptId = new AtomicLong();
 334         }
 335         this.errors    = errors;
 336         this.uniqueEvalId = new AtomicLong();
 337 
 338         // if user passed -classpath option, make a class loader with that and set it as
 339         // thread context class loader so that script can access classes from that path.
 340         final String classPath = options.getString("classpath");
 341         if (! env._compile_only && classPath != null && !classPath.isEmpty()) {
 342             // make sure that caller can create a class loader.
 343             if (sm != null) {
 344                 sm.checkPermission(new RuntimePermission("createClassLoader"));
 345             }
 346             this.classPathLoader = NashornLoader.createClassLoader(classPath);
 347         } else {
 348             this.classPathLoader = null;
 349         }
 350 





 351         // print version info if asked.
 352         if (env._version) {
 353             getErr().println("nashorn " + Version.version());
 354         }
 355 
 356         if (env._fullversion) {
 357             getErr().println("nashorn full version " + Version.fullVersion());
 358         }
 359     }
 360 
 361     /**
 362      * Get the error manager for this context
 363      * @return error manger
 364      */
 365     public ErrorManager getErrorManager() {
 366         return errors;
 367     }
 368 
 369     /**
 370      * Get the script environment for this context


 642     public static void checkPackageAccess(final Class<?> clazz) {
 643         final SecurityManager sm = System.getSecurityManager();
 644         if (sm != null) {
 645             Class<?> bottomClazz = clazz;
 646             while (bottomClazz.isArray()) {
 647                 bottomClazz = bottomClazz.getComponentType();
 648             }
 649             checkPackageAccess(sm, bottomClazz.getName());
 650         }
 651     }
 652 
 653     /**
 654      * Checks that the given package name can be accessed from no permissions context.
 655      *
 656      * @param pkgName package name
 657      * @throw SecurityException if not accessible
 658      */
 659     public static void checkPackageAccess(final String pkgName) {
 660         final SecurityManager sm = System.getSecurityManager();
 661         if (sm != null) {
 662             checkPackageAccess(sm, pkgName.endsWith(".")? pkgName : pkgName + ".");
 663         }
 664     }
 665 
 666     /**
 667      * Checks that the given package can be accessed from no permissions context.
 668      *
 669      * @param sm current security manager instance
 670      * @param fullName fully qualified package name
 671      * @throw SecurityException if not accessible
 672      */
 673     private static void checkPackageAccess(final SecurityManager sm, final String fullName) {
 674         sm.getClass(); // null check
 675         final int index = fullName.lastIndexOf('.');
 676         if (index != -1) {
 677             final String pkgName = fullName.substring(0, index);
 678             AccessController.doPrivileged(new PrivilegedAction<Void>() {
 679                 @Override
 680                 public Void run() {
 681                     sm.checkPackageAccess(pkgName);
 682                     return null;


 908         boolean strict;
 909 
 910         try {
 911             strict = script.getField(STRICT_MODE.symbolName()).getBoolean(null);
 912         } catch (final NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
 913             strict = false;
 914         }
 915 
 916         // Package as a JavaScript function and pass function back to shell.
 917         return ((GlobalObject)Context.getGlobalTrusted()).newScriptFunction(RUN_SCRIPT.symbolName(), runMethodHandle, scope, strict);
 918     }
 919 
 920     private ScriptFunction compileScript(final Source source, final ScriptObject scope, final ErrorManager errMan) {
 921         return getRunScriptFunction(compile(source, errMan, this._strict), scope);
 922     }
 923 
 924     private synchronized Class<?> compile(final Source source, final ErrorManager errMan, final boolean strict) {
 925         // start with no errors, no warnings.
 926         errMan.reset();
 927 
 928         GlobalObject global = null;
 929         Class<?> script;
 930 
 931         if (env._class_cache_size > 0) {
 932             global = (GlobalObject)Context.getGlobalTrusted();
 933             script = global.findCachedClass(source);
 934             if (script != null) {
 935                 Compiler.LOG.fine("Code cache hit for ", source, " avoiding recompile.");
 936                 return script;
 937             }
 938         }
 939 
 940         final FunctionNode functionNode = new Parser(env, source, errMan, strict).parse();
 941         if (errors.hasErrors()) {
 942             return null;
 943         }
 944 
 945         if (env._print_ast) {
 946             getErr().println(new ASTWriter(functionNode));
 947         }
 948 
 949         if (env._print_parse) {
 950             getErr().println(new PrintVisitor(functionNode));
 951         }
 952 
 953         if (env._parse_only) {
 954             return null;
 955         }
 956 
 957         final URL          url    = source.getURL();
 958         final ScriptLoader loader = env._loader_per_compile ? createNewLoader() : scriptLoader;
 959         final CodeSource   cs     = new CodeSource(url, (CodeSigner[])null);
 960         final CodeInstaller<ScriptEnvironment> installer = new ContextCodeInstaller(this, loader, cs);
 961 
 962         final Compiler compiler = new Compiler(installer, strict);
 963 
 964         final FunctionNode newFunctionNode = compiler.compile(functionNode);
 965         script = compiler.install(newFunctionNode);
 966 
 967         if (global != null) {
 968             global.cacheClass(source, script);
 969         }
 970 
 971         return script;
 972     }
 973 
 974     private ScriptLoader createNewLoader() {
 975         return AccessController.doPrivileged(
 976              new PrivilegedAction<ScriptLoader>() {
 977                 @Override
 978                 public ScriptLoader run() {
 979                     return new ScriptLoader(appLoader, Context.this);
 980                 }
 981              }, CREATE_LOADER_ACC_CTXT);
 982     }
 983 
 984     private long getUniqueEvalId() {
 985         return uniqueEvalId.getAndIncrement();
 986     }
 987 
 988     private long getUniqueScriptId() {
 989         return uniqueScriptId.getAndIncrement();
 990     }
























































 991 }


  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.ref.ReferenceQueue;
  40 import java.lang.ref.SoftReference;
  41 import java.lang.reflect.Modifier;
  42 import java.net.MalformedURLException;
  43 import java.net.URL;
  44 import java.security.AccessControlContext;
  45 import java.security.AccessController;
  46 import java.security.CodeSigner;
  47 import java.security.CodeSource;
  48 import java.security.Permissions;
  49 import java.security.PrivilegedAction;
  50 import java.security.ProtectionDomain;
  51 import java.util.LinkedHashMap;
  52 import java.util.Map;
  53 import java.util.concurrent.atomic.AtomicLong;
  54 import jdk.internal.org.objectweb.asm.ClassReader;
  55 import jdk.internal.org.objectweb.asm.util.CheckClassAdapter;
  56 import jdk.nashorn.api.scripting.ScriptObjectMirror;
  57 import jdk.nashorn.internal.codegen.Compiler;
  58 import jdk.nashorn.internal.codegen.ObjectClassGenerator;
  59 import jdk.nashorn.internal.ir.FunctionNode;
  60 import jdk.nashorn.internal.ir.debug.ASTWriter;
  61 import jdk.nashorn.internal.ir.debug.PrintVisitor;
  62 import jdk.nashorn.internal.objects.Global;
  63 import jdk.nashorn.internal.parser.Parser;
  64 import jdk.nashorn.internal.runtime.options.Options;
  65 
  66 /**
  67  * This class manages the global state of execution. Context is immutable.
  68  */
  69 public final class Context {
  70     // nashorn specific security runtime access permission names
  71     /**


 141         public void verify(final byte[] code) {
 142             context.verify(code);
 143         }
 144 
 145         @Override
 146         public long getUniqueScriptId() {
 147             return context.getUniqueScriptId();
 148         }
 149 
 150         @Override
 151         public long getUniqueEvalId() {
 152             return context.getUniqueEvalId();
 153         }
 154     }
 155 
 156     /** Is Context global debug mode enabled ? */
 157     public static final boolean DEBUG = Options.getBooleanProperty("nashorn.debug");
 158 
 159     private static final ThreadLocal<ScriptObject> currentGlobal = new ThreadLocal<>();
 160 
 161     // class cache
 162     private ClassCache classCache;
 163 
 164     /**
 165      * Get the current global scope
 166      * @return the current global scope
 167      */
 168     public static ScriptObject getGlobal() {
 169         // This class in a package.access protected package.
 170         // Trusted code only can call this method.
 171         return getGlobalTrusted();
 172     }
 173 
 174     /**
 175      * Set the current global scope
 176      * @param global the global scope
 177      */
 178     public static void setGlobal(final ScriptObject global) {
 179         if (global != null && !(global instanceof Global)) {
 180             throw new IllegalArgumentException("global is not an instance of Global!");
 181         }
 182 
 183         setGlobalTrusted(global);


 337         } else {
 338             this.scriptLoader = createNewLoader();
 339             this.uniqueScriptId = new AtomicLong();
 340         }
 341         this.errors    = errors;
 342         this.uniqueEvalId = new AtomicLong();
 343 
 344         // if user passed -classpath option, make a class loader with that and set it as
 345         // thread context class loader so that script can access classes from that path.
 346         final String classPath = options.getString("classpath");
 347         if (! env._compile_only && classPath != null && !classPath.isEmpty()) {
 348             // make sure that caller can create a class loader.
 349             if (sm != null) {
 350                 sm.checkPermission(new RuntimePermission("createClassLoader"));
 351             }
 352             this.classPathLoader = NashornLoader.createClassLoader(classPath);
 353         } else {
 354             this.classPathLoader = null;
 355         }
 356 
 357         final int cacheSize = env._class_cache_size;
 358         if (cacheSize > 0) {
 359             classCache = new ClassCache(cacheSize);
 360         }
 361 
 362         // print version info if asked.
 363         if (env._version) {
 364             getErr().println("nashorn " + Version.version());
 365         }
 366 
 367         if (env._fullversion) {
 368             getErr().println("nashorn full version " + Version.fullVersion());
 369         }
 370     }
 371 
 372     /**
 373      * Get the error manager for this context
 374      * @return error manger
 375      */
 376     public ErrorManager getErrorManager() {
 377         return errors;
 378     }
 379 
 380     /**
 381      * Get the script environment for this context


 653     public static void checkPackageAccess(final Class<?> clazz) {
 654         final SecurityManager sm = System.getSecurityManager();
 655         if (sm != null) {
 656             Class<?> bottomClazz = clazz;
 657             while (bottomClazz.isArray()) {
 658                 bottomClazz = bottomClazz.getComponentType();
 659             }
 660             checkPackageAccess(sm, bottomClazz.getName());
 661         }
 662     }
 663 
 664     /**
 665      * Checks that the given package name can be accessed from no permissions context.
 666      *
 667      * @param pkgName package name
 668      * @throw SecurityException if not accessible
 669      */
 670     public static void checkPackageAccess(final String pkgName) {
 671         final SecurityManager sm = System.getSecurityManager();
 672         if (sm != null) {
 673             checkPackageAccess(sm, pkgName.endsWith(".") ? pkgName : pkgName + ".");
 674         }
 675     }
 676 
 677     /**
 678      * Checks that the given package can be accessed from no permissions context.
 679      *
 680      * @param sm current security manager instance
 681      * @param fullName fully qualified package name
 682      * @throw SecurityException if not accessible
 683      */
 684     private static void checkPackageAccess(final SecurityManager sm, final String fullName) {
 685         sm.getClass(); // null check
 686         final int index = fullName.lastIndexOf('.');
 687         if (index != -1) {
 688             final String pkgName = fullName.substring(0, index);
 689             AccessController.doPrivileged(new PrivilegedAction<Void>() {
 690                 @Override
 691                 public Void run() {
 692                     sm.checkPackageAccess(pkgName);
 693                     return null;


 919         boolean strict;
 920 
 921         try {
 922             strict = script.getField(STRICT_MODE.symbolName()).getBoolean(null);
 923         } catch (final NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
 924             strict = false;
 925         }
 926 
 927         // Package as a JavaScript function and pass function back to shell.
 928         return ((GlobalObject)Context.getGlobalTrusted()).newScriptFunction(RUN_SCRIPT.symbolName(), runMethodHandle, scope, strict);
 929     }
 930 
 931     private ScriptFunction compileScript(final Source source, final ScriptObject scope, final ErrorManager errMan) {
 932         return getRunScriptFunction(compile(source, errMan, this._strict), scope);
 933     }
 934 
 935     private synchronized Class<?> compile(final Source source, final ErrorManager errMan, final boolean strict) {
 936         // start with no errors, no warnings.
 937         errMan.reset();
 938 
 939         Class<?> script = findCachedClass(source);





 940         if (script != null) {
 941             Compiler.LOG.fine("Code cache hit for ", source, " avoiding recompile.");
 942             return script;
 943         }

 944 
 945         final FunctionNode functionNode = new Parser(env, source, errMan, strict).parse();
 946         if (errors.hasErrors()) {
 947             return null;
 948         }
 949 
 950         if (env._print_ast) {
 951             getErr().println(new ASTWriter(functionNode));
 952         }
 953 
 954         if (env._print_parse) {
 955             getErr().println(new PrintVisitor(functionNode));
 956         }
 957 
 958         if (env._parse_only) {
 959             return null;
 960         }
 961 
 962         final URL          url    = source.getURL();
 963         final ScriptLoader loader = env._loader_per_compile ? createNewLoader() : scriptLoader;
 964         final CodeSource   cs     = new CodeSource(url, (CodeSigner[])null);
 965         final CodeInstaller<ScriptEnvironment> installer = new ContextCodeInstaller(this, loader, cs);
 966 
 967         final Compiler compiler = new Compiler(installer, strict);
 968 
 969         final FunctionNode newFunctionNode = compiler.compile(functionNode);
 970         script = compiler.install(newFunctionNode);
 971         cacheClass(source, script);



 972 
 973         return script;
 974     }
 975 
 976     private ScriptLoader createNewLoader() {
 977         return AccessController.doPrivileged(
 978              new PrivilegedAction<ScriptLoader>() {
 979                 @Override
 980                 public ScriptLoader run() {
 981                     return new ScriptLoader(appLoader, Context.this);
 982                 }
 983              }, CREATE_LOADER_ACC_CTXT);
 984     }
 985 
 986     private long getUniqueEvalId() {
 987         return uniqueEvalId.getAndIncrement();
 988     }
 989 
 990     private long getUniqueScriptId() {
 991         return uniqueScriptId.getAndIncrement();
 992     }
 993 
 994     /**
 995      * Cache for compiled script classes.
 996      */
 997     @SuppressWarnings("serial")
 998     private static class ClassCache extends LinkedHashMap<Source, ClassReference> {
 999         private final int size;
1000         private final ReferenceQueue<Class<?>> queue;
1001 
1002         ClassCache(int size) {
1003             super(size, 0.75f, true);
1004             this.size = size;
1005             this.queue = new ReferenceQueue<>();
1006         }
1007 
1008         void cache(final Source source, final Class<?> clazz) {
1009             put(source, new ClassReference(clazz, queue, source));
1010         }
1011 
1012         @Override
1013         protected boolean removeEldestEntry(final Map.Entry<Source, ClassReference> eldest) {
1014             return size() > size;
1015         }
1016 
1017         @Override
1018         public ClassReference get(Object key) {
1019             for (ClassReference ref; (ref = (ClassReference)queue.poll()) != null; ) {
1020                 remove(ref.source);
1021             }
1022             return super.get(key);
1023         }
1024 
1025     }
1026 
1027     private static class ClassReference extends SoftReference<Class<?>> {
1028         private final Source source;
1029 
1030         ClassReference(final Class<?> clazz, final ReferenceQueue<Class<?>> queue, final Source source) {
1031             super(clazz, queue);
1032             this.source = source;
1033         }
1034     }
1035 
1036     // Class cache management
1037     private Class<?> findCachedClass(final Source source) {
1038         ClassReference ref = classCache == null ? null : classCache.get(source);
1039         return ref != null ? ref.get() : null;
1040     }
1041 
1042     private void cacheClass(final Source source, final Class<?> clazz) {
1043         if (classCache != null) {
1044             classCache.cache(source, clazz);
1045         }
1046     }
1047 
1048 
1049 }