# HG changeset patch # User lagergren # Date 1414063140 -14400 # Node ID 78eb2b415108c2016314de6084b3f106af13cdc2 # Parent 094f0d95ef7858c910788fde0ec183efa6a8d1f8 8061391: concat as a builtin optimistic form, had to remove NoTypedArrayData and replace it, as we throw away a lot of optimistic link opportunities with NoTypedArrayData not being Continuous Reviewed-by: attila, hannesw diff -r 094f0d95ef78 -r 78eb2b415108 bin/runopt.sh --- a/bin/runopt.sh Fri Oct 24 13:25:23 2014 +0200 +++ b/bin/runopt.sh Thu Oct 23 15:19:00 2014 +0400 @@ -28,14 +28,35 @@ # known flags for performance for the current configration ########################################################################################### +# Flags to enable assertions, we need the system assertions too, since +# this script runs Nashorn in the BCP to override any nashorn.jar that might +# reside in your $JAVA_HOME/jre/lib/ext/nashorn.jar +# +ENABLE_ASSERTIONS_FLAGS="-ea -esa" + # Flags to instrument lambdaform computation, caching, interpretation and compilation # Default compile threshold for lambdaforms is 30 -#FLAGS="-Djava.lang.invoke.MethodHandle.COMPILE_THRESHOLD=3 -Djava.lang.invoke.MethodHandle.DUMP_CLASS_FILES=true -Djava.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE=true -Djava.lang.invoke.MethodHandle.TRACE_INTERPRETER=true" - +# +#LAMBDAFORM_FLAGS="\ +# -Djava.lang.invoke.MethodHandle.COMPILE_THRESHOLD=3 \ +# -Djava.lang.invoke.MethodHandle.DUMP_CLASS_FILES=true \ +# -Djava.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE=true \ +# -Djava.lang.invoke.MethodHandle.TRACE_INTERPRETER=true" # Flags to run trusted tests from the Nashorn test suite -#FLAGS="-Djava.security.manager -Djava.security.policy=../build/nashorn.policy -Dnashorn.debug" +# +#TRUSTED_TEST_FLAGS="\ +#-Djava.security.manager \ +#-Djava.security.policy=../build/nashorn.policy -Dnashorn.debug" +# Testing out new code optimizations using the generic hotspot "new code" parameter +# +#USE_NEW_CODE_FLAGS=-XX:+UnlockDiagnosticVMOptions -XX:+UseNewCode + +# +#-Dnashorn.typeInfo.disabled=false \ +# and for Nashorn options: +# --class-cache-size=0 --persistent-code-cache=false # Unique timestamped file name for JFR recordings. For JFR, we also have to # crank up the stack cutoff depth to 1024, because of ridiculously long lambda form @@ -46,8 +67,42 @@ # can go (10 ms on most platforms). The default is normally higher. The increased # sampling overhead is usually negligible for Nashorn runs, but the data is better -JFR_FILENAME="./nashorn_$(date|sed "s/ /_/g"|sed "s/:/_/g").jfr" +if [ -z $JFR_FILENAME ]; then + JFR_FILENAME="./nashorn_$(date|sed "s/ /_/g"|sed "s/:/_/g").jfr" +fi + +# Flight recorder +# +# see above - already in place, copy the flags down here to disable +ENABLE_FLIGHT_RECORDER_FLAGS="\ + -XX:+UnlockCommercialFeatures \ + -XX:+FlightRecorder \ + -XX:FlightRecorderOptions=defaultrecording=true,disk=true,dumponexit=true,dumponexitpath=$JFR_FILENAME,stackdepth=1024" + +# Type specialization and math intrinsic replacement should be enabled by default in 8u20 and nine, +# keeping this flag around for experimental reasons. Replace + with - to switch it off +# +#ENABLE_TYPE_SPECIALIZATION_FLAGS=-XX:+UseTypeSpeculation +# Same with math intrinsics. They should be enabled by default in 8u20 and 9, so +# this disables them if needed +# +#DISABLE_MATH_INTRINSICS_FLAGS=-XX:-UseMathExactIntrinsics + +# Add timing to time the compilation phases. +#ENABLE_TIME_FLAGS=--log=time + +# Add ShowHiddenFrames to get lambda form internals on the stack traces +#ENABLE_SHOW_HIDDEN_FRAMES_FLAGS=-XX:+ShowHiddenFrames + +# Add print optoassembly to get an asm dump. This requires 1) a debug build, not product, +# That tired compilation is switched off, for C2 only output and that the number of +# compiler threads is set to 1 for determinsm. +# +#PRINT_ASM_FLAGS=-XX:+PrintOptoAssembly -XX:-TieredCompilation -XX:CICompilerCount=1 \ + +# Tier compile threasholds. Default value is 10. (1-100 is useful for experiments) +#TIER_COMPILATION_THRESHOLD_FLAGS=-XX:IncreaseFirstTierCompileThresholdAt=10 # Directory where to look for nashorn.jar in a dist folder. The default is "..", assuming # that we run the script from the make dir @@ -59,49 +114,23 @@ # nashorn.jar in $JAVA_HOME/jre/lib/ext. Thus, we also need -esa, as assertions in # nashorn count as system assertions in this configuration +# Type profiling default level is 111, 222 adds some compile time, but is faster + $JAVA_HOME/bin/java \ -$FLAGS \ --ea \ --esa \ +$ENABLE_ASSERTIONS_FLAGS \ +$LAMBDAFORM_FLAGS \ +$TRUSTED_FLAGS \ +$USE_NEW_CODE_FLAGS \ +$ENABLE_SHOW_HIDDEN_FRAMES_FLAGS \ +$ENABLE_FLIGHT_RECORDER_FLAGS \ +$ENABLE_TYPE_SPECIALIZATION_FLAGS \ +$TIERED_COMPILATION_THRESOLD_FLAGS \ +$DISABLE_MATH_INTRINSICS_FLAGS \ +$PRINT_ASM_FLAGS \ -Xbootclasspath/p:$NASHORN_JAR \ -Xms2G -Xmx2G \ +-XX:TypeProfileLevel=222 \ -cp $CLASSPATH:../build/test/classes/ \ -jdk.nashorn.tools.Shell ${@} - -# Below are flags that may come in handy, but aren't used for default runs - - -# Type profiling default level is 111, 222 adds some compile time, but produces better code. -# -XX:TypeProfileLevel=222 \ - - -# Testing out new code optimizations using the generic hotspot "new code" parameter -#-XX:+UnlockDiagnosticVMOptions \ -#-XX:+UseNewCode \ +jdk.nashorn.tools.Shell $ENABLE_TIME_FLAGS ${@} -# Type specialization and math intrinsic replacement should be enabled by default in 8u20 and nine, -# keeping this flag around for experimental reasons. Replace + with - to switch it off -#-XX:+UseTypeSpeculation \ - - -# Same with math intrinsics. They should be enabled by default in 8u20 and 9 -#-XX:+UseMathExactIntrinsics \ - - -# Add -Dnashorn.time to time the compilation phases. -#-Dnashorn.time \ - - -# Add ShowHiddenFrames to get lambda form internals on the stack traces -#-XX:+ShowHiddenFrames \ - - -# Add print optoassembly to get an asm dump. This requires 1) a debug build, not product, -# That tired compilation is switched off, for C2 only output and that the number of -# compiler threads is set to 1 for determinsm. -#-XX:+PrintOptoAssembly -XX:-TieredCompilation -XX:CICompilerCount=1 \ - -# Tier compile threasholds. Default value is 10. (1-100 is useful for experiments) -# -XX:IncreaseFirstTierCompileThresholdAt=XX - diff -r 094f0d95ef78 -r 78eb2b415108 src/jdk/nashorn/internal/codegen/types/Type.java --- a/src/jdk/nashorn/internal/codegen/types/Type.java Fri Oct 24 13:25:23 2014 +0200 +++ b/src/jdk/nashorn/internal/codegen/types/Type.java Thu Oct 23 15:19:00 2014 +0400 @@ -586,6 +586,7 @@ public int getSlots() { return slots; } + /** * Returns the widest or most common of two types * @@ -609,6 +610,18 @@ } /** + * Returns the widest or most common of two types, given as classes + * + * @param type0 type one + * @param type1 type two + * + * @return the widest type + */ + public static Class widest(final Class type0, final Class type1) { + return widest(Type.typeFor(type0), Type.typeFor(type1)).getTypeClass(); + } + + /** * When doing widening for return types of a function or a ternary operator, it is not valid to widen a boolean to * anything other than object. Note that this wouldn't be necessary if {@code Type.widest} did not allow * boolean-to-number widening. Eventually, we should address it there, but it affects too many other parts of the diff -r 094f0d95ef78 -r 78eb2b415108 src/jdk/nashorn/internal/objects/NativeArray.java --- a/src/jdk/nashorn/internal/objects/NativeArray.java Fri Oct 24 13:25:23 2014 +0200 +++ b/src/jdk/nashorn/internal/objects/NativeArray.java Thu Oct 23 15:19:00 2014 +0400 @@ -93,9 +93,10 @@ private static final Object CALL_CMP = new Object(); private static final Object TO_LOCALE_STRING = new Object(); - private SwitchPoint lengthMadeNotWritableSwitchPoint; - private PushLinkLogic pushLinkLogic; - private PopLinkLogic popLinkLogic; + private SwitchPoint lengthMadeNotWritableSwitchPoint; + private PushLinkLogic pushLinkLogic; + private PopLinkLogic popLinkLogic; + private ConcatLinkLogic concatLinkLogic; /** * Index for the modification SwitchPoint that triggers when length @@ -131,7 +132,9 @@ this(ArrayData.allocate(array.length)); ArrayData arrayData = this.getArray(); - arrayData.ensure(array.length - 1); + if (array.length > 0) { + arrayData.ensure(array.length - 1); + } for (int index = 0; index < array.length; index++) { final Object value = array[index]; @@ -758,12 +761,86 @@ * ECMA 15.4.4.4 Array.prototype.concat ( [ item1 [ , item2 [ , ... ] ] ] ) * * @param self self reference + * @param arg argument + * @return resulting NativeArray + */ + @SpecializedFunction(linkLogic=ConcatLinkLogic.class) + public static NativeArray concat(final Object self, final int arg) { + final ContinuousArrayData newData = getContinuousArrayDataCCE(self, Integer.class).copy(); //get at least an integer data copy of this data + newData.fastPush(arg); //add an integer to its end + return new NativeArray(newData); + } + + /** + * ECMA 15.4.4.4 Array.prototype.concat ( [ item1 [ , item2 [ , ... ] ] ] ) + * + * @param self self reference + * @param arg argument + * @return resulting NativeArray + */ + @SpecializedFunction(linkLogic=ConcatLinkLogic.class) + public static NativeArray concat(final Object self, final long arg) { + final ContinuousArrayData newData = getContinuousArrayDataCCE(self, Long.class).copy(); //get at least a long array data copy of this data + newData.fastPush(arg); //add a long at the end + return new NativeArray(newData); + } + + /** + * ECMA 15.4.4.4 Array.prototype.concat ( [ item1 [ , item2 [ , ... ] ] ] ) + * + * @param self self reference + * @param arg argument + * @return resulting NativeArray + */ + @SpecializedFunction(linkLogic=ConcatLinkLogic.class) + public static NativeArray concat(final Object self, final double arg) { + final ContinuousArrayData newData = getContinuousArrayDataCCE(self, Double.class).copy(); //get at least a number array data copy of this data + newData.fastPush(arg); //add a double at the end + return new NativeArray(newData); + } + + /** + * ECMA 15.4.4.4 Array.prototype.concat ( [ item1 [ , item2 [ , ... ] ] ] ) + * + * @param self self reference + * @param arg argument + * @return resulting NativeArray + */ + @SpecializedFunction(linkLogic=ConcatLinkLogic.class) + public static NativeArray concat(final Object self, final Object arg) { + //arg is [NativeArray] of same type. + final ContinuousArrayData selfData = getContinuousArrayDataCCE(self); + final ContinuousArrayData newData; + + if (arg instanceof NativeArray) { + final ContinuousArrayData argData = (ContinuousArrayData)((NativeArray)arg).getArray(); + if (argData.isEmpty()) { + newData = selfData.copy(); + } else if (selfData.isEmpty()) { + newData = argData.copy(); + } else { + final Class widestElementType = selfData.widest(argData).getBoxedElementType(); + newData = ((ContinuousArrayData)selfData.convert(widestElementType)).fastConcat((ContinuousArrayData)argData.convert(widestElementType)); + } + } else { + newData = getContinuousArrayDataCCE(self, Object.class).copy(); + newData.fastPush(arg); + } + + return new NativeArray(newData); + } + + /** + * ECMA 15.4.4.4 Array.prototype.concat ( [ item1 [ , item2 [ , ... ] ] ] ) + * + * @param self self reference * @param args arguments * @return resulting NativeArray */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) public static NativeArray concat(final Object self, final Object... args) { final ArrayList list = new ArrayList<>(); + concatToList(list, Global.toObject(self)); for (final Object obj : args) { @@ -1693,13 +1770,15 @@ return pushLinkLogic == null ? new PushLinkLogic(this) : pushLinkLogic; } else if (clazz == PopLinkLogic.class) { return popLinkLogic == null ? new PopLinkLogic(this) : pushLinkLogic; + } else if (clazz == ConcatLinkLogic.class) { + return concatLinkLogic == null ? new ConcatLinkLogic(this) : concatLinkLogic; } return null; } @Override public boolean hasPerInstanceAssumptions() { - return true; //length switchpoint + return true; //length writable switchpoint } /** @@ -1799,6 +1878,40 @@ } /** + * This is linker logic for optimistic concatenations + */ + private static final class ConcatLinkLogic extends ArrayLinkLogic { + private ConcatLinkLogic(final NativeArray array) { + super(array); + } + + @Override + public boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request) { + final Object[] args = request.getArguments(); + + if (args.length != 3) { //single argument check + return false; + } + + final ContinuousArrayData selfData = getContinuousArrayData(self); + if (selfData == null) { + return false; + } + + final Object arg = args[2]; + //args[2] continuousarray or non arraydata, let past non array datas + if (arg instanceof NativeArray) { + final ContinuousArrayData argData = getContinuousArrayData(arg); + if (argData == null) { + return false; + } + } + + return true; + } + } + + /** * This is linker logic for optimistic pushes */ private static final class PushLinkLogic extends ArrayLinkLogic { @@ -1865,6 +1978,14 @@ throw new ClassCastException(); } + private static final ContinuousArrayData getContinuousArrayDataCCE(final Object self) { + try { + return (ContinuousArrayData)((NativeArray)self).getArray(); + } catch (final NullPointerException e) { + throw new ClassCastException(); + } + } + private static final ContinuousArrayData getContinuousArrayDataCCE(final Object self, final Class elementType) { try { return (ContinuousArrayData)((NativeArray)self).getArray(elementType); //ensure element type can fit "elementType" diff -r 094f0d95ef78 -r 78eb2b415108 src/jdk/nashorn/internal/objects/NativeFloat32Array.java --- a/src/jdk/nashorn/internal/objects/NativeFloat32Array.java Fri Oct 24 13:25:23 2014 +0200 +++ b/src/jdk/nashorn/internal/objects/NativeFloat32Array.java Thu Oct 23 15:19:00 2014 +0400 @@ -90,6 +90,11 @@ } @Override + public Class getBoxedElementType() { + return Double.class; + } + + @Override protected MethodHandle getGetElem() { return GET_ELEM; } diff -r 094f0d95ef78 -r 78eb2b415108 src/jdk/nashorn/internal/objects/NativeFloat64Array.java --- a/src/jdk/nashorn/internal/objects/NativeFloat64Array.java Fri Oct 24 13:25:23 2014 +0200 +++ b/src/jdk/nashorn/internal/objects/NativeFloat64Array.java Thu Oct 23 15:19:00 2014 +0400 @@ -99,6 +99,11 @@ return double.class; } + @Override + public Class getBoxedElementType() { + return Double.class; + } + private double getElem(final int index) { try { return nb.get(index); diff -r 094f0d95ef78 -r 78eb2b415108 src/jdk/nashorn/internal/objects/NativeInt16Array.java --- a/src/jdk/nashorn/internal/objects/NativeInt16Array.java Fri Oct 24 13:25:23 2014 +0200 +++ b/src/jdk/nashorn/internal/objects/NativeInt16Array.java Thu Oct 23 15:19:00 2014 +0400 @@ -100,6 +100,11 @@ return int.class; } + @Override + public Class getBoxedElementType() { + return Integer.class; + } + private int getElem(final int index) { try { return nb.get(index); diff -r 094f0d95ef78 -r 78eb2b415108 src/jdk/nashorn/internal/objects/NativeInt32Array.java --- a/src/jdk/nashorn/internal/objects/NativeInt32Array.java Fri Oct 24 13:25:23 2014 +0200 +++ b/src/jdk/nashorn/internal/objects/NativeInt32Array.java Thu Oct 23 15:19:00 2014 +0400 @@ -118,6 +118,11 @@ } @Override + public Class getBoxedElementType() { + return Integer.class; + } + + @Override public int getInt(final int index) { return getElem(index); } diff -r 094f0d95ef78 -r 78eb2b415108 src/jdk/nashorn/internal/objects/NativeInt8Array.java --- a/src/jdk/nashorn/internal/objects/NativeInt8Array.java Fri Oct 24 13:25:23 2014 +0200 +++ b/src/jdk/nashorn/internal/objects/NativeInt8Array.java Thu Oct 23 15:19:00 2014 +0400 @@ -98,6 +98,11 @@ return int.class; } + @Override + public Class getBoxedElementType() { + return Integer.class; + } + private int getElem(final int index) { try { return nb.get(index); diff -r 094f0d95ef78 -r 78eb2b415108 src/jdk/nashorn/internal/objects/NativeObject.java --- a/src/jdk/nashorn/internal/objects/NativeObject.java Fri Oct 24 13:25:23 2014 +0200 +++ b/src/jdk/nashorn/internal/objects/NativeObject.java Thu Oct 23 15:19:00 2014 +0400 @@ -28,7 +28,6 @@ import static jdk.nashorn.internal.lookup.Lookup.MH; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; - import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; diff -r 094f0d95ef78 -r 78eb2b415108 src/jdk/nashorn/internal/objects/NativeUint16Array.java --- a/src/jdk/nashorn/internal/objects/NativeUint16Array.java Fri Oct 24 13:25:23 2014 +0200 +++ b/src/jdk/nashorn/internal/objects/NativeUint16Array.java Thu Oct 23 15:19:00 2014 +0400 @@ -124,6 +124,11 @@ } @Override + public Class getBoxedElementType() { + return Integer.class; + } + + @Override public int getInt(final int index) { return getElem(index); } diff -r 094f0d95ef78 -r 78eb2b415108 src/jdk/nashorn/internal/objects/NativeUint32Array.java --- a/src/jdk/nashorn/internal/objects/NativeUint32Array.java Fri Oct 24 13:25:23 2014 +0200 +++ b/src/jdk/nashorn/internal/objects/NativeUint32Array.java Thu Oct 23 15:19:00 2014 +0400 @@ -133,6 +133,11 @@ } @Override + public Class getBoxedElementType() { + return Integer.class; + } + + @Override public int getInt(final int index) { return (int)getLong(index); } diff -r 094f0d95ef78 -r 78eb2b415108 src/jdk/nashorn/internal/objects/NativeUint8Array.java --- a/src/jdk/nashorn/internal/objects/NativeUint8Array.java Fri Oct 24 13:25:23 2014 +0200 +++ b/src/jdk/nashorn/internal/objects/NativeUint8Array.java Thu Oct 23 15:19:00 2014 +0400 @@ -124,6 +124,11 @@ } @Override + public Class getBoxedElementType() { + return Integer.class; + } + + @Override public int getInt(final int index) { return getElem(index); } diff -r 094f0d95ef78 -r 78eb2b415108 src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java --- a/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java Fri Oct 24 13:25:23 2014 +0200 +++ b/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java Thu Oct 23 15:19:00 2014 +0400 @@ -103,6 +103,11 @@ return int.class; } + @Override + public Class getBoxedElementType() { + return int.class; + } + private int getElem(final int index) { try { return nb.get(index) & 0xff; diff -r 094f0d95ef78 -r 78eb2b415108 src/jdk/nashorn/internal/parser/JSONParser.java --- a/src/jdk/nashorn/internal/parser/JSONParser.java Fri Oct 24 13:25:23 2014 +0200 +++ b/src/jdk/nashorn/internal/parser/JSONParser.java Thu Oct 23 15:19:00 2014 +0400 @@ -32,7 +32,6 @@ import static jdk.nashorn.internal.parser.TokenType.RBRACE; import static jdk.nashorn.internal.parser.TokenType.RBRACKET; import static jdk.nashorn.internal.parser.TokenType.STRING; - import java.util.ArrayList; import java.util.List; import jdk.nashorn.internal.ir.Expression; diff -r 094f0d95ef78 -r 78eb2b415108 src/jdk/nashorn/internal/runtime/JSType.java --- a/src/jdk/nashorn/internal/runtime/JSType.java Fri Oct 24 13:25:23 2014 +0200 +++ b/src/jdk/nashorn/internal/runtime/JSType.java Thu Oct 23 15:19:00 2014 +0400 @@ -29,7 +29,6 @@ import static jdk.nashorn.internal.codegen.ObjectClassGenerator.OBJECT_FIELDS_ONLY; import static jdk.nashorn.internal.lookup.Lookup.MH; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; - import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.reflect.Array; @@ -1789,6 +1788,23 @@ } /** + * Returns the boxed version of a primitive class + * @param clazz the class + * @return the boxed type of clazz, or unchanged if not primitive + */ + public static Class getBoxedClass(final Class clazz) { + if (clazz == int.class) { + return Integer.class; + } else if (clazz == long.class) { + return Long.class; + } else if (clazz == double.class) { + return Double.class; + } + assert !clazz.isPrimitive(); + return clazz; + } + + /** * Create a method handle constant of the correct primitive type * for a constant object * @param o object diff -r 094f0d95ef78 -r 78eb2b415108 src/jdk/nashorn/internal/runtime/ScriptObject.java --- a/src/jdk/nashorn/internal/runtime/ScriptObject.java Fri Oct 24 13:25:23 2014 +0200 +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java Thu Oct 23 15:19:00 2014 +0400 @@ -692,8 +692,7 @@ assert isValidArrayIndex(index) : "invalid array index"; final long longIndex = ArrayIndex.toLongIndex(index); doesNotHaveEnsureDelete(longIndex, getArray().length(), false); - setArray(getArray().ensure(longIndex)); - setArray(getArray().set(index, value, false)); + setArray(getArray().ensure(longIndex).set(index,value, false)); } private void checkIntegerKey(final String key) { @@ -1462,9 +1461,8 @@ //invalidate any fast array setters final ArrayData array = getArray(); - if (array != null) { - array.invalidateSetters(); - } + assert array != null; + setArray(ArrayData.preventExtension(array)); return this; } @@ -2645,20 +2643,22 @@ * @param newLength new length to set */ public final void setLength(final long newLength) { - final long arrayLength = getArray().length(); - if (newLength == arrayLength) { - return; - } - - if (newLength > arrayLength) { - setArray(getArray().ensure(newLength - 1)); - if (getArray().canDelete(arrayLength, newLength - 1, false)) { - setArray(getArray().delete(arrayLength, newLength - 1)); - } - return; - } - - if (newLength < arrayLength) { + ArrayData data = getArray(); + final long arrayLength = data.length(); + if (newLength == arrayLength) { + return; + } + + if (newLength > arrayLength) { + data = data.ensure(newLength - 1); + if (data.canDelete(arrayLength, newLength - 1, false)) { + data = data.delete(arrayLength, newLength - 1); + } + setArray(data); + return; + } + + if (newLength < arrayLength) { long actualLength = newLength; // Check for numeric keys in property map and delete them or adjust length, depending on whether @@ -2680,8 +2680,8 @@ } } - setArray(getArray().shrink(actualLength)); - getArray().setLength(actualLength); + setArray(data.shrink(actualLength)); + data.setLength(actualLength); } } @@ -3194,8 +3194,9 @@ final int index = getArrayIndex(primitiveKey); if (isValidArrayIndex(index)) { - if (getArray().has(index)) { - setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + final ArrayData data = getArray(); + if (data.has(index)) { + setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3213,8 +3214,9 @@ final int index = getArrayIndex(primitiveKey); if (isValidArrayIndex(index)) { - if (getArray().has(index)) { - setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + final ArrayData data = getArray(); + if (data.has(index)) { + setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3232,8 +3234,9 @@ final int index = getArrayIndex(primitiveKey); if (isValidArrayIndex(index)) { - if (getArray().has(index)) { - setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + final ArrayData data = getArray(); + if (data.has(index)) { + setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3251,8 +3254,9 @@ final int index = getArrayIndex(primitiveKey); if (isValidArrayIndex(index)) { - if (getArray().has(index)) { - setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + final ArrayData data = getArray(); + if (data.has(index)) { + setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3269,8 +3273,9 @@ final int index = getArrayIndex(key); if (isValidArrayIndex(index)) { - if (getArray().has(index)) { - setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + final ArrayData data = getArray(); + if (data.has(index)) { + setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3287,8 +3292,9 @@ final int index = getArrayIndex(key); if (isValidArrayIndex(index)) { - if (getArray().has(index)) { - setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + final ArrayData data = getArray(); + if (data.has(index)) { + setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3305,8 +3311,9 @@ final int index = getArrayIndex(key); if (isValidArrayIndex(index)) { - if (getArray().has(index)) { - setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + final ArrayData data = getArray(); + if (data.has(index)) { + setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3323,8 +3330,9 @@ final int index = getArrayIndex(key); if (isValidArrayIndex(index)) { - if (getArray().has(index)) { - setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + final ArrayData data = getArray(); + if (data.has(index)) { + setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3341,8 +3349,9 @@ final int index = getArrayIndex(key); if (isValidArrayIndex(index)) { - if (getArray().has(index)) { - setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + final ArrayData data = getArray(); + if (data.has(index)) { + setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3359,8 +3368,9 @@ final int index = getArrayIndex(key); if (isValidArrayIndex(index)) { - if (getArray().has(index)) { - setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + final ArrayData data = getArray(); + if (data.has(index)) { + setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3377,8 +3387,9 @@ final int index = getArrayIndex(key); if (isValidArrayIndex(index)) { - if (getArray().has(index)) { - setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + final ArrayData data = getArray(); + if (data.has(index)) { + setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3395,8 +3406,9 @@ final int index = getArrayIndex(key); if (isValidArrayIndex(index)) { - if (getArray().has(index)) { - setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + final ArrayData data = getArray(); + if (data.has(index)) { + setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3413,7 +3425,8 @@ final int index = getArrayIndex(key); if (isValidArrayIndex(index)) { if (getArray().has(index)) { - setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + final ArrayData data = getArray(); + setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3429,8 +3442,9 @@ final int index = getArrayIndex(key); if (isValidArrayIndex(index)) { - if (getArray().has(index)) { - setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + final ArrayData data = getArray(); + if (data.has(index)) { + setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3447,8 +3461,9 @@ final int index = getArrayIndex(key); if (isValidArrayIndex(index)) { - if (getArray().has(index)) { - setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + final ArrayData data = getArray(); + if (data.has(index)) { + setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3465,8 +3480,9 @@ final int index = getArrayIndex(key); if (isValidArrayIndex(index)) { - if (getArray().has(index)) { - setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + final ArrayData data = getArray(); + if (data.has(index)) { + setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } diff -r 094f0d95ef78 -r 78eb2b415108 src/jdk/nashorn/internal/runtime/arrays/AnyElements.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk/nashorn/internal/runtime/arrays/AnyElements.java Thu Oct 23 15:19:00 2014 +0400 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.nashorn.internal.runtime.arrays; + +/** + * Marker interface for any ContinuousArray with any elements + * Used for type checks that throw ClassCastExceptions and force relinks + * for fast NativeArray specializations of builtin methods + */ +public interface AnyElements { + /** + * Return a numeric weight of the element type - wider is higher + * @return element type weight + */ + public int getElementWeight(); +} \ No newline at end of file diff -r 094f0d95ef78 -r 78eb2b415108 src/jdk/nashorn/internal/runtime/arrays/ArrayData.java --- a/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java Fri Oct 24 13:25:23 2014 +0200 +++ b/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java Thu Oct 23 15:19:00 2014 +0400 @@ -28,6 +28,7 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; +import java.lang.reflect.Array; import java.nio.ByteBuffer; import jdk.internal.dynalink.CallSiteDescriptor; import jdk.internal.dynalink.linker.GuardedInvocation; @@ -37,6 +38,7 @@ import jdk.nashorn.internal.objects.Global; import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.PropertyDescriptor; +import jdk.nashorn.internal.runtime.ScriptRuntime; import jdk.nashorn.internal.runtime.UnwarrantedOptimismException; /** @@ -49,10 +51,180 @@ /** Mask for getting a chunk */ protected static final int CHUNK_MASK = CHUNK_SIZE - 1; + /** Untouched data - still link callsites as IntArrayData, but expands to + * a proper ArrayData when we try to write to it */ + public static final ArrayData EMPTY_ARRAY = new UntouchedArrayData(); + /** * Immutable empty array to get ScriptObjects started. + * Use the same array and convert it to mutable as soon as it is modified */ - public static final ArrayData EMPTY_ARRAY = new NoTypeArrayData(); + private static class UntouchedArrayData extends ContinuousArrayData { + private UntouchedArrayData() { + this(0); + } + + private UntouchedArrayData(final int length) { + super(length); + } + + private ArrayData toRealArrayData() { + return toRealArrayData(0); + } + + private ArrayData toRealArrayData(final int index) { + final IntArrayData newData = new IntArrayData(index + 1); + if (index == 0) { + return newData; + } + return new DeletedRangeArrayFilter(newData, 0, index); + } + + @Override + public ContinuousArrayData copy() { + return new UntouchedArrayData((int)length); + } + + @Override + public Object asArrayOfType(final Class componentType) { + return Array.newInstance(componentType, 0); + } + + @Override + public Object[] asObjectArray() { + return ScriptRuntime.EMPTY_ARRAY; + } + + @Override + public ArrayData ensure(final long safeIndex) { + if (safeIndex > 0L) { + return toRealArrayData((int)safeIndex).ensure(safeIndex); + } + return this; + } + + @Override + public ArrayData convert(final Class type) { + return toRealArrayData(0).convert(type); + } + + @Override + public void shiftLeft(final int by) { + //nop, always empty or we wouldn't be of this class + } + + @Override + public ArrayData shiftRight(final int by) { + return this; //always empty or we wouldn't be of this class + } + + @Override + public ArrayData shrink(final long newLength) { + return this; + } + + @Override + public ArrayData set(final int index, final Object value, final boolean strict) { + return toRealArrayData(index).set(index, value, strict); + } + + @Override + public ArrayData set(final int index, final int value, final boolean strict) { + return toRealArrayData(index).set(index, value, strict); + } + + @Override + public ArrayData set(final int index, final long value, final boolean strict) { + return toRealArrayData(index).set(index, value, strict); + } + + @Override + public ArrayData set(final int index, final double value, final boolean strict) { + return toRealArrayData(index).set(index, value, strict); + } + + @Override + public int getInt(final int index) { + throw new ArrayIndexOutOfBoundsException(index); //empty + } + + @Override + public long getLong(final int index) { + throw new ArrayIndexOutOfBoundsException(index); //empty + } + + @Override + public double getDouble(final int index) { + throw new ArrayIndexOutOfBoundsException(index); //empty + } + + @Override + public Object getObject(final int index) { + throw new ArrayIndexOutOfBoundsException(index); //empty + } + + @Override + public boolean has(final int index) { + return false; //empty + } + + @Override + public ArrayData delete(final int index) { + return new DeletedRangeArrayFilter(this, index, index); + } + + @Override + public ArrayData delete(final long fromIndex, final long toIndex) { + return new DeletedRangeArrayFilter(this, fromIndex, toIndex); + } + + @Override + public Object pop() { + return ScriptRuntime.UNDEFINED; + } + + @Override + public ArrayData push(final boolean strict, final Object item) { + return toRealArrayData().push(strict, item); + } + + @Override + public ArrayData slice(final long from, final long to) { + return this; //empty + } + + @Override + public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) { + return otherData.copy(); + } + + //no need to override fastPopInt, as the default behavior is to throw classcast exception so we + //can relink and return an undefined, this is the IntArrayData default behavior + @Override + public String toString() { + return getClass().getSimpleName(); + } + + @Override + public MethodHandle getElementGetter(final Class returnType, final int programPoint) { + return null; + } + + @Override + public MethodHandle getElementSetter(final Class elementType) { + return null; + } + + @Override + public Class getElementType() { + return int.class; + } + + @Override + public Class getBoxedElementType() { + return Integer.class; + } + }; /** * Length of the array data. Not necessarily length of the wrapped array. @@ -77,7 +249,7 @@ * Factory method for unspecified array - start as int * @return ArrayData */ - public static ArrayData initialArray() { + public final static ArrayData initialArray() { return new IntArrayData(); } @@ -92,24 +264,13 @@ throw new UnwarrantedOptimismException(data.getObject(index), programPoint); } - private static int alignUp(final int size) { - return size + CHUNK_SIZE - 1 & ~(CHUNK_SIZE - 1); - } - /** - * Generic invalidation hook for script object to have call sites to this array indexing - * relinked, e.g. when a native array is marked as non extensible + * Align an array size up to the nearest array chunk size + * @param size size required + * @return size given, always >= size */ - public void invalidateGetters() { - //subclass responsibility - } - - /** - * Generic invalidation hook for script object to have call sites to this array indexing - * relinked, e.g. when a native array is marked as non extensible - */ - public void invalidateSetters() { - //subclass responsibility + protected final static int alignUp(final int size) { + return size + CHUNK_SIZE - 1 & ~(CHUNK_SIZE - 1); } /** @@ -118,7 +279,7 @@ * @param length the initial length * @return ArrayData */ - public static ArrayData allocate(final int length) { + public static final ArrayData allocate(final int length) { if (length == 0) { return new IntArrayData(); } else if (length >= SparseArrayData.MAX_DENSE_LENGTH) { @@ -134,7 +295,7 @@ * @param array the array * @return ArrayData wrapping this array */ - public static ArrayData allocate(final Object array) { + public static final ArrayData allocate(final Object array) { final Class clazz = array.getClass(); if (clazz == int[].class) { @@ -154,7 +315,7 @@ * @param array the array to use for initial elements * @return the ArrayData */ - public static ArrayData allocate(final int[] array) { + public static final ArrayData allocate(final int[] array) { return new IntArrayData(array, array.length); } @@ -164,7 +325,7 @@ * @param array the array to use for initial elements * @return the ArrayData */ - public static ArrayData allocate(final long[] array) { + public static final ArrayData allocate(final long[] array) { return new LongArrayData(array, array.length); } @@ -174,7 +335,7 @@ * @param array the array to use for initial elements * @return the ArrayData */ - public static ArrayData allocate(final double[] array) { + public static final ArrayData allocate(final double[] array) { return new NumberArrayData(array, array.length); } @@ -184,7 +345,7 @@ * @param array the array to use for initial elements * @return the ArrayData */ - public static ArrayData allocate(final Object[] array) { + public static final ArrayData allocate(final Object[] array) { return new ObjectArrayData(array, array.length); } @@ -194,7 +355,7 @@ * @param buf the nio ByteBuffer to wrap * @return the ArrayData */ - public static ArrayData allocate(final ByteBuffer buf) { + public static final ArrayData allocate(final ByteBuffer buf) { return new ByteBufferArrayData(buf); } @@ -204,7 +365,7 @@ * @param underlying the underlying ArrayData to wrap in the freeze filter * @return the frozen ArrayData */ - public static ArrayData freeze(final ArrayData underlying) { + public static final ArrayData freeze(final ArrayData underlying) { return new FrozenArrayFilter(underlying); } @@ -214,11 +375,21 @@ * @param underlying the underlying ArrayData to wrap in the seal filter * @return the sealed ArrayData */ - public static ArrayData seal(final ArrayData underlying) { + public static final ArrayData seal(final ArrayData underlying) { return new SealedArrayFilter(underlying); } /** + * Prevent this array from being extended + * + * @param underlying the underlying ArrayData to wrap in the non extensible filter + * @return new array data, filtered + */ + public static final ArrayData preventExtension(final ArrayData underlying) { + return new NonExtensibleArrayFilter(underlying); + } + + /** * Return the length of the array data. This may differ from the actual * length of the array this wraps as length may be set or gotten as any * other JavaScript Property @@ -728,5 +899,4 @@ public GuardedInvocation findFastSetIndexMethod(final Class clazz, final CallSiteDescriptor desc, final LinkRequest request) { // array, index, value return null; } - } diff -r 094f0d95ef78 -r 78eb2b415108 src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java --- a/src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java Fri Oct 24 13:25:23 2014 +0200 +++ b/src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java Thu Oct 23 15:19:00 2014 +0400 @@ -1,5 +1,4 @@ /* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +29,6 @@ import static jdk.nashorn.internal.runtime.JSType.getAccessorTypeIndex; import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT; import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid; - import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; @@ -50,9 +48,6 @@ */ @Logger(name="arrays") public abstract class ContinuousArrayData extends ArrayData { - - private SwitchPoint sp; - /** * Constructor * @param length length (elementLength) @@ -61,18 +56,6 @@ super(length); } - private SwitchPoint ensureSwitchPointExists() { - if (sp == null){ - sp = new SwitchPoint(); - } - return sp; - } - - @Override - public void invalidateSetters() { - SwitchPoint.invalidateAll(new SwitchPoint[] { ensureSwitchPointExists() }); - } - /** * Check if we can put one more element at the end of this continous * array without reallocating, or if we are overwriting an already @@ -86,6 +69,14 @@ } /** + * Check if an arraydata is empty + * @return true if empty + */ + public boolean isEmpty() { + return length == 0L; + } + + /** * Return element getter for a certain type at a certain program point * @param returnType return type * @param programPoint program point @@ -109,13 +100,16 @@ * @param index index to check - currently only int indexes * @return index */ - protected int throwHas(final int index) { + protected final int throwHas(final int index) { if (!has(index)) { throw new ClassCastException(); } return index; } + @Override + public abstract ContinuousArrayData copy(); + /** * Returns the type used to store an element in this array * @return element type @@ -128,6 +122,25 @@ } /** + * Returns the boxed type of the type used to store an element in this array + * @return element type + */ + public abstract Class getBoxedElementType(); + + /** + * Get the widest element type of two arrays. This can be done faster in subclasses, but + * this works for all ContinuousArrayDatas and for where more optimal checks haven't been + * implemented. + * + * @param otherData another ContinuousArrayData + * @return the widest boxed element type + */ + public ContinuousArrayData widest(final ContinuousArrayData otherData) { + final Class elementType = getElementType(); + return Type.widest(elementType, otherData.getElementType()) == elementType ? this : otherData; + } + + /** * Look up a continuous array element getter * @param get getter, sometimes combined with a has check that throws CCE on failure for relink * @param returnType return type @@ -256,12 +269,7 @@ final Object[] args = request.getArguments(); final int index = (int)args[args.length - 2]; - //sp may be invalidated by e.g. preventExtensions before the first setter is linked - //then it is already created. otherwise, create it here to guard against future - //invalidations - ensureSwitchPointExists(); - - if (!sp.hasBeenInvalidated() && hasRoomFor(index)) { + if (hasRoomFor(index)) { MethodHandle setElement = getElementSetter(elementType); //Z(continuousarraydata, int, int), return true if successful if (setElement != null) { //else we are dealing with a wider type than supported by this callsite @@ -269,7 +277,7 @@ getArray = MH.asType(getArray, getArray.type().changeReturnType(getClass())); setElement = MH.filterArguments(setElement, 0, getArray); final MethodHandle guard = MH.insertArguments(FAST_ACCESS_GUARD, 0, clazz); - return new GuardedInvocation(setElement, guard, sp, ClassCastException.class); //CCE if not a scriptObject anymore + return new GuardedInvocation(setElement, guard, (SwitchPoint)null, ClassCastException.class); //CCE if not a scriptObject anymore } } } @@ -344,4 +352,13 @@ public Object fastPopObject() { throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink } + + /** + * Specialization - fast concat implementation + * @param otherData data to concat + * @return new arraydata + */ + public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) { + throw new ClassCastException(String.valueOf(getClass()) + " != " + String.valueOf(otherData.getClass())); + } } diff -r 094f0d95ef78 -r 78eb2b415108 src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java --- a/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java Fri Oct 24 13:25:23 2014 +0200 +++ b/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java Thu Oct 23 15:19:00 2014 +0400 @@ -26,7 +26,6 @@ package jdk.nashorn.internal.runtime.arrays; import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall; - import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.util.Arrays; @@ -57,17 +56,32 @@ * @param array an int array * @param length a length, not necessarily array.length */ - IntArrayData(final int array[], final int length) { + IntArrayData(final int[] array, final int length) { super(length); - assert array.length >= length; + assert array == null || array.length >= length; this.array = array; } @Override - public Class getElementType() { + public final Class getElementType() { return int.class; } + @Override + public final Class getBoxedElementType() { + return Integer.class; + } + + @Override + public final int getElementWeight() { + return 1; + } + + @Override + public final ContinuousArrayData widest(final ContinuousArrayData otherData) { + return otherData; + } + private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), IntArrayData.class, "getElem", int.class, int.class).methodHandle(); private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), IntArrayData.class, "setElem", void.class, int.class, int.class).methodHandle(); @@ -104,7 +118,7 @@ } @Override - public ArrayData copy() { + public IntArrayData copy() { return new IntArrayData(array.clone(), (int)length); } @@ -165,8 +179,7 @@ public ArrayData convert(final Class type) { if (type == Integer.class) { return this; - } - if (type == Long.class) { + } else if (type == Long.class) { return convertToLong(); } else if (type == Double.class) { return convertToDouble(); @@ -209,8 +222,7 @@ @Override public ArrayData shrink(final long newLength) { - Arrays.fill(array, (int) newLength, array.length, 0); - + Arrays.fill(array, (int)newLength, array.length, 0); return this; } @@ -322,10 +334,7 @@ @Override public ArrayData slice(final long from, final long to) { - final long start = from < 0 ? from + length : from; - final long newLength = to - start; - - return new IntArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength); + return new IntArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)(to - (from < 0 ? from + length : from))); } @Override @@ -347,7 +356,13 @@ throw new UnsupportedOperationException(); } final ArrayData returnValue = removed == 0 ? - EMPTY_ARRAY : new IntArrayData(Arrays.copyOfRange(array, start, start + removed), removed); + EMPTY_ARRAY : + new IntArrayData( + Arrays.copyOfRange( + array, + start, + start + removed), + removed); if (newLength != oldLength) { final int[] newArray; @@ -403,4 +418,26 @@ public Object fastPopObject() { return fastPopInt(); } + + @Override + public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) { + final int otherLength = (int)otherData.length; + final int thisLength = (int)length; + assert otherLength > 0 && thisLength > 0; + + final int[] otherArray = ((IntArrayData)otherData).array; + final int newLength = otherLength + thisLength; + final int[] newArray = new int[ArrayData.alignUp(newLength)]; + + System.arraycopy(array, 0, newArray, 0, thisLength); + System.arraycopy(otherArray, 0, newArray, thisLength, otherLength); + + return new IntArrayData(newArray, newLength); + } + + @Override + public String toString() { + assert length <= array.length : length + " > " + array.length; + return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length)); + } } diff -r 094f0d95ef78 -r 78eb2b415108 src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java --- a/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java Fri Oct 24 13:25:23 2014 +0200 +++ b/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java Thu Oct 23 15:19:00 2014 +0400 @@ -52,16 +52,31 @@ LongArrayData(final long array[], final int length) { super(length); assert array.length >= length; - this.array = array; + this.array = array; } @Override - public Class getElementType() { + public final Class getElementType() { return long.class; } @Override - public ArrayData copy() { + public final Class getBoxedElementType() { + return Long.class; + } + + @Override + public final ContinuousArrayData widest(final ContinuousArrayData otherData) { + return otherData instanceof IntElements ? this : otherData; + } + + @Override + public final int getElementWeight() { + return 2; + } + + @Override + public LongArrayData copy() { return new LongArrayData(array.clone(), (int)length); } @@ -101,7 +116,7 @@ } @Override - public ArrayData convert(final Class type) { + public ContinuousArrayData convert(final Class type) { if (type == Integer.class || type == Long.class) { return this; } @@ -145,8 +160,7 @@ @Override public ArrayData shrink(final long newLength) { - Arrays.fill(array, (int) newLength, array.length, 0); - + Arrays.fill(array, (int)newLength, array.length, 0L); return this; } @@ -359,4 +373,37 @@ public Object fastPopObject() { return fastPopLong(); } + + @Override + public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) { + final int otherLength = (int)otherData.length; + final int thisLength = (int)length; + assert otherLength > 0 && thisLength > 0; + + final long[] otherArray = ((LongArrayData)otherData).array; + final int newLength = otherLength + thisLength; + final long[] newArray = new long[ArrayData.alignUp(newLength)]; + + System.arraycopy(array, 0, newArray, 0, thisLength); + System.arraycopy(otherArray, 0, newArray, thisLength, otherLength); + + return new LongArrayData(newArray, newLength); + } + + @Override + public String toString() { + assert length <= array.length : length + " > " + array.length; + + final StringBuilder sb = new StringBuilder(getClass().getSimpleName()). + append(": ["); + for (int i = 0; i < length; i++) { + sb.append(array[i]).append('L'); //make sure L suffix is on elements, to discriminate this from IntArrayData.toString() + if (i + 1 < length) { + sb.append(", "); + } + } + sb.append(']'); + + return sb.toString(); + } } diff -r 094f0d95ef78 -r 78eb2b415108 src/jdk/nashorn/internal/runtime/arrays/NoTypeArrayData.java --- a/src/jdk/nashorn/internal/runtime/arrays/NoTypeArrayData.java Fri Oct 24 13:25:23 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,186 +0,0 @@ -/* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.nashorn.internal.runtime.arrays; - -import java.lang.reflect.Array; -import jdk.nashorn.internal.runtime.ScriptRuntime; - -/** - * Place holding array data for non-array objects. Activates a true array when - * accessed. Should only exist as a singleton defined in ArrayData. - */ -final class NoTypeArrayData extends ArrayData { - NoTypeArrayData() { - super(0); - } - - NoTypeArrayData(final long length) { - super(length); - } - - @Override - public Object[] asObjectArray() { - return ScriptRuntime.EMPTY_ARRAY; - } - - @Override - public ArrayData copy() { - return new NoTypeArrayData(); - } - - @Override - public Object asArrayOfType(final Class componentType) { - return Array.newInstance(componentType, 0); - } - - @Override - public ArrayData convert(final Class type) { - final long len = length; - final ArrayData arrayData; - if (type == Long.class) { - arrayData = new LongArrayData(new long[ArrayData.nextSize((int)len)], (int)len); - } else if (type == Double.class) { - arrayData = new NumberArrayData(new double[ArrayData.nextSize((int)len)], (int)len); - } else if (type == Integer.class) { - arrayData = new IntArrayData(new int[ArrayData.nextSize((int)len)], (int)len); - } else { - assert !type.isPrimitive(); - arrayData = new ObjectArrayData(new Object[ArrayData.nextSize((int)len)], (int)len); - } - return length == 0 ? arrayData : new DeletedRangeArrayFilter(arrayData, 0, len - 1); - } - - @Override - public void shiftLeft(final int by) { - //empty - } - - @Override - public ArrayData shiftRight(final int by) { - return this; - } - - @Override - public ArrayData ensure(final long safeIndex) { - if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH) { - return new SparseArrayData(this, safeIndex + 1); - } - - // Don't trample the shared EMPTY_ARRAY. - if (length == 0) { - return new NoTypeArrayData(Math.max(safeIndex + 1, length)); - } - - setLength(Math.max(safeIndex + 1, length)); - return this; - } - - @Override - public ArrayData shrink(final long newLength) { - return this; - } - - @Override - public ArrayData set(final int index, final Object value, final boolean strict) { - ArrayData newData; - - if (value instanceof Double) { - newData = convert(Double.class); - } else if (value instanceof Long) { - newData = convert(Long.class); - } else if (value instanceof Integer) { - newData = convert(Integer.class); - } else { - assert !(value instanceof Number); - newData = convert(value == null ? Object.class : value.getClass()); - } - - return newData.set(index, value, strict); - } - - @Override - public ArrayData set(final int index, final int value, final boolean strict) { - final ArrayData newData = convert(Integer.class); - return newData.set(index, value, strict); - } - - @Override - public ArrayData set(final int index, final long value, final boolean strict) { - final ArrayData newData = convert(Long.class); - return newData.set(index, value, strict); - } - - @Override - public ArrayData set(final int index, final double value, final boolean strict) { - final ArrayData newData = convert(Double.class); - return newData.set(index, value, strict); - } - - @Override - public int getInt(final int index) { - throw new ArrayIndexOutOfBoundsException(index); - } - - @Override - public long getLong(final int index) { - throw new ArrayIndexOutOfBoundsException(index); - } - - @Override - public double getDouble(final int index) { - throw new ArrayIndexOutOfBoundsException(index); - } - - @Override - public Object getObject(final int index) { - throw new ArrayIndexOutOfBoundsException(index); - } - - @Override - public boolean has(final int index) { - return false; - } - - @Override - public ArrayData delete(final int index) { - return new DeletedRangeArrayFilter(this, index, index); - } - - @Override - public ArrayData delete(final long fromIndex, final long toIndex) { - return new DeletedRangeArrayFilter(this, fromIndex, toIndex); - } - - @Override - public Object pop() { - return ScriptRuntime.UNDEFINED; - } - - @Override - public ArrayData slice(final long from, final long to) { - return this; - } -} diff -r 094f0d95ef78 -r 78eb2b415108 src/jdk/nashorn/internal/runtime/arrays/NonExtensibleArrayFilter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk/nashorn/internal/runtime/arrays/NonExtensibleArrayFilter.java Thu Oct 23 15:19:00 2014 +0400 @@ -0,0 +1,68 @@ +package jdk.nashorn.internal.runtime.arrays; + +import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; +import jdk.nashorn.internal.objects.Global; +import jdk.nashorn.internal.runtime.ScriptRuntime; + +/** + * Filter class that wrap arrays that have been tagged non extensible + */ +public class NonExtensibleArrayFilter extends ArrayFilter { + + /** + * Constructor + * @param underlying array + */ + public NonExtensibleArrayFilter(final ArrayData underlying) { + super(underlying); + } + + @Override + public ArrayData copy() { + return new NonExtensibleArrayFilter(underlying.copy()); + } + + @Override + public ArrayData slice(final long from, final long to) { + return new NonExtensibleArrayFilter(underlying.slice(from, to)); + } + + private ArrayData extensionCheck(final boolean strict, final int index) { + if (!strict) { + return this; + } + throw typeError(Global.instance(), "object.non.extensible", String.valueOf(index), ScriptRuntime.safeToString(this)); + } + + @Override + public ArrayData set(final int index, final Object value, final boolean strict) { + if (has(index)) { + return underlying.set(index, value, strict); + } + return extensionCheck(strict, index); + } + + @Override + public ArrayData set(final int index, final int value, final boolean strict) { + if (has(index)) { + return underlying.set(index, value, strict); + } + return extensionCheck(strict, index); + } + + @Override + public ArrayData set(final int index, final long value, final boolean strict) { + if (has(index)) { + return underlying.set(index, value, strict); + } + return extensionCheck(strict, index); + } + + @Override + public ArrayData set(final int index, final double value, final boolean strict) { + if (has(index)) { + return underlying.set(index, value, strict); + } + return extensionCheck(strict, index); + } +} diff -r 094f0d95ef78 -r 78eb2b415108 src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java --- a/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java Fri Oct 24 13:25:23 2014 +0200 +++ b/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java Thu Oct 23 15:19:00 2014 +0400 @@ -48,19 +48,34 @@ * @param array an int array * @param length a length, not necessarily array.length */ - NumberArrayData(final double array[], final int length) { + NumberArrayData(final double[] array, final int length) { super(length); assert array.length >= length; - this.array = array; + this.array = array; } @Override - public Class getElementType() { + public final Class getElementType() { return double.class; } @Override - public ArrayData copy() { + public final Class getBoxedElementType() { + return Double.class; + } + + @Override + public final int getElementWeight() { + return 3; + } + + @Override + public final ContinuousArrayData widest(final ContinuousArrayData otherData) { + return otherData instanceof IntOrLongElements ? this : otherData; + } + + @Override + public NumberArrayData copy() { return new NumberArrayData(array.clone(), (int)length); } @@ -88,7 +103,7 @@ } @Override - public ArrayData convert(final Class type) { + public ContinuousArrayData convert(final Class type) { if (type != Double.class && type != Integer.class && type != Long.class) { final int len = (int)length; return new ObjectArrayData(toObjectArray(false), len); @@ -129,7 +144,7 @@ @Override public ArrayData shrink(final long newLength) { - Arrays.fill(array, (int) newLength, array.length, 0.0); + Arrays.fill(array, (int)newLength, array.length, 0.0); return this; } @@ -334,4 +349,26 @@ public Object fastPopObject() { return fastPopDouble(); } + + @Override + public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) { + final int otherLength = (int)otherData.length; + final int thisLength = (int)length; + assert otherLength > 0 && thisLength > 0; + + final double[] otherArray = ((NumberArrayData)otherData).array; + final int newLength = otherLength + thisLength; + final double[] newArray = new double[ArrayData.alignUp(newLength)]; + + System.arraycopy(array, 0, newArray, 0, thisLength); + System.arraycopy(otherArray, 0, newArray, thisLength, otherLength); + + return new NumberArrayData(newArray, newLength); + } + + @Override + public String toString() { + assert length <= array.length : length + " > " + array.length; + return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length)); + } } diff -r 094f0d95ef78 -r 78eb2b415108 src/jdk/nashorn/internal/runtime/arrays/NumericElements.java --- a/src/jdk/nashorn/internal/runtime/arrays/NumericElements.java Fri Oct 24 13:25:23 2014 +0200 +++ b/src/jdk/nashorn/internal/runtime/arrays/NumericElements.java Thu Oct 23 15:19:00 2014 +0400 @@ -30,6 +30,6 @@ * Used for type checks that throw ClassCastExceptions and force relinks * for fast NativeArray specializations of builtin methods */ -public interface NumericElements { +public interface NumericElements extends AnyElements { //empty } diff -r 094f0d95ef78 -r 78eb2b415108 src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java --- a/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java Fri Oct 24 13:25:23 2014 +0200 +++ b/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java Thu Oct 23 15:19:00 2014 +0400 @@ -37,7 +37,7 @@ * Implementation of {@link ArrayData} as soon as an Object has been * written to the array */ -final class ObjectArrayData extends ContinuousArrayData { +final class ObjectArrayData extends ContinuousArrayData implements AnyElements { /** * The wrapped array @@ -49,19 +49,34 @@ * @param array an int array * @param length a length, not necessarily array.length */ - ObjectArrayData(final Object array[], final int length) { + ObjectArrayData(final Object[] array, final int length) { super(length); assert array.length >= length; this.array = array; } @Override - public Class getElementType() { + public final Class getElementType() { return Object.class; } @Override - public ArrayData copy() { + public final Class getBoxedElementType() { + return getElementType(); + } + + @Override + public final int getElementWeight() { + return 4; + } + + @Override + public final ContinuousArrayData widest(final ContinuousArrayData otherData) { + return otherData instanceof NumericElements ? this : otherData; + } + + @Override + public ObjectArrayData copy() { return new ObjectArrayData(array.clone(), (int)length); } @@ -79,7 +94,7 @@ } @Override - public ArrayData convert(final Class type) { + public ObjectArrayData convert(final Class type) { return this; } @@ -325,4 +340,26 @@ return returnValue; } + + @Override + public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) { + final int otherLength = (int)otherData.length; + final int thisLength = (int)length; + assert otherLength > 0 && thisLength > 0; + + final Object[] otherArray = ((ObjectArrayData)otherData).array; + final int newLength = otherLength + thisLength; + final Object[] newArray = new Object[ArrayData.alignUp(newLength)]; + + System.arraycopy(array, 0, newArray, 0, thisLength); + System.arraycopy(otherArray, 0, newArray, thisLength, otherLength); + + return new ObjectArrayData(newArray, newLength); + } + + @Override + public String toString() { + assert length <= array.length : length + " > " + array.length; + return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length)); + } } diff -r 094f0d95ef78 -r 78eb2b415108 src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java --- a/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java Fri Oct 24 13:25:23 2014 +0200 +++ b/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java Thu Oct 23 15:19:00 2014 +0400 @@ -88,7 +88,7 @@ } @Override - public ArrayData copy() { + public TypedArrayData copy() { throw new UnsupportedOperationException(); } @@ -133,7 +133,7 @@ } @Override - public ArrayData convert(final Class type) { + public TypedArrayData convert(final Class type) { throw new UnsupportedOperationException(); } diff -r 094f0d95ef78 -r 78eb2b415108 test/script/basic/JDK-8061391.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8061391.js Thu Oct 23 15:19:00 2014 +0400 @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * JDK-8061391 - Checks that the optimistic builtin for concat is semantically + * correct. + * + * @test + * @run + */ + +var maxJavaInt = 0x7fffffff; + +var ia = [1, 2, 3, 4]; +var la = [maxJavaInt + 1000, maxJavaInt + 2000, maxJavaInt + 3000, maxJavaInt + 4000]; +var da = [1.1, 2.2, 3.3, 4.4]; +var oa = ["one", "two", "three", "four"]; + +var aa = [ia, la, da, oa]; + +function concats() { + print("shared callsite"); + + print(ia); + print(la); + print(da); + print(oa); + print(aa); + + for (var i = 0; i < aa.length; i++) { + print(aa[i].concat(aa[i][0])); + for (var j = 0; j < aa.length ; j++) { + print(aa[i].concat(aa[j])); + } + } +} + +function concats_inline() { + print("separate callsites"); + + print(ia); + print(la); + print(da); + print(oa); + print(aa); + + print(aa[0].concat(aa[0])); + print(aa[0].concat(aa[1])); + print(aa[0].concat(aa[2])); + print(aa[0].concat(aa[3])); + print(aa[0].concat(aa[0][0])); + + print(aa[1].concat(aa[0])); + print(aa[1].concat(aa[1])); + print(aa[1].concat(aa[2])); + print(aa[1].concat(aa[3])); + print(aa[1].concat(aa[1][0])); + + print(aa[2].concat(aa[0])); + print(aa[2].concat(aa[1])); + print(aa[2].concat(aa[2])); + print(aa[2].concat(aa[3])); + print(aa[2].concat(aa[2][0])); + + print(aa[3].concat(aa[0])); + print(aa[3].concat(aa[1])); + print(aa[3].concat(aa[2])); + print(aa[3].concat(aa[3])); + print(aa[3].concat(aa[3][0])); +} + +concats(); +concats_inline(); + +print(); +var oldia = ia.slice(0); //clone ia +print("oldia = " + oldia); +ia[10] = "sparse"; +print("oldia = " + oldia); + +print(); +print("Redoing with sparse arrays"); + +concats(); +concats_inline(); + +ia = oldia; +print("Restored ia = " + ia); + +function concat_expand() { + print("concat type expansion"); + print(ia.concat(la)); + print(ia.concat(da)); + print(ia.concat(oa)); + print(la.concat(ia)); + print(la.concat(da)); + print(la.concat(oa)); + print(da.concat(ia)); + print(da.concat(la)); + print(da.concat(oa)); +} + +print(); +concat_expand(); + +print(); + +function concat_varargs() { + print("concat varargs"); + print(ia.concat(la)); //fast + print(ia.concat(la, da, oa)); //slow + var slow = ia.concat(1, maxJavaInt * 2, 4711.17, function() { print("hello, world") }); //slow + print(slow); + return slow; +} + +var slow = concat_varargs(); + +print(); +print("sanity checks"); +slow.map( + function(elem) { + if (elem instanceof Function) { + elem(); + } else { + print((typeof elem) + " = " + elem); + } + }); + +print(ia.concat({key: "value"})); +print(ia.concat({key: "value"}, {key2: "value2"})); diff -r 094f0d95ef78 -r 78eb2b415108 test/script/basic/JDK-8061391.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8061391.js.EXPECTED Thu Oct 23 15:19:00 2014 +0400 @@ -0,0 +1,138 @@ +shared callsite +1,2,3,4 +2147484647,2147485647,2147486647,2147487647 +1.1,2.2,3.3,4.4 +one,two,three,four +1,2,3,4,2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4,one,two,three,four +1,2,3,4,1 +1,2,3,4,1,2,3,4 +1,2,3,4,2147484647,2147485647,2147486647,2147487647 +1,2,3,4,1.1,2.2,3.3,4.4 +1,2,3,4,one,two,three,four +2147484647,2147485647,2147486647,2147487647,2147484647 +2147484647,2147485647,2147486647,2147487647,1,2,3,4 +2147484647,2147485647,2147486647,2147487647,2147484647,2147485647,2147486647,2147487647 +2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4 +2147484647,2147485647,2147486647,2147487647,one,two,three,four +1.1,2.2,3.3,4.4,1.1 +1.1,2.2,3.3,4.4,1,2,3,4 +1.1,2.2,3.3,4.4,2147484647,2147485647,2147486647,2147487647 +1.1,2.2,3.3,4.4,1.1,2.2,3.3,4.4 +1.1,2.2,3.3,4.4,one,two,three,four +one,two,three,four,one +one,two,three,four,1,2,3,4 +one,two,three,four,2147484647,2147485647,2147486647,2147487647 +one,two,three,four,1.1,2.2,3.3,4.4 +one,two,three,four,one,two,three,four +separate callsites +1,2,3,4 +2147484647,2147485647,2147486647,2147487647 +1.1,2.2,3.3,4.4 +one,two,three,four +1,2,3,4,2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4,one,two,three,four +1,2,3,4,1,2,3,4 +1,2,3,4,2147484647,2147485647,2147486647,2147487647 +1,2,3,4,1.1,2.2,3.3,4.4 +1,2,3,4,one,two,three,four +1,2,3,4,1 +2147484647,2147485647,2147486647,2147487647,1,2,3,4 +2147484647,2147485647,2147486647,2147487647,2147484647,2147485647,2147486647,2147487647 +2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4 +2147484647,2147485647,2147486647,2147487647,one,two,three,four +2147484647,2147485647,2147486647,2147487647,2147484647 +1.1,2.2,3.3,4.4,1,2,3,4 +1.1,2.2,3.3,4.4,2147484647,2147485647,2147486647,2147487647 +1.1,2.2,3.3,4.4,1.1,2.2,3.3,4.4 +1.1,2.2,3.3,4.4,one,two,three,four +1.1,2.2,3.3,4.4,1.1 +one,two,three,four,1,2,3,4 +one,two,three,four,2147484647,2147485647,2147486647,2147487647 +one,two,three,four,1.1,2.2,3.3,4.4 +one,two,three,four,one,two,three,four +one,two,three,four,one + +oldia = 1,2,3,4 +oldia = 1,2,3,4 + +Redoing with sparse arrays +shared callsite +1,2,3,4,,,,,,,sparse +2147484647,2147485647,2147486647,2147487647 +1.1,2.2,3.3,4.4 +one,two,three,four +1,2,3,4,,,,,,,sparse,2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4,one,two,three,four +1,2,3,4,,,,,,,sparse,1 +1,2,3,4,,,,,,,sparse,1,2,3,4,,,,,,,sparse +1,2,3,4,,,,,,,sparse,2147484647,2147485647,2147486647,2147487647 +1,2,3,4,,,,,,,sparse,1.1,2.2,3.3,4.4 +1,2,3,4,,,,,,,sparse,one,two,three,four +2147484647,2147485647,2147486647,2147487647,2147484647 +2147484647,2147485647,2147486647,2147487647,1,2,3,4,,,,,,,sparse +2147484647,2147485647,2147486647,2147487647,2147484647,2147485647,2147486647,2147487647 +2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4 +2147484647,2147485647,2147486647,2147487647,one,two,three,four +1.1,2.2,3.3,4.4,1.1 +1.1,2.2,3.3,4.4,1,2,3,4,,,,,,,sparse +1.1,2.2,3.3,4.4,2147484647,2147485647,2147486647,2147487647 +1.1,2.2,3.3,4.4,1.1,2.2,3.3,4.4 +1.1,2.2,3.3,4.4,one,two,three,four +one,two,three,four,one +one,two,three,four,1,2,3,4,,,,,,,sparse +one,two,three,four,2147484647,2147485647,2147486647,2147487647 +one,two,three,four,1.1,2.2,3.3,4.4 +one,two,three,four,one,two,three,four +separate callsites +1,2,3,4,,,,,,,sparse +2147484647,2147485647,2147486647,2147487647 +1.1,2.2,3.3,4.4 +one,two,three,four +1,2,3,4,,,,,,,sparse,2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4,one,two,three,four +1,2,3,4,,,,,,,sparse,1,2,3,4,,,,,,,sparse +1,2,3,4,,,,,,,sparse,2147484647,2147485647,2147486647,2147487647 +1,2,3,4,,,,,,,sparse,1.1,2.2,3.3,4.4 +1,2,3,4,,,,,,,sparse,one,two,three,four +1,2,3,4,,,,,,,sparse,1 +2147484647,2147485647,2147486647,2147487647,1,2,3,4,,,,,,,sparse +2147484647,2147485647,2147486647,2147487647,2147484647,2147485647,2147486647,2147487647 +2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4 +2147484647,2147485647,2147486647,2147487647,one,two,three,four +2147484647,2147485647,2147486647,2147487647,2147484647 +1.1,2.2,3.3,4.4,1,2,3,4,,,,,,,sparse +1.1,2.2,3.3,4.4,2147484647,2147485647,2147486647,2147487647 +1.1,2.2,3.3,4.4,1.1,2.2,3.3,4.4 +1.1,2.2,3.3,4.4,one,two,three,four +1.1,2.2,3.3,4.4,1.1 +one,two,three,four,1,2,3,4,,,,,,,sparse +one,two,three,four,2147484647,2147485647,2147486647,2147487647 +one,two,three,four,1.1,2.2,3.3,4.4 +one,two,three,four,one,two,three,four +one,two,three,four,one +Restored ia = 1,2,3,4 + +concat type expansion +1,2,3,4,2147484647,2147485647,2147486647,2147487647 +1,2,3,4,1.1,2.2,3.3,4.4 +1,2,3,4,one,two,three,four +2147484647,2147485647,2147486647,2147487647,1,2,3,4 +2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4 +2147484647,2147485647,2147486647,2147487647,one,two,three,four +1.1,2.2,3.3,4.4,1,2,3,4 +1.1,2.2,3.3,4.4,2147484647,2147485647,2147486647,2147487647 +1.1,2.2,3.3,4.4,one,two,three,four + +concat varargs +1,2,3,4,2147484647,2147485647,2147486647,2147487647 +1,2,3,4,2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4,one,two,three,four +1,2,3,4,1,4294967294,4711.17,function() { print("hello, world") } + +sanity checks +number = 1 +number = 2 +number = 3 +number = 4 +number = 1 +number = 4294967294 +number = 4711.17 +hello, world +1,2,3,4,[object Object] +1,2,3,4,[object Object],[object Object] diff -r 094f0d95ef78 -r 78eb2b415108 test/script/basic/JDK-8061391_2.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8061391_2.js Thu Oct 23 15:19:00 2014 +0400 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * Array extension check + * + * @test + * @run + */ + +"use strict"; +var a = [1,2,3]; +Object.preventExtensions(a); +try { + a[4] = 4; + print(a); +} catch (e) { + if (!(e instanceof TypeError)) { + print("TypeError expected but got e"); + } +} + +if (a[0] != 1) { + throw "element 0 is wrong"; +} +if (a[1] != 2) { + throw "element 1 is wrong"; +} +if (a[2] != 3) { + throw "element 2 is wrong"; +} + diff -r 094f0d95ef78 -r 78eb2b415108 test/script/basic/JDK-8061391_3.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8061391_3.js Thu Oct 23 15:19:00 2014 +0400 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * Array extension check + * + * @test + * @run + */ + +var a = [1,2,3]; +Object.preventExtensions(a); +a[4] = 4; +print(a); +if (a[0] != 1) { + throw "element 0 is wrong"; +} +if (a[1] != 2) { + throw "element 1 is wrong"; +} +if (a[2] != 3) { + throw "element 2 is wrong"; +} + diff -r 094f0d95ef78 -r 78eb2b415108 test/script/basic/JDK-8061391_3.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8061391_3.js.EXPECTED Thu Oct 23 15:19:00 2014 +0400 @@ -0,0 +1,1 @@ +1,2,3