Merge jdk8u20-b11

Wed, 16 Apr 2014 15:05:39 -0700

author
lana
date
Wed, 16 Apr 2014 15:05:39 -0700
changeset 837
c116e9229e09
parent 827
ef90d0fc9533
parent 836
14f081aae67a
child 838
c720454d2435

Merge

     1.1 --- a/src/jdk/internal/dynalink/beans/BeanLinker.java	Wed Apr 16 12:32:47 2014 -0700
     1.2 +++ b/src/jdk/internal/dynalink/beans/BeanLinker.java	Wed Apr 16 15:05:39 2014 -0700
     1.3 @@ -113,6 +113,8 @@
     1.4              // explicit property is beneficial for them.
     1.5              // REVISIT: is it maybe a code smell that "dyn:getLength" is not needed?
     1.6              setPropertyGetter("length", GET_ARRAY_LENGTH, ValidationType.IS_ARRAY);
     1.7 +        } else if(List.class.isAssignableFrom(clazz)) {
     1.8 +            setPropertyGetter("length", GET_COLLECTION_LENGTH, ValidationType.INSTANCE_OF);
     1.9          }
    1.10      }
    1.11  
     2.1 --- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Wed Apr 16 12:32:47 2014 -0700
     2.2 +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Wed Apr 16 15:05:39 2014 -0700
     2.3 @@ -3228,7 +3228,7 @@
     2.4          final String      className          = SCRIPTFUNCTION_IMPL_OBJECT;
     2.5          final int         fieldCount         = ObjectClassGenerator.getPaddedFieldCount(functionNode.countThisProperties());
     2.6          final String      allocatorClassName = Compiler.binaryName(ObjectClassGenerator.getClassName(fieldCount));
     2.7 -        final PropertyMap allocatorMap       = PropertyMap.newMap(null, 0, fieldCount, 0);
     2.8 +        final PropertyMap allocatorMap       = PropertyMap.newMap(null, allocatorClassName, 0, fieldCount, 0);
     2.9  
    2.10          method._new(className).dup();
    2.11          loadConstant(new RecompilableScriptFunctionData(functionNode, compiler.getCodeInstaller(), allocatorClassName, allocatorMap));
     3.1 --- a/src/jdk/nashorn/internal/codegen/Compiler.java	Wed Apr 16 12:32:47 2014 -0700
     3.2 +++ b/src/jdk/nashorn/internal/codegen/Compiler.java	Wed Apr 16 15:05:39 2014 -0700
     3.3 @@ -405,32 +405,8 @@
     3.4          return newFunctionNode;
     3.5      }
     3.6  
     3.7 -    private Class<?> install(final String className, final byte[] code) {
     3.8 -        LOG.fine("Installing class ", className);
     3.9 -
    3.10 -        final Class<?> clazz = installer.install(Compiler.binaryName(className), code);
    3.11 -
    3.12 -        try {
    3.13 -            final Object[] constants = getConstantData().toArray();
    3.14 -            // Need doPrivileged because these fields are private
    3.15 -            AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
    3.16 -                @Override
    3.17 -                public Void run() throws Exception {
    3.18 -                    //use reflection to write source and constants table to installed classes
    3.19 -                    final Field sourceField    = clazz.getDeclaredField(SOURCE.symbolName());
    3.20 -                    final Field constantsField = clazz.getDeclaredField(CONSTANTS.symbolName());
    3.21 -                    sourceField.setAccessible(true);
    3.22 -                    constantsField.setAccessible(true);
    3.23 -                    sourceField.set(null, source);
    3.24 -                    constantsField.set(null, constants);
    3.25 -                    return null;
    3.26 -                }
    3.27 -            });
    3.28 -        } catch (final PrivilegedActionException e) {
    3.29 -            throw new RuntimeException(e);
    3.30 -        }
    3.31 -
    3.32 -        return clazz;
    3.33 +    private Class<?> install(final String className, final byte[] code, final Object[] constants) {
    3.34 +        return installer.install(className, code, source, constants);
    3.35      }
    3.36  
    3.37      /**
    3.38 @@ -444,10 +420,15 @@
    3.39          assert functionNode.hasState(CompilationState.EMITTED) : functionNode.getName() + " has no bytecode and cannot be installed";
    3.40  
    3.41          final Map<String, Class<?>> installedClasses = new HashMap<>();
    3.42 +        final Object[] constants = getConstantData().toArray();
    3.43  
    3.44          final String   rootClassName = firstCompileUnitName();
    3.45          final byte[]   rootByteCode  = bytecode.get(rootClassName);
    3.46 -        final Class<?> rootClass     = install(rootClassName, rootByteCode);
    3.47 +        final Class<?> rootClass     = install(rootClassName, rootByteCode, constants);
    3.48 +
    3.49 +        if (!isLazy()) {
    3.50 +            installer.storeCompiledScript(source, rootClassName, bytecode, constants);
    3.51 +        }
    3.52  
    3.53          int length = rootByteCode.length;
    3.54  
    3.55 @@ -461,7 +442,7 @@
    3.56              final byte[] code = entry.getValue();
    3.57              length += code.length;
    3.58  
    3.59 -            installedClasses.put(className, install(className, code));
    3.60 +            installedClasses.put(className, install(className, code, constants));
    3.61          }
    3.62  
    3.63          for (final CompileUnit unit : compileUnits) {
     4.1 --- a/src/jdk/nashorn/internal/codegen/MapCreator.java	Wed Apr 16 12:32:47 2014 -0700
     4.2 +++ b/src/jdk/nashorn/internal/codegen/MapCreator.java	Wed Apr 16 15:05:39 2014 -0700
     4.3 @@ -83,7 +83,7 @@
     4.4              }
     4.5          }
     4.6  
     4.7 -        return PropertyMap.newMap(properties, fieldCount, fieldMaximum, 0);
     4.8 +        return PropertyMap.newMap(properties, structure.getName(), fieldCount, fieldMaximum, 0);
     4.9      }
    4.10  
    4.11      PropertyMap makeSpillMap(final boolean hasArguments) {
    4.12 @@ -100,7 +100,7 @@
    4.13              }
    4.14          }
    4.15  
    4.16 -        return PropertyMap.newMap(properties, 0, 0, spillIndex);
    4.17 +        return PropertyMap.newMap(properties, structure.getName(), 0, 0, spillIndex);
    4.18      }
    4.19  
    4.20      /**
     5.1 --- a/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java	Wed Apr 16 12:32:47 2014 -0700
     5.2 +++ b/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java	Wed Apr 16 15:05:39 2014 -0700
     5.3 @@ -89,6 +89,15 @@
     5.4          }
     5.5  
     5.6          @Override
     5.7 +        protected void setImpl(final int index, final long value) {
     5.8 +            if (JSType.isRepresentableAsInt(value)) {
     5.9 +                setImpl(index, (int)value);
    5.10 +            } else {
    5.11 +                buffer.getByteArray()[byteIndex(index)] = value > 0 ? (byte)0xff : 0;
    5.12 +            }
    5.13 +        }
    5.14 +
    5.15 +        @Override
    5.16          protected void setImpl(final int key, final double value) {
    5.17              setImpl(key, (int)Math.rint(value));
    5.18          }
     6.1 --- a/src/jdk/nashorn/internal/runtime/AccessorProperty.java	Wed Apr 16 12:32:47 2014 -0700
     6.2 +++ b/src/jdk/nashorn/internal/runtime/AccessorProperty.java	Wed Apr 16 15:05:39 2014 -0700
     6.3 @@ -39,6 +39,9 @@
     6.4  import static jdk.nashorn.internal.lookup.Lookup.MH;
     6.5  import static jdk.nashorn.internal.lookup.MethodHandleFactory.stripName;
     6.6  
     6.7 +import java.io.IOException;
     6.8 +import java.io.ObjectInputStream;
     6.9 +import java.io.Serializable;
    6.10  import java.lang.invoke.MethodHandle;
    6.11  import java.lang.invoke.MethodHandles;
    6.12  import java.lang.invoke.MethodType;
    6.13 @@ -51,11 +54,12 @@
    6.14   * An AccessorProperty is the most generic property type. An AccessorProperty is
    6.15   * represented as fields in a ScriptObject class.
    6.16   */
    6.17 -public final class AccessorProperty extends Property {
    6.18 +public final class AccessorProperty extends Property implements Serializable {
    6.19      private static final MethodHandles.Lookup lookup = MethodHandles.lookup();
    6.20      private static final MethodHandle REPLACE_MAP = findOwnMH("replaceMap", Object.class, Object.class, PropertyMap.class, String.class, Class.class, Class.class);
    6.21  
    6.22      private static final int NOOF_TYPES = getNumberOfAccessorTypes();
    6.23 +    private static final long serialVersionUID = 3371720170182154920L;
    6.24  
    6.25      /**
    6.26       * Properties in different maps for the same structure class will share their field getters and setters. This could
    6.27 @@ -71,7 +75,7 @@
    6.28      };
    6.29  
    6.30      /** Property getter cache */
    6.31 -    private MethodHandle[] getters = new MethodHandle[NOOF_TYPES];
    6.32 +    private transient MethodHandle[] getters = new MethodHandle[NOOF_TYPES];
    6.33  
    6.34      private static final MethodType[] ACCESSOR_GETTER_TYPES = new MethodType[NOOF_TYPES];
    6.35      private static final MethodType[] ACCESSOR_SETTER_TYPES = new MethodType[NOOF_TYPES];
    6.36 @@ -122,16 +126,16 @@
    6.37      }
    6.38  
    6.39      /** Seed getter for the primitive version of this field (in -Dnashorn.fields.dual=true mode) */
    6.40 -    private MethodHandle primitiveGetter;
    6.41 +    private transient MethodHandle primitiveGetter;
    6.42  
    6.43      /** Seed setter for the primitive version of this field (in -Dnashorn.fields.dual=true mode) */
    6.44 -    private MethodHandle primitiveSetter;
    6.45 +    private transient MethodHandle primitiveSetter;
    6.46  
    6.47      /** Seed getter for the Object version of this field */
    6.48 -    private MethodHandle objectGetter;
    6.49 +    private transient MethodHandle objectGetter;
    6.50  
    6.51      /** Seed setter for the Object version of this field */
    6.52 -    private MethodHandle objectSetter;
    6.53 +    private transient MethodHandle objectSetter;
    6.54  
    6.55      /**
    6.56       * Current type of this object, in object only mode, this is an Object.class. In dual-fields mode
    6.57 @@ -243,6 +247,12 @@
    6.58      public AccessorProperty(final String key, final int flags, final Class<?> structure, final int slot) {
    6.59          super(key, flags, slot);
    6.60  
    6.61 +        initGetterSetter(structure);
    6.62 +    }
    6.63 +
    6.64 +    private void initGetterSetter(final Class<?> structure) {
    6.65 +        final int slot = getSlot();
    6.66 +        final String key = getKey();
    6.67          /*
    6.68           * primitiveGetter and primitiveSetter are only used in dual fields mode. Setting them to null also
    6.69           * works in dual field mode, it only means that the property never has a primitive
    6.70 @@ -305,6 +315,12 @@
    6.71          setCurrentType(property.getCurrentType());
    6.72      }
    6.73  
    6.74 +    private void readObject(final ObjectInputStream s) throws IOException, ClassNotFoundException {
    6.75 +        s.defaultReadObject();
    6.76 +        // Restore getters array
    6.77 +        getters = new MethodHandle[NOOF_TYPES];
    6.78 +    }
    6.79 +
    6.80      private static MethodHandle bindTo(final MethodHandle mh, final Object receiver) {
    6.81          if (mh == null) {
    6.82              return null;
    6.83 @@ -364,6 +380,16 @@
    6.84      }
    6.85  
    6.86      @Override
    6.87 +    void initMethodHandles(final Class<?> structure) {
    6.88 +        if (!ScriptObject.class.isAssignableFrom(structure) || !StructureLoader.isStructureClass(structure.getName())) {
    6.89 +            throw new IllegalArgumentException();
    6.90 +        }
    6.91 +        if (!isSpill()) {
    6.92 +            initGetterSetter(structure);
    6.93 +        }
    6.94 +    }
    6.95 +
    6.96 +    @Override
    6.97      public MethodHandle getGetter(final Class<?> type) {
    6.98          final int i = getAccessorTypeIndex(type);
    6.99          ensureObjectGetter();
     7.1 --- a/src/jdk/nashorn/internal/runtime/CodeInstaller.java	Wed Apr 16 12:32:47 2014 -0700
     7.2 +++ b/src/jdk/nashorn/internal/runtime/CodeInstaller.java	Wed Apr 16 15:05:39 2014 -0700
     7.3 @@ -25,6 +25,7 @@
     7.4  
     7.5  package jdk.nashorn.internal.runtime;
     7.6  
     7.7 +import java.util.Map;
     7.8  import jdk.nashorn.internal.codegen.ClassEmitter;
     7.9  
    7.10  /**
    7.11 @@ -52,7 +53,7 @@
    7.12       * @param bytecode  bytecode
    7.13       * @return the installed class
    7.14       */
    7.15 -    public Class<?> install(final String className, final byte[] bytecode);
    7.16 +    public Class<?> install(final String className, final byte[] bytecode, final Source source, final Object[] constants);
    7.17  
    7.18      /**
    7.19       * Verify generated bytecode before emission. This is called back from the
    7.20 @@ -74,4 +75,13 @@
    7.21       * @return unique eval id
    7.22       */
    7.23      public long getUniqueEvalId();
    7.24 +
    7.25 +    /**
    7.26 +     * Store a compiled script for later reuse
    7.27 +     * @param source the script source
    7.28 +     * @param mainClassName the main class name
    7.29 +     * @param classBytes map of class names to class bytes
    7.30 +     * @param constants constants array
    7.31 +     */
    7.32 +    public void storeCompiledScript(Source source, String mainClassName, Map<String, byte[]> classBytes, Object[] constants);
    7.33  }
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/src/jdk/nashorn/internal/runtime/CodeStore.java	Wed Apr 16 15:05:39 2014 -0700
     8.3 @@ -0,0 +1,179 @@
     8.4 +/*
     8.5 + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
     8.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     8.7 + *
     8.8 + * This code is free software; you can redistribute it and/or modify it
     8.9 + * under the terms of the GNU General Public License version 2 only, as
    8.10 + * published by the Free Software Foundation.  Oracle designates this
    8.11 + * particular file as subject to the "Classpath" exception as provided
    8.12 + * by Oracle in the LICENSE file that accompanied this code.
    8.13 + *
    8.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    8.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    8.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    8.17 + * version 2 for more details (a copy is included in the LICENSE file that
    8.18 + * accompanied this code).
    8.19 + *
    8.20 + * You should have received a copy of the GNU General Public License version
    8.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    8.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    8.23 + *
    8.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    8.25 + * or visit www.oracle.com if you need additional information or have any
    8.26 + * questions.
    8.27 + */
    8.28 +
    8.29 +package jdk.nashorn.internal.runtime;
    8.30 +
    8.31 +import java.io.BufferedInputStream;
    8.32 +import java.io.BufferedOutputStream;
    8.33 +import java.io.File;
    8.34 +import java.io.FileInputStream;
    8.35 +import java.io.FileOutputStream;
    8.36 +import java.io.IOException;
    8.37 +import java.io.ObjectInputStream;
    8.38 +import java.io.ObjectOutputStream;
    8.39 +import java.io.Serializable;
    8.40 +import java.security.AccessController;
    8.41 +import java.security.PrivilegedActionException;
    8.42 +import java.security.PrivilegedExceptionAction;
    8.43 +import java.util.Base64;
    8.44 +import java.util.Map;
    8.45 +
    8.46 +/**
    8.47 + * A code cache for persistent caching of compiled scripts.
    8.48 + */
    8.49 +final class CodeStore {
    8.50 +
    8.51 +    private final File dir;
    8.52 +    private final int minSize;
    8.53 +
    8.54 +    // Message digest to file name encoder
    8.55 +    private final static Base64.Encoder BASE64 = Base64.getUrlEncoder().withoutPadding();
    8.56 +
    8.57 +    // Default minimum size for storing a compiled script class
    8.58 +    private final static int DEFAULT_MIN_SIZE = 1000;
    8.59 +
    8.60 +    /**
    8.61 +     * Constructor
    8.62 +     * @param path directory to store code in
    8.63 +     * @throws IOException
    8.64 +     */
    8.65 +    public CodeStore(final String path) throws IOException {
    8.66 +        this(path, DEFAULT_MIN_SIZE);
    8.67 +    }
    8.68 +
    8.69 +    /**
    8.70 +     * Constructor
    8.71 +     * @param path directory to store code in
    8.72 +     * @param minSize minimum file size for caching scripts
    8.73 +     * @throws IOException
    8.74 +     */
    8.75 +    public CodeStore(final String path, final int minSize) throws IOException {
    8.76 +        this.dir = checkDirectory(path);
    8.77 +        this.minSize = minSize;
    8.78 +    }
    8.79 +
    8.80 +    private static File checkDirectory(final String path) throws IOException {
    8.81 +        try {
    8.82 +            return AccessController.doPrivileged(new PrivilegedExceptionAction<File>() {
    8.83 +                @Override
    8.84 +                public File run() throws IOException {
    8.85 +                    final File dir = new File(path).getAbsoluteFile();
    8.86 +                    if (!dir.exists() && !dir.mkdirs()) {
    8.87 +                        throw new IOException("Could not create directory: " + dir);
    8.88 +                    } else if (!dir.isDirectory()) {
    8.89 +                        throw new IOException("Not a directory: " + dir);
    8.90 +                    } else if (!dir.canRead() || !dir.canWrite()) {
    8.91 +                        throw new IOException("Directory not readable or writable: " + dir);
    8.92 +                    }
    8.93 +                    return dir;
    8.94 +                }
    8.95 +            });
    8.96 +        } catch (PrivilegedActionException e) {
    8.97 +            throw (IOException) e.getException();
    8.98 +        }
    8.99 +    }
   8.100 +
   8.101 +    /**
   8.102 +     * Return a compiled script from the cache, or null if it isn't found.
   8.103 +     *
   8.104 +     * @param source the source
   8.105 +     * @return the compiled script or null
   8.106 +     * @throws IOException
   8.107 +     * @throws ClassNotFoundException
   8.108 +     */
   8.109 +    public CompiledScript getScript(final Source source) throws IOException, ClassNotFoundException {
   8.110 +        if (source.getLength() < minSize) {
   8.111 +            return null;
   8.112 +        }
   8.113 +
   8.114 +        final String digest = BASE64.encodeToString(source.getDigest());
   8.115 +        final File file = new File(dir, digest);
   8.116 +
   8.117 +        try {
   8.118 +            return AccessController.doPrivileged(new PrivilegedExceptionAction<CompiledScript>() {
   8.119 +                @Override
   8.120 +                public CompiledScript run() throws IOException, ClassNotFoundException {
   8.121 +                    if (!file.exists()) {
   8.122 +                        return null;
   8.123 +                    }
   8.124 +                    try (ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(new FileInputStream(file)))) {
   8.125 +                        CompiledScript compiledScript = (CompiledScript) in.readObject();
   8.126 +                        compiledScript.setSource(source);
   8.127 +                        return compiledScript;
   8.128 +                    }
   8.129 +                }
   8.130 +            });
   8.131 +        } catch (PrivilegedActionException e) {
   8.132 +            final Exception ex = e.getException();
   8.133 +            if (ex instanceof IOException) {
   8.134 +                throw  (IOException) ex;
   8.135 +            } else if (ex instanceof ClassNotFoundException) {
   8.136 +                throw (ClassNotFoundException) ex;
   8.137 +            }
   8.138 +            throw (new RuntimeException(ex));
   8.139 +        }
   8.140 +    }
   8.141 +
   8.142 +    /**
   8.143 +     * Store a compiled script in the cache.
   8.144 +     *
   8.145 +     * @param source the source
   8.146 +     * @param mainClassName the main class name
   8.147 +     * @param classBytes a map of class bytes
   8.148 +     * @param constants the constants array
   8.149 +     * @throws IOException
   8.150 +     */
   8.151 +    public void putScript(final Source source, final String mainClassName, final Map<String, byte[]> classBytes, final Object[] constants)
   8.152 +            throws IOException {
   8.153 +        if (source.getLength() < minSize) {
   8.154 +            return;
   8.155 +        }
   8.156 +        for (final Object constant : constants) {
   8.157 +            // Make sure all constant data is serializable
   8.158 +            if (! (constant instanceof Serializable)) {
   8.159 +                return;
   8.160 +            }
   8.161 +        }
   8.162 +
   8.163 +        final String digest = BASE64.encodeToString(source.getDigest());
   8.164 +        final File file = new File(dir, digest);
   8.165 +        final CompiledScript script = new CompiledScript(source, mainClassName, classBytes, constants);
   8.166 +
   8.167 +        try {
   8.168 +            AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
   8.169 +                @Override
   8.170 +                public Void run() throws IOException {
   8.171 +                    try (ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(file)))) {
   8.172 +                        out.writeObject(script);
   8.173 +                    }
   8.174 +                    return null;
   8.175 +                }
   8.176 +            });
   8.177 +        } catch (PrivilegedActionException e) {
   8.178 +             throw (IOException) e.getException();
   8.179 +        }
   8.180 +    }
   8.181 +}
   8.182 +
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/src/jdk/nashorn/internal/runtime/CompiledScript.java	Wed Apr 16 15:05:39 2014 -0700
     9.3 @@ -0,0 +1,127 @@
     9.4 +/*
     9.5 + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
     9.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     9.7 + *
     9.8 + * This code is free software; you can redistribute it and/or modify it
     9.9 + * under the terms of the GNU General Public License version 2 only, as
    9.10 + * published by the Free Software Foundation.  Oracle designates this
    9.11 + * particular file as subject to the "Classpath" exception as provided
    9.12 + * by Oracle in the LICENSE file that accompanied this code.
    9.13 + *
    9.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    9.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    9.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    9.17 + * version 2 for more details (a copy is included in the LICENSE file that
    9.18 + * accompanied this code).
    9.19 + *
    9.20 + * You should have received a copy of the GNU General Public License version
    9.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    9.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    9.23 + *
    9.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    9.25 + * or visit www.oracle.com if you need additional information or have any
    9.26 + * questions.
    9.27 + */
    9.28 +
    9.29 +package jdk.nashorn.internal.runtime;
    9.30 +
    9.31 +import java.io.Serializable;
    9.32 +import java.util.Arrays;
    9.33 +import java.util.Map;
    9.34 +
    9.35 +/**
    9.36 + * Class representing a compiled script.
    9.37 + */
    9.38 +final class CompiledScript implements Serializable {
    9.39 +
    9.40 +    /** Main class name. */
    9.41 +    private final String mainClassName;
    9.42 +
    9.43 +    /** Map of class names to class bytes. */
    9.44 +    private final Map<String, byte[]> classBytes;
    9.45 +
    9.46 +    /** Constants array. */
    9.47 +    private final Object[] constants;
    9.48 +
    9.49 +    /** The source */
    9.50 +    private transient Source source;
    9.51 +
    9.52 +    private static final long serialVersionUID = 2958227232195298340L;
    9.53 +
    9.54 +    /**
    9.55 +     * Constructor.
    9.56 +     *
    9.57 +     * @param mainClassName main class name
    9.58 +     * @param classBytes map of class names to class bytes
    9.59 +     * @param constants constants array
    9.60 +     */
    9.61 +    CompiledScript(final Source source, final String mainClassName, final Map<String, byte[]> classBytes, final Object[] constants) {
    9.62 +        this.source = source;
    9.63 +        this.mainClassName = mainClassName;
    9.64 +        this.classBytes = classBytes;
    9.65 +        this.constants = constants;
    9.66 +    }
    9.67 +
    9.68 +    /**
    9.69 +     * Returns the main class name.
    9.70 +     * @return the main class name
    9.71 +     */
    9.72 +    public String getMainClassName() {
    9.73 +        return mainClassName;
    9.74 +    }
    9.75 +
    9.76 +    /**
    9.77 +     * Returns a map of class names to class bytes.
    9.78 +     * @return map of class bytes
    9.79 +     */
    9.80 +    public Map<String, byte[]> getClassBytes() {
    9.81 +        return classBytes;
    9.82 +    }
    9.83 +
    9.84 +    /**
    9.85 +     * Returns the constants array.
    9.86 +     * @return constants array
    9.87 +     */
    9.88 +    public Object[] getConstants() {
    9.89 +        return constants;
    9.90 +    }
    9.91 +
    9.92 +    /**
    9.93 +     * Returns the source of this cached script.
    9.94 +     * @return the source
    9.95 +     */
    9.96 +    public Source getSource() {
    9.97 +        return source;
    9.98 +    }
    9.99 +
   9.100 +    /**
   9.101 +     * Sets the source of this cached script.
   9.102 +     * @param source the source
   9.103 +     */
   9.104 +    void setSource(final Source source) {
   9.105 +        this.source = source;
   9.106 +    }
   9.107 +
   9.108 +    @Override
   9.109 +    public int hashCode() {
   9.110 +        int hash = mainClassName.hashCode();
   9.111 +        hash = 31 * hash + classBytes.hashCode();
   9.112 +        hash = 31 * hash + Arrays.hashCode(constants);
   9.113 +        return hash;
   9.114 +    }
   9.115 +
   9.116 +    @Override
   9.117 +    public boolean equals(Object obj) {
   9.118 +        if (obj == this) {
   9.119 +            return true;
   9.120 +        }
   9.121 +        if (!(obj instanceof CompiledScript)) {
   9.122 +            return false;
   9.123 +        }
   9.124 +
   9.125 +        final CompiledScript cs = (CompiledScript) obj;
   9.126 +        return mainClassName.equals(cs.mainClassName)
   9.127 +                && classBytes.equals(cs.classBytes)
   9.128 +                && Arrays.equals(constants, cs.constants);
   9.129 +    }
   9.130 +}
    10.1 --- a/src/jdk/nashorn/internal/runtime/Context.java	Wed Apr 16 12:32:47 2014 -0700
    10.2 +++ b/src/jdk/nashorn/internal/runtime/Context.java	Wed Apr 16 15:05:39 2014 -0700
    10.3 @@ -25,7 +25,9 @@
    10.4  
    10.5  package jdk.nashorn.internal.runtime;
    10.6  
    10.7 +import static jdk.nashorn.internal.codegen.CompilerConstants.CONSTANTS;
    10.8  import static jdk.nashorn.internal.codegen.CompilerConstants.RUN_SCRIPT;
    10.9 +import static jdk.nashorn.internal.codegen.CompilerConstants.SOURCE;
   10.10  import static jdk.nashorn.internal.codegen.CompilerConstants.STRICT_MODE;
   10.11  import static jdk.nashorn.internal.lookup.Lookup.MH;
   10.12  import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
   10.13 @@ -38,6 +40,7 @@
   10.14  import java.lang.invoke.MethodHandles;
   10.15  import java.lang.ref.ReferenceQueue;
   10.16  import java.lang.ref.SoftReference;
   10.17 +import java.lang.reflect.Field;
   10.18  import java.lang.reflect.Modifier;
   10.19  import java.util.concurrent.atomic.AtomicLong;
   10.20  import java.net.MalformedURLException;
   10.21 @@ -48,7 +51,10 @@
   10.22  import java.security.CodeSource;
   10.23  import java.security.Permissions;
   10.24  import java.security.PrivilegedAction;
   10.25 +import java.security.PrivilegedActionException;
   10.26 +import java.security.PrivilegedExceptionAction;
   10.27  import java.security.ProtectionDomain;
   10.28 +import java.util.HashMap;
   10.29  import java.util.LinkedHashMap;
   10.30  import java.util.Map;
   10.31  
   10.32 @@ -134,8 +140,32 @@
   10.33          }
   10.34  
   10.35          @Override
   10.36 -        public Class<?> install(final String className, final byte[] bytecode) {
   10.37 -            return loader.installClass(className, bytecode, codeSource);
   10.38 +        public Class<?> install(final String className, final byte[] bytecode, final Source source, final Object[] constants) {
   10.39 +            Compiler.LOG.fine("Installing class ", className);
   10.40 +
   10.41 +            final String   binaryName = Compiler.binaryName(className);
   10.42 +            final Class<?> clazz      = loader.installClass(binaryName, bytecode, codeSource);
   10.43 +
   10.44 +            try {
   10.45 +                // Need doPrivileged because these fields are private
   10.46 +                AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
   10.47 +                    @Override
   10.48 +                    public Void run() throws Exception {
   10.49 +                        //use reflection to write source and constants table to installed classes
   10.50 +                        final Field sourceField    = clazz.getDeclaredField(SOURCE.symbolName());
   10.51 +                        final Field constantsField = clazz.getDeclaredField(CONSTANTS.symbolName());
   10.52 +                        sourceField.setAccessible(true);
   10.53 +                        constantsField.setAccessible(true);
   10.54 +                        sourceField.set(null, source);
   10.55 +                        constantsField.set(null, constants);
   10.56 +                        return null;
   10.57 +                    }
   10.58 +                });
   10.59 +            } catch (final PrivilegedActionException e) {
   10.60 +                throw new RuntimeException(e);
   10.61 +            }
   10.62 +
   10.63 +            return clazz;
   10.64          }
   10.65  
   10.66          @Override
   10.67 @@ -152,6 +182,18 @@
   10.68          public long getUniqueEvalId() {
   10.69              return context.getUniqueEvalId();
   10.70          }
   10.71 +
   10.72 +        @Override
   10.73 +        public void storeCompiledScript(final Source source, final String mainClassName,
   10.74 +                                        final Map<String, byte[]> classBytes, final Object[] constants) {
   10.75 +            if (context.codeStore != null) {
   10.76 +                try {
   10.77 +                    context.codeStore.putScript(source, mainClassName, classBytes, constants);
   10.78 +                } catch (final IOException e) {
   10.79 +                    throw new RuntimeException(e);
   10.80 +                }
   10.81 +            }
   10.82 +        }
   10.83      }
   10.84  
   10.85      /** Is Context global debug mode enabled ? */
   10.86 @@ -159,9 +201,12 @@
   10.87  
   10.88      private static final ThreadLocal<Global> currentGlobal = new ThreadLocal<>();
   10.89  
   10.90 -    // class cache
   10.91 +    // in-memory cache for loaded classes
   10.92      private ClassCache classCache;
   10.93  
   10.94 +    // persistent code store
   10.95 +    private CodeStore codeStore;
   10.96 +
   10.97      /**
   10.98       * Get the current global scope
   10.99       * @return the current global scope
  10.100 @@ -369,6 +414,19 @@
  10.101              classCache = new ClassCache(cacheSize);
  10.102          }
  10.103  
  10.104 +        if (env._persistent_cache) {
  10.105 +            if (env._lazy_compilation || env._specialize_calls != null) {
  10.106 +                getErr().println("Can not use persistent class caching with lazy compilation or call specialization.");
  10.107 +            } else {
  10.108 +                try {
  10.109 +                    final String cacheDir = Options.getStringProperty("nashorn.persistent.code.cache", "nashorn_code_cache");
  10.110 +                    codeStore = new CodeStore(cacheDir);
  10.111 +                } catch (IOException e) {
  10.112 +                    throw new RuntimeException("Error initializing code cache", e);
  10.113 +                }
  10.114 +            }
  10.115 +        }
  10.116 +
  10.117          // print version info if asked.
  10.118          if (env._version) {
  10.119              getErr().println("nashorn " + Version.version());
  10.120 @@ -933,17 +991,32 @@
  10.121              return script;
  10.122          }
  10.123  
  10.124 -        final FunctionNode functionNode = new Parser(env, source, errMan, strict).parse();
  10.125 -        if (errors.hasErrors()) {
  10.126 -            return null;
  10.127 +        CompiledScript compiledScript = null;
  10.128 +        FunctionNode functionNode = null;
  10.129 +
  10.130 +        if (!env._parse_only && codeStore != null) {
  10.131 +            try {
  10.132 +                compiledScript = codeStore.getScript(source);
  10.133 +            } catch (IOException | ClassNotFoundException e) {
  10.134 +                Compiler.LOG.warning("Error loading ", source, " from cache: ", e);
  10.135 +                // Fall back to normal compilation
  10.136 +            }
  10.137          }
  10.138  
  10.139 -        if (env._print_ast) {
  10.140 -            getErr().println(new ASTWriter(functionNode));
  10.141 -        }
  10.142 +        if (compiledScript == null) {
  10.143 +            functionNode = new Parser(env, source, errMan, strict).parse();
  10.144  
  10.145 -        if (env._print_parse) {
  10.146 -            getErr().println(new PrintVisitor(functionNode));
  10.147 +            if (errors.hasErrors()) {
  10.148 +                return null;
  10.149 +            }
  10.150 +
  10.151 +            if (env._print_ast) {
  10.152 +                getErr().println(new ASTWriter(functionNode));
  10.153 +            }
  10.154 +
  10.155 +            if (env._print_parse) {
  10.156 +                getErr().println(new PrintVisitor(functionNode));
  10.157 +            }
  10.158          }
  10.159  
  10.160          if (env._parse_only) {
  10.161 @@ -955,12 +1028,15 @@
  10.162          final CodeSource   cs     = new CodeSource(url, (CodeSigner[])null);
  10.163          final CodeInstaller<ScriptEnvironment> installer = new ContextCodeInstaller(this, loader, cs);
  10.164  
  10.165 -        final Compiler compiler = new Compiler(installer, strict);
  10.166 +        if (functionNode != null) {
  10.167 +            final Compiler compiler = new Compiler(installer, strict);
  10.168 +            final FunctionNode newFunctionNode = compiler.compile(functionNode);
  10.169 +            script = compiler.install(newFunctionNode);
  10.170 +        } else {
  10.171 +            script = install(compiledScript, installer);
  10.172 +        }
  10.173  
  10.174 -        final FunctionNode newFunctionNode = compiler.compile(functionNode);
  10.175 -        script = compiler.install(newFunctionNode);
  10.176          cacheClass(source, script);
  10.177 -
  10.178          return script;
  10.179      }
  10.180  
  10.181 @@ -982,6 +1058,42 @@
  10.182          return uniqueScriptId.getAndIncrement();
  10.183      }
  10.184  
  10.185 +
  10.186 +    /**
  10.187 +     * Install a previously compiled class from the code cache.
  10.188 +     *
  10.189 +     * @param compiledScript cached script containing class bytes and constants
  10.190 +     * @return main script class
  10.191 +     */
  10.192 +    private Class<?> install(final CompiledScript compiledScript, final CodeInstaller<ScriptEnvironment> installer) {
  10.193 +
  10.194 +        final Map<String, Class<?>> installedClasses = new HashMap<>();
  10.195 +        final Source   source        = compiledScript.getSource();
  10.196 +        final Object[] constants     = compiledScript.getConstants();
  10.197 +        final String   rootClassName = compiledScript.getMainClassName();
  10.198 +        final byte[]   rootByteCode  = compiledScript.getClassBytes().get(rootClassName);
  10.199 +        final Class<?> rootClass     = installer.install(rootClassName, rootByteCode, source, constants);
  10.200 +
  10.201 +        installedClasses.put(rootClassName, rootClass);
  10.202 +
  10.203 +        for (final Map.Entry<String, byte[]> entry : compiledScript.getClassBytes().entrySet()) {
  10.204 +            final String className = entry.getKey();
  10.205 +            if (className.equals(rootClassName)) {
  10.206 +                continue;
  10.207 +            }
  10.208 +            final byte[] code = entry.getValue();
  10.209 +
  10.210 +            installedClasses.put(className, installer.install(className, code, source, constants));
  10.211 +        }
  10.212 +        for (Object constant : constants) {
  10.213 +            if (constant instanceof RecompilableScriptFunctionData) {
  10.214 +                ((RecompilableScriptFunctionData) constant).setCodeAndSource(installedClasses, source);
  10.215 +            }
  10.216 +        }
  10.217 +
  10.218 +        return rootClass;
  10.219 +    }
  10.220 +
  10.221      /**
  10.222       * Cache for compiled script classes.
  10.223       */
    11.1 --- a/src/jdk/nashorn/internal/runtime/JSType.java	Wed Apr 16 12:32:47 2014 -0700
    11.2 +++ b/src/jdk/nashorn/internal/runtime/JSType.java	Wed Apr 16 15:05:39 2014 -0700
    11.3 @@ -438,7 +438,9 @@
    11.4  
    11.5          // encode integer part from least significant digit, then reverse
    11.6          do {
    11.7 -            sb.append(chars.charAt((int) (intPart % radix)));
    11.8 +            final double remainder = intPart % radix;
    11.9 +            sb.append(chars.charAt((int) remainder));
   11.10 +            intPart -= remainder;
   11.11              intPart /= radix;
   11.12          } while (intPart >= 1.0);
   11.13  
    12.1 --- a/src/jdk/nashorn/internal/runtime/Property.java	Wed Apr 16 12:32:47 2014 -0700
    12.2 +++ b/src/jdk/nashorn/internal/runtime/Property.java	Wed Apr 16 15:05:39 2014 -0700
    12.3 @@ -29,6 +29,7 @@
    12.4  import static jdk.nashorn.internal.runtime.PropertyDescriptor.ENUMERABLE;
    12.5  import static jdk.nashorn.internal.runtime.PropertyDescriptor.WRITABLE;
    12.6  
    12.7 +import java.io.Serializable;
    12.8  import java.lang.invoke.MethodHandle;
    12.9  import java.util.Objects;
   12.10  import jdk.nashorn.internal.codegen.ObjectClassGenerator;
   12.11 @@ -43,7 +44,7 @@
   12.12   * @see AccessorProperty
   12.13   * @see UserAccessorProperty
   12.14   */
   12.15 -public abstract class Property {
   12.16 +public abstract class Property implements Serializable {
   12.17      /*
   12.18       * ECMA 8.6.1 Property Attributes
   12.19       *
   12.20 @@ -100,6 +101,8 @@
   12.21      /** Property field number or spill slot. */
   12.22      private final int slot;
   12.23  
   12.24 +    private static final long serialVersionUID = 2099814273074501176L;
   12.25 +
   12.26      /**
   12.27       * Constructor
   12.28       *
   12.29 @@ -358,6 +361,13 @@
   12.30      public abstract MethodHandle getGetter(final Class<?> type);
   12.31  
   12.32      /**
   12.33 +     * Hook to initialize method handles after deserialization.
   12.34 +     *
   12.35 +     * @param structure the structure class
   12.36 +     */
   12.37 +    abstract void initMethodHandles(final Class<?> structure);
   12.38 +
   12.39 +    /**
   12.40       * Get the key for this property. This key is an ordinary string. The "name".
   12.41       * @return key for property
   12.42       */
    13.1 --- a/src/jdk/nashorn/internal/runtime/PropertyMap.java	Wed Apr 16 12:32:47 2014 -0700
    13.2 +++ b/src/jdk/nashorn/internal/runtime/PropertyMap.java	Wed Apr 16 15:05:39 2014 -0700
    13.3 @@ -29,6 +29,10 @@
    13.4  import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndex;
    13.5  import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex;
    13.6  
    13.7 +import java.io.IOException;
    13.8 +import java.io.ObjectInputStream;
    13.9 +import java.io.ObjectOutputStream;
   13.10 +import java.io.Serializable;
   13.11  import java.lang.invoke.SwitchPoint;
   13.12  import java.lang.ref.SoftReference;
   13.13  import java.util.Arrays;
   13.14 @@ -37,6 +41,7 @@
   13.15  import java.util.Iterator;
   13.16  import java.util.NoSuchElementException;
   13.17  import java.util.WeakHashMap;
   13.18 +import jdk.nashorn.internal.scripts.JO;
   13.19  
   13.20  /**
   13.21   * Map of object properties. The PropertyMap is the "template" for JavaScript object
   13.22 @@ -47,7 +52,7 @@
   13.23   * All property maps are immutable. If a property is added, modified or removed, the mutator
   13.24   * will return a new map.
   13.25   */
   13.26 -public final class PropertyMap implements Iterable<Object> {
   13.27 +public final class PropertyMap implements Iterable<Object>, Serializable {
   13.28      /** Used for non extensible PropertyMaps, negative logic as the normal case is extensible. See {@link ScriptObject#preventExtensions()} */
   13.29      public static final int NOT_EXTENSIBLE        = 0b0000_0001;
   13.30      /** Does this map contain valid array keys? */
   13.31 @@ -57,7 +62,7 @@
   13.32      private int flags;
   13.33  
   13.34      /** Map of properties. */
   13.35 -    private final PropertyHashMap properties;
   13.36 +    private transient PropertyHashMap properties;
   13.37  
   13.38      /** Number of fields in use. */
   13.39      private int fieldCount;
   13.40 @@ -68,17 +73,22 @@
   13.41      /** Length of spill in use. */
   13.42      private int spillLength;
   13.43  
   13.44 +    /** Structure class name */
   13.45 +    private String className;
   13.46 +
   13.47      /** {@link SwitchPoint}s for gets on inherited properties. */
   13.48 -    private HashMap<String, SwitchPoint> protoGetSwitches;
   13.49 +    private transient HashMap<String, SwitchPoint> protoGetSwitches;
   13.50  
   13.51      /** History of maps, used to limit map duplication. */
   13.52 -    private WeakHashMap<Property, SoftReference<PropertyMap>> history;
   13.53 +    private transient WeakHashMap<Property, SoftReference<PropertyMap>> history;
   13.54  
   13.55      /** History of prototypes, used to limit map duplication. */
   13.56 -    private WeakHashMap<PropertyMap, SoftReference<PropertyMap>> protoHistory;
   13.57 +    private transient WeakHashMap<PropertyMap, SoftReference<PropertyMap>> protoHistory;
   13.58  
   13.59      /** property listeners */
   13.60 -    private PropertyListeners listeners;
   13.61 +    private transient PropertyListeners listeners;
   13.62 +
   13.63 +    private static final long serialVersionUID = -7041836752008732533L;
   13.64  
   13.65      /**
   13.66       * Constructor.
   13.67 @@ -89,8 +99,10 @@
   13.68       * @param spillLength  Number of spill slots used.
   13.69       * @param containsArrayKeys True if properties contain numeric keys
   13.70       */
   13.71 -    private PropertyMap(final PropertyHashMap properties, final int fieldCount, final int fieldMaximum, final int spillLength, final boolean containsArrayKeys) {
   13.72 +    private PropertyMap(final PropertyHashMap properties, final String className, final int fieldCount,
   13.73 +                        final int fieldMaximum, final int spillLength, final boolean containsArrayKeys) {
   13.74          this.properties   = properties;
   13.75 +        this.className    = className;
   13.76          this.fieldCount   = fieldCount;
   13.77          this.fieldMaximum = fieldMaximum;
   13.78          this.spillLength  = spillLength;
   13.79 @@ -145,7 +157,25 @@
   13.80          if (Context.DEBUG) {
   13.81              duplicatedCount++;
   13.82          }
   13.83 -        return new PropertyMap(this.properties, 0, 0, 0, containsArrayKeys());
   13.84 +        return new PropertyMap(this.properties, this.className, 0, 0, 0, containsArrayKeys());
   13.85 +    }
   13.86 +
   13.87 +    private void writeObject(final ObjectOutputStream out) throws IOException {
   13.88 +        out.defaultWriteObject();
   13.89 +        out.writeObject(properties.getProperties());
   13.90 +    }
   13.91 +
   13.92 +    private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
   13.93 +        in.defaultReadObject();
   13.94 +
   13.95 +        final Property[] props = (Property[]) in.readObject();
   13.96 +        this.properties = EMPTY_HASHMAP.immutableAdd(props);
   13.97 +
   13.98 +        assert className != null;
   13.99 +        final Class<?> structure = Context.forStructureClass(className);
  13.100 +        for (Property prop : props) {
  13.101 +            prop.initMethodHandles(structure);
  13.102 +        }
  13.103      }
  13.104  
  13.105      /**
  13.106 @@ -160,9 +190,9 @@
  13.107       * @param spillLength  Number of used spill slots.
  13.108       * @return New {@link PropertyMap}.
  13.109       */
  13.110 -    public static PropertyMap newMap(final Collection<Property> properties, final int fieldCount, final int fieldMaximum,  final int spillLength) {
  13.111 +    public static PropertyMap newMap(final Collection<Property> properties, final String className, final int fieldCount, final int fieldMaximum,  final int spillLength) {
  13.112          PropertyHashMap newProperties = EMPTY_HASHMAP.immutableAdd(properties);
  13.113 -        return new PropertyMap(newProperties, fieldCount, fieldMaximum, spillLength, false);
  13.114 +        return new PropertyMap(newProperties, className, fieldCount, fieldMaximum, spillLength, false);
  13.115      }
  13.116  
  13.117      /**
  13.118 @@ -175,7 +205,7 @@
  13.119       * @return New {@link PropertyMap}.
  13.120       */
  13.121      public static PropertyMap newMap(final Collection<Property> properties) {
  13.122 -        return (properties == null || properties.isEmpty())? newMap() : newMap(properties, 0, 0, 0);
  13.123 +        return (properties == null || properties.isEmpty())? newMap() : newMap(properties, JO.class.getName(), 0, 0, 0);
  13.124      }
  13.125  
  13.126      /**
  13.127 @@ -184,7 +214,7 @@
  13.128       * @return New empty {@link PropertyMap}.
  13.129       */
  13.130      public static PropertyMap newMap() {
  13.131 -        return new PropertyMap(EMPTY_HASHMAP, 0, 0, 0, false);
  13.132 +        return new PropertyMap(EMPTY_HASHMAP, JO.class.getName(), 0, 0, 0, false);
  13.133      }
  13.134  
  13.135      /**
    14.1 --- a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Wed Apr 16 12:32:47 2014 -0700
    14.2 +++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Wed Apr 16 15:05:39 2014 -0700
    14.3 @@ -27,14 +27,15 @@
    14.4  
    14.5  import static jdk.nashorn.internal.lookup.Lookup.MH;
    14.6  
    14.7 +import java.io.Serializable;
    14.8  import java.lang.invoke.MethodHandle;
    14.9  import java.lang.invoke.MethodHandles;
   14.10  import java.lang.invoke.MethodType;
   14.11  import java.util.ArrayList;
   14.12  import java.util.Arrays;
   14.13  import java.util.LinkedList;
   14.14 +import java.util.Map;
   14.15  import jdk.internal.dynalink.support.NameCodec;
   14.16 -
   14.17  import jdk.nashorn.internal.codegen.Compiler;
   14.18  import jdk.nashorn.internal.codegen.CompilerConstants;
   14.19  import jdk.nashorn.internal.codegen.FunctionSignature;
   14.20 @@ -43,6 +44,7 @@
   14.21  import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
   14.22  import jdk.nashorn.internal.parser.Token;
   14.23  import jdk.nashorn.internal.parser.TokenType;
   14.24 +import jdk.nashorn.internal.scripts.JS;
   14.25  
   14.26  /**
   14.27   * This is a subclass that represents a script function that may be regenerated,
   14.28 @@ -50,13 +52,19 @@
   14.29   * The common denominator is that it can get new invokers during its lifespan,
   14.30   * unlike {@code FinalScriptFunctionData}
   14.31   */
   14.32 -public final class RecompilableScriptFunctionData extends ScriptFunctionData {
   14.33 +public final class RecompilableScriptFunctionData extends ScriptFunctionData implements Serializable {
   14.34  
   14.35      /** FunctionNode with the code for this ScriptFunction */
   14.36 -    private FunctionNode functionNode;
   14.37 +    private transient FunctionNode functionNode;
   14.38  
   14.39      /** Source from which FunctionNode was parsed. */
   14.40 -    private final Source source;
   14.41 +    private transient Source source;
   14.42 +
   14.43 +    /** The line number where this function begins. */
   14.44 +    private final int lineNumber;
   14.45 +
   14.46 +    /** Allows us to retrieve the method handle for this function once the code is compiled */
   14.47 +    private MethodLocator methodLocator;
   14.48  
   14.49      /** Token of this function within the source. */
   14.50      private final long token;
   14.51 @@ -65,13 +73,13 @@
   14.52      private final PropertyMap allocatorMap;
   14.53  
   14.54      /** Code installer used for all further recompilation/specialization of this ScriptFunction */
   14.55 -    private CodeInstaller<ScriptEnvironment> installer;
   14.56 +    private transient CodeInstaller<ScriptEnvironment> installer;
   14.57  
   14.58      /** Name of class where allocator function resides */
   14.59      private final String allocatorClassName;
   14.60  
   14.61      /** lazily generated allocator */
   14.62 -    private MethodHandle allocator;
   14.63 +    private transient MethodHandle allocator;
   14.64  
   14.65      private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
   14.66  
   14.67 @@ -79,7 +87,7 @@
   14.68       * Used for specialization based on runtime arguments. Whenever we specialize on
   14.69       * callsite parameter types at runtime, we need to use a parameter type guard to
   14.70       * ensure that the specialized version of the script function continues to be
   14.71 -     * applicable for a particular callsite *
   14.72 +     * applicable for a particular callsite.
   14.73       */
   14.74      private static final MethodHandle PARAM_TYPE_GUARD = findOwnMH("paramTypeGuard", boolean.class, Type[].class,  Object[].class);
   14.75  
   14.76 @@ -88,10 +96,12 @@
   14.77       * (or java.lang.Number instance) to specialize the parameter to an integer, if the
   14.78       * parameter in question can be represented as one. The double typically only exists
   14.79       * because the compiler doesn't know any better than "a number type" and conservatively
   14.80 -     * picks doubles when it can't prove that an integer addition wouldn't overflow
   14.81 +     * picks doubles when it can't prove that an integer addition wouldn't overflow.
   14.82       */
   14.83      private static final MethodHandle ENSURE_INT = findOwnMH("ensureInt", int.class, Object.class);
   14.84  
   14.85 +    private static final long serialVersionUID = 4914839316174633726L;
   14.86 +
   14.87      /**
   14.88       * Constructor - public as scripts use it
   14.89       *
   14.90 @@ -104,13 +114,16 @@
   14.91          super(functionName(functionNode),
   14.92                functionNode.getParameters().size(),
   14.93                getFlags(functionNode));
   14.94 -
   14.95          this.functionNode       = functionNode;
   14.96          this.source             = functionNode.getSource();
   14.97 +        this.lineNumber         = functionNode.getLineNumber();
   14.98          this.token              = tokenFor(functionNode);
   14.99          this.installer          = installer;
  14.100          this.allocatorClassName = allocatorClassName;
  14.101          this.allocatorMap       = allocatorMap;
  14.102 +        if (!functionNode.isLazy()) {
  14.103 +            methodLocator = new MethodLocator(functionNode);
  14.104 +        }
  14.105      }
  14.106  
  14.107      @Override
  14.108 @@ -122,16 +135,19 @@
  14.109          return "function " + (name == null ? "" : name) + "() { [native code] }";
  14.110      }
  14.111  
  14.112 +    public void setCodeAndSource(final Map<String, Class<?>> code, final Source source) {
  14.113 +        this.source = source;
  14.114 +        if (methodLocator != null) {
  14.115 +            methodLocator.setClass(code.get(methodLocator.getClassName()));
  14.116 +        }
  14.117 +    }
  14.118 +
  14.119      @Override
  14.120      public String toString() {
  14.121          final StringBuilder sb = new StringBuilder();
  14.122  
  14.123          if (source != null) {
  14.124 -            sb.append(source.getName());
  14.125 -            if (functionNode != null) {
  14.126 -                sb.append(':').append(functionNode.getLineNumber());
  14.127 -            }
  14.128 -            sb.append(' ');
  14.129 +            sb.append(source.getName()).append(':').append(lineNumber).append(' ');
  14.130          }
  14.131  
  14.132          return sb.toString() + super.toString();
  14.133 @@ -204,8 +220,13 @@
  14.134              functionNode = compiler.compile(functionNode);
  14.135              assert !functionNode.isLazy();
  14.136              compiler.install(functionNode);
  14.137 +            methodLocator = new MethodLocator(functionNode);
  14.138              flags = getFlags(functionNode);
  14.139          }
  14.140 +
  14.141 +        if (functionNode != null) {
  14.142 +            methodLocator.setClass(functionNode.getCompileUnit().getCode());
  14.143 +        }
  14.144      }
  14.145  
  14.146      @Override
  14.147 @@ -221,12 +242,13 @@
  14.148           * eager compilation or from running a lazy compile on the lines above
  14.149           */
  14.150  
  14.151 -        assert functionNode.hasState(CompilationState.EMITTED) : functionNode.getName() + " " + functionNode.getState() + " " + Debug.id(functionNode);
  14.152 +        assert functionNode == null || functionNode.hasState(CompilationState.EMITTED) :
  14.153 +                    functionNode.getName() + " " + functionNode.getState() + " " + Debug.id(functionNode);
  14.154  
  14.155          // code exists - look it up and add it into the automatically sorted invoker list
  14.156          addCode(functionNode);
  14.157  
  14.158 -        if (! functionNode.canSpecialize()) {
  14.159 +        if (functionNode != null && !functionNode.canSpecialize()) {
  14.160              // allow GC to claim IR stuff that is not needed anymore
  14.161              functionNode = null;
  14.162              installer = null;
  14.163 @@ -238,13 +260,9 @@
  14.164      }
  14.165  
  14.166      private MethodHandle addCode(final FunctionNode fn, final MethodType runtimeType, final MethodHandle guard, final MethodHandle fallback) {
  14.167 -        final MethodType targetType = new FunctionSignature(fn).getMethodType();
  14.168 -        MethodHandle target =
  14.169 -            MH.findStatic(
  14.170 -                    LOOKUP,
  14.171 -                    fn.getCompileUnit().getCode(),
  14.172 -                    fn.getName(),
  14.173 -                    targetType);
  14.174 +        assert methodLocator != null;
  14.175 +        MethodHandle target = methodLocator.getMethodHandle();
  14.176 +        final MethodType targetType = methodLocator.getMethodType();
  14.177  
  14.178          /*
  14.179           * For any integer argument. a double that is representable as an integer is OK.
  14.180 @@ -424,7 +442,6 @@
  14.181  
  14.182          Compiler.LOG.info("Callsite specialized ", name, " runtimeType=", runtimeType, " parameters=", snapshot.getParameters(), " args=", Arrays.asList(args));
  14.183  
  14.184 -        assert snapshot != null;
  14.185          assert snapshot != functionNode;
  14.186  
  14.187          final Compiler compiler = new Compiler(installer);
  14.188 @@ -450,5 +467,45 @@
  14.189          return MH.findStatic(MethodHandles.lookup(), RecompilableScriptFunctionData.class, name, MH.type(rtype, types));
  14.190      }
  14.191  
  14.192 +    /**
  14.193 +     * Helper class that allows us to retrieve the method handle for this function once it has been generated.
  14.194 +     */
  14.195 +    private static class MethodLocator implements Serializable {
  14.196 +        private transient Class<?> clazz;
  14.197 +        private final String className;
  14.198 +        private final String methodName;
  14.199 +        private final MethodType methodType;
  14.200 +
  14.201 +        private static final long serialVersionUID = -5420835725902966692L;
  14.202 +
  14.203 +        MethodLocator(final FunctionNode functionNode) {
  14.204 +            this.className  = functionNode.getCompileUnit().getUnitClassName();
  14.205 +            this.methodName = functionNode.getName();
  14.206 +            this.methodType = new FunctionSignature(functionNode).getMethodType();
  14.207 +
  14.208 +            assert className != null;
  14.209 +            assert methodName != null;
  14.210 +        }
  14.211 +
  14.212 +        void setClass(final Class<?> clazz) {
  14.213 +            if (!JS.class.isAssignableFrom(clazz)) {
  14.214 +                throw new IllegalArgumentException();
  14.215 +            }
  14.216 +            this.clazz = clazz;
  14.217 +        }
  14.218 +
  14.219 +        String getClassName() {
  14.220 +            return className;
  14.221 +        }
  14.222 +
  14.223 +        MethodType getMethodType() {
  14.224 +            return methodType;
  14.225 +        }
  14.226 +
  14.227 +        MethodHandle getMethodHandle() {
  14.228 +            return MH.findStatic(LOOKUP, clazz, methodName, methodType);
  14.229 +        }
  14.230 +    }
  14.231 +
  14.232  }
  14.233  
    15.1 --- a/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java	Wed Apr 16 12:32:47 2014 -0700
    15.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java	Wed Apr 16 15:05:39 2014 -0700
    15.3 @@ -134,6 +134,9 @@
    15.4      /** Only parse the source code, do not compile */
    15.5      public final boolean _parse_only;
    15.6  
    15.7 +    /** Enable disk cache for compiled scripts */
    15.8 +    public final boolean _persistent_cache;
    15.9 +
   15.10      /** Print the AST before lowering */
   15.11      public final boolean _print_ast;
   15.12  
   15.13 @@ -218,6 +221,7 @@
   15.14          _no_syntax_extensions = options.getBoolean("no.syntax.extensions");
   15.15          _no_typed_arrays      = options.getBoolean("no.typed.arrays");
   15.16          _parse_only           = options.getBoolean("parse.only");
   15.17 +        _persistent_cache     = options.getBoolean("persistent.code.cache");
   15.18          _print_ast            = options.getBoolean("print.ast");
   15.19          _print_lower_ast      = options.getBoolean("print.lower.ast");
   15.20          _print_code           = options.getBoolean("print.code");
    16.1 --- a/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java	Wed Apr 16 12:32:47 2014 -0700
    16.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java	Wed Apr 16 15:05:39 2014 -0700
    16.3 @@ -29,10 +29,10 @@
    16.4  import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
    16.5  import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
    16.6  
    16.7 +import java.io.Serializable;
    16.8  import java.lang.invoke.MethodHandle;
    16.9  import java.lang.invoke.MethodHandles;
   16.10  import java.lang.invoke.MethodType;
   16.11 -import jdk.nashorn.internal.objects.Global;
   16.12  import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory;
   16.13  
   16.14  /**
   16.15 @@ -40,7 +40,7 @@
   16.16   * Instances of this class are created during codegen and stored in script classes'
   16.17   * constants array to reduce function instantiation overhead during runtime.
   16.18   */
   16.19 -public abstract class ScriptFunctionData {
   16.20 +public abstract class ScriptFunctionData implements Serializable {
   16.21  
   16.22      /** Name of the function or "" for anonynous functions */
   16.23      protected final String name;
   16.24 @@ -74,6 +74,8 @@
   16.25      /** Flag for strict constructors */
   16.26      public static final int IS_STRICT_CONSTRUCTOR = IS_STRICT | IS_CONSTRUCTOR;
   16.27  
   16.28 +    private static final long serialVersionUID = 4252901245508769114L;
   16.29 +
   16.30      /**
   16.31       * Constructor
   16.32       *
    17.1 --- a/src/jdk/nashorn/internal/runtime/Source.java	Wed Apr 16 12:32:47 2014 -0700
    17.2 +++ b/src/jdk/nashorn/internal/runtime/Source.java	Wed Apr 16 15:05:39 2014 -0700
    17.3 @@ -39,6 +39,8 @@
    17.4  import java.nio.file.Files;
    17.5  import java.nio.file.Path;
    17.6  import java.nio.file.Paths;
    17.7 +import java.security.MessageDigest;
    17.8 +import java.security.NoSuchAlgorithmException;
    17.9  import java.util.Arrays;
   17.10  import java.util.Objects;
   17.11  import jdk.nashorn.internal.parser.Token;
   17.12 @@ -71,6 +73,9 @@
   17.13      /** Cached hash code */
   17.14      private int hash;
   17.15  
   17.16 +    /** Message digest */
   17.17 +    private byte[] digest;
   17.18 +
   17.19      /** Source URL if available */
   17.20      private final URL url;
   17.21  
   17.22 @@ -417,6 +422,40 @@
   17.23      }
   17.24  
   17.25      /**
   17.26 +     * Get a message digest for this source.
   17.27 +     *
   17.28 +     * @return a message digest for this source
   17.29 +     */
   17.30 +    public synchronized byte[] getDigest() {
   17.31 +        if (digest == null) {
   17.32 +
   17.33 +            final byte[] bytes = new byte[content.length * 2];
   17.34 +
   17.35 +            for (int i = 0; i < content.length; i++) {
   17.36 +                bytes[i * 2]     = (byte)  (content[i] & 0x00ff);
   17.37 +                bytes[i * 2 + 1] = (byte) ((content[i] & 0xff00) >> 8);
   17.38 +            }
   17.39 +
   17.40 +            try {
   17.41 +                final MessageDigest md = MessageDigest.getInstance("SHA-1");
   17.42 +                if (name != null) {
   17.43 +                    md.update(name.getBytes(StandardCharsets.UTF_8));
   17.44 +                }
   17.45 +                if (base != null) {
   17.46 +                    md.update(base.getBytes(StandardCharsets.UTF_8));
   17.47 +                }
   17.48 +                if (url != null) {
   17.49 +                    md.update(url.toString().getBytes(StandardCharsets.UTF_8));
   17.50 +                }
   17.51 +                digest = md.digest(bytes);
   17.52 +            } catch (NoSuchAlgorithmException e) {
   17.53 +                throw new RuntimeException(e);
   17.54 +            }
   17.55 +        }
   17.56 +        return digest;
   17.57 +    }
   17.58 +
   17.59 +    /**
   17.60       * Get the base url. This is currently used for testing only
   17.61       * @param url a URL
   17.62       * @return base URL for url
    18.1 --- a/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java	Wed Apr 16 12:32:47 2014 -0700
    18.2 +++ b/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java	Wed Apr 16 15:05:39 2014 -0700
    18.3 @@ -187,6 +187,11 @@
    18.4      }
    18.5  
    18.6      @Override
    18.7 +    void initMethodHandles(final Class<?> structure) {
    18.8 +        throw new UnsupportedOperationException();
    18.9 +    }
   18.10 +
   18.11 +    @Override
   18.12      public ScriptFunction getGetterFunction(final ScriptObject obj) {
   18.13          final Object value = obj.getSpill(getterSlot);
   18.14          return (value instanceof ScriptFunction) ? (ScriptFunction) value : null;
    19.1 --- a/src/jdk/nashorn/internal/runtime/resources/Options.properties	Wed Apr 16 12:32:47 2014 -0700
    19.2 +++ b/src/jdk/nashorn/internal/runtime/resources/Options.properties	Wed Apr 16 15:05:39 2014 -0700
    19.3 @@ -230,6 +230,14 @@
    19.4      desc="Parse without compiling." \
    19.5  }
    19.6  
    19.7 +nashorn.option.persistent.code.cache = {            \
    19.8 +    name="--persistent-code-cache",                 \
    19.9 +    short_name="-pcc",                              \
   19.10 +    desc="Enable disk cache for compiled scripts.", \
   19.11 +    is_undocumented=true,                           \
   19.12 +    default=false                                   \
   19.13 +}
   19.14 +
   19.15  nashorn.option.profile.callsites = {   \
   19.16      name="--profile-callsites",        \
   19.17      short_name="-pcs",                 \
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/test/script/basic/JDK-8030199.js	Wed Apr 16 15:05:39 2014 -0700
    20.3 @@ -0,0 +1,50 @@
    20.4 +/*
    20.5 + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
    20.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    20.7 + * 
    20.8 + * This code is free software; you can redistribute it and/or modify it
    20.9 + * under the terms of the GNU General Public License version 2 only, as
   20.10 + * published by the Free Software Foundation.
   20.11 + * 
   20.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
   20.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   20.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   20.15 + * version 2 for more details (a copy is included in the LICENSE file that
   20.16 + * accompanied this code).
   20.17 + * 
   20.18 + * You should have received a copy of the GNU General Public License version
   20.19 + * 2 along with this work; if not, write to the Free Software Foundation,
   20.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20.21 + * 
   20.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   20.23 + * or visit www.oracle.com if you need additional information or have any
   20.24 + * questions.
   20.25 + */
   20.26 +
   20.27 +/**
   20.28 + * JDK-8030199: Nashorn: Uint8ClampedArray - Incorrect ToUint8Clamp implementation
   20.29 + *
   20.30 + * @test
   20.31 + * @run
   20.32 + */
   20.33 +
   20.34 +function testTypedArray(ArrayType) {
   20.35 +    print(ArrayType.BYTES_PER_ELEMENT);
   20.36 +    var a = new ArrayType(7);
   20.37 +    a[0] = 4294967296;
   20.38 +    a[1] = -4294967295;
   20.39 +    a[2] = 4294967298;
   20.40 +    a[3] = -4294967298;
   20.41 +    a[4] = Infinity;
   20.42 +    a[5] = -Infinity;
   20.43 +    a[6] = NaN;
   20.44 +    print(Array.prototype.join.call(a));
   20.45 +}
   20.46 +
   20.47 +testTypedArray(Uint8ClampedArray);
   20.48 +testTypedArray(Uint8Array);
   20.49 +testTypedArray(Int8Array);
   20.50 +testTypedArray(Uint16Array);
   20.51 +testTypedArray(Int16Array);
   20.52 +testTypedArray(Uint32Array);
   20.53 +testTypedArray(Int32Array);
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/test/script/basic/JDK-8030199.js.EXPECTED	Wed Apr 16 15:05:39 2014 -0700
    21.3 @@ -0,0 +1,14 @@
    21.4 +1
    21.5 +255,0,255,0,255,0,0
    21.6 +1
    21.7 +0,1,2,254,0,0,0
    21.8 +1
    21.9 +0,1,2,-2,0,0,0
   21.10 +2
   21.11 +0,1,2,65534,0,0,0
   21.12 +2
   21.13 +0,1,2,-2,0,0,0
   21.14 +4
   21.15 +0,1,2,4294967294,0,0,0
   21.16 +4
   21.17 +0,1,2,-2,0,0,0
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/test/script/basic/JDK-8030200.js	Wed Apr 16 15:05:39 2014 -0700
    22.3 @@ -0,0 +1,36 @@
    22.4 +/*
    22.5 + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
    22.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    22.7 + * 
    22.8 + * This code is free software; you can redistribute it and/or modify it
    22.9 + * under the terms of the GNU General Public License version 2 only, as
   22.10 + * published by the Free Software Foundation.
   22.11 + * 
   22.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
   22.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   22.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   22.15 + * version 2 for more details (a copy is included in the LICENSE file that
   22.16 + * accompanied this code).
   22.17 + * 
   22.18 + * You should have received a copy of the GNU General Public License version
   22.19 + * 2 along with this work; if not, write to the Free Software Foundation,
   22.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   22.21 + * 
   22.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22.23 + * or visit www.oracle.com if you need additional information or have any
   22.24 + * questions.
   22.25 + */
   22.26 +
   22.27 +/**
   22.28 + * JDK-8030200: Wrong result for Number.prototype.toString() for certain radix/inputs
   22.29 + *
   22.30 + * @test
   22.31 + * @run
   22.32 + */
   22.33 +
   22.34 +var n = 0x8000000000000800;
   22.35 +print(n);
   22.36 +var s = n.toString(5);
   22.37 +var m = parseInt(s, 5);
   22.38 +print(m === n);
   22.39 +print(n);
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/test/script/basic/JDK-8030200.js.EXPECTED	Wed Apr 16 15:05:39 2014 -0700
    23.3 @@ -0,0 +1,3 @@
    23.4 +9223372036854778000
    23.5 +true
    23.6 +9223372036854778000
    24.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.2 +++ b/test/script/basic/JDK-8039387.js	Wed Apr 16 15:05:39 2014 -0700
    24.3 @@ -0,0 +1,39 @@
    24.4 +/*
    24.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
    24.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    24.7 + * 
    24.8 + * This code is free software; you can redistribute it and/or modify it
    24.9 + * under the terms of the GNU General Public License version 2 only, as
   24.10 + * published by the Free Software Foundation.
   24.11 + * 
   24.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
   24.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   24.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   24.15 + * version 2 for more details (a copy is included in the LICENSE file that
   24.16 + * accompanied this code).
   24.17 + * 
   24.18 + * You should have received a copy of the GNU General Public License version
   24.19 + * 2 along with this work; if not, write to the Free Software Foundation,
   24.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   24.21 + * 
   24.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   24.23 + * or visit www.oracle.com if you need additional information or have any
   24.24 + * questions.
   24.25 + */
   24.26 +
   24.27 +/**
   24.28 + * JDK-8039387: Nashorn supports indexed access of List elements, but length property is not supported
   24.29 + *
   24.30 + * @test
   24.31 + * @run
   24.32 + */
   24.33 +
   24.34 +var ArrayList = Java.type("java.util.ArrayList")
   24.35 +var list = new ArrayList(3)
   24.36 +list.add("nashorn")
   24.37 +list.add("js")
   24.38 +list.add("ecmascript")
   24.39 +var len = list.length
   24.40 +print("length = " + len)
   24.41 +for (var i = 0; i < len; i++)
   24.42 +    print(list[i])
    25.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.2 +++ b/test/script/basic/JDK-8039387.js.EXPECTED	Wed Apr 16 15:05:39 2014 -0700
    25.3 @@ -0,0 +1,4 @@
    25.4 +length = 3
    25.5 +nashorn
    25.6 +js
    25.7 +ecmascript
    26.1 --- a/test/script/basic/NASHORN-173.js.EXPECTED	Wed Apr 16 12:32:47 2014 -0700
    26.2 +++ b/test/script/basic/NASHORN-173.js.EXPECTED	Wed Apr 16 15:05:39 2014 -0700
    26.3 @@ -132,7 +132,7 @@
    26.4  2.3423446609034533e+21
    26.5  2.3423446609034533e+21
    26.6  11111101111101010001111111010101101000101011011001001000000000000000000
    26.7 -2224143002343343220233144213324
    26.8 +2224143002343343220233044213324
    26.9  375752177255053311000000
   26.10  73b92b9962990aa44400
   26.11  7efa8fead15b240000
    27.1 --- a/test/script/basic/list.js	Wed Apr 16 12:32:47 2014 -0700
    27.2 +++ b/test/script/basic/list.js	Wed Apr 16 15:05:39 2014 -0700
    27.3 @@ -33,7 +33,7 @@
    27.4  l.add("foo")
    27.5  l.add("bar")
    27.6  
    27.7 -print("l.length=" + l.length) // doesn't work, returns undefined
    27.8 +print("l.length=" + l.length) // works, maps to l.size()
    27.9  print("l.size()=" + l.size()) // this will work
   27.10  
   27.11  print("l[0]=" + l[0])
    28.1 --- a/test/script/basic/list.js.EXPECTED	Wed Apr 16 12:32:47 2014 -0700
    28.2 +++ b/test/script/basic/list.js.EXPECTED	Wed Apr 16 15:05:39 2014 -0700
    28.3 @@ -1,5 +1,5 @@
    28.4  l.class.name=java.util.ArrayList
    28.5 -l.length=undefined
    28.6 +l.length=2
    28.7  l.size()=2
    28.8  l[0]=foo
    28.9  l[1]=bar
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/test/src/jdk/nashorn/internal/runtime/CodeStoreAndPathTest.java	Wed Apr 16 15:05:39 2014 -0700
    29.3 @@ -0,0 +1,159 @@
    29.4 +/*
    29.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
    29.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    29.7 + *
    29.8 + * This code is free software; you can redistribute it and/or modify it
    29.9 + * under the terms of the GNU General Public License version 2 only, as
   29.10 + * published by the Free Software Foundation.  Oracle designates this
   29.11 + * particular file as subject to the "Classpath" exception as provided
   29.12 + * by Oracle in the LICENSE file that accompanied this code.
   29.13 + *
   29.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   29.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   29.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   29.17 + * version 2 for more details (a copy is included in the LICENSE file that
   29.18 + * accompanied this code).
   29.19 + *
   29.20 + * You should have received a copy of the GNU General Public License version
   29.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   29.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   29.23 + *
   29.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   29.25 + * or visit www.oracle.com if you need additional information or have any
   29.26 + * questions.
   29.27 + */
   29.28 +package jdk.nashorn.internal.runtime;
   29.29 +
   29.30 +import java.io.File;
   29.31 +import java.io.IOException;
   29.32 +import java.nio.file.Files;
   29.33 +import java.nio.file.DirectoryStream;
   29.34 +import java.nio.file.Path;
   29.35 +import java.nio.file.FileSystems;
   29.36 +import javax.script.ScriptException;
   29.37 +import org.testng.annotations.Test;
   29.38 +import javax.script.ScriptEngine;
   29.39 +import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
   29.40 +import static org.testng.Assert.assertFalse;
   29.41 +import static org.testng.Assert.assertEquals;
   29.42 +
   29.43 +/**
   29.44 + * @test
   29.45 + * @bug 8039185 8039403
   29.46 + * @summary  Test for persistent code cache and path handling
   29.47 + * @run testng jdk.nashorn.internal.runtime.CodeStoreAndPathTest
   29.48 + */
   29.49 +
   29.50 +public class CodeStoreAndPathTest {
   29.51 +
   29.52 +    final String code1 = "var code1; var x = 'Hello Script'; var x1 = 'Hello Script'; "
   29.53 +                + "var x2 = 'Hello Script'; var x3 = 'Hello Script'; "
   29.54 +                + "var x4 = 'Hello Script'; var x5 = 'Hello Script';"
   29.55 +                + "var x6 = 'Hello Script'; var x7 = 'Hello Script'; "
   29.56 +                + "var x8 = 'Hello Script'; var x9 = 'Hello Script'; "
   29.57 +                + "var x10 = 'Hello Script';"
   29.58 +                + "function f() {x ='Bye Script'; x1 ='Bye Script'; x2='Bye Script';"
   29.59 +                + "x3='Bye Script'; x4='Bye Script'; x5='Bye Script'; x6='Bye Script';"
   29.60 +                + "x7='Bye Script'; x8='Bye Script'; var x9 = 'Hello Script'; "
   29.61 +                + "var x10 = 'Hello Script';}"
   29.62 +                + "function g() {x ='Bye Script'; x1 ='Bye Script'; x2='Bye Script';"
   29.63 +                + "x3='Bye Script'; x4='Bye Script'; x5='Bye Script'; x6='Bye Script';"
   29.64 +                + "x7='Bye Script'; x8='Bye Script'; var x9 = 'Hello Script'; "
   29.65 +                + "var x10 = 'Hello Script';}"
   29.66 +                + "function h() {x ='Bye Script'; x1 ='Bye Script'; x2='Bye Script';"
   29.67 +                + "x3='Bye Script'; x4='Bye Script'; x5='Bye Script'; x6='Bye Script';"
   29.68 +                + "x7='Bye Script'; x8='Bye Script'; var x9 = 'Hello Script'; "
   29.69 +                + "var x10 = 'Hello Script';}"
   29.70 +                + "function i() {x ='Bye Script'; x1 ='Bye Script'; x2='Bye Script';"
   29.71 +                + "x3='Bye Script'; x4='Bye Script'; x5='Bye Script'; x6='Bye Script';"
   29.72 +                + "x7='Bye Script'; x8='Bye Script'; var x9 = 'Hello Script'; "
   29.73 +                + "var x10 = 'Hello Script';}";
   29.74 +    final String code2 = "var code2; var x = 'Hello Script'; var x1 = 'Hello Script'; "
   29.75 +                + "var x2 = 'Hello Script'; var x3 = 'Hello Script'; "
   29.76 +                + "var x4 = 'Hello Script'; var x5 = 'Hello Script';"
   29.77 +                + "var x6 = 'Hello Script'; var x7 = 'Hello Script'; "
   29.78 +                + "var x8 = 'Hello Script'; var x9 = 'Hello Script'; "
   29.79 +                + "var x10 = 'Hello Script';"
   29.80 +                + "function f() {x ='Bye Script'; x1 ='Bye Script'; x2='Bye Script';"
   29.81 +                + "x3='Bye Script'; x4='Bye Script'; x5='Bye Script'; x6='Bye Script';"
   29.82 +                + "x7='Bye Script'; x8='Bye Script'; var x9 = 'Hello Script'; "
   29.83 +                + "var x10 = 'Hello Script';}"
   29.84 +                + "function g() {x ='Bye Script'; x1 ='Bye Script'; x2='Bye Script';"
   29.85 +                + "x3='Bye Script'; x4='Bye Script'; x5='Bye Script'; x6='Bye Script';"
   29.86 +                + "x7='Bye Script'; x8='Bye Script'; var x9 = 'Hello Script'; "
   29.87 +                + "var x10 = 'Hello Script';}"
   29.88 +                + "function h() {x ='Bye Script'; x1 ='Bye Script'; x2='Bye Script';"
   29.89 +                + "x3='Bye Script'; x4='Bye Script'; x5='Bye Script'; x6='Bye Script';"
   29.90 +                + "x7='Bye Script'; x8='Bye Script'; var x9 = 'Hello Script'; "
   29.91 +                + "var x10 = 'Hello Script';}"
   29.92 +                + "function i() {x ='Bye Script'; x1 ='Bye Script'; x2='Bye Script';"
   29.93 +                + "x3='Bye Script'; x4='Bye Script'; x5='Bye Script'; x6='Bye Script';"
   29.94 +                + "x7='Bye Script'; x8='Bye Script'; var x9 = 'Hello Script'; "
   29.95 +                + "var x10 = 'Hello Script';}";
   29.96 +    // Script size < Default minimum size for storing a compiled script class
   29.97 +    final String code3 = "var code3; var x = 'Hello Script'; var x1 = 'Hello Script'; ";
   29.98 +    final String codeCache = "build/nashorn_code_cache";
   29.99 +    final String oldUserDir = System.getProperty("user.dir");
  29.100 +
  29.101 +    public void checkCompiledScripts(DirectoryStream<Path> stream, int numberOfScripts) throws IOException {
  29.102 +        for (Path file : stream) {
  29.103 +            numberOfScripts--;
  29.104 +        }
  29.105 +        stream.close();
  29.106 +        assertEquals(numberOfScripts,0);
  29.107 +    }
  29.108 +
  29.109 +    @Test
  29.110 +    public void pathHandlingTest() throws ScriptException, IOException {
  29.111 +        System.setProperty("nashorn.persistent.code.cache", codeCache);
  29.112 +        String[] options = new String[]{"--persistent-code-cache"};
  29.113 +        NashornScriptEngineFactory fac = new NashornScriptEngineFactory();
  29.114 +        ScriptEngine e = fac.getScriptEngine(options);
  29.115 +        Path expectedCodeCachePath = FileSystems.getDefault().getPath(oldUserDir + File.separator + codeCache);
  29.116 +        Path actualCodeCachePath = FileSystems.getDefault().getPath(System.getProperty(
  29.117 +                            "nashorn.persistent.code.cache")).toAbsolutePath();
  29.118 +        // Check that nashorn code cache is created in current working directory
  29.119 +        assertEquals(actualCodeCachePath, expectedCodeCachePath);
  29.120 +        // Check that code cache dir exists and it's not empty
  29.121 +        File file = new File(actualCodeCachePath.toUri());
  29.122 +        assertFalse(!file.isDirectory(), "No code cache directory was created!");
  29.123 +        assertFalse(file.list().length == 0, "Code cache directory is empty!");
  29.124 +    }
  29.125 +
  29.126 +    @Test
  29.127 +    public void changeUserDirTest() throws ScriptException, IOException {
  29.128 +        System.setProperty("nashorn.persistent.code.cache", codeCache);
  29.129 +        String[] options = new String[]{"--persistent-code-cache"};
  29.130 +        NashornScriptEngineFactory fac = new NashornScriptEngineFactory();
  29.131 +        ScriptEngine e = fac.getScriptEngine(options);
  29.132 +        Path codeCachePath = FileSystems.getDefault().getPath(System.getProperty(
  29.133 +                            "nashorn.persistent.code.cache")).toAbsolutePath();
  29.134 +        String newUserDir = "build/newUserDir";
  29.135 +        // Now changing current working directory
  29.136 +        System.setProperty("user.dir", System.getProperty("user.dir") + File.separator + newUserDir);
  29.137 +        // Check that a new compiled script is stored in exisitng code cache
  29.138 +        e.eval(code1);
  29.139 +        DirectoryStream<Path> stream = Files.newDirectoryStream(codeCachePath);
  29.140 +        // Already one compiled script has been stored in the cache during initialization
  29.141 +        checkCompiledScripts(stream, 2);
  29.142 +        // Setting to default current working dir
  29.143 +        System.setProperty("user.dir", oldUserDir);
  29.144 +    }
  29.145 +
  29.146 +    @Test
  29.147 +    public void codeCacheTest() throws ScriptException, IOException {
  29.148 +        System.setProperty("nashorn.persistent.code.cache", codeCache);
  29.149 +        String[] options = new String[]{"--persistent-code-cache"};
  29.150 +        NashornScriptEngineFactory fac = new NashornScriptEngineFactory();
  29.151 +        ScriptEngine e = fac.getScriptEngine(options);
  29.152 +        Path codeCachePath = FileSystems.getDefault().getPath(System.getProperty(
  29.153 +                            "nashorn.persistent.code.cache")).toAbsolutePath();
  29.154 +        e.eval(code1);
  29.155 +        e.eval(code2);
  29.156 +        e.eval(code3);// less than minimum size for storing
  29.157 +        // Already one compiled script has been stored in the cache during initialization
  29.158 +        // adding code1 and code2.
  29.159 +        DirectoryStream<Path> stream = Files.newDirectoryStream(codeCachePath);
  29.160 +        checkCompiledScripts(stream, 3);
  29.161 +    }
  29.162 +}
    30.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.2 +++ b/test/src/jdk/nashorn/internal/runtime/NoPersistenceCachingTest.java	Wed Apr 16 15:05:39 2014 -0700
    30.3 @@ -0,0 +1,135 @@
    30.4 +/*
    30.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
    30.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    30.7 + *
    30.8 + * This code is free software; you can redistribute it and/or modify it
    30.9 + * under the terms of the GNU General Public License version 2 only, as
   30.10 + * published by the Free Software Foundation.  Oracle designates this
   30.11 + * particular file as subject to the "Classpath" exception as provided
   30.12 + * by Oracle in the LICENSE file that accompanied this code.
   30.13 + *
   30.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   30.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   30.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   30.17 + * version 2 for more details (a copy is included in the LICENSE file that
   30.18 + * accompanied this code).
   30.19 + *
   30.20 + * You should have received a copy of the GNU General Public License version
   30.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   30.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   30.23 + *
   30.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   30.25 + * or visit www.oracle.com if you need additional information or have any
   30.26 + * questions.
   30.27 + */
   30.28 +package jdk.nashorn.internal.runtime;
   30.29 +
   30.30 +import java.io.ByteArrayOutputStream;
   30.31 +import java.io.PrintStream;
   30.32 +import java.util.regex.Matcher;
   30.33 +import java.util.regex.Pattern;
   30.34 +import static org.testng.Assert.fail;
   30.35 +import org.testng.annotations.Test;
   30.36 +
   30.37 +import javax.script.ScriptContext;
   30.38 +import javax.script.ScriptEngine;
   30.39 +import javax.script.ScriptEngineFactory;
   30.40 +import javax.script.ScriptEngineManager;
   30.41 +import javax.script.SimpleScriptContext;
   30.42 +import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
   30.43 +import org.testng.annotations.AfterTest;
   30.44 +import org.testng.annotations.BeforeTest;
   30.45 +
   30.46 +/**
   30.47 + * @test
   30.48 + * @bug 8037378
   30.49 + * @summary Sanity tests for no persistence caching
   30.50 + * @run testng/othervm jdk.nashorn.internal.runtime.NoPersistenceCachingTest
   30.51 + */
   30.52 +public class NoPersistenceCachingTest {
   30.53 +
   30.54 +   private ScriptEngine engine;
   30.55 +   private ScriptContext context1, context2, context3;
   30.56 +   private ByteArrayOutputStream stderr;
   30.57 +   private PrintStream prevStderr;
   30.58 +
   30.59 +   @BeforeTest
   30.60 +   public void setupTest() {
   30.61 +      stderr = new ByteArrayOutputStream();
   30.62 +      prevStderr = System.err;
   30.63 +      System.setErr(new PrintStream(stderr));
   30.64 +      NashornScriptEngineFactory nashornFactory = null;
   30.65 +      ScriptEngineManager sm = new ScriptEngineManager();
   30.66 +      for (ScriptEngineFactory fac : sm.getEngineFactories()) {
   30.67 +         if (fac instanceof NashornScriptEngineFactory) {
   30.68 +            nashornFactory = (NashornScriptEngineFactory) fac;
   30.69 +            break;
   30.70 +         }
   30.71 +      }
   30.72 +      if (nashornFactory == null) {
   30.73 +         fail("Cannot find nashorn factory!");
   30.74 +      }
   30.75 +      String[] options = new String[]{"--log=compiler:finest"};
   30.76 +      engine = nashornFactory.getScriptEngine(options);
   30.77 +      context1 = engine.getContext();
   30.78 +      context2 = new SimpleScriptContext();
   30.79 +      context2.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE);
   30.80 +      context3 = new SimpleScriptContext();
   30.81 +      context3.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE);
   30.82 +   }
   30.83 +
   30.84 +   @AfterTest
   30.85 +   public void setErrTest() {
   30.86 +      System.setErr(prevStderr);
   30.87 +   }
   30.88 +
   30.89 +   public void runTest(int numberOfContext, String expectedOutputPattern,
   30.90 +                       int expectedPatternOccurrence) {
   30.91 +
   30.92 +      try {
   30.93 +         switch (numberOfContext) {
   30.94 +         case 2:
   30.95 +            String scriptTwoContexts = "print('HelloTwoContexts')";
   30.96 +            engine.eval(scriptTwoContexts, context1);
   30.97 +            engine.eval(scriptTwoContexts, context2);
   30.98 +            break;
   30.99 +         case 3:
  30.100 +            String scriptThreeContexts = "print('HelloThreeContexts')";
  30.101 +            engine.eval(scriptThreeContexts, context1);
  30.102 +            engine.eval(scriptThreeContexts, context2);
  30.103 +            engine.eval(scriptThreeContexts, context3);
  30.104 +            break;
  30.105 +         }
  30.106 +      } catch (final Exception se) {
  30.107 +         se.printStackTrace();
  30.108 +         fail(se.getMessage());
  30.109 +      }
  30.110 +      Pattern deoptimizing = Pattern.compile(expectedOutputPattern);
  30.111 +      Matcher matcher = deoptimizing.matcher(stderr.toString());
  30.112 +      int matches = 0;
  30.113 +      while (matcher.find()) {
  30.114 +         matches++;
  30.115 +      }
  30.116 +      if (matches != expectedPatternOccurrence) {
  30.117 +         fail("Number of cache hit is not correct, expected: "
  30.118 +                    + expectedPatternOccurrence + " and found: " + matches + "\n"
  30.119 +              + stderr);
  30.120 +      }
  30.121 +      stderr.reset();
  30.122 +   }
  30.123 +
  30.124 +   private static String getCodeCachePattern() {
  30.125 +      return ("\\[compiler\\]\\sCode\\scache\\shit\\sfor\\s<eval>\\savoiding\\srecompile.");
  30.126 +   }
  30.127 +
  30.128 +    @Test
  30.129 +    public void twoContextTest() {
  30.130 +       runTest(2, getCodeCachePattern(), 1);
  30.131 +
  30.132 +    }
  30.133 +
  30.134 +    @Test
  30.135 +    public void threeContextTest() {
  30.136 +       runTest(3, getCodeCachePattern(), 2);
  30.137 +    }
  30.138 +}

mercurial