Mercurial > hg > shenandoah-preopenjdk-archive > openjdk8 > nashorn
changeset 1074:d60fbb5343c1 jdk8u40-b13
Merge
author | lana |
---|---|
date | Fri, 31 Oct 2014 20:17:42 -0700 |
parents | 21efaa9e20a5 (current diff) 73ca7a752ba1 (diff) |
children | 7e34104c55ca ad5f0c0eb313 |
files | src/jdk/nashorn/internal/runtime/arrays/NoTypeArrayData.java |
diffstat | 55 files changed, 1821 insertions(+), 541 deletions(-) [+] |
line wrap: on
line diff
--- a/bin/runopt.sh Wed Oct 29 10:50:44 2014 -0700 +++ b/bin/runopt.sh Fri Oct 31 20:17:42 2014 -0700 @@ -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 -
--- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java Fri Oct 31 20:17:42 2014 -0700 @@ -208,6 +208,8 @@ private static final Type ITERATOR_TYPE = Type.typeFor(ITERATOR_CLASS); private static final Type EXCEPTION_TYPE = Type.typeFor(CompilerConstants.EXCEPTION_PREFIX.type()); + private static final Integer INT_ZERO = Integer.valueOf(0); + /** Constant data & installation. The only reason the compiler keeps this is because it is assigned * by reflection in class installation */ private final Compiler compiler; @@ -3817,7 +3819,12 @@ private void doSHR() { // TODO: make SHR optimistic - method.shr().convert(Type.LONG).load(JSType.MAX_UINT).and(); + method.shr(); + toUint(); + } + + private void toUint() { + JSType.TO_UINT32_I.invoke(method); } private void loadASSIGN_SUB(final BinaryNode binaryNode) { @@ -3879,8 +3886,18 @@ } private void loadBIT_OR(final BinaryNode binaryNode) { - loadBinaryOperands(binaryNode); - method.or(); + // Optimize x|0 to (int)x + if (isRhsZero(binaryNode)) { + loadExpressionAsType(binaryNode.lhs(), Type.INT); + } else { + loadBinaryOperands(binaryNode); + method.or(); + } + } + + private static boolean isRhsZero(final BinaryNode binaryNode) { + final Expression rhs = binaryNode.rhs(); + return rhs instanceof LiteralNode && INT_ZERO.equals(((LiteralNode)rhs).getValue()); } private void loadBIT_XOR(final BinaryNode binaryNode) { @@ -3957,8 +3974,14 @@ } private void loadSHR(final BinaryNode binaryNode) { - loadBinaryOperands(binaryNode); - doSHR(); + // Optimize x >>> 0 to (uint)x + if (isRhsZero(binaryNode)) { + loadExpressionAsType(binaryNode.lhs(), Type.INT); + toUint(); + } else { + loadBinaryOperands(binaryNode); + doSHR(); + } } private void loadSUB(final BinaryNode binaryNode, final TypeBounds resultBounds) {
--- a/src/jdk/nashorn/internal/codegen/FoldConstants.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/codegen/FoldConstants.java Fri Oct 31 20:17:42 2014 -0700 @@ -291,7 +291,7 @@ value = lhs.getNumber() - rhs.getNumber(); break; case SHR: - return LiteralNode.newInstance(token, finish, (lhs.getInt32() >>> rhs.getInt32()) & JSType.MAX_UINT); + return LiteralNode.newInstance(token, finish, JSType.toUint32(lhs.getInt32() >>> rhs.getInt32())); case SAR: return LiteralNode.newInstance(token, finish, lhs.getInt32() >> rhs.getInt32()); case SHL:
--- a/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java Fri Oct 31 20:17:42 2014 -0700 @@ -88,7 +88,7 @@ final Property property = propertyMap.findProperty(key); if (property != null) { // normal property key - property.setCurrentType(JSType.unboxedFieldType(constantValue)); + property.setType(JSType.unboxedFieldType(constantValue)); final int slot = property.getSlot(); if (!OBJECT_FIELDS_ONLY && constantValue instanceof Number) { jpresetValues[slot] = ObjectClassGenerator.pack((Number)constantValue);
--- a/src/jdk/nashorn/internal/codegen/TypeEvaluator.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/codegen/TypeEvaluator.java Fri Oct 31 20:17:42 2014 -0700 @@ -117,7 +117,7 @@ } final Property property = find.getProperty(); - final Class<?> propertyClass = property.getCurrentType(); + final Class<?> propertyClass = property.getType(); if (propertyClass == null) { // propertyClass == null means its value is Undefined. It is probably not initialized yet, so we won't make // a type assumption yet.
--- a/src/jdk/nashorn/internal/codegen/types/Type.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/codegen/types/Type.java Fri Oct 31 20:17:42 2014 -0700 @@ -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
--- a/src/jdk/nashorn/internal/objects/NativeArray.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/objects/NativeArray.java Fri Oct 31 20:17:42 2014 -0700 @@ -33,6 +33,7 @@ import static jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator.arrayLikeIterator; import static jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator.reverseArrayLikeIterator; import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_STRICT; + import java.lang.invoke.MethodHandle; import java.lang.invoke.SwitchPoint; import java.util.ArrayList; @@ -92,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 @@ -130,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]; @@ -266,7 +270,7 @@ @Override public Object getLength() { - final long length = getArray().length() & JSType.MAX_UINT; + final long length = JSType.toUint32(getArray().length()); if(length < Integer.MAX_VALUE) { return (int)length; } @@ -476,7 +480,7 @@ @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE) public static Object length(final Object self) { if (isArray(self)) { - return ((ScriptObject) self).getArray().length() & JSType.MAX_UINT; + return JSType.toUint32(((ScriptObject) self).getArray().length()); } return 0; @@ -757,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<Object> list = new ArrayList<>(); + concatToList(list, Global.toObject(self)); for (final Object obj : args) { @@ -1692,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 } /** @@ -1798,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 { @@ -1864,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"
--- a/src/jdk/nashorn/internal/objects/NativeDataView.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/objects/NativeDataView.java Fri Oct 31 20:17:42 2014 -0700 @@ -27,6 +27,7 @@ import static jdk.nashorn.internal.runtime.ECMAErrors.rangeError; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; + import java.nio.ByteBuffer; import java.nio.ByteOrder; import jdk.nashorn.internal.objects.annotations.Attribute; @@ -432,7 +433,7 @@ @SpecializedFunction public static long getUint32(final Object self, final int byteOffset) { try { - return JSType.MAX_UINT & getBuffer(self, false).getInt(JSType.toInt32(byteOffset)); + return JSType.toUint32(getBuffer(self, false).getInt(JSType.toInt32(byteOffset))); } catch (final IllegalArgumentException iae) { throw rangeError(iae, "dataview.offset"); } @@ -449,7 +450,7 @@ @SpecializedFunction public static long getUint32(final Object self, final int byteOffset, final boolean littleEndian) { try { - return JSType.MAX_UINT & getBuffer(self, littleEndian).getInt(JSType.toInt32(byteOffset)); + return JSType.toUint32(getBuffer(self, littleEndian).getInt(JSType.toInt32(byteOffset))); } catch (final IllegalArgumentException iae) { throw rangeError(iae, "dataview.offset"); }
--- a/src/jdk/nashorn/internal/objects/NativeDate.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/objects/NativeDate.java Fri Oct 31 20:17:42 2014 -0700 @@ -1045,7 +1045,8 @@ // ECMA 15.9.1.2 TimeWithinDay (t) private static double timeWithinDay(final double t) { - return t % msPerDay; + final double val = t % msPerDay; + return val < 0? val + msPerDay : val; } // ECMA 15.9.1.3 InLeapYear (t)
--- a/src/jdk/nashorn/internal/objects/NativeFloat32Array.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/objects/NativeFloat32Array.java Fri Oct 31 20:17:42 2014 -0700 @@ -90,6 +90,11 @@ } @Override + public Class<?> getBoxedElementType() { + return Double.class; + } + + @Override protected MethodHandle getGetElem() { return GET_ELEM; }
--- a/src/jdk/nashorn/internal/objects/NativeFloat64Array.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/objects/NativeFloat64Array.java Fri Oct 31 20:17:42 2014 -0700 @@ -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);
--- a/src/jdk/nashorn/internal/objects/NativeInt16Array.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/objects/NativeInt16Array.java Fri Oct 31 20:17:42 2014 -0700 @@ -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);
--- a/src/jdk/nashorn/internal/objects/NativeInt32Array.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/objects/NativeInt32Array.java Fri Oct 31 20:17:42 2014 -0700 @@ -118,6 +118,11 @@ } @Override + public Class<?> getBoxedElementType() { + return Integer.class; + } + + @Override public int getInt(final int index) { return getElem(index); }
--- a/src/jdk/nashorn/internal/objects/NativeInt8Array.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/objects/NativeInt8Array.java Fri Oct 31 20:17:42 2014 -0700 @@ -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);
--- a/src/jdk/nashorn/internal/objects/NativeObject.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/objects/NativeObject.java Fri Oct 31 20:17:42 2014 -0700 @@ -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; @@ -673,7 +672,7 @@ for (final Property prop : properties) { if (prop.isEnumerable()) { final Object value = sourceObj.get(prop.getKey()); - prop.setCurrentType(Object.class); + prop.setType(Object.class); prop.setValue(sourceObj, sourceObj, value, false); propList.add(prop); }
--- a/src/jdk/nashorn/internal/objects/NativeRegExpExecResult.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/objects/NativeRegExpExecResult.java Fri Oct 31 20:17:42 2014 -0700 @@ -74,7 +74,7 @@ @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE) public static Object length(final Object self) { if (self instanceof ScriptObject) { - return ((ScriptObject)self).getArray().length() & JSType.MAX_UINT; + return JSType.toUint32(((ScriptObject)self).getArray().length()); } return 0;
--- a/src/jdk/nashorn/internal/objects/NativeUint16Array.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/objects/NativeUint16Array.java Fri Oct 31 20:17:42 2014 -0700 @@ -124,6 +124,11 @@ } @Override + public Class<?> getBoxedElementType() { + return Integer.class; + } + + @Override public int getInt(final int index) { return getElem(index); }
--- a/src/jdk/nashorn/internal/objects/NativeUint32Array.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/objects/NativeUint32Array.java Fri Oct 31 20:17:42 2014 -0700 @@ -105,7 +105,7 @@ private long getElem(final int index) { try { - return nb.get(index) & JSType.MAX_UINT; + return JSType.toUint32(nb.get(index)); } catch (final IndexOutOfBoundsException e) { throw new ClassCastException(); //force relink - this works for unoptimistic too } @@ -133,6 +133,11 @@ } @Override + public Class<?> getBoxedElementType() { + return Integer.class; + } + + @Override public int getInt(final int index) { return (int)getLong(index); }
--- a/src/jdk/nashorn/internal/objects/NativeUint8Array.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/objects/NativeUint8Array.java Fri Oct 31 20:17:42 2014 -0700 @@ -124,6 +124,11 @@ } @Override + public Class<?> getBoxedElementType() { + return Integer.class; + } + + @Override public int getInt(final int index) { return getElem(index); }
--- a/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java Fri Oct 31 20:17:42 2014 -0700 @@ -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;
--- a/src/jdk/nashorn/internal/parser/JSONParser.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/parser/JSONParser.java Fri Oct 31 20:17:42 2014 -0700 @@ -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;
--- a/src/jdk/nashorn/internal/runtime/AccessorProperty.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/runtime/AccessorProperty.java Fri Oct 31 20:17:42 2014 -0700 @@ -145,13 +145,6 @@ transient MethodHandle objectSetter; /** - * Current type of this object, in object only mode, this is an Object.class. In dual-fields mode - * null means undefined, and primitive types are allowed. The reason a special type is used for - * undefined, is that are no bits left to represent it in primitive types - */ - private Class<?> currentType; - - /** * Delegate constructor for bound properties. This is used for properties created by * {@link ScriptRuntime#mergeScope} and the Nashorn {@code Object.bindProperties} method. * The former is used to add a script's defined globals to the current global scope while @@ -171,7 +164,7 @@ this.objectSetter = bindTo(property.objectSetter, delegate); property.GETTER_CACHE = new MethodHandle[NOOF_TYPES]; // Properties created this way are bound to a delegate - setCurrentType(property.getCurrentType()); + setType(property.getType()); } /** @@ -248,7 +241,7 @@ objectGetter = getter.type() != Lookup.GET_OBJECT_TYPE ? MH.asType(getter, Lookup.GET_OBJECT_TYPE) : getter; objectSetter = setter != null && setter.type() != Lookup.SET_OBJECT_TYPE ? MH.asType(setter, Lookup.SET_OBJECT_TYPE) : setter; - setCurrentType(OBJECT_FIELDS_ONLY ? Object.class : getterType); + setType(OBJECT_FIELDS_ONLY ? Object.class : getterType); } /** @@ -317,7 +310,7 @@ */ public AccessorProperty(final String key, final int flags, final Class<?> structure, final int slot, final Class<?> initialType) { this(key, flags, structure, slot); - setCurrentType(OBJECT_FIELDS_ONLY ? Object.class : initialType); + setType(OBJECT_FIELDS_ONLY ? Object.class : initialType); } /** @@ -330,13 +323,13 @@ protected AccessorProperty(final AccessorProperty property, final Class<?> newType) { super(property, property.getFlags()); - this.GETTER_CACHE = newType != property.getCurrentType() ? new MethodHandle[NOOF_TYPES] : property.GETTER_CACHE; + this.GETTER_CACHE = newType != property.getLocalType() ? new MethodHandle[NOOF_TYPES] : property.GETTER_CACHE; this.primitiveGetter = property.primitiveGetter; this.primitiveSetter = property.primitiveSetter; this.objectGetter = property.objectGetter; this.objectSetter = property.objectSetter; - setCurrentType(newType); + setType(newType); } /** @@ -345,7 +338,7 @@ * @param property source property */ protected AccessorProperty(final AccessorProperty property) { - this(property, property.getCurrentType()); + this(property, property.getLocalType()); } /** @@ -354,7 +347,7 @@ * @param initialValue initial value */ protected final void setInitialValue(final ScriptObject owner, final Object initialValue) { - setCurrentType(JSType.unboxedFieldType(initialValue)); + setType(JSType.unboxedFieldType(initialValue)); if (initialValue instanceof Integer) { invokeSetter(owner, ((Integer)initialValue).intValue()); } else if (initialValue instanceof Long) { @@ -370,7 +363,7 @@ * Initialize the type of a property */ protected final void initializeType() { - setCurrentType(OBJECT_FIELDS_ONLY ? Object.class : null); + setType(OBJECT_FIELDS_ONLY ? Object.class : null); } private void readObject(final ObjectInputStream s) throws IOException, ClassNotFoundException { @@ -557,12 +550,12 @@ } else { getter = debug( createGetter( - getCurrentType(), + getLocalType(), type, primitiveGetter, objectGetter, INVALID_PROGRAM_POINT), - getCurrentType(), + getLocalType(), type, "get"); getterCache[i] = getter; @@ -582,18 +575,18 @@ return debug( createGetter( - getCurrentType(), + getLocalType(), type, primitiveGetter, objectGetter, programPoint), - getCurrentType(), + getLocalType(), type, "get"); } private MethodHandle getOptimisticPrimitiveGetter(final Class<?> type, final int programPoint) { - final MethodHandle g = getGetter(getCurrentType()); + final MethodHandle g = getGetter(getLocalType()); return MH.asType(OptimisticReturnFilters.filterOptimisticReturnValue(g, type, programPoint), g.type().changeReturnType(type)); } @@ -631,7 +624,7 @@ } private MethodHandle generateSetter(final Class<?> forType, final Class<?> type) { - return debug(createSetter(forType, type, primitiveSetter, objectSetter), getCurrentType(), type, "set"); + return debug(createSetter(forType, type, primitiveSetter, objectSetter), getLocalType(), type, "set"); } /** @@ -639,7 +632,7 @@ * @return true if undefined */ protected final boolean isUndefined() { - return getCurrentType() == null; + return getLocalType() == null; } @Override @@ -647,7 +640,7 @@ checkUndeclared(); final int typeIndex = getAccessorTypeIndex(type); - final int currentTypeIndex = getAccessorTypeIndex(getCurrentType()); + final int currentTypeIndex = getAccessorTypeIndex(getLocalType()); //if we are asking for an object setter, but are still a primitive type, we might try to box it MethodHandle mh; @@ -656,13 +649,13 @@ final PropertyMap newMap = getWiderMap(currentMap, newProperty); final MethodHandle widerSetter = newProperty.getSetter(type, newMap); - final Class<?> ct = getCurrentType(); + final Class<?> ct = getLocalType(); mh = MH.filterArguments(widerSetter, 0, MH.insertArguments(debugReplace(ct, type, currentMap, newMap) , 1, newMap)); if (ct != null && ct.isPrimitive() && !type.isPrimitive()) { mh = ObjectClassGenerator.createGuardBoxedPrimitiveSetter(ct, generateSetter(ct, ct), mh); } } else { - final Class<?> forType = isUndefined() ? type : getCurrentType(); + final Class<?> forType = isUndefined() ? type : getLocalType(); mh = generateSetter(!forType.isPrimitive() ? Object.class : forType, type); } @@ -681,24 +674,13 @@ return false; } // Return true for currently undefined even if non-writable/configurable to allow initialization of ES6 CONST. - return getCurrentType() == null || (getCurrentType() != Object.class && (isConfigurable() || isWritable())); + return getLocalType() == null || (getLocalType() != Object.class && (isConfigurable() || isWritable())); } private boolean needsInvalidator(final int typeIndex, final int currentTypeIndex) { return canChangeType() && typeIndex > currentTypeIndex; } - @Override - public final void setCurrentType(final Class<?> currentType) { - assert currentType != boolean.class : "no boolean storage support yet - fix this"; - this.currentType = currentType == null ? null : currentType.isPrimitive() ? currentType : Object.class; - } - - @Override - public Class<?> getCurrentType() { - return currentType; - } - private MethodHandle debug(final MethodHandle mh, final Class<?> forType, final Class<?> type, final String tag) { if (!Context.DEBUG || !Global.hasInstance()) { return mh;
--- a/src/jdk/nashorn/internal/runtime/ECMAException.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/runtime/ECMAException.java Fri Oct 31 20:17:42 2014 -0700 @@ -96,15 +96,17 @@ // If thrown object is an Error or sub-object like TypeError, then // an ECMAException object has been already initialized at constructor. if (thrown instanceof ScriptObject) { - final ScriptObject sobj = (ScriptObject)thrown; - final Object exception = getException(sobj); + final Object exception = getException((ScriptObject)thrown); if (exception instanceof ECMAException) { - // copy over file name, line number and column number. final ECMAException ee = (ECMAException)exception; - ee.setFileName(fileName); - ee.setLineNumber(line); - ee.setColumnNumber(column); - return ee; + // Make sure exception has correct thrown reference because that's what will end up getting caught. + if (ee.getThrown() == thrown) { + // copy over file name, line number and column number. + ee.setFileName(fileName); + ee.setLineNumber(line); + ee.setColumnNumber(column); + return ee; + } } } @@ -154,7 +156,11 @@ * @return a {@link ECMAException} */ public static Object getException(final ScriptObject errObj) { - return errObj.get(ECMAException.EXCEPTION_PROPERTY); + // Exclude inherited properties that may belong to errors in the prototype chain. + if (errObj.hasOwnProperty(ECMAException.EXCEPTION_PROPERTY)) { + return errObj.get(ECMAException.EXCEPTION_PROPERTY); + } + return null; } /**
--- a/src/jdk/nashorn/internal/runtime/FindProperty.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/runtime/FindProperty.java Fri Oct 31 20:17:42 2014 -0700 @@ -84,13 +84,18 @@ * @return method handle for the getter */ public MethodHandle getGetter(final Class<?> type, final int programPoint, final LinkRequest request) { - final MethodHandle getter; + MethodHandle getter; if (isValid(programPoint)) { getter = property.getOptimisticGetter(type, programPoint); } else { getter = property.getGetter(type); } if (property instanceof UserAccessorProperty) { + getter = MH.insertArguments(getter, 1, UserAccessorProperty.getINVOKE_UA_GETTER(type, programPoint)); + if (isValid(programPoint) && type.isPrimitive()) { + getter = MH.insertArguments(getter, 1, programPoint); + } + property.setType(type); return insertAccessorsGetter((UserAccessorProperty) property, request, getter); } return getter; @@ -111,7 +116,8 @@ public MethodHandle getSetter(final Class<?> type, final boolean strict, final LinkRequest request) { MethodHandle setter = property.getSetter(type, getOwner().getMap()); if (property instanceof UserAccessorProperty) { - setter = MH.insertArguments(setter, 1, strict ? property.getKey() : null); + setter = MH.insertArguments(setter, 1, UserAccessorProperty.getINVOKE_UA_SETTER(type), strict ? property.getKey() : null); + property.setType(type); return insertAccessorsGetter((UserAccessorProperty) property, request, setter); }
--- a/src/jdk/nashorn/internal/runtime/JSType.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/runtime/JSType.java Fri Oct 31 20:17:42 2014 -0700 @@ -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; @@ -115,6 +114,9 @@ /** JavaScript compliant conversion function from double to int32 */ public static final Call TO_INT32_D = staticCall(JSTYPE_LOOKUP, JSType.class, "toInt32", int.class, double.class); + /** JavaScript compliant conversion function from int to uint32 */ + public static final Call TO_UINT32_I = staticCall(JSTYPE_LOOKUP, JSType.class, "toUint32", long.class, int.class); + /** JavaScript compliant conversion function from Object to uint32 */ public static final Call TO_UINT32 = staticCall(JSTYPE_LOOKUP, JSType.class, "toUint32", long.class, Object.class); @@ -1002,6 +1004,16 @@ } /** + * JavaScript compliant int to uint32 conversion + * + * @param num an int + * @return a uint32 + */ + public static long toUint32(final int num) { + return num & MAX_UINT; + } + + /** * JavaScript compliant Object to uint16 conversion * ECMA 9.7 ToUint16: (Unsigned 16 Bit Integer) * @@ -1776,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
--- a/src/jdk/nashorn/internal/runtime/Property.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/runtime/Property.java Fri Oct 31 20:17:42 2014 -0700 @@ -102,6 +102,13 @@ /** Property field number or spill slot. */ private final int slot; + /** + * Current type of this object, in object only mode, this is an Object.class. In dual-fields mode + * null means undefined, and primitive types are allowed. The reason a special type is used for + * undefined, is that are no bits left to represent it in primitive types + */ + private Class<?> type; + /** SwitchPoint that is invalidated when property is changed, optional */ protected transient SwitchPoint builtinSwitchPoint; @@ -536,7 +543,7 @@ * <p> * see {@link ObjectClassGenerator#createSetter(Class, Class, MethodHandle, MethodHandle)} * if you are interested in the internal details of this. Note that if you - * are running in default mode, with {@code -Dnashorn.fields.dual=true}, disabled, the setters + * are running with {@code -Dnashorn.fields.objects=true}, the setters * will currently never change, as all properties are represented as Object field, * the Object fields are Initialized to {@code ScriptRuntime.UNDEFINED} and primitives are * boxed/unboxed upon every access, which is not necessarily optimal @@ -569,7 +576,7 @@ @Override public int hashCode() { - final Class<?> type = getCurrentType(); + final Class<?> type = getLocalType(); return Objects.hashCode(this.key) ^ flags ^ getSlot() ^ (type == null ? 0 : type.hashCode()); } @@ -586,7 +593,7 @@ final Property otherProperty = (Property)other; return equalsWithoutType(otherProperty) && - getCurrentType() == otherProperty.getCurrentType(); + getLocalType() == otherProperty.getLocalType(); } boolean equalsWithoutType(final Property otherProperty) { @@ -615,7 +622,7 @@ */ public final String toStringShort() { final StringBuilder sb = new StringBuilder(); - final Class<?> type = getCurrentType(); + final Class<?> type = getLocalType(); sb.append(getKey()).append(" (").append(type(type)).append(')'); return sb.toString(); } @@ -632,7 +639,7 @@ @Override public String toString() { final StringBuilder sb = new StringBuilder(); - final Class<?> type = getCurrentType(); + final Class<?> type = getLocalType(); sb.append(indent(getKey(), 20)). append(" id="). @@ -656,20 +663,40 @@ } /** - * Get the current type of this field. If you are not running with dual fields enabled, + * Get the current type of this property. If you are running with object fields enabled, * this will always be Object.class. See the value representation explanation in * {@link Property#getSetter(Class, PropertyMap)} and {@link ObjectClassGenerator} * for more information. * + * <p>Note that for user accessor properties, this returns the type of the last observed + * value passed to or returned by a user accessor. Use {@link #getLocalType()} to always get + * the type of the actual value stored in the property slot.</p> + * * @return current type of property, null means undefined */ - public abstract Class<?> getCurrentType(); + public final Class<?> getType() { + return type; + } /** - * Reset the current type of this property - * @param currentType new current type + * Set the type of this property. + * @param type new type */ - public abstract void setCurrentType(final Class<?> currentType); + public final void setType(final Class<?> type) { + assert type != boolean.class : "no boolean storage support yet - fix this"; + this.type = type == null ? null : type.isPrimitive() ? type : Object.class; + } + + /** + * Get the type of the value in the local property slot. This returns the same as + * {@link #getType()} for normal properties, but always returns {@code Object.class} + * for {@link UserAccessorProperty}s as their local type is a pair of accessor references. + * + * @return the local property type + */ + protected Class<?> getLocalType() { + return getType(); + } /** * Check whether this Property can ever change its type. The default is false, and if
--- a/src/jdk/nashorn/internal/runtime/PropertyMap.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/runtime/PropertyMap.java Fri Oct 31 20:17:42 2014 -0700 @@ -84,7 +84,7 @@ private transient WeakHashMap<Property, SoftReference<PropertyMap>> history; /** History of prototypes, used to limit map duplication. */ - private transient WeakHashMap<PropertyMap, SoftReference<PropertyMap>> protoHistory; + private transient WeakHashMap<ScriptObject, SoftReference<PropertyMap>> protoHistory; /** property listeners */ private transient PropertyListeners listeners; @@ -512,7 +512,7 @@ assert sameType || oldProperty instanceof AccessorProperty && newProperty instanceof UserAccessorProperty : - "arbitrary replaceProperty attempted " + sameType + " oldProperty=" + oldProperty.getClass() + " newProperty=" + newProperty.getClass() + " [" + oldProperty.getCurrentType() + " => " + newProperty.getCurrentType() + "]"; + "arbitrary replaceProperty attempted " + sameType + " oldProperty=" + oldProperty.getClass() + " newProperty=" + newProperty.getClass() + " [" + oldProperty.getLocalType() + " => " + newProperty.getLocalType() + "]"; newMap.flags = flags; @@ -677,14 +677,14 @@ /** * Check prototype history for an existing property map with specified prototype. * - * @param parentMap New prototype object. + * @param proto New prototype object. * * @return Existing {@link PropertyMap} or {@code null} if not found. */ - private PropertyMap checkProtoHistory(final PropertyMap parentMap) { + private PropertyMap checkProtoHistory(final ScriptObject proto) { final PropertyMap cachedMap; if (protoHistory != null) { - final SoftReference<PropertyMap> weakMap = protoHistory.get(parentMap); + final SoftReference<PropertyMap> weakMap = protoHistory.get(proto); cachedMap = (weakMap != null ? weakMap.get() : null); } else { cachedMap = null; @@ -700,15 +700,15 @@ /** * Add a map to the prototype history. * - * @param parentMap Prototype to add (key.) + * @param newProto Prototype to add (key.) * @param newMap {@link PropertyMap} associated with prototype. */ - private void addToProtoHistory(final PropertyMap parentMap, final PropertyMap newMap) { + private void addToProtoHistory(final ScriptObject newProto, final PropertyMap newMap) { if (protoHistory == null) { protoHistory = new WeakHashMap<>(); } - protoHistory.put(parentMap, new SoftReference<>(newMap)); + protoHistory.put(newProto, new SoftReference<>(newMap)); } /** @@ -883,8 +883,7 @@ */ public PropertyMap changeProto(final ScriptObject newProto) { - final PropertyMap parentMap = newProto == null ? null : newProto.getMap(); - final PropertyMap nextMap = checkProtoHistory(parentMap); + final PropertyMap nextMap = checkProtoHistory(newProto); if (nextMap != null) { return nextMap; } @@ -894,7 +893,7 @@ } final PropertyMap newMap = new PropertyMap(this); - addToProtoHistory(parentMap, newMap); + addToProtoHistory(newProto, newMap); return newMap; }
--- a/src/jdk/nashorn/internal/runtime/ScriptObject.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java Fri Oct 31 20:17:42 2014 -0700 @@ -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) { @@ -970,7 +969,7 @@ final UserAccessorProperty uc = (UserAccessorProperty)oldProperty; final int slot = uc.getSlot(); - assert uc.getCurrentType() == Object.class; + assert uc.getLocalType() == Object.class; if (slot >= spillLength) { uc.setAccessors(this, getMap(), new UserAccessorProperty.Accessors(getter, setter)); } else { @@ -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); }
--- a/src/jdk/nashorn/internal/runtime/SpillProperty.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/runtime/SpillProperty.java Fri Oct 31 20:17:42 2014 -0700 @@ -161,12 +161,12 @@ */ public SpillProperty(final String key, final int flags, final int slot) { super(key, flags, slot, primitiveGetter(slot), primitiveSetter(slot), objectGetter(slot), objectSetter(slot)); - assert !OBJECT_FIELDS_ONLY || getCurrentType() == Object.class; + assert !OBJECT_FIELDS_ONLY || getLocalType() == Object.class; } SpillProperty(final String key, final int flags, final int slot, final Class<?> initialType) { this(key, flags, slot); - setCurrentType(OBJECT_FIELDS_ONLY ? Object.class : initialType); + setType(OBJECT_FIELDS_ONLY ? Object.class : initialType); } SpillProperty(final String key, final int flags, final int slot, final ScriptObject owner, final Object initialValue) {
--- a/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java Fri Oct 31 20:17:42 2014 -0700 @@ -27,16 +27,16 @@ import static jdk.nashorn.internal.lookup.Lookup.MH; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; -import static jdk.nashorn.internal.runtime.JSType.CONVERT_OBJECT_OPTIMISTIC; -import static jdk.nashorn.internal.runtime.JSType.getAccessorTypeIndex; import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; +import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT; +import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_PROGRAM_POINT_SHIFT; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -import java.util.concurrent.Callable; import jdk.nashorn.internal.lookup.Lookup; import jdk.nashorn.internal.runtime.linker.Bootstrap; +import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor; /** * Property with user defined getters/setters. Actual getter and setter @@ -69,38 +69,29 @@ private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); /** Getter method handle */ - private final static MethodHandle INVOKE_GETTER_ACCESSOR = findOwnMH_S("invokeGetterAccessor", Object.class, Accessors.class, Object.class); + private final static MethodHandle INVOKE_OBJECT_GETTER = findOwnMH_S("invokeObjectGetter", Object.class, Accessors.class, MethodHandle.class, Object.class); + private final static MethodHandle INVOKE_INT_GETTER = findOwnMH_S("invokeIntGetter", int.class, Accessors.class, MethodHandle.class, int.class, Object.class); + private final static MethodHandle INVOKE_LONG_GETTER = findOwnMH_S("invokeLongGetter", long.class, Accessors.class, MethodHandle.class, int.class, Object.class); + private final static MethodHandle INVOKE_NUMBER_GETTER = findOwnMH_S("invokeNumberGetter", double.class, Accessors.class, MethodHandle.class, int.class, Object.class); /** Setter method handle */ - private final static MethodHandle INVOKE_SETTER_ACCESSOR = findOwnMH_S("invokeSetterAccessor", void.class, Accessors.class, String.class, Object.class, Object.class); + private final static MethodHandle INVOKE_OBJECT_SETTER = findOwnMH_S("invokeObjectSetter", void.class, Accessors.class, MethodHandle.class, String.class, Object.class, Object.class); + private final static MethodHandle INVOKE_INT_SETTER = findOwnMH_S("invokeIntSetter", void.class, Accessors.class, MethodHandle.class, String.class, Object.class, int.class); + private final static MethodHandle INVOKE_LONG_SETTER = findOwnMH_S("invokeLongSetter", void.class, Accessors.class, MethodHandle.class, String.class, Object.class, long.class); + private final static MethodHandle INVOKE_NUMBER_SETTER = findOwnMH_S("invokeNumberSetter", void.class, Accessors.class, MethodHandle.class, String.class, Object.class, double.class); - /** Dynamic invoker for getter */ - private static final Object GETTER_INVOKER_KEY = new Object(); - - private static MethodHandle getINVOKE_UA_GETTER() { - return Context.getGlobal().getDynamicInvoker(GETTER_INVOKER_KEY, - new Callable<MethodHandle>() { - @Override - public MethodHandle call() { - return Bootstrap.createDynamicInvoker("dyn:call", Object.class, - Object.class, Object.class); - } - }); + static MethodHandle getINVOKE_UA_GETTER(final Class<?> returnType, final int programPoint) { + if (UnwarrantedOptimismException.isValid(programPoint)) { + final int flags = NashornCallSiteDescriptor.CALLSITE_OPTIMISTIC | programPoint << CALLSITE_PROGRAM_POINT_SHIFT; + return Bootstrap.createDynamicInvoker("dyn:call", flags, returnType, Object.class, Object.class); + } else { + return Bootstrap.createDynamicInvoker("dyn:call", Object.class, Object.class, Object.class); + } } - /** Dynamic invoker for setter */ - private static Object SETTER_INVOKER_KEY = new Object(); - - private static MethodHandle getINVOKE_UA_SETTER() { - return Context.getGlobal().getDynamicInvoker(SETTER_INVOKER_KEY, - new Callable<MethodHandle>() { - @Override - public MethodHandle call() { - return Bootstrap.createDynamicInvoker("dyn:call", void.class, - Object.class, Object.class, Object.class); - } - }); + static MethodHandle getINVOKE_UA_SETTER(final Class<?> valueType) { + return Bootstrap.createDynamicInvoker("dyn:call", void.class, Object.class, Object.class, valueType); } /** @@ -158,7 +149,7 @@ } @Override - public Class<?> getCurrentType() { + protected Class<?> getLocalType() { return Object.class; } @@ -189,7 +180,13 @@ @Override public Object getObjectValue(final ScriptObject self, final ScriptObject owner) { - return invokeGetterAccessor(getAccessors((owner != null) ? owner : self), self); + try { + return invokeObjectGetter(getAccessors((owner != null) ? owner : self), getINVOKE_UA_GETTER(Object.class, INVALID_PROGRAM_POINT), self); + } catch (final Error | RuntimeException t) { + throw t; + } catch (final Throwable t) { + throw new RuntimeException(t); + } } @Override @@ -209,41 +206,33 @@ @Override public void setValue(final ScriptObject self, final ScriptObject owner, final Object value, final boolean strict) { - invokeSetterAccessor(getAccessors((owner != null) ? owner : self), strict ? getKey() : null, self, value); + try { + invokeObjectSetter(getAccessors((owner != null) ? owner : self), getINVOKE_UA_SETTER(Object.class), strict ? getKey() : null, self, value); + } catch (final Error | RuntimeException t) { + throw t; + } catch (final Throwable t) { + throw new RuntimeException(t); + } } @Override public MethodHandle getGetter(final Class<?> type) { //this returns a getter on the format (Accessors, Object receiver) - return Lookup.filterReturnType(INVOKE_GETTER_ACCESSOR, type); + return Lookup.filterReturnType(INVOKE_OBJECT_GETTER, type); } @Override public MethodHandle getOptimisticGetter(final Class<?> type, final int programPoint) { - //fortype is always object, but in the optimistic world we have to throw - //unwarranted optimism exception for narrower types. We can improve this - //by checking for boxed types and unboxing them, but it is doubtful that - //this gives us any performance, as UserAccessorProperties are typically not - //primitives. Are there? TODO: investigate later. For now we just throw an - //exception for narrower types than object - - if (type.isPrimitive()) { - final MethodHandle getter = getGetter(Object.class); - final MethodHandle mh = - MH.asType( - MH.filterReturnValue( - getter, - MH.insertArguments( - CONVERT_OBJECT_OPTIMISTIC.get(getAccessorTypeIndex(type)), - 1, - programPoint)), - getter.type().changeReturnType(type)); - - return mh; + if (type == int.class) { + return INVOKE_INT_GETTER; + } else if (type == long.class) { + return INVOKE_LONG_GETTER; + } else if (type == double.class) { + return INVOKE_NUMBER_GETTER; + } else { + assert type == Object.class; + return INVOKE_OBJECT_GETTER; } - - assert type == Object.class; - return getGetter(type); } @Override @@ -259,7 +248,16 @@ @Override public MethodHandle getSetter(final Class<?> type, final PropertyMap currentMap) { - return INVOKE_SETTER_ACCESSOR; + if (type == int.class) { + return INVOKE_INT_SETTER; + } else if (type == long.class) { + return INVOKE_LONG_SETTER; + } else if (type == double.class) { + return INVOKE_NUMBER_SETTER; + } else { + assert type == Object.class; + return INVOKE_OBJECT_SETTER; + } } @Override @@ -282,31 +280,81 @@ // getter/setter may be inherited. If so, proto is bound during lookup. In either // inherited or self case, slot is also bound during lookup. Actual ScriptFunction // to be called is retrieved everytime and applied. - private static Object invokeGetterAccessor(final Accessors gs, final Object self) { + @SuppressWarnings("unused") + private static Object invokeObjectGetter(final Accessors gs, final MethodHandle invoker, final Object self) throws Throwable { final Object func = gs.getter; if (func instanceof ScriptFunction) { - try { - return getINVOKE_UA_GETTER().invokeExact(func, self); - } catch (final Error | RuntimeException t) { - throw t; - } catch (final Throwable t) { - throw new RuntimeException(t); - } + return invoker.invokeExact(func, self); } return UNDEFINED; } - private static void invokeSetterAccessor(final Accessors gs, final String name, final Object self, final Object value) { + @SuppressWarnings("unused") + private static int invokeIntGetter(final Accessors gs, final MethodHandle invoker, final int programPoint, final Object self) throws Throwable { + final Object func = gs.getter; + if (func instanceof ScriptFunction) { + return (int) invoker.invokeExact(func, self); + } + + throw new UnwarrantedOptimismException(UNDEFINED, programPoint); + } + + @SuppressWarnings("unused") + private static long invokeLongGetter(final Accessors gs, final MethodHandle invoker, final int programPoint, final Object self) throws Throwable { + final Object func = gs.getter; + if (func instanceof ScriptFunction) { + return (long) invoker.invokeExact(func, self); + } + + throw new UnwarrantedOptimismException(UNDEFINED, programPoint); + } + + @SuppressWarnings("unused") + private static double invokeNumberGetter(final Accessors gs, final MethodHandle invoker, final int programPoint, final Object self) throws Throwable { + final Object func = gs.getter; + if (func instanceof ScriptFunction) { + return (double) invoker.invokeExact(func, self); + } + + throw new UnwarrantedOptimismException(UNDEFINED, programPoint); + } + + @SuppressWarnings("unused") + private static void invokeObjectSetter(final Accessors gs, final MethodHandle invoker, final String name, final Object self, final Object value) throws Throwable { final Object func = gs.setter; if (func instanceof ScriptFunction) { - try { - getINVOKE_UA_SETTER().invokeExact(func, self, value); - } catch (final Error | RuntimeException t) { - throw t; - } catch (final Throwable t) { - throw new RuntimeException(t); - } + invoker.invokeExact(func, self, value); + } else if (name != null) { + throw typeError("property.has.no.setter", name, ScriptRuntime.safeToString(self)); + } + } + + @SuppressWarnings("unused") + private static void invokeIntSetter(final Accessors gs, final MethodHandle invoker, final String name, final Object self, final int value) throws Throwable { + final Object func = gs.setter; + if (func instanceof ScriptFunction) { + invoker.invokeExact(func, self, value); + } else if (name != null) { + throw typeError("property.has.no.setter", name, ScriptRuntime.safeToString(self)); + } + } + + @SuppressWarnings("unused") + private static void invokeLongSetter(final Accessors gs, final MethodHandle invoker, final String name, final Object self, final long value) throws Throwable { + final Object func = gs.setter; + if (func instanceof ScriptFunction) { + invoker.invokeExact(func, self, value); + } else if (name != null) { + throw typeError("property.has.no.setter", name, ScriptRuntime.safeToString(self)); + } + } + + @SuppressWarnings("unused") + private static void invokeNumberSetter(final Accessors gs, final MethodHandle invoker, final String name, final Object self, final double value) throws Throwable { + final Object func = gs.setter; + if (func instanceof ScriptFunction) { + invoker.invokeExact(func, self, value); } else if (name != null) { throw typeError("property.has.no.setter", name, ScriptRuntime.safeToString(self)); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk/nashorn/internal/runtime/arrays/AnyElements.java Fri Oct 31 20:17:42 2014 -0700 @@ -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
--- a/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java Fri Oct 31 20:17:42 2014 -0700 @@ -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<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request) { // array, index, value return null; } - }
--- a/src/jdk/nashorn/internal/runtime/arrays/ArrayIndex.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/runtime/arrays/ArrayIndex.java Fri Oct 31 20:17:42 2014 -0700 @@ -182,15 +182,15 @@ } /** - * Convert an index to a long value. This basically amounts to ANDing it - * with {@link JSType#MAX_UINT}, as the maximum array index in JavaScript + * Convert an index to a long value. This basically amounts to converting it into a + * {@link JSType#toUint32(int)} uint32} as the maximum array index in JavaScript * is 0xfffffffe * * @param index index to convert to long form * @return index as uint32 in a long */ public static long toLongIndex(final int index) { - return index & JSType.MAX_UINT; + return JSType.toUint32(index); } /** @@ -201,7 +201,7 @@ * @return index as string */ public static String toKey(final int index) { - return Long.toString(index & JSType.MAX_UINT); + return Long.toString(JSType.toUint32(index)); } }
--- a/src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java Fri Oct 31 20:17:42 2014 -0700 @@ -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())); + } }
--- a/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java Fri Oct 31 20:17:42 2014 -0700 @@ -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)); + } }
--- a/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java Fri Oct 31 20:17:42 2014 -0700 @@ -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(); + } }
--- a/src/jdk/nashorn/internal/runtime/arrays/NoTypeArrayData.java Wed Oct 29 10:50:44 2014 -0700 +++ /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; - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk/nashorn/internal/runtime/arrays/NonExtensibleArrayFilter.java Fri Oct 31 20:17:42 2014 -0700 @@ -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); + } +}
--- a/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java Fri Oct 31 20:17:42 2014 -0700 @@ -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)); + } }
--- a/src/jdk/nashorn/internal/runtime/arrays/NumericElements.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/runtime/arrays/NumericElements.java Fri Oct 31 20:17:42 2014 -0700 @@ -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 }
--- a/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java Fri Oct 31 20:17:42 2014 -0700 @@ -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)); + } }
--- a/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java Fri Oct 31 20:17:42 2014 -0700 @@ -88,7 +88,7 @@ } @Override - public ArrayData copy() { + public TypedArrayData<T> copy() { throw new UnsupportedOperationException(); } @@ -133,7 +133,7 @@ } @Override - public ArrayData convert(final Class<?> type) { + public TypedArrayData<T> convert(final Class<?> type) { throw new UnsupportedOperationException(); }
--- a/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java Wed Oct 29 10:50:44 2014 -0700 +++ b/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java Fri Oct 31 20:17:42 2014 -0700 @@ -337,6 +337,20 @@ /** * Returns a dynamic invoker for a specified dynamic operation using the public lookup. Similar to + * {@link #createDynamicInvoker(String, Class, Class...)} but with an additional parameter to + * set the call site flags of the dynamic invoker. + * @param opDesc Dynalink dynamic operation descriptor. + * @param flags the call site flags for the operation + * @param rtype the return type for the operation + * @param ptypes the parameter types for the operation + * @return MethodHandle for invoking the operation. + */ + public static MethodHandle createDynamicInvoker(final String opDesc, final int flags, final Class<?> rtype, final Class<?>... ptypes) { + return bootstrap(MethodHandles.publicLookup(), opDesc, MethodType.methodType(rtype, ptypes), flags).dynamicInvoker(); + } + + /** + * Returns a dynamic invoker for a specified dynamic operation using the public lookup. Similar to * {@link #createDynamicInvoker(String, Class, Class...)} but with return and parameter types composed into a * method type in the signature. See the discussion of that method for details. * @param opDesc Dynalink dynamic operation descriptor.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/examples/getter-setter-micro.js Fri Oct 31 20:17:42 2014 -0700 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * A micro-benchmark for getters and setters with primitive values, + * alternating between ints and doubles. Introduction of primitive + * and optimistic user accessors in JDK-8062401 make this faster by + * 10x or more by allowing inlining and other optimizations to take place. + */ + +var x = { + get m() { + return this._m; + }, + set m(v) { + this._m = v; + }, + get n() { + return this._n; + }, + set n(v) { + this._n = v; + } +}; + + +function bench(v1, v2, result) { + var start = Date.now(); + x.n = v1; + for (var i = 0; i < 1e8; i++) { + x.m = v2; + if (x.m + x.n !== result) { + throw "wrong result"; + } + } + print("done in", Date.now() - start, "millis"); +} + +for (var i = 0; i < 10; i++) { + bench(i, 4, 4 + i); +} + +for (var i = 0; i < 10; i++) { + bench(i, 4.5, 4.5 + i); +} + +for (var i = 0; i < 10; i++) { + bench(i, 5, 5 + i); +} + +for (var i = 0; i < 10; i++) { + bench(i, 5.5, 5.5 + i); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8061391.js Fri Oct 31 20:17:42 2014 -0700 @@ -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"}));
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8061391.js.EXPECTED Fri Oct 31 20:17:42 2014 -0700 @@ -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]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8061391_2.js Fri Oct 31 20:17:42 2014 -0700 @@ -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"; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8061391_3.js Fri Oct 31 20:17:42 2014 -0700 @@ -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"; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8061391_3.js.EXPECTED Fri Oct 31 20:17:42 2014 -0700 @@ -0,0 +1,1 @@ +1,2,3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8062024.js Fri Oct 31 20:17:42 2014 -0700 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 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. + */ + +/** + * JDK-8062024: Issue with date.setFullYear when time other than midnight + * + * @test + * @option -timezone=Asia/Calcutta + * @run + */ + +var date1 = new Date("January 01, 1950 00:00:00"); +print("Before:", date1); +date1.setFullYear(1960); +print("After:", date1); + +var date2 = new Date("January 01, 1950 00:00:01"); +print("Before:", date2); +date2.setFullYear(1960); +print("After:", date2);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8062024.js.EXPECTED Fri Oct 31 20:17:42 2014 -0700 @@ -0,0 +1,4 @@ +Before: Sun Jan 01 1950 00:00:00 GMT+0530 (IST) +After: Fri Jan 01 1960 00:00:00 GMT+0530 (IST) +Before: Sun Jan 01 1950 00:00:01 GMT+0530 (IST) +After: Fri Jan 01 1960 00:00:01 GMT+0530 (IST)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8062132.js Fri Oct 31 20:17:42 2014 -0700 @@ -0,0 +1,80 @@ +/* + * 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. + */ + +/** + * 8062132: Nashorn incorrectly binds "this" for constructor created by another function + * + * @test + * @run + */ + +function subclass(parentCtor, proto) { + function C() { + parentCtor.call(this); + } + + C.prototype = Object.create(parentCtor.prototype); + + for (var prop in proto) { + if (proto.hasOwnProperty(prop)) { + C.prototype[prop] = proto[prop]; + } + } + + return C; +} + +var Parent = function() { + this.init(); +}; + +Parent.prototype = { + init: null +}; + +var Child1 = subclass(Parent, { + prop1: 1, + init: function() { + print('child 1'); + } +}); + +var Child2 = subclass(Parent, { + init: function() { + print('child 2'); + } +}); + +var Child3 = subclass(Parent, { + prop1: 1, + init: function() { + print('child 3'); + } +}); + +new Child1(); +new Child2(); +new Child3(); +new Child1(); +new Child2(); +new Child3();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8062132.js.EXPECTED Fri Oct 31 20:17:42 2014 -0700 @@ -0,0 +1,6 @@ +child 1 +child 2 +child 3 +child 1 +child 2 +child 3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8062583.js Fri Oct 31 20:17:42 2014 -0700 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 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. + */ + +/** + * JDK-8062583: Throwing object with error prototype causes error proto to be caught + * + * @test + * @run + */ + +function CustomError() { + this.name = "CustomError"; +} + +CustomError.prototype = new Error(); + +var c1 = new CustomError(); + +try { + throw c1; +} catch (e) { + print(e === c1); + print(e === CustomError.prototype); + print(e.stack.replace(/\\/g, '/')); + print(e.nashornException.toString().replace(/\\/g, '/')); +} + +var c2 = new CustomError(); +Error.captureStackTrace(c2); +print(c2.stack.replace(/\\/g, '/')); +print(c2.nashornException.toString().replace(/\\/g, '/'));
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8062583.js.EXPECTED Fri Oct 31 20:17:42 2014 -0700 @@ -0,0 +1,8 @@ +true +false +CustomError + at <program> (test/script/basic/JDK-8062583.js:40) +test/script/basic/JDK-8062583.js:40:4 CustomError +CustomError + at <program> (test/script/basic/JDK-8062583.js:49) +test/script/basic/JDK-8062583.js:49 CustomError