8046202: Make persistent code store more flexible

Fri, 19 Sep 2014 13:13:20 +0200

author
hannesw
date
Fri, 19 Sep 2014 13:13:20 +0200
changeset 1018
acb17eade642
parent 1017
e83ceda86582
child 1019
73c31575a0c0

8046202: Make persistent code store more flexible
Reviewed-by: lagergren, sundar

src/jdk/nashorn/internal/runtime/CodeStore.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/Context.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/FunctionInitializer.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/StoredScript.java file | annotate | diff | comparison | revisions
     1.1 --- a/src/jdk/nashorn/internal/runtime/CodeStore.java	Wed Sep 17 15:02:42 2014 +0530
     1.2 +++ b/src/jdk/nashorn/internal/runtime/CodeStore.java	Fri Sep 19 13:13:20 2014 +0200
     1.3 @@ -34,51 +34,42 @@
     1.4  import java.io.ObjectInputStream;
     1.5  import java.io.ObjectOutputStream;
     1.6  import java.io.Serializable;
     1.7 +import java.security.AccessControlException;
     1.8  import java.security.AccessController;
     1.9  import java.security.PrivilegedActionException;
    1.10  import java.security.PrivilegedExceptionAction;
    1.11 +import java.util.Iterator;
    1.12  import java.util.Map;
    1.13 +import java.util.ServiceLoader;
    1.14  import jdk.nashorn.internal.codegen.types.Type;
    1.15  import jdk.nashorn.internal.runtime.logging.DebugLogger;
    1.16  import jdk.nashorn.internal.runtime.logging.Loggable;
    1.17  import jdk.nashorn.internal.runtime.logging.Logger;
    1.18 +import jdk.nashorn.internal.runtime.options.Options;
    1.19  
    1.20  /**
    1.21   * A code cache for persistent caching of compiled scripts.
    1.22   */
    1.23  @Logger(name="codestore")
    1.24 -final class CodeStore implements Loggable {
    1.25 +public abstract class CodeStore implements Loggable {
    1.26  
    1.27 -    private final File dir;
    1.28 -    private final int minSize;
    1.29 -    private final DebugLogger log;
    1.30 +    /**
    1.31 +     * Permission needed to provide a CodeStore instance via ServiceLoader.
    1.32 +     */
    1.33 +    public final static String NASHORN_PROVIDE_CODE_STORE = "nashorn.provideCodeStore";
    1.34  
    1.35 -    // Default minimum size for storing a compiled script class
    1.36 -    private final static int DEFAULT_MIN_SIZE = 1000;
    1.37 +    private DebugLogger log;
    1.38  
    1.39      /**
    1.40       * Constructor
    1.41 -     * @throws IOException
    1.42       */
    1.43 -    public CodeStore(final Context context, final String path) throws IOException {
    1.44 -        this(context, path, DEFAULT_MIN_SIZE);
    1.45 -    }
    1.46 -
    1.47 -    /**
    1.48 -     * Constructor
    1.49 -     * @param path directory to store code in
    1.50 -     * @param minSize minimum file size for caching scripts
    1.51 -     * @throws IOException
    1.52 -     */
    1.53 -    public CodeStore(final Context context, final String path, final int minSize) throws IOException {
    1.54 -        this.dir = checkDirectory(path);
    1.55 -        this.minSize = minSize;
    1.56 -        this.log = initLogger(context);
    1.57 +    protected CodeStore() {
    1.58      }
    1.59  
    1.60      @Override
    1.61      public DebugLogger initLogger(final Context context) {
    1.62 -         return context.getLogger(getClass());
    1.63 +        log = context.getLogger(getClass());
    1.64 +        return log;
    1.65      }
    1.66  
    1.67      @Override
    1.68 @@ -86,29 +77,101 @@
    1.69          return log;
    1.70      }
    1.71  
    1.72 -    private static File checkDirectory(final String path) throws IOException {
    1.73 +    /**
    1.74 +     * Returns a new code store instance.
    1.75 +     *
    1.76 +     * @param context the current context
    1.77 +     * @return The instance
    1.78 +     * @throws IOException If an error occurs
    1.79 +     */
    1.80 +    public static CodeStore newCodeStore(final Context context) throws IOException {
    1.81 +        final Class<CodeStore> baseClass = CodeStore.class;
    1.82          try {
    1.83 -            return AccessController.doPrivileged(new PrivilegedExceptionAction<File>() {
    1.84 -                @Override
    1.85 -                public File run() throws IOException {
    1.86 -                    final File dir = new File(path).getAbsoluteFile();
    1.87 -                    if (!dir.exists() && !dir.mkdirs()) {
    1.88 -                        throw new IOException("Could not create directory: " + dir.getPath());
    1.89 -                    } else if (!dir.isDirectory()) {
    1.90 -                        throw new IOException("Not a directory: " + dir.getPath());
    1.91 -                    } else if (!dir.canRead() || !dir.canWrite()) {
    1.92 -                        throw new IOException("Directory not readable or writable: " + dir.getPath());
    1.93 -                    }
    1.94 -                    return dir;
    1.95 -                }
    1.96 -            });
    1.97 -        } catch (final PrivilegedActionException e) {
    1.98 -            throw (IOException) e.getException();
    1.99 +            // security check first
   1.100 +            final SecurityManager sm = System.getSecurityManager();
   1.101 +            if (sm != null) {
   1.102 +                sm.checkPermission(new RuntimePermission(NASHORN_PROVIDE_CODE_STORE));
   1.103 +            }
   1.104 +            final ServiceLoader<CodeStore> services = ServiceLoader.load(baseClass);
   1.105 +            final Iterator<CodeStore> iterator = services.iterator();
   1.106 +            if (iterator.hasNext()) {
   1.107 +                final CodeStore store = iterator.next();
   1.108 +                store.initLogger(context).info("using code store provider ", store.getClass().getCanonicalName());
   1.109 +                return store;
   1.110 +            }
   1.111 +        } catch (final AccessControlException e) {
   1.112 +            context.getLogger(CodeStore.class).warning("failed to load code store provider ", e);
   1.113          }
   1.114 +        final CodeStore store = new DirectoryCodeStore();
   1.115 +        store.initLogger(context);
   1.116 +        return store;
   1.117      }
   1.118  
   1.119 -    private File getCacheFile(final Source source, final String functionKey) {
   1.120 -        return new File(dir, source.getDigest() + '-' + functionKey);
   1.121 +
   1.122 +    /**
   1.123 +     * Store a compiled script in the cache.
   1.124 +     *
   1.125 +     * @param functionKey   the function key
   1.126 +     * @param source        the source
   1.127 +     * @param mainClassName the main class name
   1.128 +     * @param classBytes    a map of class bytes
   1.129 +     * @param initializers  the function initializers
   1.130 +     * @param constants     the constants array
   1.131 +     * @param compilationId the compilation id
   1.132 +     */
   1.133 +    public StoredScript store(final String functionKey,
   1.134 +                              final Source source,
   1.135 +                              final String mainClassName,
   1.136 +                              final Map<String, byte[]> classBytes,
   1.137 +                              final Map<Integer, FunctionInitializer> initializers,
   1.138 +                              final Object[] constants,
   1.139 +                              final int compilationId) {
   1.140 +        return store(functionKey, source, storedScriptFor(source, mainClassName, classBytes, initializers, constants, compilationId));
   1.141 +    }
   1.142 +
   1.143 +    /**
   1.144 +     * Stores a compiled script.
   1.145 +     *
   1.146 +     * @param functionKey the function key
   1.147 +     * @param source the source
   1.148 +     * @param script The compiled script
   1.149 +     * @return The compiled script or {@code null} if not stored
   1.150 +     */
   1.151 +    public abstract StoredScript store(final String functionKey,
   1.152 +                                       final Source source,
   1.153 +                                       final StoredScript script);
   1.154 +
   1.155 +    /**
   1.156 +     * Return a compiled script from the cache, or null if it isn't found.
   1.157 +     *
   1.158 +     * @param source      the source
   1.159 +     * @param functionKey the function key
   1.160 +     * @return the stored script or null
   1.161 +     */
   1.162 +    public abstract StoredScript load(final Source source, final String functionKey);
   1.163 +
   1.164 +    /**
   1.165 +     * Returns a new StoredScript instance.
   1.166 +     *
   1.167 +     * @param mainClassName the main class name
   1.168 +     * @param classBytes a map of class bytes
   1.169 +     * @param initializers function initializers
   1.170 +     * @param constants the constants array
   1.171 +     * @param compilationId the compilation id
   1.172 +     * @return The compiled script
   1.173 +     */
   1.174 +    public StoredScript storedScriptFor(final Source source, final String mainClassName,
   1.175 +                                        final Map<String, byte[]> classBytes,
   1.176 +                                        final Map<Integer, FunctionInitializer> initializers,
   1.177 +                                        final Object[] constants, final int compilationId) {
   1.178 +        for (final Object constant : constants) {
   1.179 +            // Make sure all constant data is serializable
   1.180 +            if (!(constant instanceof Serializable)) {
   1.181 +                getLogger().warning("cannot store ", source, " non serializable constant ", constant);
   1.182 +                return null;
   1.183 +            }
   1.184 +        }
   1.185 +        return new StoredScript(compilationId, mainClassName, classBytes, initializers, constants);
   1.186      }
   1.187  
   1.188      /**
   1.189 @@ -129,77 +192,130 @@
   1.190      }
   1.191  
   1.192      /**
   1.193 -     * Return a compiled script from the cache, or null if it isn't found.
   1.194 -     *
   1.195 -     * @param source the source
   1.196 -     * @param functionKey the function key
   1.197 -     * @return the stored script or null
   1.198 +     * A store using a file system directory.
   1.199       */
   1.200 -    public StoredScript loadScript(final Source source, final String functionKey) {
   1.201 -        if (source.getLength() < minSize) {
   1.202 -            return null;
   1.203 +    public static class DirectoryCodeStore extends CodeStore {
   1.204 +
   1.205 +        // Default minimum size for storing a compiled script class
   1.206 +        private final static int DEFAULT_MIN_SIZE = 1000;
   1.207 +
   1.208 +        private final File dir;
   1.209 +        private final boolean readOnly;
   1.210 +        private final int minSize;
   1.211 +
   1.212 +        /**
   1.213 +         * Constructor
   1.214 +         *
   1.215 +         * @throws IOException
   1.216 +         */
   1.217 +        public DirectoryCodeStore() throws IOException {
   1.218 +            this(Options.getStringProperty("nashorn.persistent.code.cache", "nashorn_code_cache"), false, DEFAULT_MIN_SIZE);
   1.219          }
   1.220  
   1.221 -        final File file = getCacheFile(source, functionKey);
   1.222 +        /**
   1.223 +         * Constructor
   1.224 +         *
   1.225 +         * @param path    directory to store code in
   1.226 +         * @param minSize minimum file size for caching scripts
   1.227 +         * @throws IOException
   1.228 +         */
   1.229 +        public DirectoryCodeStore(final String path, final boolean readOnly, final int minSize) throws IOException {
   1.230 +            this.dir = checkDirectory(path, readOnly);
   1.231 +            this.readOnly = readOnly;
   1.232 +            this.minSize = minSize;
   1.233 +        }
   1.234  
   1.235 -        try {
   1.236 -            return AccessController.doPrivileged(new PrivilegedExceptionAction<StoredScript>() {
   1.237 -                @Override
   1.238 -                public StoredScript run() throws IOException, ClassNotFoundException {
   1.239 -                    if (!file.exists()) {
   1.240 -                        return null;
   1.241 +        private static File checkDirectory(final String path, final boolean readOnly) throws IOException {
   1.242 +            try {
   1.243 +                return AccessController.doPrivileged(new PrivilegedExceptionAction<File>() {
   1.244 +                    @Override
   1.245 +                    public File run() throws IOException {
   1.246 +                        final File dir = new File(path).getAbsoluteFile();
   1.247 +                        if (readOnly) {
   1.248 +                            if (!dir.exists() || !dir.isDirectory()) {
   1.249 +                                throw new IOException("Not a directory: " + dir.getPath());
   1.250 +                            } else if (!dir.canRead()) {
   1.251 +                                throw new IOException("Directory not readable: " + dir.getPath());
   1.252 +                            }
   1.253 +                        } else if (!dir.exists() && !dir.mkdirs()) {
   1.254 +                            throw new IOException("Could not create directory: " + dir.getPath());
   1.255 +                        } else if (!dir.isDirectory()) {
   1.256 +                            throw new IOException("Not a directory: " + dir.getPath());
   1.257 +                        } else if (!dir.canRead() || !dir.canWrite()) {
   1.258 +                            throw new IOException("Directory not readable or writable: " + dir.getPath());
   1.259 +                        }
   1.260 +                        return dir;
   1.261                      }
   1.262 -                    try (ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(new FileInputStream(file)))) {
   1.263 -                        final StoredScript storedScript = (StoredScript) in.readObject();
   1.264 -                        getLogger().info("loaded ", source, "-", functionKey);
   1.265 -                        return storedScript;
   1.266 -                    }
   1.267 -                }
   1.268 -            });
   1.269 -        } catch (final PrivilegedActionException e) {
   1.270 -            getLogger().warning("failed to load ", source, "-", functionKey, ": ", e.getException());
   1.271 -            return null;
   1.272 -        }
   1.273 -    }
   1.274 -
   1.275 -    /**
   1.276 -     * Store a compiled script in the cache.
   1.277 -     *
   1.278 -     * @param functionKey the function key
   1.279 -     * @param source the source
   1.280 -     * @param mainClassName the main class name
   1.281 -     * @param classBytes a map of class bytes
   1.282 -     * @param constants the constants array
   1.283 -     */
   1.284 -    public void storeScript(final String functionKey, final Source source, final String mainClassName, final Map<String, byte[]> classBytes,
   1.285 -                          final Map<Integer, FunctionInitializer> initializers, final Object[] constants, final int compilationId) {
   1.286 -        if (source.getLength() < minSize) {
   1.287 -            return;
   1.288 -        }
   1.289 -        for (final Object constant : constants) {
   1.290 -            // Make sure all constant data is serializable
   1.291 -            if (! (constant instanceof Serializable)) {
   1.292 -                getLogger().warning("cannot store ", source, " non serializable constant ", constant);
   1.293 -                return;
   1.294 +                });
   1.295 +            } catch (final PrivilegedActionException e) {
   1.296 +                throw (IOException) e.getException();
   1.297              }
   1.298          }
   1.299  
   1.300 -        final File file = getCacheFile(source, functionKey);
   1.301 -        final StoredScript script = new StoredScript(compilationId, mainClassName, classBytes, initializers, constants);
   1.302 +        @Override
   1.303 +        public StoredScript load(final Source source, final String functionKey) {
   1.304 +            if (source.getLength() < minSize) {
   1.305 +                return null;
   1.306 +            }
   1.307  
   1.308 -        try {
   1.309 -            AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
   1.310 -                @Override
   1.311 -                public Void run() throws IOException {
   1.312 -                    try (ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(file)))) {
   1.313 -                        out.writeObject(script);
   1.314 +            final File file = getCacheFile(source, functionKey);
   1.315 +
   1.316 +            try {
   1.317 +                return AccessController.doPrivileged(new PrivilegedExceptionAction<StoredScript>() {
   1.318 +                    @Override
   1.319 +                    public StoredScript run() throws IOException, ClassNotFoundException {
   1.320 +                        if (!file.exists()) {
   1.321 +                            return null;
   1.322 +                        }
   1.323 +                        try (ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(new FileInputStream(file)))) {
   1.324 +                            final StoredScript storedScript = (StoredScript) in.readObject();
   1.325 +                            getLogger().info("loaded ", source, "-", functionKey);
   1.326 +                            return storedScript;
   1.327 +                        }
   1.328                      }
   1.329 -                    getLogger().info("stored ", source, "-", functionKey);
   1.330 -                    return null;
   1.331 -                }
   1.332 -            });
   1.333 -        } catch (final PrivilegedActionException e) {
   1.334 -            getLogger().warning("failed to store ", script, "-", functionKey, ": ", e.getException());
   1.335 +                });
   1.336 +            } catch (final PrivilegedActionException e) {
   1.337 +                getLogger().warning("failed to load ", source, "-", functionKey, ": ", e.getException());
   1.338 +                return null;
   1.339 +            }
   1.340 +        }
   1.341 +
   1.342 +        @Override
   1.343 +        public StoredScript store(final String functionKey, final Source source, final StoredScript script) {
   1.344 +            if (readOnly || script == null || belowThreshold(source)) {
   1.345 +                return null;
   1.346 +            }
   1.347 +
   1.348 +            final File file = getCacheFile(source, functionKey);
   1.349 +
   1.350 +            try {
   1.351 +                return AccessController.doPrivileged(new PrivilegedExceptionAction<StoredScript>() {
   1.352 +                    @Override
   1.353 +                    public StoredScript run() throws IOException {
   1.354 +                        try (ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(file)))) {
   1.355 +                            out.writeObject(script);
   1.356 +                        }
   1.357 +                        getLogger().info("stored ", source, "-", functionKey);
   1.358 +                        return script;
   1.359 +                    }
   1.360 +                });
   1.361 +            } catch (final PrivilegedActionException e) {
   1.362 +                getLogger().warning("failed to store ", script, "-", functionKey, ": ", e.getException());
   1.363 +                return null;
   1.364 +            }
   1.365 +        }
   1.366 +
   1.367 +
   1.368 +        private File getCacheFile(final Source source, final String functionKey) {
   1.369 +            return new File(dir, source.getDigest() + '-' + functionKey);
   1.370 +        }
   1.371 +
   1.372 +        private boolean belowThreshold(final Source source) {
   1.373 +            if (source.getLength() < minSize) {
   1.374 +                getLogger().info("below size threshold ", source);
   1.375 +                return true;
   1.376 +            }
   1.377 +            return false;
   1.378          }
   1.379      }
   1.380  }
     2.1 --- a/src/jdk/nashorn/internal/runtime/Context.java	Wed Sep 17 15:02:42 2014 +0530
     2.2 +++ b/src/jdk/nashorn/internal/runtime/Context.java	Fri Sep 19 13:13:20 2014 +0200
     2.3 @@ -29,6 +29,7 @@
     2.4  import static jdk.nashorn.internal.codegen.CompilerConstants.CREATE_PROGRAM_FUNCTION;
     2.5  import static jdk.nashorn.internal.codegen.CompilerConstants.SOURCE;
     2.6  import static jdk.nashorn.internal.codegen.CompilerConstants.STRICT_MODE;
     2.7 +import static jdk.nashorn.internal.runtime.CodeStore.newCodeStore;
     2.8  import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
     2.9  import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
    2.10  import static jdk.nashorn.internal.runtime.Source.sourceFor;
    2.11 @@ -200,14 +201,14 @@
    2.12                                  final Map<String,byte[]> classBytes, final Map<Integer, FunctionInitializer> initializers,
    2.13                                  final Object[] constants, final int compilationId) {
    2.14              if (context.codeStore != null) {
    2.15 -                context.codeStore.storeScript(cacheKey, source, mainClassName, classBytes, initializers, constants, compilationId);
    2.16 +                context.codeStore.store(cacheKey, source, mainClassName, classBytes, initializers, constants, compilationId);
    2.17              }
    2.18          }
    2.19  
    2.20          @Override
    2.21          public StoredScript loadScript(final Source source, final String functionKey) {
    2.22              if (context.codeStore != null) {
    2.23 -                return context.codeStore.loadScript(source, functionKey);
    2.24 +                return context.codeStore.load(source, functionKey);
    2.25              }
    2.26              return null;
    2.27          }
    2.28 @@ -463,8 +464,7 @@
    2.29  
    2.30          if (env._persistent_cache) {
    2.31              try {
    2.32 -                final String cacheDir = Options.getStringProperty("nashorn.persistent.code.cache", "nashorn_code_cache");
    2.33 -                codeStore = new CodeStore(this, cacheDir);
    2.34 +                codeStore = newCodeStore(this);
    2.35              } catch (final IOException e) {
    2.36                  throw new RuntimeException("Error initializing code cache", e);
    2.37              }
    2.38 @@ -1117,7 +1117,7 @@
    2.39          final String cacheKey = useCodeStore ? CodeStore.getCacheKey(0, null) : null;
    2.40  
    2.41          if (useCodeStore) {
    2.42 -            storedScript = codeStore.loadScript(source, cacheKey);
    2.43 +            storedScript = codeStore.load(source, cacheKey);
    2.44          }
    2.45  
    2.46          if (storedScript == null) {
    2.47 @@ -1194,15 +1194,16 @@
    2.48      private static Class<?> install(final StoredScript storedScript, final Source source, final CodeInstaller<ScriptEnvironment> installer) {
    2.49  
    2.50          final Map<String, Class<?>> installedClasses = new HashMap<>();
    2.51 +        final Map<String, byte[]>   classBytes       = storedScript.getClassBytes();
    2.52          final Object[] constants       = storedScript.getConstants();
    2.53          final String   mainClassName   = storedScript.getMainClassName();
    2.54 -        final byte[]   mainClassBytes  = storedScript.getClassBytes().get(mainClassName);
    2.55 +        final byte[]   mainClassBytes  = classBytes.get(mainClassName);
    2.56          final Class<?> mainClass       = installer.install(mainClassName, mainClassBytes);
    2.57          final Map<Integer, FunctionInitializer> initialzers = storedScript.getInitializers();
    2.58  
    2.59          installedClasses.put(mainClassName, mainClass);
    2.60  
    2.61 -        for (final Map.Entry<String, byte[]> entry : storedScript.getClassBytes().entrySet()) {
    2.62 +        for (final Map.Entry<String, byte[]> entry : classBytes.entrySet()) {
    2.63              final String className = entry.getKey();
    2.64              if (className.equals(mainClassName)) {
    2.65                  continue;
     3.1 --- a/src/jdk/nashorn/internal/runtime/FunctionInitializer.java	Wed Sep 17 15:02:42 2014 +0530
     3.2 +++ b/src/jdk/nashorn/internal/runtime/FunctionInitializer.java	Fri Sep 19 13:13:20 2014 +0200
     3.3 @@ -60,6 +60,17 @@
     3.4      }
     3.5  
     3.6      /**
     3.7 +     * Copy constructor.
     3.8 +     *
     3.9 +     * @param init original initializer
    3.10 +     */
    3.11 +    FunctionInitializer(final FunctionInitializer init) {
    3.12 +        this.className = init.getClassName();
    3.13 +        this.methodType = init.getMethodType();
    3.14 +        this.flags = init.getFlags();
    3.15 +    }
    3.16 +
    3.17 +    /**
    3.18       * Constructor.
    3.19       *
    3.20       * @param functionNode the function node
     4.1 --- a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Wed Sep 17 15:02:42 2014 +0530
     4.2 +++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Fri Sep 19 13:13:20 2014 +0200
     4.3 @@ -491,14 +491,15 @@
     4.4      private FunctionInitializer install(final StoredScript script) {
     4.5  
     4.6          final Map<String, Class<?>> installedClasses = new HashMap<>();
     4.7 +        final Map<String, byte[]>   classBytes       = script.getClassBytes();
     4.8          final String   mainClassName   = script.getMainClassName();
     4.9 -        final byte[]   mainClassBytes  = script.getClassBytes().get(mainClassName);
    4.10 +        final byte[]   mainClassBytes  = classBytes.get(mainClassName);
    4.11  
    4.12          final Class<?> mainClass       = installer.install(mainClassName, mainClassBytes);
    4.13  
    4.14          installedClasses.put(mainClassName, mainClass);
    4.15  
    4.16 -        for (final Map.Entry<String, byte[]> entry : script.getClassBytes().entrySet()) {
    4.17 +        for (final Map.Entry<String, byte[]> entry : classBytes.entrySet()) {
    4.18              final String className = entry.getKey();
    4.19              final byte[] code = entry.getValue();
    4.20  
     5.1 --- a/src/jdk/nashorn/internal/runtime/StoredScript.java	Wed Sep 17 15:02:42 2014 +0530
     5.2 +++ b/src/jdk/nashorn/internal/runtime/StoredScript.java	Fri Sep 19 13:13:20 2014 +0200
     5.3 @@ -27,6 +27,7 @@
     5.4  
     5.5  import java.io.Serializable;
     5.6  import java.util.Arrays;
     5.7 +import java.util.LinkedHashMap;
     5.8  import java.util.Map;
     5.9  
    5.10  /**
    5.11 @@ -83,7 +84,11 @@
    5.12       * @return map of class bytes
    5.13       */
    5.14      public Map<String, byte[]> getClassBytes() {
    5.15 -        return classBytes;
    5.16 +        final Map<String, byte[]> clonedMap = new LinkedHashMap<>();
    5.17 +        for (final Map.Entry<String, byte[]> entry : classBytes.entrySet()) {
    5.18 +            clonedMap.put(entry.getKey(), entry.getValue().clone());
    5.19 +        }
    5.20 +        return clonedMap;
    5.21      }
    5.22  
    5.23      /**
    5.24 @@ -91,11 +96,19 @@
    5.25       * @return constants array
    5.26       */
    5.27      public Object[] getConstants() {
    5.28 -        return constants;
    5.29 +        return constants.clone();
    5.30      }
    5.31  
    5.32 -    Map<Integer, FunctionInitializer> getInitializers() {
    5.33 -        return initializers;
    5.34 +    /**
    5.35 +     * Returns the function initializers map.
    5.36 +     * @return The initializers map.
    5.37 +     */
    5.38 +    public Map<Integer, FunctionInitializer> getInitializers() {
    5.39 +        final Map<Integer, FunctionInitializer> clonedMap = new LinkedHashMap<>();
    5.40 +        for (final Map.Entry<Integer, FunctionInitializer> entry : initializers.entrySet()) {
    5.41 +            clonedMap.put(entry.getKey(), new FunctionInitializer(entry.getValue()));
    5.42 +        }
    5.43 +        return clonedMap;
    5.44      }
    5.45  
    5.46      @Override

mercurial