nashorn/src/jdk/nashorn/internal/runtime/Context.java
changeset 23767 7c0614b75e23
parent 23375 a1110f2cbe75
child 24206 40c6d45af73f
equal deleted inserted replaced
23766:a3ef17770bab 23767:7c0614b75e23
    23  * questions.
    23  * questions.
    24  */
    24  */
    25 
    25 
    26 package jdk.nashorn.internal.runtime;
    26 package jdk.nashorn.internal.runtime;
    27 
    27 
       
    28 import static jdk.nashorn.internal.codegen.CompilerConstants.CONSTANTS;
    28 import static jdk.nashorn.internal.codegen.CompilerConstants.RUN_SCRIPT;
    29 import static jdk.nashorn.internal.codegen.CompilerConstants.RUN_SCRIPT;
       
    30 import static jdk.nashorn.internal.codegen.CompilerConstants.SOURCE;
    29 import static jdk.nashorn.internal.codegen.CompilerConstants.STRICT_MODE;
    31 import static jdk.nashorn.internal.codegen.CompilerConstants.STRICT_MODE;
    30 import static jdk.nashorn.internal.lookup.Lookup.MH;
    32 import static jdk.nashorn.internal.lookup.Lookup.MH;
    31 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
    33 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
    32 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
    34 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
    33 
    35 
    36 import java.io.PrintWriter;
    38 import java.io.PrintWriter;
    37 import java.lang.invoke.MethodHandle;
    39 import java.lang.invoke.MethodHandle;
    38 import java.lang.invoke.MethodHandles;
    40 import java.lang.invoke.MethodHandles;
    39 import java.lang.ref.ReferenceQueue;
    41 import java.lang.ref.ReferenceQueue;
    40 import java.lang.ref.SoftReference;
    42 import java.lang.ref.SoftReference;
       
    43 import java.lang.reflect.Field;
    41 import java.lang.reflect.Modifier;
    44 import java.lang.reflect.Modifier;
    42 import java.net.MalformedURLException;
    45 import java.net.MalformedURLException;
    43 import java.net.URL;
    46 import java.net.URL;
    44 import java.security.AccessControlContext;
    47 import java.security.AccessControlContext;
    45 import java.security.AccessController;
    48 import java.security.AccessController;
    46 import java.security.CodeSigner;
    49 import java.security.CodeSigner;
    47 import java.security.CodeSource;
    50 import java.security.CodeSource;
    48 import java.security.Permissions;
    51 import java.security.Permissions;
    49 import java.security.PrivilegedAction;
    52 import java.security.PrivilegedAction;
       
    53 import java.security.PrivilegedActionException;
       
    54 import java.security.PrivilegedExceptionAction;
    50 import java.security.ProtectionDomain;
    55 import java.security.ProtectionDomain;
       
    56 import java.util.HashMap;
    51 import java.util.LinkedHashMap;
    57 import java.util.LinkedHashMap;
    52 import java.util.Map;
    58 import java.util.Map;
    53 import java.util.concurrent.atomic.AtomicLong;
    59 import java.util.concurrent.atomic.AtomicLong;
    54 import jdk.internal.org.objectweb.asm.ClassReader;
    60 import jdk.internal.org.objectweb.asm.ClassReader;
    55 import jdk.internal.org.objectweb.asm.util.CheckClassAdapter;
    61 import jdk.internal.org.objectweb.asm.util.CheckClassAdapter;
   131         public ScriptEnvironment getOwner() {
   137         public ScriptEnvironment getOwner() {
   132             return context.env;
   138             return context.env;
   133         }
   139         }
   134 
   140 
   135         @Override
   141         @Override
   136         public Class<?> install(final String className, final byte[] bytecode) {
   142         public Class<?> install(final String className, final byte[] bytecode, final Source source, final Object[] constants) {
   137             return loader.installClass(className, bytecode, codeSource);
   143             Compiler.LOG.fine("Installing class ", className);
       
   144 
       
   145             final String   binaryName = Compiler.binaryName(className);
       
   146             final Class<?> clazz      = loader.installClass(binaryName, bytecode, codeSource);
       
   147 
       
   148             try {
       
   149                 // Need doPrivileged because these fields are private
       
   150                 AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
       
   151                     @Override
       
   152                     public Void run() throws Exception {
       
   153                         //use reflection to write source and constants table to installed classes
       
   154                         final Field sourceField    = clazz.getDeclaredField(SOURCE.symbolName());
       
   155                         final Field constantsField = clazz.getDeclaredField(CONSTANTS.symbolName());
       
   156                         sourceField.setAccessible(true);
       
   157                         constantsField.setAccessible(true);
       
   158                         sourceField.set(null, source);
       
   159                         constantsField.set(null, constants);
       
   160                         return null;
       
   161                     }
       
   162                 });
       
   163             } catch (final PrivilegedActionException e) {
       
   164                 throw new RuntimeException(e);
       
   165             }
       
   166 
       
   167             return clazz;
   138         }
   168         }
   139 
   169 
   140         @Override
   170         @Override
   141         public void verify(final byte[] code) {
   171         public void verify(final byte[] code) {
   142             context.verify(code);
   172             context.verify(code);
   149 
   179 
   150         @Override
   180         @Override
   151         public long getUniqueEvalId() {
   181         public long getUniqueEvalId() {
   152             return context.getUniqueEvalId();
   182             return context.getUniqueEvalId();
   153         }
   183         }
       
   184 
       
   185         @Override
       
   186         public void storeCompiledScript(final Source source, final String mainClassName,
       
   187                                         final Map<String, byte[]> classBytes, final Object[] constants) {
       
   188             if (context.codeStore != null) {
       
   189                 try {
       
   190                     context.codeStore.putScript(source, mainClassName, classBytes, constants);
       
   191                 } catch (final IOException e) {
       
   192                     throw new RuntimeException(e);
       
   193                 }
       
   194             }
       
   195         }
   154     }
   196     }
   155 
   197 
   156     /** Is Context global debug mode enabled ? */
   198     /** Is Context global debug mode enabled ? */
   157     public static final boolean DEBUG = Options.getBooleanProperty("nashorn.debug");
   199     public static final boolean DEBUG = Options.getBooleanProperty("nashorn.debug");
   158 
   200 
   159     private static final ThreadLocal<Global> currentGlobal = new ThreadLocal<>();
   201     private static final ThreadLocal<Global> currentGlobal = new ThreadLocal<>();
   160 
   202 
   161     // class cache
   203     // in-memory cache for loaded classes
   162     private ClassCache classCache;
   204     private ClassCache classCache;
       
   205 
       
   206     // persistent code store
       
   207     private CodeStore codeStore;
   163 
   208 
   164     /**
   209     /**
   165      * Get the current global scope
   210      * Get the current global scope
   166      * @return the current global scope
   211      * @return the current global scope
   167      */
   212      */
   364         }
   409         }
   365 
   410 
   366         final int cacheSize = env._class_cache_size;
   411         final int cacheSize = env._class_cache_size;
   367         if (cacheSize > 0) {
   412         if (cacheSize > 0) {
   368             classCache = new ClassCache(cacheSize);
   413             classCache = new ClassCache(cacheSize);
       
   414         }
       
   415 
       
   416         if (env._persistent_cache) {
       
   417             if (env._lazy_compilation || env._specialize_calls != null) {
       
   418                 getErr().println("Can not use persistent class caching with lazy compilation or call specialization.");
       
   419             } else {
       
   420                 try {
       
   421                     final String cacheDir = Options.getStringProperty("nashorn.persistent.code.cache", "nashorn_code_cache");
       
   422                     codeStore = new CodeStore(cacheDir);
       
   423                 } catch (IOException e) {
       
   424                     throw new RuntimeException("Error initializing code cache", e);
       
   425                 }
       
   426             }
   369         }
   427         }
   370 
   428 
   371         // print version info if asked.
   429         // print version info if asked.
   372         if (env._version) {
   430         if (env._version) {
   373             getErr().println("nashorn " + Version.version());
   431             getErr().println("nashorn " + Version.version());
   930         if (script != null) {
   988         if (script != null) {
   931             Compiler.LOG.fine("Code cache hit for ", source, " avoiding recompile.");
   989             Compiler.LOG.fine("Code cache hit for ", source, " avoiding recompile.");
   932             return script;
   990             return script;
   933         }
   991         }
   934 
   992 
   935         final FunctionNode functionNode = new Parser(env, source, errMan, strict).parse();
   993         CompiledScript compiledScript = null;
   936         if (errors.hasErrors()) {
   994         FunctionNode functionNode = null;
   937             return null;
   995 
   938         }
   996         if (!env._parse_only && codeStore != null) {
   939 
   997             try {
   940         if (env._print_ast) {
   998                 compiledScript = codeStore.getScript(source);
   941             getErr().println(new ASTWriter(functionNode));
   999             } catch (IOException | ClassNotFoundException e) {
   942         }
  1000                 Compiler.LOG.warning("Error loading ", source, " from cache: ", e);
   943 
  1001                 // Fall back to normal compilation
   944         if (env._print_parse) {
  1002             }
   945             getErr().println(new PrintVisitor(functionNode));
  1003         }
       
  1004 
       
  1005         if (compiledScript == null) {
       
  1006             functionNode = new Parser(env, source, errMan, strict).parse();
       
  1007 
       
  1008             if (errors.hasErrors()) {
       
  1009                 return null;
       
  1010             }
       
  1011 
       
  1012             if (env._print_ast) {
       
  1013                 getErr().println(new ASTWriter(functionNode));
       
  1014             }
       
  1015 
       
  1016             if (env._print_parse) {
       
  1017                 getErr().println(new PrintVisitor(functionNode));
       
  1018             }
   946         }
  1019         }
   947 
  1020 
   948         if (env._parse_only) {
  1021         if (env._parse_only) {
   949             return null;
  1022             return null;
   950         }
  1023         }
   952         final URL          url    = source.getURL();
  1025         final URL          url    = source.getURL();
   953         final ScriptLoader loader = env._loader_per_compile ? createNewLoader() : scriptLoader;
  1026         final ScriptLoader loader = env._loader_per_compile ? createNewLoader() : scriptLoader;
   954         final CodeSource   cs     = new CodeSource(url, (CodeSigner[])null);
  1027         final CodeSource   cs     = new CodeSource(url, (CodeSigner[])null);
   955         final CodeInstaller<ScriptEnvironment> installer = new ContextCodeInstaller(this, loader, cs);
  1028         final CodeInstaller<ScriptEnvironment> installer = new ContextCodeInstaller(this, loader, cs);
   956 
  1029 
   957         final Compiler compiler = new Compiler(installer, strict);
  1030         if (functionNode != null) {
   958 
  1031             final Compiler compiler = new Compiler(installer, strict);
   959         final FunctionNode newFunctionNode = compiler.compile(functionNode);
  1032             final FunctionNode newFunctionNode = compiler.compile(functionNode);
   960         script = compiler.install(newFunctionNode);
  1033             script = compiler.install(newFunctionNode);
       
  1034         } else {
       
  1035             script = install(compiledScript, installer);
       
  1036         }
       
  1037 
   961         cacheClass(source, script);
  1038         cacheClass(source, script);
   962 
       
   963         return script;
  1039         return script;
   964     }
  1040     }
   965 
  1041 
   966     private ScriptLoader createNewLoader() {
  1042     private ScriptLoader createNewLoader() {
   967         return AccessController.doPrivileged(
  1043         return AccessController.doPrivileged(
   979 
  1055 
   980     private long getUniqueScriptId() {
  1056     private long getUniqueScriptId() {
   981         return uniqueScriptId.getAndIncrement();
  1057         return uniqueScriptId.getAndIncrement();
   982     }
  1058     }
   983 
  1059 
       
  1060 
       
  1061     /**
       
  1062      * Install a previously compiled class from the code cache.
       
  1063      *
       
  1064      * @param compiledScript cached script containing class bytes and constants
       
  1065      * @return main script class
       
  1066      */
       
  1067     private Class<?> install(final CompiledScript compiledScript, final CodeInstaller<ScriptEnvironment> installer) {
       
  1068 
       
  1069         final Map<String, Class<?>> installedClasses = new HashMap<>();
       
  1070         final Source   source        = compiledScript.getSource();
       
  1071         final Object[] constants     = compiledScript.getConstants();
       
  1072         final String   rootClassName = compiledScript.getMainClassName();
       
  1073         final byte[]   rootByteCode  = compiledScript.getClassBytes().get(rootClassName);
       
  1074         final Class<?> rootClass     = installer.install(rootClassName, rootByteCode, source, constants);
       
  1075 
       
  1076         installedClasses.put(rootClassName, rootClass);
       
  1077 
       
  1078         for (final Map.Entry<String, byte[]> entry : compiledScript.getClassBytes().entrySet()) {
       
  1079             final String className = entry.getKey();
       
  1080             if (className.equals(rootClassName)) {
       
  1081                 continue;
       
  1082             }
       
  1083             final byte[] code = entry.getValue();
       
  1084 
       
  1085             installedClasses.put(className, installer.install(className, code, source, constants));
       
  1086         }
       
  1087         for (Object constant : constants) {
       
  1088             if (constant instanceof RecompilableScriptFunctionData) {
       
  1089                 ((RecompilableScriptFunctionData) constant).setCodeAndSource(installedClasses, source);
       
  1090             }
       
  1091         }
       
  1092 
       
  1093         return rootClass;
       
  1094     }
       
  1095 
   984     /**
  1096     /**
   985      * Cache for compiled script classes.
  1097      * Cache for compiled script classes.
   986      */
  1098      */
   987     @SuppressWarnings("serial")
  1099     @SuppressWarnings("serial")
   988     private static class ClassCache extends LinkedHashMap<Source, ClassReference> {
  1100     private static class ClassCache extends LinkedHashMap<Source, ClassReference> {