8059346: Single class loader is used to load compiled bytecode

Thu, 02 Oct 2014 16:30:49 +0200

author
attila
date
Thu, 02 Oct 2014 16:30:49 +0200
changeset 1030
7eba45a08557
parent 1029
70597fd25c61
child 1031
9b24fc6da691

8059346: Single class loader is used to load compiled bytecode
Reviewed-by: hannesw, lagergren

src/jdk/nashorn/internal/runtime/CodeInstaller.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/Context.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java file | annotate | diff | comparison | revisions
     1.1 --- a/src/jdk/nashorn/internal/runtime/CodeInstaller.java	Mon Sep 29 14:39:58 2014 -0700
     1.2 +++ b/src/jdk/nashorn/internal/runtime/CodeInstaller.java	Thu Oct 02 16:30:49 2014 +0200
     1.3 @@ -100,4 +100,21 @@
     1.4       * @return compiled script data
     1.5       */
     1.6      public StoredScript loadScript(Source source, String functionKey);
     1.7 +
     1.8 +    /**
     1.9 +     * Returns a new code installer that shares most of the functionality of this code installer, but uses a
    1.10 +     * new, independent class loader.
    1.11 +     * @return a new code installer with a new independent class loader.
    1.12 +     */
    1.13 +    public CodeInstaller<T> withNewLoader();
    1.14 +
    1.15 +    /**
    1.16 +     * Returns true if this code installer is compatible with the other code installer. Compatibility is expected to be
    1.17 +     * an equivalence relation, and installers are supposed to be compatible with those they create using
    1.18 +     * {@link #withNewLoader()}.
    1.19 +     * @param other the other code installer tested for compatibility with this code installer.
    1.20 +     * @return true if this code installer is compatible with the other code installer.
    1.21 +     */
    1.22 +    public boolean isCompatibleWith(CodeInstaller<T> other);
    1.23 +
    1.24  }
     2.1 --- a/src/jdk/nashorn/internal/runtime/Context.java	Mon Sep 29 14:39:58 2014 -0700
     2.2 +++ b/src/jdk/nashorn/internal/runtime/Context.java	Thu Oct 02 16:30:49 2014 +0200
     2.3 @@ -33,6 +33,7 @@
     2.4  import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
     2.5  import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
     2.6  import static jdk.nashorn.internal.runtime.Source.sourceFor;
     2.7 +
     2.8  import java.io.File;
     2.9  import java.io.IOException;
    2.10  import java.io.PrintWriter;
    2.11 @@ -158,7 +159,7 @@
    2.12          }
    2.13  
    2.14          /**
    2.15 -         * Return the context for this installer
    2.16 +         * Return the script environment for this installer
    2.17           * @return ScriptEnvironment
    2.18           */
    2.19          @Override
    2.20 @@ -222,6 +223,20 @@
    2.21              }
    2.22              return null;
    2.23          }
    2.24 +
    2.25 +        @Override
    2.26 +        public CodeInstaller<ScriptEnvironment> withNewLoader() {
    2.27 +            return new ContextCodeInstaller(context, context.createNewLoader(), codeSource);
    2.28 +        }
    2.29 +
    2.30 +        @Override
    2.31 +        public boolean isCompatibleWith(final CodeInstaller<ScriptEnvironment> other) {
    2.32 +            if (other instanceof ContextCodeInstaller) {
    2.33 +                final ContextCodeInstaller cci = (ContextCodeInstaller)other;
    2.34 +                return cci.context == context && cci.codeSource == codeSource;
    2.35 +            }
    2.36 +            return false;
    2.37 +        }
    2.38      }
    2.39  
    2.40      /** Is Context global debug mode enabled ? */
     3.1 --- a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Mon Sep 29 14:39:58 2014 -0700
     3.2 +++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Thu Oct 02 16:30:49 2014 +0200
     3.3 @@ -26,6 +26,7 @@
     3.4  package jdk.nashorn.internal.runtime;
     3.5  
     3.6  import static jdk.nashorn.internal.lookup.Lookup.MH;
     3.7 +
     3.8  import java.io.IOException;
     3.9  import java.lang.invoke.MethodHandle;
    3.10  import java.lang.invoke.MethodHandles;
    3.11 @@ -268,7 +269,7 @@
    3.12          if (this.source == null && this.installer == null) {
    3.13              this.source    = src;
    3.14              this.installer = inst;
    3.15 -        } else if (this.source != src || this.installer != inst) {
    3.16 +        } else if (this.source != src || !this.installer.isCompatibleWith(inst)) {
    3.17              // Existing values must be same as those passed as parameters
    3.18              throw new IllegalArgumentException();
    3.19          }
    3.20 @@ -407,6 +408,17 @@
    3.21          return getCompiler(fn, actualCallSiteType, newLocals(runtimeScope), null, null);
    3.22      }
    3.23  
    3.24 +    /**
    3.25 +     * Returns a code installer for installing new code. If we're using either optimistic typing or loader-per-compile,
    3.26 +     * then asks for a code installer with a new class loader; otherwise just uses the current installer. We use
    3.27 +     * a new class loader with optimistic typing so that deoptimized code can get reclaimed by GC.
    3.28 +     * @return a code installer for installing new code.
    3.29 +     */
    3.30 +    private CodeInstaller<ScriptEnvironment> getInstallerForNewCode() {
    3.31 +        final ScriptEnvironment env = installer.getOwner();
    3.32 +        return env._optimistic_types || env._loader_per_compile ? installer.withNewLoader() : installer;
    3.33 +    }
    3.34 +
    3.35      Compiler getCompiler(final FunctionNode functionNode, final MethodType actualCallSiteType,
    3.36              final ScriptObject runtimeScope, final Map<Integer, Type> invalidatedProgramPoints,
    3.37              final int[] continuationEntryPoints) {
    3.38 @@ -417,7 +429,7 @@
    3.39          return new Compiler(
    3.40                  context,
    3.41                  context.getEnv(),
    3.42 -                installer,
    3.43 +                getInstallerForNewCode(),
    3.44                  functionNode.getSource(),  // source
    3.45                  context.getErrorManager(),
    3.46                  isStrict() | functionNode.isStrict(), // is strict
    3.47 @@ -463,11 +475,12 @@
    3.48              final TypeMap typeMap = typeMap(actualCallSiteType);
    3.49              final Type[] paramTypes = typeMap == null ? null : typeMap.getParameterTypes(functionNodeId);
    3.50              cacheKey = CodeStore.getCacheKey(functionNodeId, paramTypes);
    3.51 -            final StoredScript script = installer.loadScript(source, cacheKey);
    3.52 +            final CodeInstaller<ScriptEnvironment> newInstaller = getInstallerForNewCode();
    3.53 +            final StoredScript script = newInstaller.loadScript(source, cacheKey);
    3.54  
    3.55              if (script != null) {
    3.56                  Compiler.updateCompilationId(script.getCompilationId());
    3.57 -                return install(script);
    3.58 +                return installStoredScript(script, newInstaller);
    3.59              }
    3.60          }
    3.61  
    3.62 @@ -481,15 +494,7 @@
    3.63          return new FunctionInitializer(compiledFn, compiler.getInvalidatedProgramPoints());
    3.64      }
    3.65  
    3.66 -
    3.67 -    /**
    3.68 -     * Install this script using the given {@code installer}.
    3.69 -     *
    3.70 -     * @param script the compiled script
    3.71 -     * @return the function initializer
    3.72 -     */
    3.73 -    private FunctionInitializer install(final StoredScript script) {
    3.74 -
    3.75 +    private static Map<String, Class<?>> installStoredScriptClasses(final StoredScript script, final CodeInstaller<ScriptEnvironment> installer) {
    3.76          final Map<String, Class<?>> installedClasses = new HashMap<>();
    3.77          final Map<String, byte[]>   classBytes       = script.getClassBytes();
    3.78          final String   mainClassName   = script.getMainClassName();
    3.79 @@ -509,6 +514,17 @@
    3.80  
    3.81              installedClasses.put(className, installer.install(className, bytecode));
    3.82          }
    3.83 +        return installedClasses;
    3.84 +    }
    3.85 +
    3.86 +    /**
    3.87 +     * Install this script using the given {@code installer}.
    3.88 +     *
    3.89 +     * @param script the compiled script
    3.90 +     * @return the function initializer
    3.91 +     */
    3.92 +    private FunctionInitializer installStoredScript(final StoredScript script, final CodeInstaller<ScriptEnvironment> newInstaller) {
    3.93 +        final Map<String, Class<?>> installedClasses = installStoredScriptClasses(script, newInstaller);
    3.94  
    3.95          final Map<Integer, FunctionInitializer> initializers = script.getInitializers();
    3.96          assert initializers != null;
    3.97 @@ -523,7 +539,7 @@
    3.98              }
    3.99          }
   3.100  
   3.101 -        installer.initialize(installedClasses.values(), source, constants);
   3.102 +        newInstaller.initialize(installedClasses.values(), source, constants);
   3.103          initializer.setCode(installedClasses.get(initializer.getClassName()));
   3.104          return initializer;
   3.105      }

mercurial