Wed, 16 Apr 2014 15:05:39 -0700
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 +}