From 8cdfe05d08735de8ecaee3c6cba6deb5395906a5 Mon Sep 17 00:00:00 2001 From: asaha Date: Tue, 8 Jul 2014 09:41:10 -0700 Subject: Added tag jdk8u31-b00 for changeset 9b692a6e5f22 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index b92bdb07..96dc36d0 100644 --- a/.hgtags +++ b/.hgtags @@ -302,3 +302,4 @@ b84d92194c367411fcd8b5f510d4589709a8e71e jdk8u25-b03 894ab2f06c93987f8596f5906985ff0a452f2fb2 jdk8u25-b04 25b89ca363c41e1a1d90d7e95d5227d23e4292f3 jdk8u25-b05 0a50d568a901700213fe40c38089748ca1d1af88 jdk8u25-b06 +9b692a6e5f22228f822973d35610d37cb9dd9693 jdk8u31-b00 -- cgit v1.2.1 From 0fd66737b49cae5ecf19ca2ddf38a2fe4dcb194e Mon Sep 17 00:00:00 2001 From: katleman Date: Thu, 14 Aug 2014 12:31:03 -0700 Subject: Added tag jdk8u20-b31 for changeset aa30541c5f0d --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index c64b43e8..51f37f16 100644 --- a/.hgtags +++ b/.hgtags @@ -300,3 +300,4 @@ ad36f9454ce38d78be39fc819902e1223765ee5e jdk8u20-b23 d3da140e179343011017669a6dbfcc52b0e56f52 jdk8u20-b24 d3da140e179343011017669a6dbfcc52b0e56f52 jdk8u20-b25 a23ac9db4227d78b3389e01fa94a8cb695a8fb0a jdk8u20-b26 +aa30541c5f0db0d03ae6625268642ac71f59c4e6 jdk8u20-b31 -- cgit v1.2.1 From fdf300f5593dbd37891ba6f0c527393757ebc914 Mon Sep 17 00:00:00 2001 From: asaha Date: Mon, 22 Sep 2014 11:31:51 -0700 Subject: Added tag jdk8u31-b01 for changeset 6bf53bb6c969 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 9cb67c1e..af29ff0d 100644 --- a/.hgtags +++ b/.hgtags @@ -320,3 +320,4 @@ f76715cd4e902602bdbb4ba9a3774c10afeee012 jdk8u25-b12 1500138ce513600457be6bfa10979ecce6515aa6 jdk8u25-b16 4b9cc65dd24d398c4f921c0beccfb8caeaaaf584 jdk8u25-b17 9b692a6e5f22228f822973d35610d37cb9dd9693 jdk8u31-b00 +6bf53bb6c969678488b1c073d56dd55df1a0ea17 jdk8u31-b01 -- cgit v1.2.1 From 9eb5fe298d36076b5dac185f03496b3a1e88e79a Mon Sep 17 00:00:00 2001 From: katleman Date: Tue, 23 Sep 2014 18:49:23 -0700 Subject: Added tag jdk8u20-b32 for changeset bc4b5edeb826 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 51f37f16..1135bcc3 100644 --- a/.hgtags +++ b/.hgtags @@ -301,3 +301,4 @@ d3da140e179343011017669a6dbfcc52b0e56f52 jdk8u20-b24 d3da140e179343011017669a6dbfcc52b0e56f52 jdk8u20-b25 a23ac9db4227d78b3389e01fa94a8cb695a8fb0a jdk8u20-b26 aa30541c5f0db0d03ae6625268642ac71f59c4e6 jdk8u20-b31 +bc4b5edeb8268a75718e65a84864f09c95b3032c jdk8u20-b32 -- cgit v1.2.1 From 3a0ea411f197e9776f6ad6f6ba187502e43cb2cc Mon Sep 17 00:00:00 2001 From: asaha Date: Mon, 29 Sep 2014 11:52:10 -0700 Subject: Added tag jdk8u31-b02 for changeset 809bf97d7e70 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index aa14754d..8e9a2be2 100644 --- a/.hgtags +++ b/.hgtags @@ -322,3 +322,4 @@ f76715cd4e902602bdbb4ba9a3774c10afeee012 jdk8u25-b12 4b9cc65dd24d398c4f921c0beccfb8caeaaaf584 jdk8u25-b17 9b692a6e5f22228f822973d35610d37cb9dd9693 jdk8u31-b00 6bf53bb6c969678488b1c073d56dd55df1a0ea17 jdk8u31-b01 +809bf97d7e70dcb3873fcbc10f12f62580b1c11d jdk8u31-b02 -- cgit v1.2.1 From a5154220132a3f323df4a3a312dd4af0e25b2b97 Mon Sep 17 00:00:00 2001 From: asaha Date: Mon, 6 Oct 2014 14:13:11 -0700 Subject: Added tag jdk8u31-b03 for changeset 3505d266634d --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 8e9a2be2..35593dbb 100644 --- a/.hgtags +++ b/.hgtags @@ -323,3 +323,4 @@ f76715cd4e902602bdbb4ba9a3774c10afeee012 jdk8u25-b12 9b692a6e5f22228f822973d35610d37cb9dd9693 jdk8u31-b00 6bf53bb6c969678488b1c073d56dd55df1a0ea17 jdk8u31-b01 809bf97d7e70dcb3873fcbc10f12f62580b1c11d jdk8u31-b02 +3505d266634ded89bf9617ff6b385ab8a52f78cf jdk8u31-b03 -- cgit v1.2.1 From df98b16e8ef2a402b00e56ef58572780a6d53438 Mon Sep 17 00:00:00 2001 From: katleman Date: Thu, 9 Oct 2014 11:53:24 -0700 Subject: Added tag jdk8u25-b31 for changeset 4f9e65387c21 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 477251a1..d62ad55f 100644 --- a/.hgtags +++ b/.hgtags @@ -321,3 +321,4 @@ f76715cd4e902602bdbb4ba9a3774c10afeee012 jdk8u25-b12 1500138ce513600457be6bfa10979ecce6515aa6 jdk8u25-b16 4b9cc65dd24d398c4f921c0beccfb8caeaaaf584 jdk8u25-b17 cdbf34dbef404b47805c8c85b11c65c2afaa6674 jdk8u25-b18 +4f9e65387c21831d0ea5726641a302c2ce73a4cc jdk8u25-b31 -- cgit v1.2.1 From 73459ec2c57928a5b83571c89ba9accf4414c845 Mon Sep 17 00:00:00 2001 From: asaha Date: Mon, 13 Oct 2014 12:34:34 -0700 Subject: Added tag jdk8u31-b04 for changeset 96acff2ad9e1 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 2f5ff90b..220c1b49 100644 --- a/.hgtags +++ b/.hgtags @@ -326,3 +326,4 @@ cdbf34dbef404b47805c8c85b11c65c2afaa6674 jdk8u25-b18 6bf53bb6c969678488b1c073d56dd55df1a0ea17 jdk8u31-b01 809bf97d7e70dcb3873fcbc10f12f62580b1c11d jdk8u31-b02 3505d266634ded89bf9617ff6b385ab8a52f78cf jdk8u31-b03 +96acff2ad9e19aa80c4f7ed60d87a422bca1ea91 jdk8u31-b04 -- cgit v1.2.1 From 8b8b61d9b83c135587d11a3542a23937c4138490 Mon Sep 17 00:00:00 2001 From: asaha Date: Mon, 20 Oct 2014 14:34:05 -0700 Subject: Added tag jdk8u31-b05 for changeset 5fc3f210872d --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 220c1b49..aa9429bb 100644 --- a/.hgtags +++ b/.hgtags @@ -327,3 +327,4 @@ cdbf34dbef404b47805c8c85b11c65c2afaa6674 jdk8u25-b18 809bf97d7e70dcb3873fcbc10f12f62580b1c11d jdk8u31-b02 3505d266634ded89bf9617ff6b385ab8a52f78cf jdk8u31-b03 96acff2ad9e19aa80c4f7ed60d87a422bca1ea91 jdk8u31-b04 +5fc3f210872d365c57ed4e8dba3926d9ed5c7e45 jdk8u31-b05 -- cgit v1.2.1 From 508f96d4adc6038d804b78ebc833dbd59bcc0b06 Mon Sep 17 00:00:00 2001 From: attila Date: Fri, 24 Oct 2014 13:25:23 +0200 Subject: 8061955: asm.js idioms result in unnecessarily code emission Reviewed-by: hannesw, jlaskey --- .../nashorn/internal/codegen/CodeGenerator.java | 33 ++++++++++++++++++---- .../nashorn/internal/codegen/FoldConstants.java | 2 +- src/jdk/nashorn/internal/objects/NativeArray.java | 5 ++-- .../nashorn/internal/objects/NativeDataView.java | 5 ++-- .../internal/objects/NativeRegExpExecResult.java | 2 +- .../internal/objects/NativeUint32Array.java | 2 +- src/jdk/nashorn/internal/runtime/JSType.java | 13 +++++++++ .../internal/runtime/arrays/ArrayIndex.java | 8 +++--- 8 files changed, 54 insertions(+), 16 deletions(-) diff --git a/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/src/jdk/nashorn/internal/codegen/CodeGenerator.java index d6743631..f6b9001e 100644 --- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java @@ -208,6 +208,8 @@ final class CodeGenerator extends NodeOperatorVisitor>> 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) { diff --git a/src/jdk/nashorn/internal/codegen/FoldConstants.java b/src/jdk/nashorn/internal/codegen/FoldConstants.java index fe81b2b4..79d20ea1 100644 --- a/src/jdk/nashorn/internal/codegen/FoldConstants.java +++ b/src/jdk/nashorn/internal/codegen/FoldConstants.java @@ -291,7 +291,7 @@ final class FoldConstants extends NodeVisitor implements Loggabl 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: diff --git a/src/jdk/nashorn/internal/objects/NativeArray.java b/src/jdk/nashorn/internal/objects/NativeArray.java index c83e8883..ad4a55fa 100644 --- a/src/jdk/nashorn/internal/objects/NativeArray.java +++ b/src/jdk/nashorn/internal/objects/NativeArray.java @@ -33,6 +33,7 @@ import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex; 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; @@ -266,7 +267,7 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin @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 +477,7 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin @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; diff --git a/src/jdk/nashorn/internal/objects/NativeDataView.java b/src/jdk/nashorn/internal/objects/NativeDataView.java index 0adde064..fb502771 100644 --- a/src/jdk/nashorn/internal/objects/NativeDataView.java +++ b/src/jdk/nashorn/internal/objects/NativeDataView.java @@ -27,6 +27,7 @@ package jdk.nashorn.internal.objects; 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 @@ public class NativeDataView extends ScriptObject { @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 @@ public class NativeDataView extends ScriptObject { @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"); } diff --git a/src/jdk/nashorn/internal/objects/NativeRegExpExecResult.java b/src/jdk/nashorn/internal/objects/NativeRegExpExecResult.java index ffd6055b..467399ae 100644 --- a/src/jdk/nashorn/internal/objects/NativeRegExpExecResult.java +++ b/src/jdk/nashorn/internal/objects/NativeRegExpExecResult.java @@ -74,7 +74,7 @@ public final class NativeRegExpExecResult extends ScriptObject { @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; diff --git a/src/jdk/nashorn/internal/objects/NativeUint32Array.java b/src/jdk/nashorn/internal/objects/NativeUint32Array.java index 4772b977..54420ea7 100644 --- a/src/jdk/nashorn/internal/objects/NativeUint32Array.java +++ b/src/jdk/nashorn/internal/objects/NativeUint32Array.java @@ -105,7 +105,7 @@ public final class NativeUint32Array extends ArrayBufferView { 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 } diff --git a/src/jdk/nashorn/internal/runtime/JSType.java b/src/jdk/nashorn/internal/runtime/JSType.java index b040b588..15c383d3 100644 --- a/src/jdk/nashorn/internal/runtime/JSType.java +++ b/src/jdk/nashorn/internal/runtime/JSType.java @@ -115,6 +115,9 @@ public enum JSType { /** 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); @@ -1001,6 +1004,16 @@ public enum JSType { return doubleToInt32(num) & MAX_UINT; } + /** + * 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) diff --git a/src/jdk/nashorn/internal/runtime/arrays/ArrayIndex.java b/src/jdk/nashorn/internal/runtime/arrays/ArrayIndex.java index 5c857e11..f979aaa9 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/ArrayIndex.java +++ b/src/jdk/nashorn/internal/runtime/arrays/ArrayIndex.java @@ -182,15 +182,15 @@ public final class ArrayIndex { } /** - * 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 @@ public final class ArrayIndex { * @return index as string */ public static String toKey(final int index) { - return Long.toString(index & JSType.MAX_UINT); + return Long.toString(JSType.toUint32(index)); } } -- cgit v1.2.1 From 79971f069e56c2fdc1791dd15b9928cb9650c500 Mon Sep 17 00:00:00 2001 From: lagergren Date: Thu, 23 Oct 2014 15:19:00 +0400 Subject: 8061391: concat as a builtin optimistic form, had to remove NoTypedArrayData and replace it, as we throw away a lot of optimistic link opportunities with NoTypedArrayData not being Continuous Reviewed-by: attila, hannesw --- bin/runopt.sh | 117 +++++++---- src/jdk/nashorn/internal/codegen/types/Type.java | 13 ++ src/jdk/nashorn/internal/objects/NativeArray.java | 131 +++++++++++- .../internal/objects/NativeFloat32Array.java | 5 + .../internal/objects/NativeFloat64Array.java | 5 + .../nashorn/internal/objects/NativeInt16Array.java | 5 + .../nashorn/internal/objects/NativeInt32Array.java | 5 + .../nashorn/internal/objects/NativeInt8Array.java | 5 + src/jdk/nashorn/internal/objects/NativeObject.java | 1 - .../internal/objects/NativeUint16Array.java | 5 + .../internal/objects/NativeUint32Array.java | 5 + .../nashorn/internal/objects/NativeUint8Array.java | 5 + .../internal/objects/NativeUint8ClampedArray.java | 5 + src/jdk/nashorn/internal/parser/JSONParser.java | 1 - src/jdk/nashorn/internal/runtime/JSType.java | 18 +- src/jdk/nashorn/internal/runtime/ScriptObject.java | 116 ++++++----- .../internal/runtime/arrays/AnyElements.java | 38 ++++ .../nashorn/internal/runtime/arrays/ArrayData.java | 226 ++++++++++++++++++--- .../runtime/arrays/ContinuousArrayData.java | 67 +++--- .../internal/runtime/arrays/IntArrayData.java | 65 ++++-- .../internal/runtime/arrays/LongArrayData.java | 59 +++++- .../internal/runtime/arrays/NoTypeArrayData.java | 186 ----------------- .../runtime/arrays/NonExtensibleArrayFilter.java | 68 +++++++ .../internal/runtime/arrays/NumberArrayData.java | 49 ++++- .../internal/runtime/arrays/NumericElements.java | 2 +- .../internal/runtime/arrays/ObjectArrayData.java | 47 ++++- .../internal/runtime/arrays/TypedArrayData.java | 4 +- test/script/basic/JDK-8061391.js | 151 ++++++++++++++ test/script/basic/JDK-8061391.js.EXPECTED | 138 +++++++++++++ test/script/basic/JDK-8061391_2.js | 52 +++++ test/script/basic/JDK-8061391_3.js | 44 ++++ test/script/basic/JDK-8061391_3.js.EXPECTED | 1 + 32 files changed, 1264 insertions(+), 375 deletions(-) create mode 100644 src/jdk/nashorn/internal/runtime/arrays/AnyElements.java delete mode 100644 src/jdk/nashorn/internal/runtime/arrays/NoTypeArrayData.java create mode 100644 src/jdk/nashorn/internal/runtime/arrays/NonExtensibleArrayFilter.java create mode 100644 test/script/basic/JDK-8061391.js create mode 100644 test/script/basic/JDK-8061391.js.EXPECTED create mode 100644 test/script/basic/JDK-8061391_2.js create mode 100644 test/script/basic/JDK-8061391_3.js create mode 100644 test/script/basic/JDK-8061391_3.js.EXPECTED diff --git a/bin/runopt.sh b/bin/runopt.sh index 6b26e287..5ec9046b 100644 --- a/bin/runopt.sh +++ b/bin/runopt.sh @@ -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=$DIR/dist/nashorn.jar # 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 \ - - -# 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 \ - +jdk.nashorn.tools.Shell $ENABLE_TIME_FLAGS ${@} -# Same with math intrinsics. They should be enabled by default in 8u20 and 9 -#-XX:+UseMathExactIntrinsics \ - - -# Add -Dnashorn.time to time the compilation phases. -#-Dnashorn.time \ - - -# Add ShowHiddenFrames to get lambda form internals on the stack traces -#-XX:+ShowHiddenFrames \ - - -# Add print optoassembly to get an asm dump. This requires 1) a debug build, not product, -# That tired compilation is switched off, for C2 only output and that the number of -# compiler threads is set to 1 for determinsm. -#-XX:+PrintOptoAssembly -XX:-TieredCompilation -XX:CICompilerCount=1 \ - -# Tier compile threasholds. Default value is 10. (1-100 is useful for experiments) -# -XX:IncreaseFirstTierCompileThresholdAt=XX diff --git a/src/jdk/nashorn/internal/codegen/types/Type.java b/src/jdk/nashorn/internal/codegen/types/Type.java index 332ee55e..b31b2503 100644 --- a/src/jdk/nashorn/internal/codegen/types/Type.java +++ b/src/jdk/nashorn/internal/codegen/types/Type.java @@ -586,6 +586,7 @@ public abstract class Type implements Comparable, BytecodeOps, Serializabl public int getSlots() { return slots; } + /** * Returns the widest or most common of two types * @@ -608,6 +609,18 @@ public abstract class Type implements Comparable, BytecodeOps, Serializabl return type0.weight() > type1.weight() ? type0 : type1; } + /** + * 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 diff --git a/src/jdk/nashorn/internal/objects/NativeArray.java b/src/jdk/nashorn/internal/objects/NativeArray.java index ad4a55fa..da07432d 100644 --- a/src/jdk/nashorn/internal/objects/NativeArray.java +++ b/src/jdk/nashorn/internal/objects/NativeArray.java @@ -93,9 +93,10 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin private static final Object CALL_CMP = new Object(); private static final Object TO_LOCALE_STRING = new Object(); - private SwitchPoint lengthMadeNotWritableSwitchPoint; - private PushLinkLogic pushLinkLogic; - private PopLinkLogic popLinkLogic; + private SwitchPoint lengthMadeNotWritableSwitchPoint; + private PushLinkLogic pushLinkLogic; + private PopLinkLogic popLinkLogic; + private ConcatLinkLogic concatLinkLogic; /** * Index for the modification SwitchPoint that triggers when length @@ -131,7 +132,9 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin 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]; @@ -754,6 +757,79 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin return construct(newObj, self, new Object[]{length}); } + /** + * 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 [ , ... ] ] ] ) * @@ -764,6 +840,7 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) public static NativeArray concat(final Object self, final Object... args) { final ArrayList list = new ArrayList<>(); + concatToList(list, Global.toObject(self)); for (final Object obj : args) { @@ -1693,13 +1770,15 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin 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 +1877,40 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin } } + /** + * 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 */ @@ -1865,6 +1978,14 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin throw new ClassCastException(); } + private static final ContinuousArrayData getContinuousArrayDataCCE(final Object self) { + try { + return (ContinuousArrayData)((NativeArray)self).getArray(); + } catch (final NullPointerException e) { + throw new ClassCastException(); + } + } + private static final ContinuousArrayData getContinuousArrayDataCCE(final Object self, final Class elementType) { try { return (ContinuousArrayData)((NativeArray)self).getArray(elementType); //ensure element type can fit "elementType" diff --git a/src/jdk/nashorn/internal/objects/NativeFloat32Array.java b/src/jdk/nashorn/internal/objects/NativeFloat32Array.java index e5ef0b5a..ef7a1ff8 100644 --- a/src/jdk/nashorn/internal/objects/NativeFloat32Array.java +++ b/src/jdk/nashorn/internal/objects/NativeFloat32Array.java @@ -89,6 +89,11 @@ public final class NativeFloat32Array extends ArrayBufferView { return double.class; } + @Override + public Class getBoxedElementType() { + return Double.class; + } + @Override protected MethodHandle getGetElem() { return GET_ELEM; diff --git a/src/jdk/nashorn/internal/objects/NativeFloat64Array.java b/src/jdk/nashorn/internal/objects/NativeFloat64Array.java index 1ad61b27..d0413d08 100644 --- a/src/jdk/nashorn/internal/objects/NativeFloat64Array.java +++ b/src/jdk/nashorn/internal/objects/NativeFloat64Array.java @@ -99,6 +99,11 @@ public final class NativeFloat64Array extends ArrayBufferView { return double.class; } + @Override + public Class getBoxedElementType() { + return Double.class; + } + private double getElem(final int index) { try { return nb.get(index); diff --git a/src/jdk/nashorn/internal/objects/NativeInt16Array.java b/src/jdk/nashorn/internal/objects/NativeInt16Array.java index 06148848..e4cdce51 100644 --- a/src/jdk/nashorn/internal/objects/NativeInt16Array.java +++ b/src/jdk/nashorn/internal/objects/NativeInt16Array.java @@ -100,6 +100,11 @@ public final class NativeInt16Array extends ArrayBufferView { return int.class; } + @Override + public Class getBoxedElementType() { + return Integer.class; + } + private int getElem(final int index) { try { return nb.get(index); diff --git a/src/jdk/nashorn/internal/objects/NativeInt32Array.java b/src/jdk/nashorn/internal/objects/NativeInt32Array.java index 5074dc68..9e664ed7 100644 --- a/src/jdk/nashorn/internal/objects/NativeInt32Array.java +++ b/src/jdk/nashorn/internal/objects/NativeInt32Array.java @@ -117,6 +117,11 @@ public final class NativeInt32Array extends ArrayBufferView { return int.class; } + @Override + public Class getBoxedElementType() { + return Integer.class; + } + @Override public int getInt(final int index) { return getElem(index); diff --git a/src/jdk/nashorn/internal/objects/NativeInt8Array.java b/src/jdk/nashorn/internal/objects/NativeInt8Array.java index 319168c0..c336d274 100644 --- a/src/jdk/nashorn/internal/objects/NativeInt8Array.java +++ b/src/jdk/nashorn/internal/objects/NativeInt8Array.java @@ -98,6 +98,11 @@ public final class NativeInt8Array extends ArrayBufferView { return int.class; } + @Override + public Class getBoxedElementType() { + return Integer.class; + } + private int getElem(final int index) { try { return nb.get(index); diff --git a/src/jdk/nashorn/internal/objects/NativeObject.java b/src/jdk/nashorn/internal/objects/NativeObject.java index 5667e6ac..dcd7587b 100644 --- a/src/jdk/nashorn/internal/objects/NativeObject.java +++ b/src/jdk/nashorn/internal/objects/NativeObject.java @@ -28,7 +28,6 @@ package jdk.nashorn.internal.objects; import static jdk.nashorn.internal.lookup.Lookup.MH; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; - import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; diff --git a/src/jdk/nashorn/internal/objects/NativeUint16Array.java b/src/jdk/nashorn/internal/objects/NativeUint16Array.java index 7f8a1923..2fc2c51a 100644 --- a/src/jdk/nashorn/internal/objects/NativeUint16Array.java +++ b/src/jdk/nashorn/internal/objects/NativeUint16Array.java @@ -123,6 +123,11 @@ public final class NativeUint16Array extends ArrayBufferView { return int.class; } + @Override + public Class getBoxedElementType() { + return Integer.class; + } + @Override public int getInt(final int index) { return getElem(index); diff --git a/src/jdk/nashorn/internal/objects/NativeUint32Array.java b/src/jdk/nashorn/internal/objects/NativeUint32Array.java index 54420ea7..4c83cc01 100644 --- a/src/jdk/nashorn/internal/objects/NativeUint32Array.java +++ b/src/jdk/nashorn/internal/objects/NativeUint32Array.java @@ -132,6 +132,11 @@ public final class NativeUint32Array extends ArrayBufferView { return long.class; } + @Override + public Class getBoxedElementType() { + return Integer.class; + } + @Override public int getInt(final int index) { return (int)getLong(index); diff --git a/src/jdk/nashorn/internal/objects/NativeUint8Array.java b/src/jdk/nashorn/internal/objects/NativeUint8Array.java index be7eb368..6e69ebad 100644 --- a/src/jdk/nashorn/internal/objects/NativeUint8Array.java +++ b/src/jdk/nashorn/internal/objects/NativeUint8Array.java @@ -123,6 +123,11 @@ public final class NativeUint8Array extends ArrayBufferView { return int.class; } + @Override + public Class getBoxedElementType() { + return Integer.class; + } + @Override public int getInt(final int index) { return getElem(index); diff --git a/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java b/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java index 125ac0a2..2dff2612 100644 --- a/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java +++ b/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java @@ -103,6 +103,11 @@ public final class NativeUint8ClampedArray extends ArrayBufferView { return int.class; } + @Override + public Class getBoxedElementType() { + return int.class; + } + private int getElem(final int index) { try { return nb.get(index) & 0xff; diff --git a/src/jdk/nashorn/internal/parser/JSONParser.java b/src/jdk/nashorn/internal/parser/JSONParser.java index a5cae0ed..7faf89a8 100644 --- a/src/jdk/nashorn/internal/parser/JSONParser.java +++ b/src/jdk/nashorn/internal/parser/JSONParser.java @@ -32,7 +32,6 @@ import static jdk.nashorn.internal.parser.TokenType.ESCSTRING; import static jdk.nashorn.internal.parser.TokenType.RBRACE; import static jdk.nashorn.internal.parser.TokenType.RBRACKET; import static jdk.nashorn.internal.parser.TokenType.STRING; - import java.util.ArrayList; import java.util.List; import jdk.nashorn.internal.ir.Expression; diff --git a/src/jdk/nashorn/internal/runtime/JSType.java b/src/jdk/nashorn/internal/runtime/JSType.java index 15c383d3..2b64ff34 100644 --- a/src/jdk/nashorn/internal/runtime/JSType.java +++ b/src/jdk/nashorn/internal/runtime/JSType.java @@ -29,7 +29,6 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall; 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; @@ -1788,6 +1787,23 @@ public enum JSType { } } + /** + * 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 diff --git a/src/jdk/nashorn/internal/runtime/ScriptObject.java b/src/jdk/nashorn/internal/runtime/ScriptObject.java index 87d28976..da1023ed 100644 --- a/src/jdk/nashorn/internal/runtime/ScriptObject.java +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java @@ -692,8 +692,7 @@ public abstract class ScriptObject implements PropertyAccess { assert isValidArrayIndex(index) : "invalid array index"; final long longIndex = ArrayIndex.toLongIndex(index); doesNotHaveEnsureDelete(longIndex, getArray().length(), false); - setArray(getArray().ensure(longIndex)); - setArray(getArray().set(index, value, false)); + setArray(getArray().ensure(longIndex).set(index,value, false)); } private void checkIntegerKey(final String key) { @@ -1462,9 +1461,8 @@ public abstract class ScriptObject implements PropertyAccess { //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 @@ public abstract class ScriptObject implements PropertyAccess { * @param newLength new length to set */ public final void setLength(final long newLength) { - final long arrayLength = getArray().length(); - if (newLength == arrayLength) { - return; - } + ArrayData data = getArray(); + final long arrayLength = data.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) { + data = data.ensure(newLength - 1); + if (data.canDelete(arrayLength, newLength - 1, false)) { + data = data.delete(arrayLength, newLength - 1); + } + setArray(data); + return; + } - if (newLength < arrayLength) { + 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 @@ public abstract class ScriptObject implements PropertyAccess { } } - setArray(getArray().shrink(actualLength)); - getArray().setLength(actualLength); + setArray(data.shrink(actualLength)); + data.setLength(actualLength); } } @@ -3194,8 +3194,9 @@ public abstract class ScriptObject implements PropertyAccess { 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 @@ public abstract class ScriptObject implements PropertyAccess { 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 @@ public abstract class ScriptObject implements PropertyAccess { 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 @@ public abstract class ScriptObject implements PropertyAccess { 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 @@ public abstract class ScriptObject implements PropertyAccess { 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 @@ public abstract class ScriptObject implements PropertyAccess { 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 @@ public abstract class ScriptObject implements PropertyAccess { 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 @@ public abstract class ScriptObject implements PropertyAccess { 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 @@ public abstract class ScriptObject implements PropertyAccess { 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 @@ public abstract class ScriptObject implements PropertyAccess { 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 @@ public abstract class ScriptObject implements PropertyAccess { 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 @@ public abstract class ScriptObject implements PropertyAccess { 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 @@ public abstract class ScriptObject implements PropertyAccess { 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 @@ public abstract class ScriptObject implements PropertyAccess { 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 @@ public abstract class ScriptObject implements PropertyAccess { 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 @@ public abstract class ScriptObject implements PropertyAccess { final int index = getArrayIndex(key); if (isValidArrayIndex(index)) { - if (getArray().has(index)) { - setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + final ArrayData data = getArray(); + if (data.has(index)) { + setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } diff --git a/src/jdk/nashorn/internal/runtime/arrays/AnyElements.java b/src/jdk/nashorn/internal/runtime/arrays/AnyElements.java new file mode 100644 index 00000000..d9e01923 --- /dev/null +++ b/src/jdk/nashorn/internal/runtime/arrays/AnyElements.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.nashorn.internal.runtime.arrays; + +/** + * Marker interface for any ContinuousArray with any elements + * Used for type checks that throw ClassCastExceptions and force relinks + * for fast NativeArray specializations of builtin methods + */ +public interface AnyElements { + /** + * Return a numeric weight of the element type - wider is higher + * @return element type weight + */ + public int getElementWeight(); +} \ No newline at end of file diff --git a/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java index 9e606ee6..dc41c4d9 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java +++ b/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java @@ -28,6 +28,7 @@ package jdk.nashorn.internal.runtime.arrays; 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.codegen.types.Type; 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 @@ public abstract class ArrayData { /** 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 @@ public abstract class ArrayData { * 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 @@ public abstract class ArrayData { 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 - */ - 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 + * Align an array size up to the nearest array chunk size + * @param size size required + * @return size given, always >= size */ - 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 @@ public abstract class ArrayData { * @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 @@ public abstract class ArrayData { * @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 @@ public abstract class ArrayData { * @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 @@ public abstract class ArrayData { * @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 @@ public abstract class ArrayData { * @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 @@ public abstract class ArrayData { * @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 @@ public abstract class ArrayData { * @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 @@ public abstract class ArrayData { * @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,10 +375,20 @@ public abstract class ArrayData { * @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 @@ -728,5 +899,4 @@ public abstract class ArrayData { public GuardedInvocation findFastSetIndexMethod(final Class clazz, final CallSiteDescriptor desc, final LinkRequest request) { // array, index, value return null; } - } diff --git a/src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java index 8724d64a..56840da9 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java +++ b/src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java @@ -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.lookup.Lookup.MH; 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 @@ import jdk.nashorn.internal.runtime.logging.Logger; */ @Logger(name="arrays") public abstract class ContinuousArrayData extends ArrayData { - - private SwitchPoint sp; - /** * Constructor * @param length length (elementLength) @@ -61,18 +56,6 @@ public abstract class ContinuousArrayData extends ArrayData { 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 @@ -85,6 +68,14 @@ public abstract class ContinuousArrayData extends ArrayData { return has(index) || (index == length && ensure(index) == this); } + /** + * 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 @@ -109,13 +100,16 @@ public abstract class ContinuousArrayData extends ArrayData { * @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 @@ -127,6 +121,25 @@ public abstract class ContinuousArrayData extends ArrayData { return Type.typeFor(getElementType()); } + /** + * 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 @@ -256,12 +269,7 @@ public abstract class ContinuousArrayData extends ArrayData { 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 @@ public abstract class ContinuousArrayData extends ArrayData { 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 abstract class ContinuousArrayData extends ArrayData { public Object fastPopObject() { throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink } + + /** + * Specialization - fast concat implementation + * @param otherData data to concat + * @return new arraydata + */ + public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) { + throw new ClassCastException(String.valueOf(getClass()) + " != " + String.valueOf(otherData.getClass())); + } } diff --git a/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java index 0792b6b6..b74b6419 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java +++ b/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java @@ -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 @@ final class IntArrayData extends ContinuousArrayData implements IntElements { * @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 @@ final class IntArrayData extends ContinuousArrayData implements IntElements { } @Override - public ArrayData copy() { + public IntArrayData copy() { return new IntArrayData(array.clone(), (int)length); } @@ -165,8 +179,7 @@ final class IntArrayData extends ContinuousArrayData implements IntElements { 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 @@ final class IntArrayData extends ContinuousArrayData implements IntElements { @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 @@ final class IntArrayData extends ContinuousArrayData implements IntElements { @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 @@ final class IntArrayData extends ContinuousArrayData implements IntElements { 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 @@ final class IntArrayData extends ContinuousArrayData implements IntElements { public Object fastPopObject() { return fastPopInt(); } + + @Override + public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) { + final int otherLength = (int)otherData.length; + final int thisLength = (int)length; + assert otherLength > 0 && thisLength > 0; + + final int[] otherArray = ((IntArrayData)otherData).array; + final int newLength = otherLength + thisLength; + final int[] newArray = new int[ArrayData.alignUp(newLength)]; + + System.arraycopy(array, 0, newArray, 0, thisLength); + System.arraycopy(otherArray, 0, newArray, thisLength, otherLength); + + return new IntArrayData(newArray, newLength); + } + + @Override + public String toString() { + assert length <= array.length : length + " > " + array.length; + return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length)); + } } diff --git a/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java index f41ee15a..cbe507b8 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java +++ b/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java @@ -52,16 +52,31 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen 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 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen } @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 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen @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 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen public Object fastPopObject() { return fastPopLong(); } + + @Override + public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) { + final int otherLength = (int)otherData.length; + final int thisLength = (int)length; + assert otherLength > 0 && thisLength > 0; + + final long[] otherArray = ((LongArrayData)otherData).array; + final int newLength = otherLength + thisLength; + final long[] newArray = new long[ArrayData.alignUp(newLength)]; + + System.arraycopy(array, 0, newArray, 0, thisLength); + System.arraycopy(otherArray, 0, newArray, thisLength, otherLength); + + return new LongArrayData(newArray, newLength); + } + + @Override + public String toString() { + assert length <= array.length : length + " > " + array.length; + + final StringBuilder sb = new StringBuilder(getClass().getSimpleName()). + append(": ["); + for (int i = 0; i < length; i++) { + sb.append(array[i]).append('L'); //make sure L suffix is on elements, to discriminate this from IntArrayData.toString() + if (i + 1 < length) { + sb.append(", "); + } + } + sb.append(']'); + + return sb.toString(); + } } diff --git a/src/jdk/nashorn/internal/runtime/arrays/NoTypeArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/NoTypeArrayData.java deleted file mode 100644 index 143cd221..00000000 --- a/src/jdk/nashorn/internal/runtime/arrays/NoTypeArrayData.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.nashorn.internal.runtime.arrays; - -import java.lang.reflect.Array; -import jdk.nashorn.internal.runtime.ScriptRuntime; - -/** - * Place holding array data for non-array objects. Activates a true array when - * accessed. Should only exist as a singleton defined in ArrayData. - */ -final class NoTypeArrayData extends ArrayData { - NoTypeArrayData() { - super(0); - } - - NoTypeArrayData(final long length) { - super(length); - } - - @Override - public Object[] asObjectArray() { - return ScriptRuntime.EMPTY_ARRAY; - } - - @Override - public ArrayData copy() { - return new NoTypeArrayData(); - } - - @Override - public Object asArrayOfType(final Class componentType) { - return Array.newInstance(componentType, 0); - } - - @Override - public ArrayData convert(final Class type) { - final long len = length; - final ArrayData arrayData; - if (type == Long.class) { - arrayData = new LongArrayData(new long[ArrayData.nextSize((int)len)], (int)len); - } else if (type == Double.class) { - arrayData = new NumberArrayData(new double[ArrayData.nextSize((int)len)], (int)len); - } else if (type == Integer.class) { - arrayData = new IntArrayData(new int[ArrayData.nextSize((int)len)], (int)len); - } else { - assert !type.isPrimitive(); - arrayData = new ObjectArrayData(new Object[ArrayData.nextSize((int)len)], (int)len); - } - return length == 0 ? arrayData : new DeletedRangeArrayFilter(arrayData, 0, len - 1); - } - - @Override - public void shiftLeft(final int by) { - //empty - } - - @Override - public ArrayData shiftRight(final int by) { - return this; - } - - @Override - public ArrayData ensure(final long safeIndex) { - if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH) { - return new SparseArrayData(this, safeIndex + 1); - } - - // Don't trample the shared EMPTY_ARRAY. - if (length == 0) { - return new NoTypeArrayData(Math.max(safeIndex + 1, length)); - } - - setLength(Math.max(safeIndex + 1, length)); - return this; - } - - @Override - public ArrayData shrink(final long newLength) { - return this; - } - - @Override - public ArrayData set(final int index, final Object value, final boolean strict) { - ArrayData newData; - - if (value instanceof Double) { - newData = convert(Double.class); - } else if (value instanceof Long) { - newData = convert(Long.class); - } else if (value instanceof Integer) { - newData = convert(Integer.class); - } else { - assert !(value instanceof Number); - newData = convert(value == null ? Object.class : value.getClass()); - } - - return newData.set(index, value, strict); - } - - @Override - public ArrayData set(final int index, final int value, final boolean strict) { - final ArrayData newData = convert(Integer.class); - return newData.set(index, value, strict); - } - - @Override - public ArrayData set(final int index, final long value, final boolean strict) { - final ArrayData newData = convert(Long.class); - return newData.set(index, value, strict); - } - - @Override - public ArrayData set(final int index, final double value, final boolean strict) { - final ArrayData newData = convert(Double.class); - return newData.set(index, value, strict); - } - - @Override - public int getInt(final int index) { - throw new ArrayIndexOutOfBoundsException(index); - } - - @Override - public long getLong(final int index) { - throw new ArrayIndexOutOfBoundsException(index); - } - - @Override - public double getDouble(final int index) { - throw new ArrayIndexOutOfBoundsException(index); - } - - @Override - public Object getObject(final int index) { - throw new ArrayIndexOutOfBoundsException(index); - } - - @Override - public boolean has(final int index) { - return false; - } - - @Override - public ArrayData delete(final int index) { - return new DeletedRangeArrayFilter(this, index, index); - } - - @Override - public ArrayData delete(final long fromIndex, final long toIndex) { - return new DeletedRangeArrayFilter(this, fromIndex, toIndex); - } - - @Override - public Object pop() { - return ScriptRuntime.UNDEFINED; - } - - @Override - public ArrayData slice(final long from, final long to) { - return this; - } -} diff --git a/src/jdk/nashorn/internal/runtime/arrays/NonExtensibleArrayFilter.java b/src/jdk/nashorn/internal/runtime/arrays/NonExtensibleArrayFilter.java new file mode 100644 index 00000000..bb73b89f --- /dev/null +++ b/src/jdk/nashorn/internal/runtime/arrays/NonExtensibleArrayFilter.java @@ -0,0 +1,68 @@ +package jdk.nashorn.internal.runtime.arrays; + +import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; +import jdk.nashorn.internal.objects.Global; +import jdk.nashorn.internal.runtime.ScriptRuntime; + +/** + * Filter class that wrap arrays that have been tagged non extensible + */ +public class NonExtensibleArrayFilter extends ArrayFilter { + + /** + * Constructor + * @param underlying array + */ + public NonExtensibleArrayFilter(final ArrayData underlying) { + super(underlying); + } + + @Override + public ArrayData copy() { + return new NonExtensibleArrayFilter(underlying.copy()); + } + + @Override + public ArrayData slice(final long from, final long to) { + return new NonExtensibleArrayFilter(underlying.slice(from, to)); + } + + private ArrayData extensionCheck(final boolean strict, final int index) { + if (!strict) { + return this; + } + throw typeError(Global.instance(), "object.non.extensible", String.valueOf(index), ScriptRuntime.safeToString(this)); + } + + @Override + public ArrayData set(final int index, final Object value, final boolean strict) { + if (has(index)) { + return underlying.set(index, value, strict); + } + return extensionCheck(strict, index); + } + + @Override + public ArrayData set(final int index, final int value, final boolean strict) { + if (has(index)) { + return underlying.set(index, value, strict); + } + return extensionCheck(strict, index); + } + + @Override + public ArrayData set(final int index, final long value, final boolean strict) { + if (has(index)) { + return underlying.set(index, value, strict); + } + return extensionCheck(strict, index); + } + + @Override + public ArrayData set(final int index, final double value, final boolean strict) { + if (has(index)) { + return underlying.set(index, value, strict); + } + return extensionCheck(strict, index); + } +} diff --git a/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java index 2c57208f..f43c25af 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java +++ b/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java @@ -48,19 +48,34 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen * @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 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen } @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 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen @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 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen public Object fastPopObject() { return fastPopDouble(); } + + @Override + public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) { + final int otherLength = (int)otherData.length; + final int thisLength = (int)length; + assert otherLength > 0 && thisLength > 0; + + final double[] otherArray = ((NumberArrayData)otherData).array; + final int newLength = otherLength + thisLength; + final double[] newArray = new double[ArrayData.alignUp(newLength)]; + + System.arraycopy(array, 0, newArray, 0, thisLength); + System.arraycopy(otherArray, 0, newArray, thisLength, otherLength); + + return new NumberArrayData(newArray, newLength); + } + + @Override + public String toString() { + assert length <= array.length : length + " > " + array.length; + return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length)); + } } diff --git a/src/jdk/nashorn/internal/runtime/arrays/NumericElements.java b/src/jdk/nashorn/internal/runtime/arrays/NumericElements.java index ad940e2a..cb87ea91 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/NumericElements.java +++ b/src/jdk/nashorn/internal/runtime/arrays/NumericElements.java @@ -30,6 +30,6 @@ package jdk.nashorn.internal.runtime.arrays; * Used for type checks that throw ClassCastExceptions and force relinks * for fast NativeArray specializations of builtin methods */ -public interface NumericElements { +public interface NumericElements extends AnyElements { //empty } diff --git a/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java index 379ba6e4..0c7f54d0 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java +++ b/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java @@ -37,7 +37,7 @@ import jdk.nashorn.internal.runtime.ScriptRuntime; * 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 @@ final class ObjectArrayData extends ContinuousArrayData { * @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 @@ final class ObjectArrayData extends ContinuousArrayData { } @Override - public ArrayData convert(final Class type) { + public ObjectArrayData convert(final Class type) { return this; } @@ -325,4 +340,26 @@ final class ObjectArrayData extends ContinuousArrayData { return returnValue; } + + @Override + public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) { + final int otherLength = (int)otherData.length; + final int thisLength = (int)length; + assert otherLength > 0 && thisLength > 0; + + final Object[] otherArray = ((ObjectArrayData)otherData).array; + final int newLength = otherLength + thisLength; + final Object[] newArray = new Object[ArrayData.alignUp(newLength)]; + + System.arraycopy(array, 0, newArray, 0, thisLength); + System.arraycopy(otherArray, 0, newArray, thisLength, otherLength); + + return new ObjectArrayData(newArray, newLength); + } + + @Override + public String toString() { + assert length <= array.length : length + " > " + array.length; + return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length)); + } } diff --git a/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java index 428678d0..405ff028 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java +++ b/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java @@ -88,7 +88,7 @@ public abstract class TypedArrayData extends ContinuousArrayDa } @Override - public ArrayData copy() { + public TypedArrayData copy() { throw new UnsupportedOperationException(); } @@ -133,7 +133,7 @@ public abstract class TypedArrayData extends ContinuousArrayDa } @Override - public ArrayData convert(final Class type) { + public TypedArrayData convert(final Class type) { throw new UnsupportedOperationException(); } diff --git a/test/script/basic/JDK-8061391.js b/test/script/basic/JDK-8061391.js new file mode 100644 index 00000000..920efe3e --- /dev/null +++ b/test/script/basic/JDK-8061391.js @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * JDK-8061391 - Checks that the optimistic builtin for concat is semantically + * correct. + * + * @test + * @run + */ + +var maxJavaInt = 0x7fffffff; + +var ia = [1, 2, 3, 4]; +var la = [maxJavaInt + 1000, maxJavaInt + 2000, maxJavaInt + 3000, maxJavaInt + 4000]; +var da = [1.1, 2.2, 3.3, 4.4]; +var oa = ["one", "two", "three", "four"]; + +var aa = [ia, la, da, oa]; + +function concats() { + print("shared callsite"); + + print(ia); + print(la); + print(da); + print(oa); + print(aa); + + for (var i = 0; i < aa.length; i++) { + print(aa[i].concat(aa[i][0])); + for (var j = 0; j < aa.length ; j++) { + print(aa[i].concat(aa[j])); + } + } +} + +function concats_inline() { + print("separate callsites"); + + print(ia); + print(la); + print(da); + print(oa); + print(aa); + + print(aa[0].concat(aa[0])); + print(aa[0].concat(aa[1])); + print(aa[0].concat(aa[2])); + print(aa[0].concat(aa[3])); + print(aa[0].concat(aa[0][0])); + + print(aa[1].concat(aa[0])); + print(aa[1].concat(aa[1])); + print(aa[1].concat(aa[2])); + print(aa[1].concat(aa[3])); + print(aa[1].concat(aa[1][0])); + + print(aa[2].concat(aa[0])); + print(aa[2].concat(aa[1])); + print(aa[2].concat(aa[2])); + print(aa[2].concat(aa[3])); + print(aa[2].concat(aa[2][0])); + + print(aa[3].concat(aa[0])); + print(aa[3].concat(aa[1])); + print(aa[3].concat(aa[2])); + print(aa[3].concat(aa[3])); + print(aa[3].concat(aa[3][0])); +} + +concats(); +concats_inline(); + +print(); +var oldia = ia.slice(0); //clone ia +print("oldia = " + oldia); +ia[10] = "sparse"; +print("oldia = " + oldia); + +print(); +print("Redoing with sparse arrays"); + +concats(); +concats_inline(); + +ia = oldia; +print("Restored ia = " + ia); + +function concat_expand() { + print("concat type expansion"); + print(ia.concat(la)); + print(ia.concat(da)); + print(ia.concat(oa)); + print(la.concat(ia)); + print(la.concat(da)); + print(la.concat(oa)); + print(da.concat(ia)); + print(da.concat(la)); + print(da.concat(oa)); +} + +print(); +concat_expand(); + +print(); + +function concat_varargs() { + print("concat varargs"); + print(ia.concat(la)); //fast + print(ia.concat(la, da, oa)); //slow + var slow = ia.concat(1, maxJavaInt * 2, 4711.17, function() { print("hello, world") }); //slow + print(slow); + return slow; +} + +var slow = concat_varargs(); + +print(); +print("sanity checks"); +slow.map( + function(elem) { + if (elem instanceof Function) { + elem(); + } else { + print((typeof elem) + " = " + elem); + } + }); + +print(ia.concat({key: "value"})); +print(ia.concat({key: "value"}, {key2: "value2"})); diff --git a/test/script/basic/JDK-8061391.js.EXPECTED b/test/script/basic/JDK-8061391.js.EXPECTED new file mode 100644 index 00000000..9b132c3c --- /dev/null +++ b/test/script/basic/JDK-8061391.js.EXPECTED @@ -0,0 +1,138 @@ +shared callsite +1,2,3,4 +2147484647,2147485647,2147486647,2147487647 +1.1,2.2,3.3,4.4 +one,two,three,four +1,2,3,4,2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4,one,two,three,four +1,2,3,4,1 +1,2,3,4,1,2,3,4 +1,2,3,4,2147484647,2147485647,2147486647,2147487647 +1,2,3,4,1.1,2.2,3.3,4.4 +1,2,3,4,one,two,three,four +2147484647,2147485647,2147486647,2147487647,2147484647 +2147484647,2147485647,2147486647,2147487647,1,2,3,4 +2147484647,2147485647,2147486647,2147487647,2147484647,2147485647,2147486647,2147487647 +2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4 +2147484647,2147485647,2147486647,2147487647,one,two,three,four +1.1,2.2,3.3,4.4,1.1 +1.1,2.2,3.3,4.4,1,2,3,4 +1.1,2.2,3.3,4.4,2147484647,2147485647,2147486647,2147487647 +1.1,2.2,3.3,4.4,1.1,2.2,3.3,4.4 +1.1,2.2,3.3,4.4,one,two,three,four +one,two,three,four,one +one,two,three,four,1,2,3,4 +one,two,three,four,2147484647,2147485647,2147486647,2147487647 +one,two,three,four,1.1,2.2,3.3,4.4 +one,two,three,four,one,two,three,four +separate callsites +1,2,3,4 +2147484647,2147485647,2147486647,2147487647 +1.1,2.2,3.3,4.4 +one,two,three,four +1,2,3,4,2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4,one,two,three,four +1,2,3,4,1,2,3,4 +1,2,3,4,2147484647,2147485647,2147486647,2147487647 +1,2,3,4,1.1,2.2,3.3,4.4 +1,2,3,4,one,two,three,four +1,2,3,4,1 +2147484647,2147485647,2147486647,2147487647,1,2,3,4 +2147484647,2147485647,2147486647,2147487647,2147484647,2147485647,2147486647,2147487647 +2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4 +2147484647,2147485647,2147486647,2147487647,one,two,three,four +2147484647,2147485647,2147486647,2147487647,2147484647 +1.1,2.2,3.3,4.4,1,2,3,4 +1.1,2.2,3.3,4.4,2147484647,2147485647,2147486647,2147487647 +1.1,2.2,3.3,4.4,1.1,2.2,3.3,4.4 +1.1,2.2,3.3,4.4,one,two,three,four +1.1,2.2,3.3,4.4,1.1 +one,two,three,four,1,2,3,4 +one,two,three,four,2147484647,2147485647,2147486647,2147487647 +one,two,three,four,1.1,2.2,3.3,4.4 +one,two,three,four,one,two,three,four +one,two,three,four,one + +oldia = 1,2,3,4 +oldia = 1,2,3,4 + +Redoing with sparse arrays +shared callsite +1,2,3,4,,,,,,,sparse +2147484647,2147485647,2147486647,2147487647 +1.1,2.2,3.3,4.4 +one,two,three,four +1,2,3,4,,,,,,,sparse,2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4,one,two,three,four +1,2,3,4,,,,,,,sparse,1 +1,2,3,4,,,,,,,sparse,1,2,3,4,,,,,,,sparse +1,2,3,4,,,,,,,sparse,2147484647,2147485647,2147486647,2147487647 +1,2,3,4,,,,,,,sparse,1.1,2.2,3.3,4.4 +1,2,3,4,,,,,,,sparse,one,two,three,four +2147484647,2147485647,2147486647,2147487647,2147484647 +2147484647,2147485647,2147486647,2147487647,1,2,3,4,,,,,,,sparse +2147484647,2147485647,2147486647,2147487647,2147484647,2147485647,2147486647,2147487647 +2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4 +2147484647,2147485647,2147486647,2147487647,one,two,three,four +1.1,2.2,3.3,4.4,1.1 +1.1,2.2,3.3,4.4,1,2,3,4,,,,,,,sparse +1.1,2.2,3.3,4.4,2147484647,2147485647,2147486647,2147487647 +1.1,2.2,3.3,4.4,1.1,2.2,3.3,4.4 +1.1,2.2,3.3,4.4,one,two,three,four +one,two,three,four,one +one,two,three,four,1,2,3,4,,,,,,,sparse +one,two,three,four,2147484647,2147485647,2147486647,2147487647 +one,two,three,four,1.1,2.2,3.3,4.4 +one,two,three,four,one,two,three,four +separate callsites +1,2,3,4,,,,,,,sparse +2147484647,2147485647,2147486647,2147487647 +1.1,2.2,3.3,4.4 +one,two,three,four +1,2,3,4,,,,,,,sparse,2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4,one,two,three,four +1,2,3,4,,,,,,,sparse,1,2,3,4,,,,,,,sparse +1,2,3,4,,,,,,,sparse,2147484647,2147485647,2147486647,2147487647 +1,2,3,4,,,,,,,sparse,1.1,2.2,3.3,4.4 +1,2,3,4,,,,,,,sparse,one,two,three,four +1,2,3,4,,,,,,,sparse,1 +2147484647,2147485647,2147486647,2147487647,1,2,3,4,,,,,,,sparse +2147484647,2147485647,2147486647,2147487647,2147484647,2147485647,2147486647,2147487647 +2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4 +2147484647,2147485647,2147486647,2147487647,one,two,three,four +2147484647,2147485647,2147486647,2147487647,2147484647 +1.1,2.2,3.3,4.4,1,2,3,4,,,,,,,sparse +1.1,2.2,3.3,4.4,2147484647,2147485647,2147486647,2147487647 +1.1,2.2,3.3,4.4,1.1,2.2,3.3,4.4 +1.1,2.2,3.3,4.4,one,two,three,four +1.1,2.2,3.3,4.4,1.1 +one,two,three,four,1,2,3,4,,,,,,,sparse +one,two,three,four,2147484647,2147485647,2147486647,2147487647 +one,two,three,four,1.1,2.2,3.3,4.4 +one,two,three,four,one,two,three,four +one,two,three,four,one +Restored ia = 1,2,3,4 + +concat type expansion +1,2,3,4,2147484647,2147485647,2147486647,2147487647 +1,2,3,4,1.1,2.2,3.3,4.4 +1,2,3,4,one,two,three,four +2147484647,2147485647,2147486647,2147487647,1,2,3,4 +2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4 +2147484647,2147485647,2147486647,2147487647,one,two,three,four +1.1,2.2,3.3,4.4,1,2,3,4 +1.1,2.2,3.3,4.4,2147484647,2147485647,2147486647,2147487647 +1.1,2.2,3.3,4.4,one,two,three,four + +concat varargs +1,2,3,4,2147484647,2147485647,2147486647,2147487647 +1,2,3,4,2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4,one,two,three,four +1,2,3,4,1,4294967294,4711.17,function() { print("hello, world") } + +sanity checks +number = 1 +number = 2 +number = 3 +number = 4 +number = 1 +number = 4294967294 +number = 4711.17 +hello, world +1,2,3,4,[object Object] +1,2,3,4,[object Object],[object Object] diff --git a/test/script/basic/JDK-8061391_2.js b/test/script/basic/JDK-8061391_2.js new file mode 100644 index 00000000..dff4ab02 --- /dev/null +++ b/test/script/basic/JDK-8061391_2.js @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * Array extension check + * + * @test + * @run + */ + +"use strict"; +var a = [1,2,3]; +Object.preventExtensions(a); +try { + a[4] = 4; + print(a); +} catch (e) { + if (!(e instanceof TypeError)) { + print("TypeError expected but got e"); + } +} + +if (a[0] != 1) { + throw "element 0 is wrong"; +} +if (a[1] != 2) { + throw "element 1 is wrong"; +} +if (a[2] != 3) { + throw "element 2 is wrong"; +} + diff --git a/test/script/basic/JDK-8061391_3.js b/test/script/basic/JDK-8061391_3.js new file mode 100644 index 00000000..6648ca51 --- /dev/null +++ b/test/script/basic/JDK-8061391_3.js @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * Array extension check + * + * @test + * @run + */ + +var a = [1,2,3]; +Object.preventExtensions(a); +a[4] = 4; +print(a); +if (a[0] != 1) { + throw "element 0 is wrong"; +} +if (a[1] != 2) { + throw "element 1 is wrong"; +} +if (a[2] != 3) { + throw "element 2 is wrong"; +} + diff --git a/test/script/basic/JDK-8061391_3.js.EXPECTED b/test/script/basic/JDK-8061391_3.js.EXPECTED new file mode 100644 index 00000000..b0246d59 --- /dev/null +++ b/test/script/basic/JDK-8061391_3.js.EXPECTED @@ -0,0 +1 @@ +1,2,3 -- cgit v1.2.1 From bbaf1ede9e59c959472782343ac1f9815f66190c Mon Sep 17 00:00:00 2001 From: sundar Date: Mon, 27 Oct 2014 17:54:00 +0530 Subject: 8062024: Issue with date.setFullYear when time other than midnight Reviewed-by: jlaskey, lagergren --- src/jdk/nashorn/internal/objects/NativeDate.java | 3 +- test/script/basic/JDK-8062024.js | 39 ++++++++++++++++++++++++ test/script/basic/JDK-8062024.js.EXPECTED | 4 +++ 3 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 test/script/basic/JDK-8062024.js create mode 100644 test/script/basic/JDK-8062024.js.EXPECTED diff --git a/src/jdk/nashorn/internal/objects/NativeDate.java b/src/jdk/nashorn/internal/objects/NativeDate.java index c85016a5..bb499c26 100644 --- a/src/jdk/nashorn/internal/objects/NativeDate.java +++ b/src/jdk/nashorn/internal/objects/NativeDate.java @@ -1045,7 +1045,8 @@ public final class NativeDate extends ScriptObject { // 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) diff --git a/test/script/basic/JDK-8062024.js b/test/script/basic/JDK-8062024.js new file mode 100644 index 00000000..453dcfad --- /dev/null +++ b/test/script/basic/JDK-8062024.js @@ -0,0 +1,39 @@ +/* + * 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 + * @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); diff --git a/test/script/basic/JDK-8062024.js.EXPECTED b/test/script/basic/JDK-8062024.js.EXPECTED new file mode 100644 index 00000000..ae18fd7d --- /dev/null +++ b/test/script/basic/JDK-8062024.js.EXPECTED @@ -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) -- cgit v1.2.1 From d35cb55d5ff169bc3de10ac2ffa15fb094e509c8 Mon Sep 17 00:00:00 2001 From: asaha Date: Mon, 27 Oct 2014 12:59:29 -0700 Subject: Added tag jdk8u31-b06 for changeset 99a3333f7f84 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index aa9429bb..6e5ae4f8 100644 --- a/.hgtags +++ b/.hgtags @@ -328,3 +328,4 @@ cdbf34dbef404b47805c8c85b11c65c2afaa6674 jdk8u25-b18 3505d266634ded89bf9617ff6b385ab8a52f78cf jdk8u31-b03 96acff2ad9e19aa80c4f7ed60d87a422bca1ea91 jdk8u31-b04 5fc3f210872d365c57ed4e8dba3926d9ed5c7e45 jdk8u31-b05 +99a3333f7f8489bb3c80f0c0643ae19e549a0941 jdk8u31-b06 -- cgit v1.2.1 From c41afbd5893527aaf273cd142461887ad71919b9 Mon Sep 17 00:00:00 2001 From: sundar Date: Tue, 28 Oct 2014 17:22:17 +0530 Subject: 8062216: [nashorn] regresion test failure with TimeZone Reviewed-by: hannesw, lagergren --- test/script/basic/JDK-8062024.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/script/basic/JDK-8062024.js b/test/script/basic/JDK-8062024.js index 453dcfad..92085cac 100644 --- a/test/script/basic/JDK-8062024.js +++ b/test/script/basic/JDK-8062024.js @@ -25,6 +25,7 @@ * JDK-8062024: Issue with date.setFullYear when time other than midnight * * @test + * @option -timezone=Asia/Calcutta * @run */ -- cgit v1.2.1 From 87575b6d0933a092cd4b23b5146d15b0cdd6cf5b Mon Sep 17 00:00:00 2001 From: katleman Date: Wed, 29 Oct 2014 10:50:44 -0700 Subject: Added tag jdk8u40-b12 for changeset 375a3a3256d0 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index d687d2bb..dde92efc 100644 --- a/.hgtags +++ b/.hgtags @@ -331,3 +331,4 @@ a2e0a985764b5afd5f316429bfab4f44bf150f7f jdk8u40-b03 6a8ecdeae4a9a438eed637b5a5d0d18fddb9f711 jdk8u40-b09 076b1f38a5ccd4692a6f93939a7fc03bc1a1bbb4 jdk8u40-b10 57c7b273277e00f7a98fafb18ff07aa3245808f0 jdk8u40-b11 +375a3a3256d041fe7334638a95e69b4c11d6104b jdk8u40-b12 -- cgit v1.2.1 From dbeb0b336bbd3a9d37f64f24938d0fd348bfc55f Mon Sep 17 00:00:00 2001 From: hannesw Date: Fri, 31 Oct 2014 16:27:58 +0100 Subject: 8062401: User accessors require boxing and do not support optimistic types Reviewed-by: jlaskey, lagergren --- .../internal/codegen/SpillObjectCreator.java | 2 +- .../nashorn/internal/codegen/TypeEvaluator.java | 2 +- src/jdk/nashorn/internal/objects/NativeObject.java | 2 +- .../nashorn/internal/runtime/AccessorProperty.java | 56 ++---- src/jdk/nashorn/internal/runtime/FindProperty.java | 10 +- src/jdk/nashorn/internal/runtime/Property.java | 47 +++-- src/jdk/nashorn/internal/runtime/PropertyMap.java | 2 +- src/jdk/nashorn/internal/runtime/ScriptObject.java | 2 +- .../nashorn/internal/runtime/SpillProperty.java | 4 +- .../internal/runtime/UserAccessorProperty.java | 198 +++++++++++++-------- .../nashorn/internal/runtime/linker/Bootstrap.java | 14 ++ test/examples/getter-setter-micro.js | 81 +++++++++ 12 files changed, 289 insertions(+), 131 deletions(-) create mode 100644 test/examples/getter-setter-micro.js diff --git a/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java b/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java index 4fa51091..40d12dfb 100644 --- a/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java +++ b/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java @@ -88,7 +88,7 @@ public final class SpillObjectCreator extends ObjectCreator { 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); diff --git a/src/jdk/nashorn/internal/codegen/TypeEvaluator.java b/src/jdk/nashorn/internal/codegen/TypeEvaluator.java index 4f3bc07f..d5282a8b 100644 --- a/src/jdk/nashorn/internal/codegen/TypeEvaluator.java +++ b/src/jdk/nashorn/internal/codegen/TypeEvaluator.java @@ -117,7 +117,7 @@ final class TypeEvaluator { } 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. diff --git a/src/jdk/nashorn/internal/objects/NativeObject.java b/src/jdk/nashorn/internal/objects/NativeObject.java index dcd7587b..7a1375d3 100644 --- a/src/jdk/nashorn/internal/objects/NativeObject.java +++ b/src/jdk/nashorn/internal/objects/NativeObject.java @@ -672,7 +672,7 @@ public final class NativeObject { 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); } diff --git a/src/jdk/nashorn/internal/runtime/AccessorProperty.java b/src/jdk/nashorn/internal/runtime/AccessorProperty.java index e2935368..a9afeb93 100644 --- a/src/jdk/nashorn/internal/runtime/AccessorProperty.java +++ b/src/jdk/nashorn/internal/runtime/AccessorProperty.java @@ -144,13 +144,6 @@ public class AccessorProperty extends Property { /** Seed setter for the Object version of this field */ 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. @@ -171,7 +164,7 @@ public class AccessorProperty extends Property { 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 @@ public class AccessorProperty extends Property { 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 class AccessorProperty extends Property { */ 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 @@ public class AccessorProperty extends Property { 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 @@ public class AccessorProperty extends Property { * @param property source property */ protected AccessorProperty(final AccessorProperty property) { - this(property, property.getCurrentType()); + this(property, property.getLocalType()); } /** @@ -354,7 +347,7 @@ public class AccessorProperty extends Property { * @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 @@ public class AccessorProperty extends Property { * 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 @@ public class AccessorProperty extends Property { } else { getter = debug( createGetter( - getCurrentType(), + getLocalType(), type, primitiveGetter, objectGetter, INVALID_PROGRAM_POINT), - getCurrentType(), + getLocalType(), type, "get"); getterCache[i] = getter; @@ -582,18 +575,18 @@ public class AccessorProperty extends Property { 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 @@ public class AccessorProperty extends Property { } 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 @@ public class AccessorProperty extends Property { * @return true if undefined */ protected final boolean isUndefined() { - return getCurrentType() == null; + return getLocalType() == null; } @Override @@ -647,7 +640,7 @@ public class AccessorProperty extends Property { 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 @@ public class AccessorProperty extends Property { 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 @@ public class AccessorProperty extends Property { 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; diff --git a/src/jdk/nashorn/internal/runtime/FindProperty.java b/src/jdk/nashorn/internal/runtime/FindProperty.java index b4e00124..3b153c58 100644 --- a/src/jdk/nashorn/internal/runtime/FindProperty.java +++ b/src/jdk/nashorn/internal/runtime/FindProperty.java @@ -84,13 +84,18 @@ public final class FindProperty { * @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 final class FindProperty { 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); } diff --git a/src/jdk/nashorn/internal/runtime/Property.java b/src/jdk/nashorn/internal/runtime/Property.java index f57246ca..41baa642 100644 --- a/src/jdk/nashorn/internal/runtime/Property.java +++ b/src/jdk/nashorn/internal/runtime/Property.java @@ -102,6 +102,13 @@ public abstract class Property implements Serializable { /** 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 @@ public abstract class Property implements Serializable { *

* 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 @@ public abstract class Property implements Serializable { @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 @@ public abstract class Property implements Serializable { final Property otherProperty = (Property)other; return equalsWithoutType(otherProperty) && - getCurrentType() == otherProperty.getCurrentType(); + getLocalType() == otherProperty.getLocalType(); } boolean equalsWithoutType(final Property otherProperty) { @@ -615,7 +622,7 @@ public abstract class Property implements Serializable { */ 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 @@ public abstract class Property implements Serializable { @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 @@ public abstract class Property implements Serializable { } /** - * 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. * + *

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.

+ * * @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 diff --git a/src/jdk/nashorn/internal/runtime/PropertyMap.java b/src/jdk/nashorn/internal/runtime/PropertyMap.java index 61912332..defd305b 100644 --- a/src/jdk/nashorn/internal/runtime/PropertyMap.java +++ b/src/jdk/nashorn/internal/runtime/PropertyMap.java @@ -512,7 +512,7 @@ public final class PropertyMap implements Iterable, Serializable { 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; diff --git a/src/jdk/nashorn/internal/runtime/ScriptObject.java b/src/jdk/nashorn/internal/runtime/ScriptObject.java index da1023ed..a76703cf 100644 --- a/src/jdk/nashorn/internal/runtime/ScriptObject.java +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java @@ -969,7 +969,7 @@ public abstract class ScriptObject implements PropertyAccess { 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 { diff --git a/src/jdk/nashorn/internal/runtime/SpillProperty.java b/src/jdk/nashorn/internal/runtime/SpillProperty.java index 8ff1b8e5..7b42b2bf 100644 --- a/src/jdk/nashorn/internal/runtime/SpillProperty.java +++ b/src/jdk/nashorn/internal/runtime/SpillProperty.java @@ -161,12 +161,12 @@ public class SpillProperty extends AccessorProperty { */ 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) { diff --git a/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java b/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java index 5fdec009..d14dd8e7 100644 --- a/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java +++ b/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java @@ -27,16 +27,16 @@ package jdk.nashorn.internal.runtime; 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 @@ public final class UserAccessorProperty extends SpillProperty { 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); - - /** 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() { - @Override - public MethodHandle call() { - return Bootstrap.createDynamicInvoker("dyn:call", Object.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); + + + 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() { - @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 @@ public final class UserAccessorProperty extends SpillProperty { } @Override - public Class getCurrentType() { + protected Class getLocalType() { return Object.class; } @@ -189,7 +180,13 @@ public final class UserAccessorProperty extends SpillProperty { @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 @@ public final class UserAccessorProperty extends SpillProperty { @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 @@ public final class UserAccessorProperty extends SpillProperty { @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 @@ public final class UserAccessorProperty extends SpillProperty { // 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) { + 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) { - 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)); } diff --git a/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java b/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java index 67dd88e2..a0842f2d 100644 --- a/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java +++ b/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java @@ -335,6 +335,20 @@ public final class Bootstrap { return createDynamicInvoker(opDesc, MethodType.methodType(rtype, ptypes)); } + /** + * 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 diff --git a/test/examples/getter-setter-micro.js b/test/examples/getter-setter-micro.js new file mode 100644 index 00000000..68ed1c30 --- /dev/null +++ b/test/examples/getter-setter-micro.js @@ -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); +} -- cgit v1.2.1 From 535a0c78031da567d66d75155681008919e28057 Mon Sep 17 00:00:00 2001 From: hannesw Date: Fri, 31 Oct 2014 16:29:22 +0100 Subject: 8062132: Nashorn incorrectly binds this for constructor created by another function Reviewed-by: jlaskey, sundar --- src/jdk/nashorn/internal/runtime/PropertyMap.java | 19 +++--- test/script/basic/JDK-8062132.js | 80 +++++++++++++++++++++++ test/script/basic/JDK-8062132.js.EXPECTED | 6 ++ 3 files changed, 95 insertions(+), 10 deletions(-) create mode 100644 test/script/basic/JDK-8062132.js create mode 100644 test/script/basic/JDK-8062132.js.EXPECTED diff --git a/src/jdk/nashorn/internal/runtime/PropertyMap.java b/src/jdk/nashorn/internal/runtime/PropertyMap.java index defd305b..30a15132 100644 --- a/src/jdk/nashorn/internal/runtime/PropertyMap.java +++ b/src/jdk/nashorn/internal/runtime/PropertyMap.java @@ -84,7 +84,7 @@ public final class PropertyMap implements Iterable, Serializable { private transient WeakHashMap> history; /** History of prototypes, used to limit map duplication. */ - private transient WeakHashMap> protoHistory; + private transient WeakHashMap> protoHistory; /** property listeners */ private transient PropertyListeners listeners; @@ -677,14 +677,14 @@ public final class PropertyMap implements Iterable, Serializable { /** * 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 weakMap = protoHistory.get(parentMap); + final SoftReference weakMap = protoHistory.get(proto); cachedMap = (weakMap != null ? weakMap.get() : null); } else { cachedMap = null; @@ -700,15 +700,15 @@ public final class PropertyMap implements Iterable, Serializable { /** * 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 final class PropertyMap implements Iterable, Serializable { */ 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 @@ public final class PropertyMap implements Iterable, Serializable { } final PropertyMap newMap = new PropertyMap(this); - addToProtoHistory(parentMap, newMap); + addToProtoHistory(newProto, newMap); return newMap; } diff --git a/test/script/basic/JDK-8062132.js b/test/script/basic/JDK-8062132.js new file mode 100644 index 00000000..604461df --- /dev/null +++ b/test/script/basic/JDK-8062132.js @@ -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(); diff --git a/test/script/basic/JDK-8062132.js.EXPECTED b/test/script/basic/JDK-8062132.js.EXPECTED new file mode 100644 index 00000000..96df4080 --- /dev/null +++ b/test/script/basic/JDK-8062132.js.EXPECTED @@ -0,0 +1,6 @@ +child 1 +child 2 +child 3 +child 1 +child 2 +child 3 -- cgit v1.2.1 From 0a092721b45904be9916f3f2f23e949feb59fa53 Mon Sep 17 00:00:00 2001 From: hannesw Date: Fri, 31 Oct 2014 20:19:49 +0100 Subject: 8062583: Throwing object with error prototype causes error proto to be caught Reviewed-by: sundar, jlaskey --- .../nashorn/internal/runtime/ECMAException.java | 22 ++++++---- test/script/basic/JDK-8062583.js | 51 ++++++++++++++++++++++ test/script/basic/JDK-8062583.js.EXPECTED | 8 ++++ 3 files changed, 73 insertions(+), 8 deletions(-) create mode 100644 test/script/basic/JDK-8062583.js create mode 100644 test/script/basic/JDK-8062583.js.EXPECTED diff --git a/src/jdk/nashorn/internal/runtime/ECMAException.java b/src/jdk/nashorn/internal/runtime/ECMAException.java index 954a1707..f906e18f 100644 --- a/src/jdk/nashorn/internal/runtime/ECMAException.java +++ b/src/jdk/nashorn/internal/runtime/ECMAException.java @@ -96,15 +96,17 @@ public final class ECMAException extends NashornException { // 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 @@ public final class ECMAException extends NashornException { * @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; } /** diff --git a/test/script/basic/JDK-8062583.js b/test/script/basic/JDK-8062583.js new file mode 100644 index 00000000..72560b34 --- /dev/null +++ b/test/script/basic/JDK-8062583.js @@ -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, '/')); diff --git a/test/script/basic/JDK-8062583.js.EXPECTED b/test/script/basic/JDK-8062583.js.EXPECTED new file mode 100644 index 00000000..75201739 --- /dev/null +++ b/test/script/basic/JDK-8062583.js.EXPECTED @@ -0,0 +1,8 @@ +true +false +CustomError + at (test/script/basic/JDK-8062583.js:40) +test/script/basic/JDK-8062583.js:40:4 CustomError +CustomError + at (test/script/basic/JDK-8062583.js:49) +test/script/basic/JDK-8062583.js:49 CustomError -- cgit v1.2.1 From 1e1da3ac540bca042275d25c6c90eda74aeae858 Mon Sep 17 00:00:00 2001 From: attila Date: Mon, 3 Nov 2014 07:28:08 +0100 Subject: 8061957: Some arithmetic operations have unnecessary widening Reviewed-by: hannesw, lagergren --- .../nashorn/internal/codegen/CodeGenerator.java | 9 ++-- .../nashorn/internal/codegen/types/IntType.java | 19 ++++---- .../nashorn/internal/codegen/types/LongType.java | 18 +++---- src/jdk/nashorn/internal/runtime/JSType.java | 56 ++++++++++++++++++++++ 4 files changed, 80 insertions(+), 22 deletions(-) diff --git a/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/src/jdk/nashorn/internal/codegen/CodeGenerator.java index f6b9001e..28b08098 100644 --- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java @@ -3569,7 +3569,8 @@ final class CodeGenerator extends NodeOperatorVisitor>> 0 == 0 */ + public static final Call DIV_ZERO_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "divZero", long.class, long.class, long.class); + + /** Mod zero wrapper for long division that handles (0%0) >>> 0 == 0 */ + public static final Call REM_ZERO_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "remZero", long.class, long.class, long.class); + /** Mod exact wrapper for potentially integer remainders that turns into float point */ public static final Call REM_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "remExact", long.class, long.class, long.class, int.class); @@ -1485,6 +1497,28 @@ public enum JSType { throw new UnwarrantedOptimismException((double)x / (double)y, programPoint); } + /** + * Implements int division but allows {@code x / 0} to be represented as 0. Basically equivalent to + * {@code (x / y)|0} JavaScript expression (division of two ints coerced to int). + * @param x the dividend + * @param y the divisor + * @return the result + */ + public static int divZero(final int x, final int y) { + return y == 0 ? 0 : x / y; + } + + /** + * Implements int remainder but allows {@code x % 0} to be represented as 0. Basically equivalent to + * {@code (x % y)|0} JavaScript expression (remainder of two ints coerced to int). + * @param x the dividend + * @param y the divisor + * @return the remainder + */ + public static int remZero(final int x, final int y) { + return y == 0 ? 0 : x % y; + } + /** * Wrapper for modExact. Throws UnwarrantedOptimismException if the modulo can't be represented as int. * @@ -1528,6 +1562,28 @@ public enum JSType { throw new UnwarrantedOptimismException((double)x / (double)y, programPoint); } + /** + * Implements long division but allows {@code x / 0} to be represented as 0. Useful when division of two longs + * is coerced to long. + * @param x the dividend + * @param y the divisor + * @return the result + */ + public static long divZero(final long x, final long y) { + return y == 0L ? 0L : x / y; + } + + /** + * Implements long remainder but allows {@code x % 0} to be represented as 0. Useful when remainder of two longs + * is coerced to long. + * @param x the dividend + * @param y the divisor + * @return the remainder + */ + public static long remZero(final long x, final long y) { + return y == 0L ? 0L : x % y; + } + /** * Wrapper for modExact. Throws UnwarrantedOptimismException if the modulo can't be represented as int. * -- cgit v1.2.1 From a2983b148c3190d7732e527a2951566c55e5bccc Mon Sep 17 00:00:00 2001 From: attila Date: Mon, 3 Nov 2014 07:29:46 +0100 Subject: 8062050: A method is considered caller sensitive, but it doesn't have the CallerSensitive annotation Reviewed-by: hannesw, lagergren --- .../dynalink/beans/AbstractJavaLinker.java | 13 +++++++- .../dynalink/beans/CallerSensitiveTest.java | 36 ++++++++++++++++++++++ .../jdk/nashorn/test/models/ClassLoaderAware.java | 31 +++++++++++++++++++ 3 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 test/src/jdk/internal/dynalink/beans/CallerSensitiveTest.java create mode 100644 test/src/jdk/nashorn/test/models/ClassLoaderAware.java diff --git a/src/jdk/internal/dynalink/beans/AbstractJavaLinker.java b/src/jdk/internal/dynalink/beans/AbstractJavaLinker.java index dab6cbf5..b8e8a3df 100644 --- a/src/jdk/internal/dynalink/beans/AbstractJavaLinker.java +++ b/src/jdk/internal/dynalink/beans/AbstractJavaLinker.java @@ -287,10 +287,21 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker { */ private static SingleDynamicMethod createDynamicMethod(final AccessibleObject m) { if(CallerSensitiveDetector.isCallerSensitive(m)) { + // Method has @CallerSensitive annotation return new CallerSensitiveDynamicMethod(m); } + // Method has no @CallerSensitive annotation + final MethodHandle mh; + try { + mh = unreflectSafely(m); + } catch (final IllegalAccessError e) { + // java.lang.invoke can in some case conservatively treat as caller sensitive methods that aren't + // marked with the annotation. In this case, we'll fall back to treating it as caller sensitive. + return new CallerSensitiveDynamicMethod(m); + } + // Proceed with non-caller sensitive final Member member = (Member)m; - return new SimpleDynamicMethod(unreflectSafely(m), member.getDeclaringClass(), member.getName(), m instanceof Constructor); + return new SimpleDynamicMethod(mh, member.getDeclaringClass(), member.getName(), m instanceof Constructor); } /** diff --git a/test/src/jdk/internal/dynalink/beans/CallerSensitiveTest.java b/test/src/jdk/internal/dynalink/beans/CallerSensitiveTest.java new file mode 100644 index 00000000..44039320 --- /dev/null +++ b/test/src/jdk/internal/dynalink/beans/CallerSensitiveTest.java @@ -0,0 +1,36 @@ +/* + * 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. 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.internal.dynalink.beans; + +import jdk.nashorn.test.models.ClassLoaderAware; +import org.testng.annotations.Test; + +public class CallerSensitiveTest { + @Test + public void testCallerSensitive() { + BeansLinker.getLinkerForClass(ClassLoaderAware.class); + } +} diff --git a/test/src/jdk/nashorn/test/models/ClassLoaderAware.java b/test/src/jdk/nashorn/test/models/ClassLoaderAware.java new file mode 100644 index 00000000..18629914 --- /dev/null +++ b/test/src/jdk/nashorn/test/models/ClassLoaderAware.java @@ -0,0 +1,31 @@ +/* + * 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. 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.test.models; + +public interface ClassLoaderAware { + public ClassLoader getContextClassLoader(); + public void checkMemberAccess(Class clazz, int which); +} -- cgit v1.2.1 From e4325507fd3bf9d3d27d485388bbb23e24c44e51 Mon Sep 17 00:00:00 2001 From: lagergren Date: Mon, 3 Nov 2014 11:47:41 +0100 Subject: 8060204: Fix warnings in Joni and tests Reviewed-by: hannesw, sundar, attila --- docs/source/EvalFile.java | 10 +- docs/source/EvalScript.java | 10 +- docs/source/InvokeScriptFunction.java | 15 +- docs/source/InvokeScriptMethod.java | 17 +- docs/source/MultiScopes.java | 17 +- docs/source/RunnableImpl.java | 19 +- docs/source/RunnableImplObject.java | 21 +- docs/source/ScriptVars.java | 14 +- src/jdk/nashorn/internal/AssertsEnabled.java | 2 +- .../codegen/CodeGeneratorLexicalContext.java | 3 +- src/jdk/nashorn/internal/codegen/Compiler.java | 1 + .../codegen/LocalVariableTypesCalculator.java | 8 +- src/jdk/nashorn/internal/codegen/types/Type.java | 8 +- .../nashorn/internal/objects/ArrayBufferView.java | 116 ++++++++- .../nashorn/internal/runtime/CompiledFunction.java | 14 +- .../runtime/RecompilableScriptFunctionData.java | 2 +- .../internal/runtime/ScriptEnvironment.java | 1 + .../runtime/events/RecompilationEvent.java | 1 - .../runtime/linker/BrowserJSObjectLinker.java | 17 +- .../internal/runtime/linker/JSObjectLinker.java | 11 +- .../internal/runtime/regexp/joni/Analyser.java | 259 +++++++++++++++------ .../runtime/regexp/joni/ApplyCaseFold.java | 6 +- .../runtime/regexp/joni/ApplyCaseFoldArg.java | 1 + .../runtime/regexp/joni/ArrayCompiler.java | 80 ++++--- .../internal/runtime/regexp/joni/BitSet.java | 48 +++- .../internal/runtime/regexp/joni/BitStatus.java | 12 +- .../runtime/regexp/joni/ByteCodeMachine.java | 217 ++++++++++------- .../runtime/regexp/joni/ByteCodePrinter.java | 18 +- .../runtime/regexp/joni/CodeRangeBuffer.java | 114 ++++++--- .../internal/runtime/regexp/joni/Compiler.java | 12 +- .../internal/runtime/regexp/joni/Config.java | 1 + .../runtime/regexp/joni/EncodingHelper.java | 18 +- .../internal/runtime/regexp/joni/Lexer.java | 235 +++++++++++++------ .../internal/runtime/regexp/joni/Matcher.java | 241 ++++++++++++------- .../runtime/regexp/joni/MatcherFactory.java | 1 + .../internal/runtime/regexp/joni/MinMaxLen.java | 54 +++-- .../internal/runtime/regexp/joni/NodeOptInfo.java | 9 +- .../runtime/regexp/joni/OptAnchorInfo.java | 44 +++- .../internal/runtime/regexp/joni/OptExactInfo.java | 55 +++-- .../internal/runtime/regexp/joni/OptMapInfo.java | 32 ++- .../internal/runtime/regexp/joni/Option.java | 51 ++-- .../internal/runtime/regexp/joni/Parser.java | 83 ++++--- .../internal/runtime/regexp/joni/Regex.java | 36 ++- .../internal/runtime/regexp/joni/Region.java | 5 +- .../runtime/regexp/joni/ScanEnvironment.java | 7 +- .../runtime/regexp/joni/ScannerSupport.java | 26 ++- .../runtime/regexp/joni/SearchAlgorithm.java | 83 +++++-- .../internal/runtime/regexp/joni/StackMachine.java | 126 +++++----- .../internal/runtime/regexp/joni/Syntax.java | 4 +- .../internal/runtime/regexp/joni/WarnCallback.java | 1 + .../internal/runtime/regexp/joni/Warnings.java | 1 + .../runtime/regexp/joni/ast/AnchorNode.java | 73 ++++-- .../runtime/regexp/joni/ast/AnyCharNode.java | 1 + .../runtime/regexp/joni/ast/BackRefNode.java | 1 + .../runtime/regexp/joni/ast/CClassNode.java | 112 ++++++--- .../runtime/regexp/joni/ast/ConsAltNode.java | 12 +- .../runtime/regexp/joni/ast/EncloseNode.java | 1 + .../internal/runtime/regexp/joni/ast/Node.java | 37 ++- .../runtime/regexp/joni/ast/QuantifierNode.java | 39 +++- .../runtime/regexp/joni/ast/StateNode.java | 1 + .../runtime/regexp/joni/ast/StringNode.java | 1 + .../runtime/regexp/joni/constants/AnchorType.java | 1 + .../runtime/regexp/joni/constants/Arguments.java | 1 + .../regexp/joni/constants/AsmConstants.java | 1 + .../runtime/regexp/joni/constants/CCSTATE.java | 1 + .../runtime/regexp/joni/constants/CCVALTYPE.java | 1 + .../runtime/regexp/joni/constants/EncloseType.java | 1 + .../runtime/regexp/joni/constants/MetaChar.java | 1 + .../runtime/regexp/joni/constants/NodeStatus.java | 1 + .../runtime/regexp/joni/constants/NodeType.java | 1 + .../runtime/regexp/joni/constants/OPCode.java | 1 + .../runtime/regexp/joni/constants/OPSize.java | 1 + .../runtime/regexp/joni/constants/RegexState.java | 1 + .../regexp/joni/constants/StackPopLevel.java | 1 + .../runtime/regexp/joni/constants/StackType.java | 1 + .../runtime/regexp/joni/constants/StringType.java | 1 + .../regexp/joni/constants/SyntaxProperties.java | 1 + .../runtime/regexp/joni/constants/TargetInfo.java | 1 + .../runtime/regexp/joni/constants/TokenType.java | 1 + .../runtime/regexp/joni/constants/Traverse.java | 1 + .../regexp/joni/encoding/CharacterType.java | 1 + .../runtime/regexp/joni/encoding/IntHolder.java | 1 + .../runtime/regexp/joni/encoding/ObjPtr.java | 1 + .../regexp/joni/exception/ErrorMessages.java | 1 + .../regexp/joni/exception/InternalException.java | 1 + .../regexp/joni/exception/JOniException.java | 1 + .../regexp/joni/exception/SyntaxException.java | 1 + .../regexp/joni/exception/ValueException.java | 3 +- .../api/javaaccess/ArrayConversionTest.java | 6 +- .../nashorn/api/javaaccess/BooleanAccessTest.java | 2 +- .../jdk/nashorn/api/javaaccess/ConsStringTest.java | 6 +- .../nashorn/api/javaaccess/MethodAccessTest.java | 2 +- .../nashorn/api/javaaccess/NumberAccessTest.java | 2 +- .../nashorn/api/javaaccess/NumberBoxingTest.java | 2 +- .../nashorn/api/javaaccess/ObjectAccessTest.java | 2 +- test/src/jdk/nashorn/api/javaaccess/Person.java | 1 + .../jdk/nashorn/api/javaaccess/SharedObject.java | 1 + .../nashorn/api/javaaccess/StringAccessTest.java | 2 +- .../jdk/nashorn/api/scripting/InvocableTest.java | 16 +- .../nashorn/api/scripting/MultipleEngineTest.java | 2 +- .../api/scripting/PluggableJSObjectTest.java | 2 + test/src/jdk/nashorn/api/scripting/ScopeTest.java | 4 +- .../api/scripting/ScriptEngineSecurityTest.java | 27 ++- .../nashorn/api/scripting/ScriptEngineTest.java | 12 +- .../api/scripting/ScriptObjectMirrorTest.java | 7 +- .../api/scripting/VariableArityTestInterface.java | 1 + test/src/jdk/nashorn/api/scripting/Window.java | 1 + .../nashorn/api/scripting/WindowEventHandler.java | 3 +- .../jdk/nashorn/internal/codegen/CompilerTest.java | 4 +- .../jdk/nashorn/internal/parser/ParserTest.java | 2 +- .../internal/performance/AuroraWrapper.java | 1 + .../nashorn/internal/performance/OctaneTest.java | 15 +- .../internal/performance/PerformanceWrapper.java | 5 +- .../nashorn/internal/performance/SplayTest.java | 5 +- .../nashorn/internal/runtime/ClassFilterTest.java | 62 ++--- .../internal/runtime/CodeStoreAndPathTest.java | 18 +- .../jdk/nashorn/internal/runtime/ContextTest.java | 6 +- .../runtime/ExceptionsNotSerializable.java | 4 +- .../internal/runtime/NoPersistenceCachingTest.java | 4 +- .../jdk/nashorn/internal/runtime/SourceTest.java | 6 +- .../internal/runtime/TrustedScriptEngineTest.java | 23 +- .../internal/runtime/regexp/joni/JoniTest.java | 1 + .../test/framework/AbstractScriptRunnable.java | 8 +- .../internal/test/framework/OrphanTestFinder.java | 1 + .../test/framework/ParallelTestRunner.java | 10 +- .../internal/test/framework/ScriptRunnable.java | 1 + .../internal/test/framework/ScriptTest.java | 3 +- .../internal/test/framework/TestConfig.java | 1 + .../internal/test/framework/TestFinder.java | 8 +- .../internal/test/framework/TestHelper.java | 1 + .../test/framework/TestReorderInterceptor.java | 5 +- .../internal/test/models/InternalRunnable.java | 1 + .../internal/test/models/RestrictedRunnable.java | 2 +- .../test/models/ClassWithFinalFinalizer.java | 3 + .../models/ClassWithInheritedFinalFinalizer.java | 2 + .../test/models/ConstructorWithArgument.java | 1 + .../jdk/nashorn/test/models/DessertTopping.java | 1 + .../test/models/DessertToppingFloorWaxDriver.java | 1 + test/src/jdk/nashorn/test/models/FinalClass.java | 1 + test/src/jdk/nashorn/test/models/FloorWax.java | 1 + .../test/models/IntFloatOverloadSelection.java | 1 + .../test/models/InternalRunnableSuperclass.java | 3 +- .../nashorn/test/models/Jdk8011362TestSubject.java | 3 +- .../nashorn/test/models/Nashorn401TestSubject.java | 1 + .../test/models/NoAccessibleConstructorClass.java | 1 + test/src/jdk/nashorn/test/models/OuterClass.java | 8 +- .../src/jdk/nashorn/test/models/OverloadedSam.java | 1 + .../jdk/nashorn/test/models/OverrideObject.java | 1 + test/src/jdk/nashorn/test/models/PropertyBind.java | 1 + test/src/jdk/nashorn/test/models/SourceHelper.java | 1 + test/src/jdk/nashorn/test/models/StringArgs.java | 1 + test/src/jdk/nashorn/test/models/Toothpaste.java | 1 + .../jdk/nashorn/test/models/VarArgConstructor.java | 1 + .../nashorn/test/tools/StaticTypeInspector.java | 1 + 154 files changed, 1912 insertions(+), 915 deletions(-) diff --git a/docs/source/EvalFile.java b/docs/source/EvalFile.java index 6bb4e381..b12e91bb 100644 --- a/docs/source/EvalFile.java +++ b/docs/source/EvalFile.java @@ -29,14 +29,16 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import javax.script.*; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +@SuppressWarnings("javadoc") public class EvalFile { - public static void main(String[] args) throws Exception { + public static void main(final String[] args) throws Exception { // create a script engine manager - ScriptEngineManager factory = new ScriptEngineManager(); + final ScriptEngineManager factory = new ScriptEngineManager(); // create JavaScript engine - ScriptEngine engine = factory.getEngineByName("nashorn"); + final ScriptEngine engine = factory.getEngineByName("nashorn"); // evaluate JavaScript code from given file - specified by first argument engine.eval(new java.io.FileReader(args[0])); } diff --git a/docs/source/EvalScript.java b/docs/source/EvalScript.java index 7fcbe1cd..49f581de 100644 --- a/docs/source/EvalScript.java +++ b/docs/source/EvalScript.java @@ -29,14 +29,16 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import javax.script.*; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +@SuppressWarnings("javadoc") public class EvalScript { - public static void main(String[] args) throws Exception { + public static void main(final String[] args) throws Exception { // create a script engine manager - ScriptEngineManager factory = new ScriptEngineManager(); + final ScriptEngineManager factory = new ScriptEngineManager(); // create a JavaScript engine - ScriptEngine engine = factory.getEngineByName("nashorn"); + final ScriptEngine engine = factory.getEngineByName("nashorn"); // evaluate JavaScript code from String engine.eval("print('Hello, World')"); } diff --git a/docs/source/InvokeScriptFunction.java b/docs/source/InvokeScriptFunction.java index 26de36c4..5ce1cae0 100644 --- a/docs/source/InvokeScriptFunction.java +++ b/docs/source/InvokeScriptFunction.java @@ -29,22 +29,25 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import javax.script.*; +import javax.script.Invocable; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +@SuppressWarnings("javadoc") public class InvokeScriptFunction { - public static void main(String[] args) throws Exception { - ScriptEngineManager manager = new ScriptEngineManager(); - ScriptEngine engine = manager.getEngineByName("nashorn"); + public static void main(final String[] args) throws Exception { + final ScriptEngineManager manager = new ScriptEngineManager(); + final ScriptEngine engine = manager.getEngineByName("nashorn"); // JavaScript code in a String - String script = "function hello(name) { print('Hello, ' + name); }"; + final String script = "function hello(name) { print('Hello, ' + name); }"; // evaluate script engine.eval(script); // javax.script.Invocable is an optional interface. // Check whether your script engine implements or not! // Note that the JavaScript engine implements Invocable interface. - Invocable inv = (Invocable) engine; + final Invocable inv = (Invocable) engine; // invoke the global function named "hello" inv.invokeFunction("hello", "Scripting!!" ); diff --git a/docs/source/InvokeScriptMethod.java b/docs/source/InvokeScriptMethod.java index a3f5ece7..d3cc788d 100644 --- a/docs/source/InvokeScriptMethod.java +++ b/docs/source/InvokeScriptMethod.java @@ -29,26 +29,29 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import javax.script.*; +import javax.script.Invocable; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +@SuppressWarnings("javadoc") public class InvokeScriptMethod { - public static void main(String[] args) throws Exception { - ScriptEngineManager manager = new ScriptEngineManager(); - ScriptEngine engine = manager.getEngineByName("nashorn"); + public static void main(final String[] args) throws Exception { + final ScriptEngineManager manager = new ScriptEngineManager(); + final ScriptEngine engine = manager.getEngineByName("nashorn"); // JavaScript code in a String. This code defines a script object 'obj' // with one method called 'hello'. - String script = "var obj = new Object(); obj.hello = function(name) { print('Hello, ' + name); }"; + final String script = "var obj = new Object(); obj.hello = function(name) { print('Hello, ' + name); }"; // evaluate script engine.eval(script); // javax.script.Invocable is an optional interface. // Check whether your script engine implements or not! // Note that the JavaScript engine implements Invocable interface. - Invocable inv = (Invocable) engine; + final Invocable inv = (Invocable) engine; // get script object on which we want to call the method - Object obj = engine.get("obj"); + final Object obj = engine.get("obj"); // invoke the method named "hello" on the script object "obj" inv.invokeMethod(obj, "hello", "Script Method !!" ); diff --git a/docs/source/MultiScopes.java b/docs/source/MultiScopes.java index 6c4fa2a2..ff4f65b4 100644 --- a/docs/source/MultiScopes.java +++ b/docs/source/MultiScopes.java @@ -29,12 +29,17 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import javax.script.*; +import javax.script.Bindings; +import javax.script.ScriptContext; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import javax.script.SimpleScriptContext; +@SuppressWarnings("javadoc") public class MultiScopes { - public static void main(String[] args) throws Exception { - ScriptEngineManager manager = new ScriptEngineManager(); - ScriptEngine engine = manager.getEngineByName("nashorn"); + public static void main(final String[] args) throws Exception { + final ScriptEngineManager manager = new ScriptEngineManager(); + final ScriptEngine engine = manager.getEngineByName("nashorn"); engine.put("x", "hello"); // print global variable "x" @@ -42,9 +47,9 @@ public class MultiScopes { // the above line prints "hello" // Now, pass a different script context - ScriptContext newContext = new SimpleScriptContext(); + final ScriptContext newContext = new SimpleScriptContext(); newContext.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE); - Bindings engineScope = newContext.getBindings(ScriptContext.ENGINE_SCOPE); + final Bindings engineScope = newContext.getBindings(ScriptContext.ENGINE_SCOPE); // add new variable "x" to the new engineScope engineScope.put("x", "world"); diff --git a/docs/source/RunnableImpl.java b/docs/source/RunnableImpl.java index 1d858d40..2b5113b1 100644 --- a/docs/source/RunnableImpl.java +++ b/docs/source/RunnableImpl.java @@ -29,28 +29,31 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import javax.script.*; +import javax.script.Invocable; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +@SuppressWarnings("javadoc") public class RunnableImpl { - public static void main(String[] args) throws Exception { - ScriptEngineManager manager = new ScriptEngineManager(); - ScriptEngine engine = manager.getEngineByName("nashorn"); + public static void main(final String[] args) throws Exception { + final ScriptEngineManager manager = new ScriptEngineManager(); + final ScriptEngine engine = manager.getEngineByName("nashorn"); // JavaScript code in a String - String script = "function run() { print('run called'); }"; + final String script = "function run() { print('run called'); }"; // evaluate script engine.eval(script); - Invocable inv = (Invocable) engine; + final Invocable inv = (Invocable) engine; // get Runnable interface object from engine. This interface methods // are implemented by script functions with the matching name. - Runnable r = inv.getInterface(Runnable.class); + final Runnable r = inv.getInterface(Runnable.class); // start a new thread that runs the script implemented // runnable interface - Thread th = new Thread(r); + final Thread th = new Thread(r); th.start(); th.join(); } diff --git a/docs/source/RunnableImplObject.java b/docs/source/RunnableImplObject.java index 877f8c15..0d5f5032 100644 --- a/docs/source/RunnableImplObject.java +++ b/docs/source/RunnableImplObject.java @@ -29,31 +29,34 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import javax.script.*; +import javax.script.Invocable; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +@SuppressWarnings("javadoc") public class RunnableImplObject { - public static void main(String[] args) throws Exception { - ScriptEngineManager manager = new ScriptEngineManager(); - ScriptEngine engine = manager.getEngineByName("nashorn"); + public static void main(final String[] args) throws Exception { + final ScriptEngineManager manager = new ScriptEngineManager(); + final ScriptEngine engine = manager.getEngineByName("nashorn"); // JavaScript code in a String - String script = "var obj = new Object(); obj.run = function() { print('run method called'); }"; + final String script = "var obj = new Object(); obj.run = function() { print('run method called'); }"; // evaluate script engine.eval(script); // get script object on which we want to implement the interface with - Object obj = engine.get("obj"); + final Object obj = engine.get("obj"); - Invocable inv = (Invocable) engine; + final Invocable inv = (Invocable) engine; // get Runnable interface object from engine. This interface methods // are implemented by script methods of object 'obj' - Runnable r = inv.getInterface(obj, Runnable.class); + final Runnable r = inv.getInterface(obj, Runnable.class); // start a new thread that runs the script implemented // runnable interface - Thread th = new Thread(r); + final Thread th = new Thread(r); th.start(); th.join(); } diff --git a/docs/source/ScriptVars.java b/docs/source/ScriptVars.java index 7e16cfca..c697431d 100644 --- a/docs/source/ScriptVars.java +++ b/docs/source/ScriptVars.java @@ -29,15 +29,17 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import javax.script.*; -import java.io.*; +import java.io.File; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +@SuppressWarnings("javadoc") public class ScriptVars { - public static void main(String[] args) throws Exception { - ScriptEngineManager manager = new ScriptEngineManager(); - ScriptEngine engine = manager.getEngineByName("nashorn"); + public static void main(final String[] args) throws Exception { + final ScriptEngineManager manager = new ScriptEngineManager(); + final ScriptEngine engine = manager.getEngineByName("nashorn"); - File f = new File("test.txt"); + final File f = new File("test.txt"); // expose File object as variable to script engine.put("file", f); diff --git a/src/jdk/nashorn/internal/AssertsEnabled.java b/src/jdk/nashorn/internal/AssertsEnabled.java index f0678664..73d9dfdc 100644 --- a/src/jdk/nashorn/internal/AssertsEnabled.java +++ b/src/jdk/nashorn/internal/AssertsEnabled.java @@ -27,8 +27,8 @@ package jdk.nashorn.internal; /** * Class that exposes the current state of asserts. - * */ +@SuppressWarnings("all") public final class AssertsEnabled { private static boolean assertsEnabled = false; static { diff --git a/src/jdk/nashorn/internal/codegen/CodeGeneratorLexicalContext.java b/src/jdk/nashorn/internal/codegen/CodeGeneratorLexicalContext.java index 08c4b65c..87a0802c 100644 --- a/src/jdk/nashorn/internal/codegen/CodeGeneratorLexicalContext.java +++ b/src/jdk/nashorn/internal/codegen/CodeGeneratorLexicalContext.java @@ -31,7 +31,6 @@ import java.util.Collections; import java.util.Deque; import java.util.HashMap; import java.util.Map; - import jdk.nashorn.internal.IntDeque; import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.Block; @@ -250,7 +249,7 @@ final class CodeGeneratorLexicalContext extends LexicalContext { static Type getTypeForSlotDescriptor(final char typeDesc) { // Recognizing both lowercase and uppercase as we're using both to signify symbol boundaries; see // MethodEmitter.markSymbolBoundariesInLvarTypesDescriptor(). - switch(typeDesc) { + switch (typeDesc) { case 'I': case 'i': return Type.INT; diff --git a/src/jdk/nashorn/internal/codegen/Compiler.java b/src/jdk/nashorn/internal/codegen/Compiler.java index 196862f0..740022b2 100644 --- a/src/jdk/nashorn/internal/codegen/Compiler.java +++ b/src/jdk/nashorn/internal/codegen/Compiler.java @@ -389,6 +389,7 @@ public final class Compiler implements Loggable { * @param continuationEntryPoints continuation entry points for restof method * @param runtimeScope runtime scope for recompilation type lookup in {@code TypeEvaluator} */ + @SuppressWarnings("unused") public Compiler( final Context context, final ScriptEnvironment env, diff --git a/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java b/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java index ea073623..41f5be57 100644 --- a/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java +++ b/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java @@ -28,7 +28,6 @@ package jdk.nashorn.internal.codegen; import static jdk.nashorn.internal.codegen.CompilerConstants.RETURN; import static jdk.nashorn.internal.ir.Expression.isAlwaysFalse; import static jdk.nashorn.internal.ir.Expression.isAlwaysTrue; - import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collections; @@ -236,12 +235,12 @@ final class LocalVariableTypesCalculator extends NodeVisitor{ private byte conversions; void recordConversion(final LvarType from, final LvarType to) { - switch(from) { + switch (from) { case UNDEFINED: return; case INT: case BOOLEAN: - switch(to) { + switch (to) { case LONG: recordConversion(I2L); return; @@ -256,7 +255,7 @@ final class LocalVariableTypesCalculator extends NodeVisitor{ return; } case LONG: - switch(to) { + switch (to) { case DOUBLE: recordConversion(L2D); return; @@ -1425,6 +1424,7 @@ final class LocalVariableTypesCalculator extends NodeVisitor{ * @param symbol the symbol representing the variable * @param type the type */ + @SuppressWarnings("unused") private void setType(final Symbol symbol, final LvarType type) { if(getLocalVariableTypeOrNull(symbol) == type) { return; diff --git a/src/jdk/nashorn/internal/codegen/types/Type.java b/src/jdk/nashorn/internal/codegen/types/Type.java index b31b2503..2b9ccd82 100644 --- a/src/jdk/nashorn/internal/codegen/types/Type.java +++ b/src/jdk/nashorn/internal/codegen/types/Type.java @@ -356,7 +356,7 @@ public abstract class Type implements Comparable, BytecodeOps, Serializabl final int pp = input.readInt(); final int typeChar = input.readByte(); final Type type; - switch(typeChar) { + switch (typeChar) { case 'L': type = Type.OBJECT; break; case 'D': type = Type.NUMBER; break; case 'J': type = Type.LONG; break; @@ -376,13 +376,13 @@ public abstract class Type implements Comparable, BytecodeOps, Serializabl } private static jdk.internal.org.objectweb.asm.Type lookupInternalType(final Class type) { - final Map, jdk.internal.org.objectweb.asm.Type> cache = INTERNAL_TYPE_CACHE; - jdk.internal.org.objectweb.asm.Type itype = cache.get(type); + final Map, jdk.internal.org.objectweb.asm.Type> c = INTERNAL_TYPE_CACHE; + jdk.internal.org.objectweb.asm.Type itype = c.get(type); if (itype != null) { return itype; } itype = jdk.internal.org.objectweb.asm.Type.getType(type); - cache.put(type, itype); + c.put(type, itype); return itype; } diff --git a/src/jdk/nashorn/internal/objects/ArrayBufferView.java b/src/jdk/nashorn/internal/objects/ArrayBufferView.java index e33fac3b..fa3b8071 100644 --- a/src/jdk/nashorn/internal/objects/ArrayBufferView.java +++ b/src/jdk/nashorn/internal/objects/ArrayBufferView.java @@ -28,7 +28,6 @@ package jdk.nashorn.internal.objects; import static jdk.nashorn.internal.runtime.ECMAErrors.rangeError; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT; - import java.nio.ByteBuffer; import java.nio.ByteOrder; import jdk.internal.dynalink.CallSiteDescriptor; @@ -44,6 +43,9 @@ import jdk.nashorn.internal.runtime.ScriptRuntime; import jdk.nashorn.internal.runtime.arrays.ArrayData; import jdk.nashorn.internal.runtime.arrays.TypedArrayData; +/** + * ArrayBufferView, es6 class or TypedArray implementation + */ @ScriptClass("ArrayBufferView") public abstract class ArrayBufferView extends ScriptObject { private final NativeArrayBuffer buffer; @@ -71,6 +73,13 @@ public abstract class ArrayBufferView extends ScriptObject { setArray(data); } + /** + * Constructor + * + * @param buffer underlying NativeArrayBuffer + * @param byteOffset byte offset for buffer + * @param elementLength element length in bytes + */ protected ArrayBufferView(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength) { this(buffer, byteOffset, elementLength, Global.instance()); } @@ -89,22 +98,42 @@ public abstract class ArrayBufferView extends ScriptObject { return factory().bytesPerElement; } + /** + * Buffer getter as per spec + * @param self ArrayBufferView instance + * @return buffer + */ @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE) public static Object buffer(final Object self) { return ((ArrayBufferView)self).buffer; } + /** + * Buffer offset getter as per spec + * @param self ArrayBufferView instance + * @return buffer offset + */ @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE) public static int byteOffset(final Object self) { return ((ArrayBufferView)self).byteOffset; } + /** + * Byte length getter as per spec + * @param self ArrayBufferView instance + * @return array buffer view length in bytes + */ @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE) public static int byteLength(final Object self) { final ArrayBufferView view = (ArrayBufferView)self; return ((TypedArrayData)view.getArray()).getElementLength() * view.bytesPerElement(); } + /** + * Length getter as per spec + * @param self ArrayBufferView instance + * @return length in elements + */ @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE) public static int length(final Object self) { return ((ArrayBufferView)self).elementLength(); @@ -119,15 +148,29 @@ public abstract class ArrayBufferView extends ScriptObject { return ((TypedArrayData)getArray()).getElementLength(); } + /** + * Factory class for byte ArrayBufferViews + */ protected static abstract class Factory { final int bytesPerElement; final int maxElementLength; + /** + * Constructor + * + * @param bytesPerElement number of bytes per element for this buffer + */ public Factory(final int bytesPerElement) { this.bytesPerElement = bytesPerElement; this.maxElementLength = Integer.MAX_VALUE / bytesPerElement; } + /** + * Factory method + * + * @param elementLength number of elements + * @return new ArrayBufferView + */ public final ArrayBufferView construct(final int elementLength) { if (elementLength > maxElementLength) { throw rangeError("inappropriate.array.buffer.length", JSType.toString(elementLength)); @@ -135,15 +178,47 @@ public abstract class ArrayBufferView extends ScriptObject { return construct(new NativeArrayBuffer(elementLength * bytesPerElement), 0, elementLength); } - public abstract ArrayBufferView construct(NativeArrayBuffer buffer, int byteOffset, int elementLength); - - public abstract TypedArrayData createArrayData(ByteBuffer nb, int start, int end); - + /** + * Factory method + * + * @param buffer underlying buffer + * @param byteOffset byte offset + * @param elementLength number of elements + * + * @return new ArrayBufferView + */ + public abstract ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength); + + /** + * Factory method for array data + * + * @param nb underlying nativebuffer + * @param start start element + * @param end end element + * + * @return new array data + */ + public abstract TypedArrayData createArrayData(final ByteBuffer nb, final int start, final int end); + + /** + * Get the class name for this type of buffer + * + * @return class name + */ public abstract String getClassName(); } + /** + * Get the factor for this kind of buffer + * @return Factory + */ protected abstract Factory factory(); + /** + * Get the prototype for this ArrayBufferView + * @param global global instance + * @return prototype + */ protected abstract ScriptObject getPrototype(final Global global); @Override @@ -151,10 +226,23 @@ public abstract class ArrayBufferView extends ScriptObject { return factory().getClassName(); } + /** + * Check if this array contains floats + * @return true if float array (or double) + */ protected boolean isFloatArray() { return false; } + /** + * Inheritable constructor implementation + * + * @param newObj is this a new constructor + * @param args arguments + * @param factory factory + * + * @return new ArrayBufferView + */ protected static ArrayBufferView constructorImpl(final boolean newObj, final Object[] args, final Factory factory) { final Object arg0 = args.length != 0 ? args[0] : 0; final ArrayBufferView dest; @@ -200,6 +288,15 @@ public abstract class ArrayBufferView extends ScriptObject { return dest; } + /** + * Inheritable implementation of set, if no efficient implementation is available + * + * @param self ArrayBufferView instance + * @param array array + * @param offset0 array offset + * + * @return result of setter + */ protected static Object setImpl(final Object self, final Object array, final Object offset0) { final ArrayBufferView dest = (ArrayBufferView)self; final int length; @@ -244,6 +341,15 @@ public abstract class ArrayBufferView extends ScriptObject { return (int)(length & Integer.MAX_VALUE); } + /** + * Implementation of subarray if no efficient override exists + * + * @param self ArrayBufferView instance + * @param begin0 begin index + * @param end0 end index + * + * @return sub array + */ protected static ScriptObject subarrayImpl(final Object self, final Object begin0, final Object end0) { final ArrayBufferView arrayView = (ArrayBufferView)self; final int byteOffset = arrayView.byteOffset; diff --git a/src/jdk/nashorn/internal/runtime/CompiledFunction.java b/src/jdk/nashorn/internal/runtime/CompiledFunction.java index b37f94fa..64cf8f4d 100644 --- a/src/jdk/nashorn/internal/runtime/CompiledFunction.java +++ b/src/jdk/nashorn/internal/runtime/CompiledFunction.java @@ -27,7 +27,6 @@ package jdk.nashorn.internal.runtime; import static jdk.nashorn.internal.lookup.Lookup.MH; import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT; import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid; - import java.lang.invoke.CallSite; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; @@ -777,7 +776,7 @@ final class CompiledFunction { // Compiler needs a call site type as its input, which always has a callee parameter, so we must add it if // this function doesn't have a callee parameter. - final MethodType callSiteType = type.parameterType(0) == ScriptFunction.class ? + final MethodType ct = type.parameterType(0) == ScriptFunction.class ? type : type.insertParameterTypes(0, ScriptFunction.class); final OptimismInfo currentOptInfo = optimismInfo; @@ -788,29 +787,29 @@ final class CompiledFunction { final OptimismInfo effectiveOptInfo = currentOptInfo != null ? currentOptInfo : oldOptInfo; FunctionNode fn = effectiveOptInfo.reparse(); final boolean serialized = effectiveOptInfo.isSerialized(); - final Compiler compiler = effectiveOptInfo.getCompiler(fn, callSiteType, re); //set to non rest-of + final Compiler compiler = effectiveOptInfo.getCompiler(fn, ct, re); //set to non rest-of if (!shouldRecompile) { // It didn't necessarily recompile, e.g. for an outer invocation of a recursive function if we already // recompiled a deoptimized version for an inner invocation. // We still need to do the rest of from the beginning - logRecompile("Rest-of compilation [STANDALONE] ", fn, callSiteType, effectiveOptInfo.invalidatedProgramPoints); + logRecompile("Rest-of compilation [STANDALONE] ", fn, ct, effectiveOptInfo.invalidatedProgramPoints); return restOfHandle(effectiveOptInfo, compiler.compile(fn, serialized ? CompilationPhases.COMPILE_SERIALIZED_RESTOF : CompilationPhases.COMPILE_ALL_RESTOF), currentOptInfo != null); } - logRecompile("Deoptimizing recompilation (up to bytecode) ", fn, callSiteType, effectiveOptInfo.invalidatedProgramPoints); + logRecompile("Deoptimizing recompilation (up to bytecode) ", fn, ct, effectiveOptInfo.invalidatedProgramPoints); fn = compiler.compile(fn, serialized ? CompilationPhases.RECOMPILE_SERIALIZED_UPTO_BYTECODE : CompilationPhases.COMPILE_UPTO_BYTECODE); log.info("Reusable IR generated"); // compile the rest of the function, and install it log.info("Generating and installing bytecode from reusable IR..."); - logRecompile("Rest-of compilation [CODE PIPELINE REUSE] ", fn, callSiteType, effectiveOptInfo.invalidatedProgramPoints); + logRecompile("Rest-of compilation [CODE PIPELINE REUSE] ", fn, ct, effectiveOptInfo.invalidatedProgramPoints); final FunctionNode normalFn = compiler.compile(fn, CompilationPhases.GENERATE_BYTECODE_AND_INSTALL); if (effectiveOptInfo.data.usePersistentCodeCache()) { final RecompilableScriptFunctionData data = effectiveOptInfo.data; final int functionNodeId = data.getFunctionNodeId(); - final TypeMap typeMap = data.typeMap(callSiteType); + final TypeMap typeMap = data.typeMap(ct); final Type[] paramTypes = typeMap == null ? null : typeMap.getParameterTypes(functionNodeId); final String cacheKey = CodeStore.getCacheKey(functionNodeId, paramTypes); compiler.persistClassInfo(cacheKey, normalFn); @@ -871,6 +870,7 @@ final class CompiledFunction { private SwitchPoint optimisticAssumptions; private final DebugLogger log; + @SuppressWarnings("unused") OptimismInfo(final RecompilableScriptFunctionData data, final Map invalidatedProgramPoints) { this.data = data; this.log = data.getLogger(); diff --git a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java index 6b2c7620..9f666c01 100644 --- a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java +++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java @@ -26,7 +26,6 @@ package jdk.nashorn.internal.runtime; import static jdk.nashorn.internal.lookup.Lookup.MH; - import java.io.IOException; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; @@ -475,6 +474,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp * @return either the existing map, or a loaded map from the persistent type info cache, or a new empty map if * neither an existing map or a persistent cached type info is available. */ + @SuppressWarnings("unused") private static Map getEffectiveInvalidatedProgramPoints( final Map invalidatedProgramPoints, final Object typeInformationFile) { if(invalidatedProgramPoints != null) { diff --git a/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java b/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java index cd528a01..c7fd0190 100644 --- a/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java +++ b/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java @@ -212,6 +212,7 @@ public final class ScriptEnvironment { * @param out output print writer * @param err error print writer */ + @SuppressWarnings("unused") public ScriptEnvironment(final Options options, final PrintWriter out, final PrintWriter err) { this.out = out; this.err = err; diff --git a/src/jdk/nashorn/internal/runtime/events/RecompilationEvent.java b/src/jdk/nashorn/internal/runtime/events/RecompilationEvent.java index bdc73bfe..db28012b 100644 --- a/src/jdk/nashorn/internal/runtime/events/RecompilationEvent.java +++ b/src/jdk/nashorn/internal/runtime/events/RecompilationEvent.java @@ -50,7 +50,6 @@ public final class RecompilationEvent extends RuntimeEvent { * {@link RewriteException#getReturnValueNonDestructive()} public, we pass it as * an extra parameter, rather than querying the getter from another package. */ - @SuppressWarnings("javadoc") public RecompilationEvent(final Level level, final RewriteException rewriteException, final Object returnValue) { super(level, rewriteException); assert Context.getContext().getLogger(RecompilableScriptFunctionData.class).isEnabled() : diff --git a/src/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java b/src/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java index e8cfa4ed..fa43e4c8 100644 --- a/src/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java +++ b/src/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java @@ -25,8 +25,10 @@ package jdk.nashorn.internal.runtime.linker; -import static jdk.nashorn.internal.runtime.linker.BrowserJSObjectLinker.JSObjectHandles.*; - +import static jdk.nashorn.internal.runtime.linker.BrowserJSObjectLinker.JSObjectHandles.JSOBJECT_GETMEMBER; +import static jdk.nashorn.internal.runtime.linker.BrowserJSObjectLinker.JSObjectHandles.JSOBJECT_GETSLOT; +import static jdk.nashorn.internal.runtime.linker.BrowserJSObjectLinker.JSObjectHandles.JSOBJECT_SETMEMBER; +import static jdk.nashorn.internal.runtime.linker.BrowserJSObjectLinker.JSObjectHandles.JSOBJECT_SETSLOT; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import jdk.internal.dynalink.CallSiteDescriptor; @@ -114,12 +116,10 @@ final class BrowserJSObjectLinker implements TypeBasedGuardingDynamicLinker { case "getMethod": if (c > 2) { return findGetMethod(desc); - } else { - // For indexed get, we want GuardedInvocation from beans linker and pass it. - // BrowserJSObjectLinker.get uses this fallback getter for explicit signature method access. - final GuardedInvocation beanInv = nashornBeansLinker.getGuardedInvocation(request, linkerServices); - return findGetIndexMethod(beanInv); } + // For indexed get, we want GuardedInvocation from beans linker and pass it. + // BrowserJSObjectLinker.get uses this fallback getter for explicit signature method access. + return findGetIndexMethod(nashornBeansLinker.getGuardedInvocation(request, linkerServices)); case "setProp": case "setElem": return c > 2 ? findSetMethod(desc) : findSetIndexMethod(); @@ -166,9 +166,8 @@ final class BrowserJSObjectLinker implements TypeBasedGuardingDynamicLinker { final String name = (String)key; if (name.indexOf('(') != -1) { return fallback.invokeExact(jsobj, key); - } else { - return JSOBJECT_GETMEMBER.invokeExact(jsobj, (String)key); } + return JSOBJECT_GETMEMBER.invokeExact(jsobj, (String)key); } return null; } diff --git a/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java b/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java index 67c8e4bb..aaf5a2c3 100644 --- a/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java +++ b/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java @@ -120,12 +120,10 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker, GuardingTy case "getMethod": if (c > 2) { return findGetMethod(desc); - } else { - // For indexed get, we want get GuardedInvocation beans linker and pass it. - // JSObjectLinker.get uses this fallback getter for explicit signature method access. - final GuardedInvocation beanInv = nashornBeansLinker.getGuardedInvocation(request, linkerServices); - return findGetIndexMethod(beanInv); } + // For indexed get, we want get GuardedInvocation beans linker and pass it. + // JSObjectLinker.get uses this fallback getter for explicit signature method access. + return findGetIndexMethod(nashornBeansLinker.getGuardedInvocation(request, linkerServices)); case "setProp": case "setElem": return c > 2 ? findSetMethod(desc) : findSetIndexMethod(); @@ -192,9 +190,8 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker, GuardingTy // get with method name and signature. delegate it to beans linker! if (name.indexOf('(') != -1) { return fallback.invokeExact(jsobj, key); - } else { - return ((JSObject)jsobj).getMember(name); } + return ((JSObject)jsobj).getMember(name); } return null; } diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/Analyser.java b/src/jdk/nashorn/internal/runtime/regexp/joni/Analyser.java index 6a9ebc1a..64d90c03 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/Analyser.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/Analyser.java @@ -27,7 +27,6 @@ import static jdk.nashorn.internal.runtime.regexp.joni.Option.isIgnoreCase; import static jdk.nashorn.internal.runtime.regexp.joni.Option.isMultiline; import static jdk.nashorn.internal.runtime.regexp.joni.ast.ConsAltNode.newAltNode; import static jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode.isRepeatInfinite; - import java.util.HashSet; import jdk.nashorn.internal.runtime.regexp.joni.ast.AnchorNode; import jdk.nashorn.internal.runtime.regexp.joni.ast.BackRefNode; @@ -53,6 +52,7 @@ final class Analyser extends Parser { super(env, chars, p, end); } + @SuppressWarnings("unused") protected final void compile() { if (Config.DEBUG) { Config.log.println(new String(chars, getBegin(), getEnd())); @@ -76,7 +76,9 @@ final class Analyser extends Parser { root = setupTree(root, 0); if (Config.DEBUG_PARSE_TREE) { - if (Config.DEBUG_PARSE_TREE_RAW) Config.log.println(""); + if (Config.DEBUG_PARSE_TREE_RAW) { + Config.log.println(""); + } root.verifyTree(new HashSet(), env.reg.warnings); Config.log.println(root + "\n"); } @@ -94,7 +96,9 @@ final class Analyser extends Parser { regex.clearOptimizeInfo(); - if (!Config.DONT_OPTIMIZE) setOptimizedInfoFromTree(root); + if (!Config.DONT_OPTIMIZE) { + setOptimizedInfoFromTree(root); + } env.memNodes = null; @@ -110,7 +114,9 @@ final class Analyser extends Parser { if (Config.DEBUG_COMPILE) { Config.log.println("stack used: " + regex.stackNeeded); - if (Config.USE_STRING_TEMPLATES) Config.log.print("templates: " + regex.templateNum + "\n"); + if (Config.USE_STRING_TEMPLATES) { + Config.log.print("templates: " + regex.templateNum + "\n"); + } Config.log.println(new ByteCodePrinter(regex).byteCodeListToString()); } // DEBUG_COMPILE @@ -136,7 +142,9 @@ final class Analyser extends Parser { ConsAltNode can = (ConsAltNode)node; do { final int v = quantifiersMemoryInfo(can.car); - if (v > info) info = v; + if (v > info) { + info = v; + } } while ((can = can.cdr) != null); break; @@ -182,7 +190,9 @@ final class Analyser extends Parser { switch (node.getType()) { case NodeType.BREF: final BackRefNode br = (BackRefNode)node; - if (br.isRecursion()) break; + if (br.isRecursion()) { + break; + } if (br.backRef > env.numMem) { throw new ValueException(ERR_INVALID_BACKREF); @@ -249,6 +259,9 @@ final class Analyser extends Parser { case EncloseType.STOP_BACKTRACK: min = getMinMatchLength(en.target); break; + + default: + break; } // inner switch break; @@ -276,7 +289,9 @@ final class Analyser extends Parser { ConsAltNode an = (ConsAltNode)node; do { final int tmax = getMaxMatchLength(an.car); - if (max < tmax) max = tmax; + if (max < tmax) { + max = tmax; + } } while ((an = an.cdr) != null); break; @@ -304,7 +319,9 @@ final class Analyser extends Parser { throw new ValueException(ERR_INVALID_BACKREF); } final int tmax = getMaxMatchLength(env.memNodes[br.backRef]); - if (max < tmax) max = tmax; + if (max < tmax) { + max = tmax; + } break; case NodeType.QTFR: @@ -338,6 +355,9 @@ final class Analyser extends Parser { case EncloseType.STOP_BACKTRACK: max = getMaxMatchLength(en.target); break; + + default: + break; } // inner switch break; @@ -355,8 +375,8 @@ final class Analyser extends Parser { return getCharLengthTree(node, 0); } - private int getCharLengthTree(final Node node, int level) { - level++; + private int getCharLengthTree(final Node node, final int levelp) { + final int level = levelp + 1; int len = 0; returnCode = 0; @@ -366,7 +386,9 @@ final class Analyser extends Parser { ConsAltNode ln = (ConsAltNode)node; do { final int tlen = getCharLengthTree(ln.car, level); - if (returnCode == 0) len = MinMaxLen.distanceAdd(len, tlen); + if (returnCode == 0) { + len = MinMaxLen.distanceAdd(len, tlen); + } } while (returnCode == 0 && (ln = ln.cdr) != null); break; @@ -378,7 +400,9 @@ final class Analyser extends Parser { while (returnCode == 0 && (an = an.cdr) != null) { final int tlen2 = getCharLengthTree(an.car, level); if (returnCode == 0) { - if (tlen != tlen2) varLen = true; + if (tlen != tlen2) { + varLen = true; + } } } @@ -404,7 +428,9 @@ final class Analyser extends Parser { final QuantifierNode qn = (QuantifierNode)node; if (qn.lower == qn.upper) { tlen = getCharLengthTree(qn.target, level); - if (returnCode == 0) len = MinMaxLen.distanceMultiply(tlen, qn.lower); + if (returnCode == 0) { + len = MinMaxLen.distanceMultiply(tlen, qn.lower); + } } else { returnCode = GET_CHAR_LEN_VARLEN; } @@ -435,6 +461,9 @@ final class Analyser extends Parser { case EncloseType.STOP_BACKTRACK: len = getCharLengthTree(en.target, level); break; + + default: + break; } // inner switch break; @@ -448,7 +477,9 @@ final class Analyser extends Parser { } /* x is not included y ==> 1 : 0 */ - private boolean isNotIncluded(Node x, Node y) { + private static boolean isNotIncluded(final Node xn, final Node yn) { + Node x = xn; + Node y = yn; Node tmp; // !retry:! @@ -492,10 +523,14 @@ final class Analyser extends Parser { boolean v = xc.bs.at(i); if ((v && !xc.isNot()) || (!v && xc.isNot())) { v = yc.bs.at(i); - if ((v && !yc.isNot()) || (!v && yc.isNot())) return false; + if ((v && !yc.isNot()) || (!v && yc.isNot())) { + return false; + } } } - if ((xc.mbuf == null && !xc.isNot()) || yc.mbuf == null && !yc.isNot()) return true; + if ((xc.mbuf == null && !xc.isNot()) || yc.mbuf == null && !yc.isNot()) { + return true; + } return false; // break; not reached @@ -514,7 +549,9 @@ final class Analyser extends Parser { case NodeType.STR: final StringNode xs = (StringNode)x; - if (xs.length() == 0) break; + if (xs.length() == 0) { + break; + } switch (yType) { @@ -526,13 +563,16 @@ final class Analyser extends Parser { case NodeType.STR: final StringNode ys = (StringNode)y; int len = xs.length(); - if (len > ys.length()) len = ys.length(); + if (len > ys.length()) { + len = ys.length(); + } if (xs.isAmbig() || ys.isAmbig()) { /* tiny version */ return false; - } else { - for (int i=0, p=ys.p, q=xs.p; i (?<=A)|(?<=B) (? (?= sbuf.length) { final char[]tmp = new char[sbuf.length << 1]; System.arraycopy(sbuf, 0, tmp, 0, sbuf.length); @@ -798,8 +862,8 @@ final class Analyser extends Parser { updateStringNodeCaseFoldMultiByte(sn); } - private Node expandCaseFoldMakeRemString(final char[] chars, final int p, final int end) { - final StringNode node = new StringNode(chars, p, end); + private Node expandCaseFoldMakeRemString(final char[] ch, final int pp, final int end) { + final StringNode node = new StringNode(ch, pp, end); updateStringNodeCaseFold(node); node.setAmbig(); @@ -807,7 +871,7 @@ final class Analyser extends Parser { return node; } - private boolean expandCaseFoldStringAlt(final int itemNum, final char[] items, + private static boolean expandCaseFoldStringAlt(final int itemNum, final char[] items, final char[] chars, final int p, final int slen, final int end, final ObjPtr node) { ConsAltNode altNode; @@ -833,59 +897,68 @@ final class Analyser extends Parser { private Node expandCaseFoldString(final Node node) { final StringNode sn = (StringNode)node; - if (sn.isAmbig() || sn.length() <= 0) return node; + if (sn.isAmbig() || sn.length() <= 0) { + return node; + } - final char[] chars = sn.chars; - int p = sn.p; + final char[] chars1 = sn.chars; + int pt = sn.p; final int end = sn.end; int altNum = 1; - ConsAltNode topRoot = null, root = null; + ConsAltNode topRoot = null, r = null; + @SuppressWarnings("unused") final ObjPtr prevNode = new ObjPtr(); StringNode stringNode = null; - while (p < end) { - final char[] items = EncodingHelper.caseFoldCodesByString(regex.caseFoldFlag, chars[p]); + while (pt < end) { + final char[] items = EncodingHelper.caseFoldCodesByString(regex.caseFoldFlag, chars1[pt]); if (items.length == 0) { if (stringNode == null) { - if (root == null && prevNode.p != null) { - topRoot = root = ConsAltNode.listAdd(null, prevNode.p); + if (r == null && prevNode.p != null) { + topRoot = r = ConsAltNode.listAdd(null, prevNode.p); } prevNode.p = stringNode = new StringNode(); // onig_node_new_str(NULL, NULL); - if (root != null) ConsAltNode.listAdd(root, stringNode); + if (r != null) { + ConsAltNode.listAdd(r, stringNode); + } } - stringNode.cat(chars, p, p + 1); + stringNode.cat(chars1, pt, pt + 1); } else { altNum *= (items.length + 1); - if (altNum > THRESHOLD_CASE_FOLD_ALT_FOR_EXPANSION) break; + if (altNum > THRESHOLD_CASE_FOLD_ALT_FOR_EXPANSION) { + break; + } - if (root == null && prevNode.p != null) { - topRoot = root = ConsAltNode.listAdd(null, prevNode.p); + if (r == null && prevNode.p != null) { + topRoot = r = ConsAltNode.listAdd(null, prevNode.p); } - expandCaseFoldStringAlt(items.length, items, chars, p, 1, end, prevNode); - if (root != null) ConsAltNode.listAdd(root, prevNode.p); + expandCaseFoldStringAlt(items.length, items, chars1, pt, 1, end, prevNode); + if (r != null) { + ConsAltNode.listAdd(r, prevNode.p); + } stringNode = null; } - p++; + pt++; } - if (p < end) { - final Node srem = expandCaseFoldMakeRemString(chars, p, end); + if (pt < end) { + final Node srem = expandCaseFoldMakeRemString(chars1, pt, end); - if (prevNode.p != null && root == null) { - topRoot = root = ConsAltNode.listAdd(null, prevNode.p); + if (prevNode.p != null && r == null) { + topRoot = r = ConsAltNode.listAdd(null, prevNode.p); } - if (root == null) { + if (r == null) { prevNode.p = srem; } else { - ConsAltNode.listAdd(root, srem); + ConsAltNode.listAdd(r, srem); } } /* ending */ @@ -909,7 +982,10 @@ final class Analyser extends Parser { 5. find invalid patterns in look-behind. 6. expand repeated string. */ - protected final Node setupTree(Node node, int state) { + protected final Node setupTree(final Node nodep, final int statep) { + Node node = nodep; + int state = statep; + restart: while (true) { switch (node.getType()) { case NodeType.LIST: @@ -958,7 +1034,9 @@ final class Analyser extends Parser { final QuantifierNode qn = (QuantifierNode)node; Node target = qn.target; - if ((state & IN_REPEAT) != 0) qn.setInRepeat(); + if ((state & IN_REPEAT) != 0) { + qn.setInRepeat(); + } if (isRepeatInfinite(qn.upper) || qn.lower >= 1) { final int d = getMinMatchLength(target); @@ -966,14 +1044,18 @@ final class Analyser extends Parser { qn.targetEmptyInfo = TargetInfo.IS_EMPTY; if (Config.USE_MONOMANIAC_CHECK_CAPTURES_IN_ENDLESS_REPEAT) { final int info = quantifiersMemoryInfo(target); - if (info > 0) qn.targetEmptyInfo = info; + if (info > 0) { + qn.targetEmptyInfo = info; + } } // USE_INFINITE_REPEAT_MONOMANIAC_MEM_STATUS_CHECK // strange stuff here (turned off) } } state |= IN_REPEAT; - if (qn.lower != qn.upper) state |= IN_VAR_REPEAT; + if (qn.lower != qn.upper) { + state |= IN_VAR_REPEAT; + } target = setupTree(target, state); @@ -1035,11 +1117,16 @@ final class Analyser extends Parser { final QuantifierNode tqn = (QuantifierNode)en.target; if (isRepeatInfinite(tqn.upper) && tqn.lower <= 1 && tqn.greedy) { /* (?>a*), a*+ etc... */ - if (tqn.target.isSimple()) en.setStopBtSimpleRepeat(); + if (tqn.target.isSimple()) { + en.setStopBtSimpleRepeat(); + } } } break; + default: + break; + } // inner switch break; @@ -1059,7 +1146,9 @@ final class Analyser extends Parser { throw new SyntaxException(ERR_INVALID_LOOK_BEHIND_PATTERN); } node = setupLookBehind(node); - if (node.getType() != NodeType.ANCHOR) continue restart; + if (node.getType() != NodeType.ANCHOR) { + continue restart; + } setupTree(((AnchorNode)node).target, state); break; @@ -1068,12 +1157,19 @@ final class Analyser extends Parser { throw new SyntaxException(ERR_INVALID_LOOK_BEHIND_PATTERN); } node = setupLookBehind(node); - if (node.getType() != NodeType.ANCHOR) continue restart; + if (node.getType() != NodeType.ANCHOR) { + continue restart; + } setupTree(((AnchorNode)node).target, (state | IN_NOT)); break; + default: + break; + } // inner switch break; + default: + break; } // switch return node; } // restart: while @@ -1191,7 +1287,9 @@ final class Analyser extends Parser { opt.expr.copy(nopt.exm); } opt.expr.reachEnd = false; - if (nopt.map.value > 0) opt.map.copy(nopt.map); + if (nopt.map.value > 0) { + opt.map.copy(nopt.map); + } break; case AnchorType.PREC_READ_NOT: @@ -1199,6 +1297,9 @@ final class Analyser extends Parser { case AnchorType.LOOK_BEHIND_NOT: break; + default: + break; + } // inner switch break; } @@ -1282,8 +1383,12 @@ final class Analyser extends Parser { if (++en.optCount > MAX_NODE_OPT_INFO_REF_COUNT) { int min = 0; int max = MinMaxLen.INFINITE_DISTANCE; - if (en.isMinFixed()) min = en.minLength; - if (en.isMaxFixed()) max = en.maxLength; + if (en.isMinFixed()) { + min = en.minLength; + } + if (en.isMaxFixed()) { + max = en.maxLength; + } opt.length.set(min, max); } else { // USE_SUBEXP_CALL optimizeNodeLeft(en.target, opt, oenv); @@ -1298,6 +1403,9 @@ final class Analyser extends Parser { case EncloseType.STOP_BACKTRACK: optimizeNodeLeft(en.target, opt, oenv); break; + + default: + break; } // inner switch break; } @@ -1307,6 +1415,7 @@ final class Analyser extends Parser { } // switch } + @SuppressWarnings("unused") protected final void setOptimizedInfoFromTree(final Node node) { final NodeOptInfo opt = new NodeOptInfo(); final OptEnvironment oenv = new OptEnvironment(); @@ -1347,7 +1456,9 @@ final class Analyser extends Parser { regex.setSubAnchor(opt.map.anchor); } else { regex.subAnchor |= opt.anchor.leftAnchor & AnchorType.BEGIN_LINE; - if (opt.length.max == 0) regex.subAnchor |= opt.anchor.rightAnchor & AnchorType.END_LINE; + if (opt.length.max == 0) { + regex.subAnchor |= opt.anchor.rightAnchor & AnchorType.END_LINE; + } } if (Config.DEBUG_COMPILE || Config.DEBUG_MATCH) { diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/ApplyCaseFold.java b/src/jdk/nashorn/internal/runtime/regexp/joni/ApplyCaseFold.java index 0a6d4b05..5ecfec4f 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/ApplyCaseFold.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/ApplyCaseFold.java @@ -24,7 +24,7 @@ import jdk.nashorn.internal.runtime.regexp.joni.ast.CClassNode; final class ApplyCaseFold { // i_apply_case_fold - public void apply(final int from, final int to, final Object o) { + public static void apply(final int from, final int to, final Object o) { final ApplyCaseFoldArg arg = (ApplyCaseFoldArg)o; final ScanEnvironment env = arg.env; @@ -45,7 +45,9 @@ final class ApplyCaseFold { } else { if (inCC) { if (to >= BitSet.SINGLE_BYTE_SIZE) { - if (cc.isNot()) cc.clearNotFlag(); + if (cc.isNot()) { + cc.clearNotFlag(); + } cc.addCodeRange(env, to, to); } else { if (cc.isNot()) { diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/ApplyCaseFoldArg.java b/src/jdk/nashorn/internal/runtime/regexp/joni/ApplyCaseFoldArg.java index c199bea7..ce25af62 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/ApplyCaseFoldArg.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/ApplyCaseFoldArg.java @@ -22,6 +22,7 @@ package jdk.nashorn.internal.runtime.regexp.joni; import jdk.nashorn.internal.runtime.regexp.joni.ast.CClassNode; import jdk.nashorn.internal.runtime.regexp.joni.ast.ConsAltNode; +@SuppressWarnings("javadoc") public final class ApplyCaseFoldArg { final ScanEnvironment env; final CClassNode cc; diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/ArrayCompiler.java b/src/jdk/nashorn/internal/runtime/regexp/joni/ArrayCompiler.java index 294113e3..0e789333 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/ArrayCompiler.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/ArrayCompiler.java @@ -24,7 +24,6 @@ import static jdk.nashorn.internal.runtime.regexp.joni.Option.isDynamic; import static jdk.nashorn.internal.runtime.regexp.joni.Option.isIgnoreCase; import static jdk.nashorn.internal.runtime.regexp.joni.Option.isMultiline; import static jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode.isRepeatInfinite; - import jdk.nashorn.internal.runtime.regexp.joni.ast.AnchorNode; import jdk.nashorn.internal.runtime.regexp.joni.ast.BackRefNode; import jdk.nashorn.internal.runtime.regexp.joni.ast.CClassNode; @@ -98,15 +97,15 @@ final class ArrayCompiler extends Compiler { } while ((aln = aln.cdr) != null); } - private boolean isNeedStrLenOpExact(final int op) { + private static boolean isNeedStrLenOpExact(final int op) { return op == OPCode.EXACTN || op == OPCode.EXACTN_IC; } - private boolean opTemplated(final int op) { + private static boolean opTemplated(final int op) { return isNeedStrLenOpExact(op); } - private int selectStrOpcode(final int strLength, final boolean ignoreCase) { + private static int selectStrOpcode(final int strLength, final boolean ignoreCase) { int op; if (ignoreCase) { @@ -139,7 +138,7 @@ final class ArrayCompiler extends Compiler { compileTree(node); if (emptyInfo != 0) { - switch(emptyInfo) { + switch (emptyInfo) { case TargetInfo.IS_EMPTY: addOpcode(OPCode.NULL_CHECK_END); break; @@ -149,13 +148,15 @@ final class ArrayCompiler extends Compiler { case TargetInfo.IS_EMPTY_REC: addOpcode(OPCode.NULL_CHECK_END_MEMST_PUSH); break; + default: + break; } // switch addMemNum(savedNumNullCheck); /* NULL CHECK ID */ } } - private int addCompileStringlength(final char[] chars, final int p, final int strLength, final boolean ignoreCase) { + private static int addCompileStringlength(final char[] chars, final int p, final int strLength, final boolean ignoreCase) { final int op = selectStrOpcode(strLength, ignoreCase); int len = OPSize.OPCODE; @@ -163,7 +164,9 @@ final class ArrayCompiler extends Compiler { // string length, template index, template string pointer len += OPSize.LENGTH + OPSize.INDEX + OPSize.INDEX; } else { - if (isNeedStrLenOpExact(op)) len += OPSize.LENGTH; + if (isNeedStrLenOpExact(op)) { + len += OPSize.LENGTH; + } len += strLength; } return len; @@ -187,9 +190,11 @@ final class ArrayCompiler extends Compiler { } } - private int compileLengthStringNode(final Node node) { + private static int compileLengthStringNode(final Node node) { final StringNode sn = (StringNode)node; - if (sn.length() <= 0) return 0; + if (sn.length() <= 0) { + return 0; + } final boolean ambig = sn.isAmbig(); int p, prev; @@ -210,8 +215,10 @@ final class ArrayCompiler extends Compiler { return rlen; } - private int compileLengthStringRawNode(final StringNode sn) { - if (sn.length() <= 0) return 0; + private static int compileLengthStringRawNode(final StringNode sn) { + if (sn.length() <= 0) { + return 0; + } return addCompileStringlength(sn.chars, sn.p, sn.length(), false); } @@ -220,8 +227,10 @@ final class ArrayCompiler extends Compiler { addInts(mbuf.p, mbuf.used); } - private int compileLengthCClassNode(final CClassNode cc) { - if (cc.isShare()) return OPSize.OPCODE + OPSize.POINTER; + private static int compileLengthCClassNode(final CClassNode cc) { + if (cc.isShare()) { + return OPSize.OPCODE + OPSize.POINTER; + } int len; if (cc.mbuf == null) { @@ -360,9 +369,8 @@ final class ArrayCompiler extends Compiler { if (qn.greedy && infinite) { if (qn.nextHeadExact != null) { return OPSize.ANYCHAR_STAR_PEEK_NEXT + tlen * qn.lower; - } else { - return OPSize.ANYCHAR_STAR + tlen * qn.lower; } + return OPSize.ANYCHAR_STAR + tlen * qn.lower; } } @@ -425,14 +433,13 @@ final class ArrayCompiler extends Compiler { final StringNode sn = (StringNode)qn.nextHeadExact; addChars(sn.chars, sn.p, 1); return; + } + if (isMultiline(regex.options)) { + addOpcode(OPCode.ANYCHAR_ML_STAR); } else { - if (isMultiline(regex.options)) { - addOpcode(OPCode.ANYCHAR_ML_STAR); - } else { - addOpcode(OPCode.ANYCHAR_STAR); - } - return; + addOpcode(OPCode.ANYCHAR_STAR); } + return; } int modTLen; @@ -510,9 +517,8 @@ final class ArrayCompiler extends Compiler { if (isDynamic(prev ^ node.option)) { return OPSize.SET_OPTION_PUSH + OPSize.SET_OPTION + OPSize.FAIL + tlen + OPSize.SET_OPTION; - } else { - return tlen; } + return tlen; } @Override @@ -675,13 +681,15 @@ final class ArrayCompiler extends Compiler { break; case AnchorType.WORD_BEGIN: - if (Config.USE_WORD_BEGIN_END) + if (Config.USE_WORD_BEGIN_END) { addOpcode(OPCode.WORD_BEGIN); + } break; case AnchorType.WORD_END: - if (Config.USE_WORD_BEGIN_END) + if (Config.USE_WORD_BEGIN_END) { addOpcode(OPCode.WORD_END); + } break; case AnchorType.PREC_READ: @@ -701,7 +709,9 @@ final class ArrayCompiler extends Compiler { addOpcode(OPCode.LOOK_BEHIND); if (node.charLength < 0) { n = analyser.getCharLengthTree(node.target); - if (analyser.returnCode != 0) newSyntaxException(ERR_INVALID_LOOK_BEHIND_PATTERN); + if (analyser.returnCode != 0) { + newSyntaxException(ERR_INVALID_LOOK_BEHIND_PATTERN); + } } else { n = node.charLength; } @@ -714,7 +724,9 @@ final class ArrayCompiler extends Compiler { addOpcodeRelAddr(OPCode.PUSH_LOOK_BEHIND_NOT, len + OPSize.FAIL_LOOK_BEHIND_NOT); if (node.charLength < 0) { n = analyser.getCharLengthTree(node.target); - if (analyser.returnCode != 0) newSyntaxException(ERR_INVALID_LOOK_BEHIND_PATTERN); + if (analyser.returnCode != 0) { + newSyntaxException(ERR_INVALID_LOOK_BEHIND_PATTERN); + } } else { n = node.charLength; } @@ -796,7 +808,9 @@ final class ArrayCompiler extends Compiler { private void ensure(final int size) { if (size >= code.length) { int length = code.length << 1; - while (length <= size) length <<= 1; + while (length <= size) { + length <<= 1; + } final int[]tmp = new int[length]; System.arraycopy(code, 0, tmp, 0, code.length); code = tmp; @@ -829,11 +843,14 @@ final class ArrayCompiler extends Compiler { regex.operands[regex.operandLength++] = o; } - private void addChars(final char[] chars, int p ,final int length) { + private void addChars(final char[] chars, final int pp ,final int length) { ensure(codeLength + length); + int p = pp; final int end = p + length; - while (p < end) code[codeLength++] = chars[p++]; + while (p < end) { + code[codeLength++] = chars[p++]; + } } private void addInts(final int[]ints, final int length) { @@ -876,6 +893,9 @@ final class ArrayCompiler extends Compiler { case OPCode.CALL: case OPCode.RETURN: // it will appear only with CALL though regex.stackNeeded = true; + break; + default: + break; } } diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/BitSet.java b/src/jdk/nashorn/internal/runtime/regexp/joni/BitSet.java index 2aac96a8..2747c24c 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/BitSet.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/BitSet.java @@ -19,6 +19,7 @@ */ package jdk.nashorn.internal.runtime.regexp.joni; +@SuppressWarnings("javadoc") public final class BitSet { static final int BITS_PER_BYTE = 8; public static final int SINGLE_BYTE_SIZE = (1 << BITS_PER_BYTE); @@ -34,7 +35,9 @@ public final class BitSet { final StringBuilder buffer = new StringBuilder(); buffer.append("BitSet"); for (int i=0; i>>= 1) != 0) log++; + int n = np; + while ((n >>>= 1) != 0) { + log++; + } return log; } diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/BitStatus.java b/src/jdk/nashorn/internal/runtime/regexp/joni/BitStatus.java index 25806a51..91cf7198 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/BitStatus.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/BitStatus.java @@ -34,7 +34,8 @@ final class BitStatus { return (n < BIT_STATUS_BITS_NUM ? stats & (1 << n) : (stats & 1)) != 0; } - public static int bsOnAt(int stats, final int n) { + public static int bsOnAt(final int statsp, final int n) { + int stats = statsp; if (n < BIT_STATUS_BITS_NUM) { stats |= (1 << n); } else { @@ -43,12 +44,7 @@ final class BitStatus { return stats; } - public static int bsOnOff(int v, final int f, final boolean negative) { - if (negative) { - v &= ~f; - } else { - v |= f; - } - return v; + public static int bsOnOff(final int v, final int f, final boolean negative) { + return negative ? (v & ~f) : (v | f); } } diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodeMachine.java b/src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodeMachine.java index ab28f93c..30cfe907 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodeMachine.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodeMachine.java @@ -27,10 +27,8 @@ import static jdk.nashorn.internal.runtime.regexp.joni.Option.isFindNotEmpty; import static jdk.nashorn.internal.runtime.regexp.joni.Option.isNotBol; import static jdk.nashorn.internal.runtime.regexp.joni.Option.isNotEol; import static jdk.nashorn.internal.runtime.regexp.joni.Option.isPosixRegion; - import jdk.nashorn.internal.runtime.regexp.joni.ast.CClassNode; import jdk.nashorn.internal.runtime.regexp.joni.constants.OPCode; -import jdk.nashorn.internal.runtime.regexp.joni.constants.OPSize; import jdk.nashorn.internal.runtime.regexp.joni.encoding.IntHolder; import jdk.nashorn.internal.runtime.regexp.joni.exception.ErrorMessages; import jdk.nashorn.internal.runtime.regexp.joni.exception.InternalException; @@ -52,8 +50,8 @@ class ByteCodeMachine extends StackMachine { this.code = regex.code; } - private boolean stringCmpIC(final int caseFlodFlag, int s1, final IntHolder ps2, final int mbLen, final int textEnd) { - + private boolean stringCmpIC(final int caseFlodFlag, final int s1p, final IntHolder ps2, final int mbLen, final int textEnd) { + int s1 = s1p; int s2 = ps2.value; final int end1 = s1 + mbLen; @@ -83,12 +81,16 @@ class ByteCodeMachine extends StackMachine { Config.log.printf("%4d", (s - str)).print("> \""); int q, i; for (i=0, q=s; i<7 && q=0; i++) { - if (q < end) Config.log.print(new String(new char[]{chars[q++]})); + if (q < end) { + Config.log.print(new String(new char[]{chars[q++]})); + } + } + final String string = q < end ? "...\"" : "\""; + q += string.length(); + Config.log.print(string); + for (i=0; i<20-(q-s);i++) { + Config.log.print(" "); } - final String str = q < end ? "...\"" : "\""; - q += str.length(); - Config.log.print(str); - for (i=0; i<20-(q-s);i++) Config.log.print(" "); final StringBuilder sb = new StringBuilder(); new ByteCodePrinter(regex).compiledByteCodeToString(sb, ip); Config.log.println(sb.toString()); @@ -96,28 +98,34 @@ class ByteCodeMachine extends StackMachine { } @Override - protected final int matchAt(final int range, final int sstart, final int sprev) { - this.range = range; - this.sstart = sstart; - this.sprev = sprev; + protected final int matchAt(final int r, final int ss, final int sp) { + this.range = r; + this.sstart = ss; + this.sprev = sp; stk = 0; ip = 0; - if (Config.DEBUG_MATCH) debugMatchBegin(); + if (Config.DEBUG_MATCH) { + debugMatchBegin(); + } init(); bestLen = -1; - s = sstart; + s = ss; - final int[]code = this.code; + final int[] c = this.code; while (true) { - if (Config.DEBUG_MATCH) debugMatchLoop(); + if (Config.DEBUG_MATCH) { + debugMatchLoop(); + } sbegin = s; - switch (code[ip++]) { - case OPCode.END: if (opEnd()) return finish(); break; + switch (c[ip++]) { + case OPCode.END: if (opEnd()) { + return finish(); + } break; case OPCode.EXACT1: opExact1(); break; case OPCode.EXACT2: opExact2(); continue; case OPCode.EXACT3: opExact3(); continue; @@ -358,10 +366,14 @@ class ByteCodeMachine extends StackMachine { final char[] bs = regex.templates[code[ip++]]; int ps = code[ip++]; - while (tlen-- > 0) if (bs[ps++] != chars[s++]) {opFail(); return;} + while (tlen-- > 0) { + if (bs[ps++] != chars[s++]) {opFail(); return;} + } } else { - while (tlen-- > 0) if (code[ip++] != chars[s++]) {opFail(); return;} + while (tlen-- > 0) { + if (code[ip++] != chars[s++]) {opFail(); return;} + } } sprev = s - 1; } @@ -380,10 +392,14 @@ class ByteCodeMachine extends StackMachine { final char[] bs = regex.templates[code[ip++]]; int ps = code[ip++]; - while (tlen-- > 0) if (bs[ps++] != EncodingHelper.toLowerCase(chars[s++])) {opFail(); return;} + while (tlen-- > 0) { + if (bs[ps++] != EncodingHelper.toLowerCase(chars[s++])) {opFail(); return;} + } } else { - while (tlen-- > 0) if (code[ip++] != EncodingHelper.toLowerCase(chars[s++])) {opFail(); return;} + while (tlen-- > 0) { + if (code[ip++] != EncodingHelper.toLowerCase(chars[s++])) {opFail(); return;} + } } sprev = s - 1; } @@ -402,11 +418,15 @@ class ByteCodeMachine extends StackMachine { private boolean isInClassMB() { final int tlen = code[ip++]; - if (s >= range) return false; + if (s >= range) { + return false; + } final int ss = s; s++; final int c = chars[ss]; - if (!EncodingHelper.isInCodeRange(code, ip, c)) return false; + if (!EncodingHelper.isInCodeRange(code, ip, c)) { + return false; + } ip += tlen; return true; } @@ -444,7 +464,9 @@ class ByteCodeMachine extends StackMachine { final int tlen = code[ip++]; if (!(s + 1 <= range)) { - if (s >= range) return false; + if (s >= range) { + return false; + } s = end; ip += tlen; return true; @@ -454,7 +476,9 @@ class ByteCodeMachine extends StackMachine { s++; final int c = chars[ss]; - if (EncodingHelper.isInCodeRange(code, ip, c)) return false; + if (EncodingHelper.isInCodeRange(code, ip, c)) { + return false; + } ip += tlen; return true; } @@ -511,10 +535,10 @@ class ByteCodeMachine extends StackMachine { } private void opAnyCharStar() { - final char[] chars = this.chars; + final char[] ch = this.chars; while (s < range) { pushAlt(ip, s, sprev); - if (isNewLine(chars, s, end)) {opFail(); return;} + if (isNewLine(ch, s, end)) {opFail(); return;} sprev = s; s++; } @@ -532,11 +556,13 @@ class ByteCodeMachine extends StackMachine { private void opAnyCharStarPeekNext() { final char c = (char)code[ip]; - final char[] chars = this.chars; + final char[] ch = this.chars; while (s < range) { - final char b = chars[s]; - if (c == b) pushAlt(ip + 1, s, sprev); + final char b = ch[s]; + if (c == b) { + pushAlt(ip + 1, s, sprev); + } if (isNewLine(b)) {opFail(); return;} sprev = s; s++; @@ -547,10 +573,12 @@ class ByteCodeMachine extends StackMachine { private void opAnyCharMLStarPeekNext() { final char c = (char)code[ip]; - final char[] chars = this.chars; + final char[] ch = this.chars; while (s < range) { - if (c == chars[s]) pushAlt(ip + 1, s, sprev); + if (c == ch[s]) { + pushAlt(ip + 1, s, sprev); + } sprev = s; s++; } @@ -592,29 +620,39 @@ class ByteCodeMachine extends StackMachine { private void opWordBegin() { if (s < range && EncodingHelper.isWord(chars[s])) { - if (s == str || !EncodingHelper.isWord(chars[sprev])) return; + if (s == str || !EncodingHelper.isWord(chars[sprev])) { + return; + } } opFail(); } private void opWordEnd() { if (s != str && EncodingHelper.isWord(chars[sprev])) { - if (s == end || !EncodingHelper.isWord(chars[s])) return; + if (s == end || !EncodingHelper.isWord(chars[s])) { + return; + } } opFail(); } private void opBeginBuf() { - if (s != str) opFail(); + if (s != str) { + opFail(); + } } private void opEndBuf() { - if (s != end) opFail(); + if (s != end) { + opFail(); + } } private void opBeginLine() { if (s == str) { - if (isNotBol(msaOptions)) opFail(); + if (isNotBol(msaOptions)) { + opFail(); + } return; } else if (isNewLine(chars, sprev, end) && s != end) { return; @@ -626,13 +664,16 @@ class ByteCodeMachine extends StackMachine { if (s == end) { if (Config.USE_NEWLINE_AT_END_OF_STRING_HAS_EMPTY_LINE) { if (str == end || !isNewLine(chars, sprev, end)) { - if (isNotEol(msaOptions)) opFail(); + if (isNotEol(msaOptions)) { + opFail(); + } } return; - } else { - if (isNotEol(msaOptions)) opFail(); - return; } + if (isNotEol(msaOptions)) { + opFail(); + } + return; } else if (isNewLine(chars, s, end)) { return; } @@ -643,13 +684,16 @@ class ByteCodeMachine extends StackMachine { if (s == end) { if (Config.USE_NEWLINE_AT_END_OF_STRING_HAS_EMPTY_LINE) { if (str == end || !isNewLine(chars, sprev, end)) { - if (isNotEol(msaOptions)) opFail(); + if (isNotEol(msaOptions)) { + opFail(); + } } return; - } else { - if (isNotEol(msaOptions)) opFail(); - return; } + if (isNotEol(msaOptions)) { + opFail(); + } + return; } else if (isNewLine(chars, s, end) && s + 1 == end) { return; } @@ -657,7 +701,9 @@ class ByteCodeMachine extends StackMachine { } private void opBeginPosition() { - if (s != msaStart) opFail(); + if (s != msaStart) { + opFail(); + } } private void opMemoryStartPush() { @@ -726,11 +772,15 @@ class ByteCodeMachine extends StackMachine { sprev = s; // STRING_CMP - while(n-- > 0) if (chars[pstart++] != chars[s++]) {opFail(); return;} + while(n-- > 0) { + if (chars[pstart++] != chars[s++]) {opFail(); return;} + } // beyond string check if (sprev < range) { - while (sprev + 1 < s) sprev++; + while (sprev + 1 < s) { + sprev++; + } } } @@ -764,7 +814,9 @@ class ByteCodeMachine extends StackMachine { s = value; // if (sprev < chars.length) - while (sprev + 1 < s) sprev++; + while (sprev + 1 < s) { + sprev++; + } } private void opBackRefMulti() { @@ -773,7 +825,9 @@ class ByteCodeMachine extends StackMachine { int i; loop:for (i=0; i 0) { - if (chars[pstart++] != chars[swork++]) continue loop; + if (chars[pstart++] != chars[swork++]) { + continue loop; + } } s = swork; // beyond string check if (sprev < range) { - while (sprev + 1 < s) sprev++; + while (sprev + 1 < s) { + sprev++; + } } ip += tlen - i - 1; // * SIZE_MEMNUM (1) @@ -807,7 +865,9 @@ class ByteCodeMachine extends StackMachine { int i; loop:for (i=0; i end - s) return false; /* or goto next_mem; */ + if (pend - pstart > end - s) { + return false; /* or goto next_mem; */ + } int p = pstart; value = s; @@ -867,7 +936,9 @@ class ByteCodeMachine extends StackMachine { } } else { while (p < pend) { - if (chars[p++] != chars[value++]) return false; /* or goto next_mem; */ + if (chars[p++] != chars[value++]) { + return false; /* or goto next_mem; */ + } } } s = value; @@ -893,24 +964,15 @@ class ByteCodeMachine extends StackMachine { sprev = s; if (backrefMatchAtNestedLevel(ic != 0, regex.caseFoldFlag, level, tlen, ip)) { // (s) and (end) implicit - while (sprev + 1 < s) sprev++; + while (sprev + 1 < s) { + sprev++; + } ip += tlen; // * SIZE_MEMNUM } else { {opFail(); return;} } } - /* no need: IS_DYNAMIC_OPTION() == 0 */ - private void opSetOptionPush() { - // option = code[ip++]; // final for now - pushAlt(ip, s, sprev); - ip += OPSize.SET_OPTION + OPSize.FAIL; - } - - private void opSetOption() { - // option = code[ip++]; // final for now - } - private void opNullCheckStart() { final int mem = code[ip++]; pushNullCheckStart(mem, s); @@ -1142,13 +1204,6 @@ class ByteCodeMachine extends StackMachine { sprev = EncodingHelper.prevCharHead(str, s); } - private void opLookBehindSb() { - final int tlen = code[ip++]; - s -= tlen; - if (s < str) {opFail(); return;} - sprev = s == str ? -1 : s - 1; - } - private void opPushLookBehindNot() { final int addr = code[ip++]; final int tlen = code[ip++]; diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodePrinter.java b/src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodePrinter.java index 46ee2619..fc61ee80 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodePrinter.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodePrinter.java @@ -236,16 +236,17 @@ class ByteCodePrinter { sb.append(new String(code, s, len)); } - private void pLenStringFromTemplate(final StringBuilder sb, final int len, final char[] tm, final int idx) { + private static void pLenStringFromTemplate(final StringBuilder sb, final int len, final char[] tm, final int idx) { sb.append(":T:").append(len).append(":"); sb.append(tm, idx, len); } - public int compiledByteCodeToString(final StringBuilder sb, int bp) { + public int compiledByteCodeToString(final StringBuilder sb, final int bptr) { int len, n, mem, addr, scn, cod; BitSet bs; CClassNode cc; int tm, idx; + int bp = bptr; sb.append("[").append(OpCodeNames[code[bp]]); final int argType = OpCodeArgTypes[code[bp]]; @@ -253,6 +254,7 @@ class ByteCodePrinter { if (argType != Arguments.SPECIAL) { bp++; switch (argType) { + default: case Arguments.NON: break; @@ -410,7 +412,9 @@ class ByteCodePrinter { for (int i=0; i 0) sb.append(", "); + if (i > 0) { + sb.append(", "); + } sb.append(mem); } break; @@ -428,7 +432,9 @@ class ByteCodePrinter { for (int i=0; i 0) sb.append(", "); + if (i > 0) { + sb.append(", "); + } sb.append(mem); } break; @@ -501,7 +507,9 @@ class ByteCodePrinter { while (bp < end) { ncode++; - if (bp > 0) sb.append(ncode % 5 == 0 ? "\n" : " "); + if (bp > 0) { + sb.append(ncode % 5 == 0 ? "\n" : " "); + } bp = compiledByteCodeToString(sb, bp); } diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/CodeRangeBuffer.java b/src/jdk/nashorn/internal/runtime/regexp/joni/CodeRangeBuffer.java index 96c60808..3436e122 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/CodeRangeBuffer.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/CodeRangeBuffer.java @@ -22,6 +22,7 @@ package jdk.nashorn.internal.runtime.regexp.joni; import jdk.nashorn.internal.runtime.regexp.joni.exception.ErrorMessages; import jdk.nashorn.internal.runtime.regexp.joni.exception.ValueException; +@SuppressWarnings("javadoc") public final class CodeRangeBuffer implements Cloneable { private static final int INIT_MULTI_BYTE_RANGE_SIZE = 5; private static final int ALL_MULTI_BYTE_RANGE = 0x7fffffff; @@ -68,7 +69,9 @@ public final class CodeRangeBuffer implements Cloneable { for (int i=0; i 0 && i % 6 == 0) buf.append("\n "); + if (i > 0 && i % 6 == 0) { + buf.append("\n "); + } } return buf.toString(); @@ -97,9 +100,13 @@ public final class CodeRangeBuffer implements Cloneable { } private void moveRight(final int from, final int to, final int n) { - if (to + n > p.length) expand(to + n); + if (to + n > p.length) { + expand(to + n); + } System.arraycopy(p, from, p, to, n); - if (to + n > used) used = to + n; + if (to + n > used) { + used = to + n; + } } protected void moveLeft(final int from, final int to, final int n) { @@ -113,9 +120,13 @@ public final class CodeRangeBuffer implements Cloneable { public void writeCodePoint(final int pos, final int b) { final int u = pos + 1; - if (p.length < u) expand(u); + if (p.length < u) { + expand(u); + } p[pos] = b; - if (used < u) used = u; + if (used < u) { + used = u; + } } @Override @@ -125,14 +136,19 @@ public final class CodeRangeBuffer implements Cloneable { // ugly part: these methods should be made OO // add_code_range_to_buf - public static CodeRangeBuffer addCodeRangeToBuff(CodeRangeBuffer pbuf, int from, int to) { + public static CodeRangeBuffer addCodeRangeToBuff(final CodeRangeBuffer pbufp, final int fromp, final int top) { + int from = fromp, to = top; + CodeRangeBuffer pbuf = pbufp; + if (from > to) { final int n = from; from = to; to = n; } - if (pbuf == null) pbuf = new CodeRangeBuffer(); // move to CClassNode + if (pbuf == null) { + pbuf = new CodeRangeBuffer(); // move to CClassNode + } final int[]p = pbuf.p; int n = p[0]; @@ -163,11 +179,17 @@ public final class CodeRangeBuffer implements Cloneable { final int incN = low + 1 - high; - if (n + incN > Config.MAX_MULTI_BYTE_RANGES_NUM) throw new ValueException(ErrorMessages.ERR_TOO_MANY_MULTI_BYTE_RANGES); + if (n + incN > Config.MAX_MULTI_BYTE_RANGES_NUM) { + throw new ValueException(ErrorMessages.ERR_TOO_MANY_MULTI_BYTE_RANGES); + } if (incN != 1) { - if (from > p[low * 2 + 1]) from = p[low * 2 + 1]; - if (to < p[(high - 1) * 2 + 2]) to = p[(high - 1) * 2 + 2]; + if (from > p[low * 2 + 1]) { + from = p[low * 2 + 1]; + } + if (to < p[(high - 1) * 2 + 2]) { + to = p[(high - 1) * 2 + 2]; + } } if (incN != 0 && high < n) { @@ -197,9 +219,8 @@ public final class CodeRangeBuffer implements Cloneable { if (from > to) { if (env.syntax.allowEmptyRangeInCC()) { return pbuf; - } else { - throw new ValueException(ErrorMessages.ERR_EMPTY_RANGE_IN_CHAR_CLASS); } + throw new ValueException(ErrorMessages.ERR_EMPTY_RANGE_IN_CHAR_CLASS); } return addCodeRangeToBuff(pbuf, from, to); } @@ -218,12 +239,16 @@ public final class CodeRangeBuffer implements Cloneable { public static CodeRangeBuffer notCodeRangeBuff(final CodeRangeBuffer bbuf) { CodeRangeBuffer pbuf = null; - if (bbuf == null) return setAllMultiByteRange(pbuf); + if (bbuf == null) { + return setAllMultiByteRange(pbuf); + } final int[]p = bbuf.p; final int n = p[0]; - if (n <= 0) return setAllMultiByteRange(pbuf); + if (n <= 0) { + return setAllMultiByteRange(pbuf); + } int pre = EncodingHelper.mbcodeStartPosition(); @@ -235,18 +260,26 @@ public final class CodeRangeBuffer implements Cloneable { if (pre <= from - 1) { pbuf = addCodeRangeToBuff(pbuf, pre, from - 1); } - if (to == ALL_MULTI_BYTE_RANGE) break; + if (to == ALL_MULTI_BYTE_RANGE) { + break; + } pre = to + 1; } - if (to < ALL_MULTI_BYTE_RANGE) pbuf = addCodeRangeToBuff(pbuf, to + 1, ALL_MULTI_BYTE_RANGE); + if (to < ALL_MULTI_BYTE_RANGE) { + pbuf = addCodeRangeToBuff(pbuf, to + 1, ALL_MULTI_BYTE_RANGE); + } return pbuf; } // or_code_range_buf - public static CodeRangeBuffer orCodeRangeBuff(CodeRangeBuffer bbuf1, boolean not1, - CodeRangeBuffer bbuf2, boolean not2) { + public static CodeRangeBuffer orCodeRangeBuff(final CodeRangeBuffer bbuf1p, final boolean not1p, + final CodeRangeBuffer bbuf2p, final boolean not2p) { CodeRangeBuffer pbuf = null; + CodeRangeBuffer bbuf1 = bbuf1p; + CodeRangeBuffer bbuf2 = bbuf2p; + boolean not1 = not1p; + boolean not2 = not2p; if (bbuf1 == null && bbuf2 == null) { if (not1 || not2) { @@ -266,13 +299,11 @@ public final class CodeRangeBuffer implements Cloneable { if (bbuf1 == null) { if (not1) { return setAllMultiByteRange(pbuf); - } else { - if (!not2) { - return bbuf2.clone(); - } else { - return notCodeRangeBuff(bbuf2); - } } + if (!not2) { + return bbuf2.clone(); + } + return notCodeRangeBuff(bbuf2); } if (not1) { @@ -302,16 +333,18 @@ public final class CodeRangeBuffer implements Cloneable { } // and_code_range1 - public static CodeRangeBuffer andCodeRange1(CodeRangeBuffer pbuf, int from1, int to1, final int[]data, final int n) { + public static CodeRangeBuffer andCodeRange1(final CodeRangeBuffer pbufp, final int from1p, final int to1p, final int[]data, final int n) { + CodeRangeBuffer pbuf = pbufp; + int from1 = from1p, to1 = to1p; + for (int i=0; i to1) break; + if (from1 > to1) { + break; + } } if (from1 <= to1) { @@ -335,15 +370,22 @@ public final class CodeRangeBuffer implements Cloneable { } // and_code_range_buf - public static CodeRangeBuffer andCodeRangeBuff(CodeRangeBuffer bbuf1, boolean not1, - CodeRangeBuffer bbuf2, boolean not2) { + public static CodeRangeBuffer andCodeRangeBuff(final CodeRangeBuffer bbuf1p, final boolean not1p, + final CodeRangeBuffer bbuf2p, final boolean not2p) { CodeRangeBuffer pbuf = null; + CodeRangeBuffer bbuf1 = bbuf1p; + CodeRangeBuffer bbuf2 = bbuf2p; + boolean not1 = not1p, not2 = not2p; if (bbuf1 == null) { - if (not1 && bbuf2 != null) return bbuf2.clone(); /* not1 != 0 -> not2 == 0 */ + if (not1 && bbuf2 != null) { + return bbuf2.clone(); /* not1 != 0 -> not2 == 0 */ + } return null; } else if (bbuf2 == null) { - if (not2) return bbuf1.clone(); + if (not2) { + return bbuf1.clone(); + } return null; } @@ -369,8 +411,12 @@ public final class CodeRangeBuffer implements Cloneable { final int from2 = p2[j * 2 + 1]; final int to2 = p2[j * 2 + 2]; - if (from2 > to1) break; - if (to2 < from1) continue; + if (from2 > to1) { + break; + } + if (to2 < from1) { + continue; + } final int from = from1 > from2 ? from1 : from2; final int to = to1 < to2 ? to1 : to2; pbuf = addCodeRangeToBuff(pbuf, from, to); diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/Compiler.java b/src/jdk/nashorn/internal/runtime/regexp/joni/Compiler.java index 86ef0625..73752caa 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/Compiler.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/Compiler.java @@ -53,13 +53,17 @@ abstract class Compiler implements ErrorMessages { protected abstract void compileAltNode(ConsAltNode node); private void compileStringRawNode(final StringNode sn) { - if (sn.length() <= 0) return; + if (sn.length() <= 0) { + return; + } addCompileString(sn.chars, sn.p, sn.length(), false); } private void compileStringNode(final StringNode node) { final StringNode sn = node; - if (sn.length() <= 0) return; + if (sn.length() <= 0) { + return; + } final boolean ambig = sn.isAmbig(); @@ -145,7 +149,9 @@ abstract class Compiler implements ErrorMessages { } protected final void compileTreeNTimes(final Node node, final int n) { - for (int i=0; i 0) { - if (s <= p) return -1; + public static int stepBack(final int p, final int sp, final int np) { + int s = sp, n = np; + while (s != -1 && n-- > 0) { + if (s <= p) { + return -1; + } s--; } return s; @@ -122,7 +128,7 @@ public final class EncodingHelper { final int upper = toUpperCase(c); if (upper != c) { - fun.apply(c, upper, arg); + ApplyCaseFold.apply(c, upper, arg); } } } @@ -133,7 +139,7 @@ public final class EncodingHelper { final int upper = toUpperCase(c); if (upper != c) { - fun.apply(upper, c, arg); + ApplyCaseFold.apply(upper, c, arg); } } } diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/Lexer.java b/src/jdk/nashorn/internal/runtime/regexp/joni/Lexer.java index 61127a0c..27c010e8 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/Lexer.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/Lexer.java @@ -21,7 +21,6 @@ package jdk.nashorn.internal.runtime.regexp.joni; import static jdk.nashorn.internal.runtime.regexp.joni.Option.isSingleline; import static jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode.isRepeatInfinite; - import jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode; import jdk.nashorn.internal.runtime.regexp.joni.constants.AnchorType; import jdk.nashorn.internal.runtime.regexp.joni.constants.MetaChar; @@ -53,9 +52,8 @@ class Lexer extends ScannerSupport { if (!left()) { if (synAllow) { return 1; /* "....{" : OK! */ - } else { - throw new SyntaxException(ERR_END_PATTERN_AT_LEFT_BRACE); } + throw new SyntaxException(ERR_END_PATTERN_AT_LEFT_BRACE); } if (!synAllow) { @@ -83,7 +81,9 @@ class Lexer extends ScannerSupport { } } - if (!left()) return invalidRangeQuantifier(synAllow); + if (!left()) { + return invalidRangeQuantifier(synAllow); + } fetch(); int up; @@ -99,25 +99,35 @@ class Lexer extends ScannerSupport { } if (p == prev) { - if (nonLow) return invalidRangeQuantifier(synAllow); + if (nonLow) { + return invalidRangeQuantifier(synAllow); + } up = QuantifierNode.REPEAT_INFINITE; /* {n,} : {n,infinite} */ } } else { - if (nonLow) return invalidRangeQuantifier(synAllow); + if (nonLow) { + return invalidRangeQuantifier(synAllow); + } unfetch(); up = low; /* {n} : exact n times */ ret = 2; /* fixed */ } - if (!left()) return invalidRangeQuantifier(synAllow); + if (!left()) { + return invalidRangeQuantifier(synAllow); + } fetch(); if (syntax.opEscBraceInterval()) { - if (c != syntax.metaCharTable.esc) return invalidRangeQuantifier(synAllow); + if (c != syntax.metaCharTable.esc) { + return invalidRangeQuantifier(synAllow); + } fetch(); } - if (c != '}') return invalidRangeQuantifier(synAllow); + if (c != '}') { + return invalidRangeQuantifier(synAllow); + } if (!isRepeatInfinite(up) && low > up) { throw new ValueException(ERR_UPPER_SMALLER_THAN_LOWER_IN_REPEAT_RANGE); @@ -134,9 +144,8 @@ class Lexer extends ScannerSupport { if (synAllow) { restore(); return 1; - } else { - throw new SyntaxException(ERR_INVALID_REPEAT_RANGE_PATTERN); } + throw new SyntaxException(ERR_INVALID_REPEAT_RANGE_PATTERN); } @SuppressWarnings("fallthrough") @@ -218,17 +227,6 @@ class Lexer extends ScannerSupport { } } - private int nameEndCodePoint(final int start) { - switch(start) { - case '<': - return '>'; - case '\'': - return '\''; - default: - return 0; - } - } - private void fetchTokenInCCFor_charType(final boolean flag, final int type) { token.type = TokenType.CHAR_TYPE; token.setPropCType(type); @@ -236,7 +234,9 @@ class Lexer extends ScannerSupport { } private void fetchTokenInCCFor_x() { - if (!left()) return; + if (!left()) { + return; + } final int last = p; if (peekIs('{') && syntax.opEscXBraceHex8()) { @@ -274,7 +274,9 @@ class Lexer extends ScannerSupport { } private void fetchTokenInCCFor_u() { - if (!left()) return; + if (!left()) { + return; + } final int last = p; if (syntax.op2EscUHex4()) { @@ -329,7 +331,9 @@ class Lexer extends ScannerSupport { } else if (c == '-') { token.type = TokenType.CC_RANGE; } else if (c == syntax.metaCharTable.esc) { - if (!syntax.backSlashEscapeInCC()) return token.type; + if (!syntax.backSlashEscapeInCC()) { + return token.type; + } if (!left()) { throw new SyntaxException(ERR_END_PATTERN_AT_ESCAPE); } @@ -357,10 +361,14 @@ class Lexer extends ScannerSupport { fetchTokenInCCFor_charType(true, Config.NON_UNICODE_SDW ? CharacterType.S : CharacterType.SPACE); break; case 'h': - if (syntax.op2EscHXDigit()) fetchTokenInCCFor_charType(false, CharacterType.XDIGIT); + if (syntax.op2EscHXDigit()) { + fetchTokenInCCFor_charType(false, CharacterType.XDIGIT); + } break; case 'H': - if (syntax.op2EscHXDigit()) fetchTokenInCCFor_charType(true, CharacterType.XDIGIT); + if (syntax.op2EscHXDigit()) { + fetchTokenInCCFor_charType(true, CharacterType.XDIGIT); + } break; case 'x': fetchTokenInCCFor_x(); @@ -424,7 +432,9 @@ class Lexer extends ScannerSupport { } private void fetchTokenFor_xBrace() { - if (!left()) return; + if (!left()) { + return; + } final int last = p; if (peekIs('{') && syntax.opEscXBraceHex8()) { @@ -461,7 +471,9 @@ class Lexer extends ScannerSupport { } private void fetchTokenFor_uHex() { - if (!left()) return; + if (!left()) { + return; + } final int last = p; if (syntax.op2EscUHex4()) { @@ -562,79 +574,129 @@ class Lexer extends ScannerSupport { switch(c) { case '*': - if (syntax.opEscAsteriskZeroInf()) fetchTokenFor_repeat(0, QuantifierNode.REPEAT_INFINITE); + if (syntax.opEscAsteriskZeroInf()) { + fetchTokenFor_repeat(0, QuantifierNode.REPEAT_INFINITE); + } break; case '+': - if (syntax.opEscPlusOneInf()) fetchTokenFor_repeat(1, QuantifierNode.REPEAT_INFINITE); + if (syntax.opEscPlusOneInf()) { + fetchTokenFor_repeat(1, QuantifierNode.REPEAT_INFINITE); + } break; case '?': - if (syntax.opEscQMarkZeroOne()) fetchTokenFor_repeat(0, 1); + if (syntax.opEscQMarkZeroOne()) { + fetchTokenFor_repeat(0, 1); + } break; case '{': - if (syntax.opEscBraceInterval()) fetchTokenFor_openBrace(); + if (syntax.opEscBraceInterval()) { + fetchTokenFor_openBrace(); + } break; case '|': - if (syntax.opEscVBarAlt()) token.type = TokenType.ALT; + if (syntax.opEscVBarAlt()) { + token.type = TokenType.ALT; + } break; case '(': - if (syntax.opEscLParenSubexp()) token.type = TokenType.SUBEXP_OPEN; + if (syntax.opEscLParenSubexp()) { + token.type = TokenType.SUBEXP_OPEN; + } break; case ')': - if (syntax.opEscLParenSubexp()) token.type = TokenType.SUBEXP_CLOSE; + if (syntax.opEscLParenSubexp()) { + token.type = TokenType.SUBEXP_CLOSE; + } break; case 'w': - if (syntax.opEscWWord()) fetchTokenInCCFor_charType(false, Config.NON_UNICODE_SDW ? CharacterType.W : CharacterType.WORD); + if (syntax.opEscWWord()) { + fetchTokenInCCFor_charType(false, Config.NON_UNICODE_SDW ? CharacterType.W : CharacterType.WORD); + } break; case 'W': - if (syntax.opEscWWord()) fetchTokenInCCFor_charType(true, Config.NON_UNICODE_SDW ? CharacterType.W : CharacterType.WORD); + if (syntax.opEscWWord()) { + fetchTokenInCCFor_charType(true, Config.NON_UNICODE_SDW ? CharacterType.W : CharacterType.WORD); + } break; case 'b': - if (syntax.opEscBWordBound()) fetchTokenFor_anchor(AnchorType.WORD_BOUND); + if (syntax.opEscBWordBound()) { + fetchTokenFor_anchor(AnchorType.WORD_BOUND); + } break; case 'B': - if (syntax.opEscBWordBound()) fetchTokenFor_anchor(AnchorType.NOT_WORD_BOUND); + if (syntax.opEscBWordBound()) { + fetchTokenFor_anchor(AnchorType.NOT_WORD_BOUND); + } break; case '<': - if (Config.USE_WORD_BEGIN_END && syntax.opEscLtGtWordBeginEnd()) fetchTokenFor_anchor(AnchorType.WORD_BEGIN); + if (Config.USE_WORD_BEGIN_END && syntax.opEscLtGtWordBeginEnd()) { + fetchTokenFor_anchor(AnchorType.WORD_BEGIN); + } break; case '>': - if (Config.USE_WORD_BEGIN_END && syntax.opEscLtGtWordBeginEnd()) fetchTokenFor_anchor(AnchorType.WORD_END); + if (Config.USE_WORD_BEGIN_END && syntax.opEscLtGtWordBeginEnd()) { + fetchTokenFor_anchor(AnchorType.WORD_END); + } break; case 's': - if (syntax.opEscSWhiteSpace()) fetchTokenInCCFor_charType(false, Config.NON_UNICODE_SDW ? CharacterType.S : CharacterType.SPACE); + if (syntax.opEscSWhiteSpace()) { + fetchTokenInCCFor_charType(false, Config.NON_UNICODE_SDW ? CharacterType.S : CharacterType.SPACE); + } break; case 'S': - if (syntax.opEscSWhiteSpace()) fetchTokenInCCFor_charType(true, Config.NON_UNICODE_SDW ? CharacterType.S : CharacterType.SPACE); + if (syntax.opEscSWhiteSpace()) { + fetchTokenInCCFor_charType(true, Config.NON_UNICODE_SDW ? CharacterType.S : CharacterType.SPACE); + } break; case 'd': - if (syntax.opEscDDigit()) fetchTokenInCCFor_charType(false, Config.NON_UNICODE_SDW ? CharacterType.D : CharacterType.DIGIT); + if (syntax.opEscDDigit()) { + fetchTokenInCCFor_charType(false, Config.NON_UNICODE_SDW ? CharacterType.D : CharacterType.DIGIT); + } break; case 'D': - if (syntax.opEscDDigit()) fetchTokenInCCFor_charType(true, Config.NON_UNICODE_SDW ? CharacterType.D : CharacterType.DIGIT); + if (syntax.opEscDDigit()) { + fetchTokenInCCFor_charType(true, Config.NON_UNICODE_SDW ? CharacterType.D : CharacterType.DIGIT); + } break; case 'h': - if (syntax.op2EscHXDigit()) fetchTokenInCCFor_charType(false, CharacterType.XDIGIT); + if (syntax.op2EscHXDigit()) { + fetchTokenInCCFor_charType(false, CharacterType.XDIGIT); + } break; case 'H': - if (syntax.op2EscHXDigit()) fetchTokenInCCFor_charType(true, CharacterType.XDIGIT); + if (syntax.op2EscHXDigit()) { + fetchTokenInCCFor_charType(true, CharacterType.XDIGIT); + } break; case 'A': - if (syntax.opEscAZBufAnchor()) fetchTokenFor_anchor(AnchorType.BEGIN_BUF); + if (syntax.opEscAZBufAnchor()) { + fetchTokenFor_anchor(AnchorType.BEGIN_BUF); + } break; case 'Z': - if (syntax.opEscAZBufAnchor()) fetchTokenFor_anchor(AnchorType.SEMI_END_BUF); + if (syntax.opEscAZBufAnchor()) { + fetchTokenFor_anchor(AnchorType.SEMI_END_BUF); + } break; case 'z': - if (syntax.opEscAZBufAnchor()) fetchTokenFor_anchor(AnchorType.END_BUF); + if (syntax.opEscAZBufAnchor()) { + fetchTokenFor_anchor(AnchorType.END_BUF); + } break; case 'G': - if (syntax.opEscCapitalGBeginAnchor()) fetchTokenFor_anchor(AnchorType.BEGIN_POSITION); + if (syntax.opEscCapitalGBeginAnchor()) { + fetchTokenFor_anchor(AnchorType.BEGIN_POSITION); + } break; case '`': - if (syntax.op2EscGnuBufAnchor()) fetchTokenFor_anchor(AnchorType.BEGIN_BUF); + if (syntax.op2EscGnuBufAnchor()) { + fetchTokenFor_anchor(AnchorType.BEGIN_BUF); + } break; case '\'': - if (syntax.op2EscGnuBufAnchor()) fetchTokenFor_anchor(AnchorType.END_BUF); + if (syntax.op2EscGnuBufAnchor()) { + fetchTokenFor_anchor(AnchorType.END_BUF); + } break; case 'x': fetchTokenFor_xBrace(); @@ -684,22 +746,34 @@ class Lexer extends ScannerSupport { { switch(c) { case '.': - if (syntax.opDotAnyChar()) token.type = TokenType.ANYCHAR; + if (syntax.opDotAnyChar()) { + token.type = TokenType.ANYCHAR; + } break; case '*': - if (syntax.opAsteriskZeroInf()) fetchTokenFor_repeat(0, QuantifierNode.REPEAT_INFINITE); + if (syntax.opAsteriskZeroInf()) { + fetchTokenFor_repeat(0, QuantifierNode.REPEAT_INFINITE); + } break; case '+': - if (syntax.opPlusOneInf()) fetchTokenFor_repeat(1, QuantifierNode.REPEAT_INFINITE); + if (syntax.opPlusOneInf()) { + fetchTokenFor_repeat(1, QuantifierNode.REPEAT_INFINITE); + } break; case '?': - if (syntax.opQMarkZeroOne()) fetchTokenFor_repeat(0, 1); + if (syntax.opQMarkZeroOne()) { + fetchTokenFor_repeat(0, 1); + } break; case '{': - if (syntax.opBraceInterval()) fetchTokenFor_openBrace(); + if (syntax.opBraceInterval()) { + fetchTokenFor_openBrace(); + } break; case '|': - if (syntax.opVBarAlt()) token.type = TokenType.ALT; + if (syntax.opVBarAlt()) { + token.type = TokenType.ALT; + } break; case '(': @@ -713,9 +787,13 @@ class Lexer extends ScannerSupport { } fetch(); if (c == syntax.metaCharTable.esc) { - if (left()) fetch(); + if (left()) { + fetch(); + } } else { - if (c == ')') break; + if (c == ')') { + break; + } } } continue start; // goto start @@ -723,19 +801,29 @@ class Lexer extends ScannerSupport { unfetch(); } - if (syntax.opLParenSubexp()) token.type = TokenType.SUBEXP_OPEN; + if (syntax.opLParenSubexp()) { + token.type = TokenType.SUBEXP_OPEN; + } break; case ')': - if (syntax.opLParenSubexp()) token.type = TokenType.SUBEXP_CLOSE; + if (syntax.opLParenSubexp()) { + token.type = TokenType.SUBEXP_CLOSE; + } break; case '^': - if (syntax.opLineAnchor()) fetchTokenFor_anchor(isSingleline(env.option) ? AnchorType.BEGIN_BUF : AnchorType.BEGIN_LINE); + if (syntax.opLineAnchor()) { + fetchTokenFor_anchor(isSingleline(env.option) ? AnchorType.BEGIN_BUF : AnchorType.BEGIN_LINE); + } break; case '$': - if (syntax.opLineAnchor()) fetchTokenFor_anchor(isSingleline(env.option) ? AnchorType.END_BUF : AnchorType.END_LINE); + if (syntax.opLineAnchor()) { + fetchTokenFor_anchor(isSingleline(env.option) ? AnchorType.END_BUF : AnchorType.END_LINE); + } break; case '[': - if (syntax.opBracketCC()) token.type = TokenType.CC_CC_OPEN; + if (syntax.opBracketCC()) { + token.type = TokenType.CC_CC_OPEN; + } break; case ']': //if (*src > env->pattern) /* /].../ is allowed. */ @@ -745,7 +833,9 @@ class Lexer extends ScannerSupport { if (Option.isExtend(env.option)) { while (left()) { fetch(); - if (EncodingHelper.isNewLine(c)) break; + if (EncodingHelper.isNewLine(c)) { + break; + } } continue start; // goto start } @@ -756,7 +846,10 @@ class Lexer extends ScannerSupport { case '\n': case '\r': case '\f': - if (Option.isExtend(env.option)) continue start; // goto start + if (Option.isExtend(env.option)) + { + continue start; // goto start + } break; default: // string @@ -798,8 +891,8 @@ class Lexer extends ScannerSupport { } } - protected final void syntaxWarn(final String message, final char c) { - syntaxWarn(message.replace("<%n>", Character.toString(c))); + protected final void syntaxWarn(final String message, final char ch) { + syntaxWarn(message.replace("<%n>", Character.toString(ch))); } protected final void syntaxWarn(final String message) { diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/Matcher.java b/src/jdk/nashorn/internal/runtime/regexp/joni/Matcher.java index 3d2af295..b1a733d9 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/Matcher.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/Matcher.java @@ -21,10 +21,10 @@ package jdk.nashorn.internal.runtime.regexp.joni; import static jdk.nashorn.internal.runtime.regexp.joni.Option.isFindLongest; - import jdk.nashorn.internal.runtime.regexp.joni.constants.AnchorType; import jdk.nashorn.internal.runtime.regexp.joni.encoding.IntHolder; +@SuppressWarnings("javadoc") public abstract class Matcher extends IntHolder { protected final Regex regex; @@ -73,7 +73,9 @@ public abstract class Matcher extends IntHolder { protected final void msaInit(final int option, final int start) { msaOptions = option; msaStart = start; - if (Config.USE_FIND_LONGEST_SEARCH_ALL_OF_RANGE) msaBestLen = -1; + if (Config.USE_FIND_LONGEST_SEARCH_ALL_OF_RANGE) { + msaBestLen = -1; + } } public final int match(final int at, final int range, final int option) { @@ -83,20 +85,19 @@ public abstract class Matcher extends IntHolder { if (Config.USE_MATCH_RANGE_MUST_BE_INSIDE_OF_SPECIFIED_RANGE) { return matchAt(end /*range*/, at, prev); - } else { - return matchAt(range /*range*/, at, prev); } + return matchAt(range /*range*/, at, prev); } int low, high; // these are the return values - private boolean forwardSearchRange(final char[] chars, final int str, final int end, final int s, final int range, final IntHolder lowPrev) { + private boolean forwardSearchRange(final char[] ch, final int string, final int e, final int s, final int range, final IntHolder lowPrev) { int pprev = -1; int p = s; if (Config.DEBUG_SEARCH) { Config.log.println("forward_search_range: "+ - "str: " + str + - ", end: " + end + + "str: " + string + + ", end: " + e + ", s: " + s + ", range: " + range); } @@ -106,7 +107,7 @@ public abstract class Matcher extends IntHolder { } retry:while (true) { - p = regex.searchAlgorithm.search(regex, chars, p, end, range); + p = regex.searchAlgorithm.search(regex, ch, p, e, range); if (p != -1 && p < range) { if (p - regex.dMin < s) { @@ -119,9 +120,9 @@ public abstract class Matcher extends IntHolder { if (regex.subAnchor != 0) { switch (regex.subAnchor) { case AnchorType.BEGIN_LINE: - if (p != str) { - final int prev = EncodingHelper.prevCharHead((pprev != -1) ? pprev : str, p); - if (!EncodingHelper.isNewLine(chars, prev, end)) { + if (p != string) { + final int prev = EncodingHelper.prevCharHead((pprev != -1) ? pprev : string, p); + if (!EncodingHelper.isNewLine(ch, prev, e)) { // goto retry_gate; pprev = p; p++; @@ -131,17 +132,17 @@ public abstract class Matcher extends IntHolder { break; case AnchorType.END_LINE: - if (p == end) { + if (p == e) { if (!Config.USE_NEWLINE_AT_END_OF_STRING_HAS_EMPTY_LINE) { - final int prev = EncodingHelper.prevCharHead((pprev != -1) ? pprev : str, p); - if (prev != -1 && EncodingHelper.isNewLine(chars, prev, end)) { + final int prev = EncodingHelper.prevCharHead((pprev != -1) ? pprev : string, p); + if (prev != -1 && EncodingHelper.isNewLine(ch, prev, e)) { // goto retry_gate; pprev = p; p++; continue retry; } } - } else if (!EncodingHelper.isNewLine(chars, p, end)) { + } else if (!EncodingHelper.isNewLine(ch, p, e)) { //if () break; // goto retry_gate; pprev = p; @@ -149,6 +150,9 @@ public abstract class Matcher extends IntHolder { continue retry; } break; + + default: + break; } // switch } @@ -158,7 +162,7 @@ public abstract class Matcher extends IntHolder { if (low > s) { lowPrev.value = EncodingHelper.prevCharHead(s, p); } else { - lowPrev.value = EncodingHelper.prevCharHead((pprev != -1) ? pprev : str, p); + lowPrev.value = EncodingHelper.prevCharHead((pprev != -1) ? pprev : string, p); } } } else { @@ -172,7 +176,7 @@ public abstract class Matcher extends IntHolder { } } else { if (lowPrev != null) { - lowPrev.value = EncodingHelper.prevCharHead((pprev != -1) ? pprev : str, low); + lowPrev.value = EncodingHelper.prevCharHead((pprev != -1) ? pprev : string, low); } } } @@ -182,8 +186,8 @@ public abstract class Matcher extends IntHolder { if (Config.DEBUG_SEARCH) { Config.log.println("forward_search_range success: "+ - "low: " + (low - str) + - ", high: " + (high - str) + + "low: " + (low - string) + + ", high: " + (high - string) + ", dmin: " + regex.dMin + ", dmax: " + regex.dMax); } @@ -196,20 +200,21 @@ public abstract class Matcher extends IntHolder { } // low, high - private boolean backwardSearchRange(final char[] chars, final int str, final int end, final int s, int range, final int adjrange) { - range += regex.dMin; + private boolean backwardSearchRange(final char[] ch, final int string, final int e, final int s, final int range, final int adjrange) { + int r = range; + r += regex.dMin; int p = s; retry:while (true) { - p = regex.searchAlgorithm.searchBackward(regex, chars, range, adjrange, end, p, s, range); + p = regex.searchAlgorithm.searchBackward(regex, ch, r, adjrange, e, p, s, r); if (p != -1) { if (regex.subAnchor != 0) { switch (regex.subAnchor) { case AnchorType.BEGIN_LINE: - if (p != str) { - final int prev = EncodingHelper.prevCharHead(str, p); - if (!EncodingHelper.isNewLine(chars, prev, end)) { + if (p != string) { + final int prev = EncodingHelper.prevCharHead(string, p); + if (!EncodingHelper.isNewLine(ch, prev, e)) { p = prev; continue retry; } @@ -217,21 +222,28 @@ public abstract class Matcher extends IntHolder { break; case AnchorType.END_LINE: - if (p == end) { + if (p == e) { if (!Config.USE_NEWLINE_AT_END_OF_STRING_HAS_EMPTY_LINE) { final int prev = EncodingHelper.prevCharHead(adjrange, p); - if (prev == -1) return false; - if (EncodingHelper.isNewLine(chars, prev, end)) { + if (prev == -1) { + return false; + } + if (EncodingHelper.isNewLine(ch, prev, e)) { p = prev; continue retry; } } - } else if (!EncodingHelper.isNewLine(chars, p, end)) { + } else if (!EncodingHelper.isNewLine(ch, p, e)) { p = EncodingHelper.prevCharHead(adjrange, p); - if (p == -1) return false; + if (p == -1) { + return false; + } continue retry; } break; + + default: + break; } // switch } @@ -243,14 +255,16 @@ public abstract class Matcher extends IntHolder { if (Config.DEBUG_SEARCH) { Config.log.println("backward_search_range: "+ - "low: " + (low - str) + - ", high: " + (high - str)); + "low: " + (low - string) + + ", high: " + (high - string)); } return true; } - if (Config.DEBUG_SEARCH) Config.log.println("backward_search_range: fail."); + if (Config.DEBUG_SEARCH) { + Config.log.println("backward_search_range: fail."); + } return false; } // while } @@ -261,27 +275,36 @@ public abstract class Matcher extends IntHolder { if (Config.USE_FIND_LONGEST_SEARCH_ALL_OF_RANGE) { //range = upperRange; if (matchAt(upperRange, s, prev) != -1) { - if (!isFindLongest(regex.options)) return true; + if (!isFindLongest(regex.options)) { + return true; + } } } else { //range = upperRange; - if (matchAt(upperRange, s, prev) != -1) return true; + if (matchAt(upperRange, s, prev) != -1) { + return true; + } } } else { if (Config.USE_FIND_LONGEST_SEARCH_ALL_OF_RANGE) { if (matchAt(end, s, prev) != -1) { //range = upperRange; - if (!isFindLongest(regex.options)) return true; + if (!isFindLongest(regex.options)) { + return true; + } } } else { //range = upperRange; - if (matchAt(end, s, prev) != -1) return true; + if (matchAt(end, s, prev) != -1) { + return true; + } } } return false; } - public final int search(int start, int range, final int option) { + public final int search(final int startp, final int rangep, final int option) { + int start = startp, range = rangep; int s, prev; int origStart = start; final int origRange = range; @@ -294,7 +317,9 @@ public abstract class Matcher extends IntHolder { ", range " + (range - str)); } - if (start > end || start < str) return -1; + if (start > end || start < str) { + return -1; + } /* anchor optimize: resume search range */ if (regex.anchor != 0 && str < end) { @@ -311,7 +336,10 @@ public abstract class Matcher extends IntHolder { } else if ((regex.anchor & AnchorType.BEGIN_BUF) != 0) { /* search str-position only */ if (range > start) { - if (start != str) return -1; // mismatch_no_msa; + if (start != str) + { + return -1; // mismatch_no_msa; + } range = str + 1; } else { if (range <= str) { @@ -324,7 +352,10 @@ public abstract class Matcher extends IntHolder { } else if ((regex.anchor & AnchorType.END_BUF) != 0) { minSemiEnd = maxSemiEnd = end; // !end_buf:! - if (endBuf(start, range, minSemiEnd, maxSemiEnd)) return -1; // mismatch_no_msa; + if (endBuf(start, range, minSemiEnd, maxSemiEnd)) + { + return -1; // mismatch_no_msa; + } } else if ((regex.anchor & AnchorType.SEMI_END_BUF) != 0) { final int preEnd = EncodingHelper.stepBack(str, end, 1); maxSemiEnd = end; @@ -332,12 +363,18 @@ public abstract class Matcher extends IntHolder { minSemiEnd = preEnd; if (minSemiEnd > str && start <= minSemiEnd) { // !goto end_buf;! - if (endBuf(start, range, minSemiEnd, maxSemiEnd)) return -1; // mismatch_no_msa; + if (endBuf(start, range, minSemiEnd, maxSemiEnd)) + { + return -1; // mismatch_no_msa; + } } } else { minSemiEnd = end; // !goto end_buf;! - if (endBuf(start, range, minSemiEnd, maxSemiEnd)) return -1; // mismatch_no_msa; + if (endBuf(start, range, minSemiEnd, maxSemiEnd)) + { + return -1; // mismatch_no_msa; + } } } else if ((regex.anchor & AnchorType.ANYCHAR_STAR_ML) != 0) { // goto !begin_position;! @@ -359,7 +396,9 @@ public abstract class Matcher extends IntHolder { prev = -1; msaInit(option, start); - if (matchCheck(end, s, prev)) return match(s); + if (matchCheck(end, s, prev)) { + return match(s); + } return mismatch(); } return -1; // goto mismatch_no_msa; @@ -389,49 +428,62 @@ public abstract class Matcher extends IntHolder { schRange = end; } else { schRange += regex.dMax; - if (schRange > end) schRange = end; + if (schRange > end) { + schRange = end; + } } } - if ((end - start) < regex.thresholdLength) return mismatch(); + if ((end - start) < regex.thresholdLength) { + return mismatch(); + } if (regex.dMax != MinMaxLen.INFINITE_DISTANCE) { do { - if (!forwardSearchRange(chars, str, end, s, schRange, this)) return mismatch(); // low, high, lowPrev + if (!forwardSearchRange(chars, str, end, s, schRange, this)) { + return mismatch(); // low, high, lowPrev + } if (s < low) { s = low; prev = value; } while (s <= high) { - if (matchCheck(origRange, s, prev)) return match(s); // ??? + if (matchCheck(origRange, s, prev)) { + return match(s); // ??? + } prev = s; s++; } } while (s < range); + } + /* check only. */ + if (!forwardSearchRange(chars, str, end, s, schRange, null)) { return mismatch(); + } - } else { /* check only. */ - if (!forwardSearchRange(chars, str, end, s, schRange, null)) return mismatch(); - - if ((regex.anchor & AnchorType.ANYCHAR_STAR) != 0) { - do { - if (matchCheck(origRange, s, prev)) return match(s); - prev = s; - s++; - } while (s < range); - return mismatch(); - } - + if ((regex.anchor & AnchorType.ANYCHAR_STAR) != 0) { + do { + if (matchCheck(origRange, s, prev)) { + return match(s); + } + prev = s; + s++; + } while (s < range); + return mismatch(); } } do { - if (matchCheck(origRange, s, prev)) return match(s); + if (matchCheck(origRange, s, prev)) { + return match(s); + } prev = s; s++; } while (s < range); if (s == range) { /* because empty match with /$/. */ - if (matchCheck(origRange, s, prev)) return match(s); + if (matchCheck(origRange, s, prev)) { + return match(s); + } } } else { /* backward search */ if (Config.USE_MATCH_RANGE_MUST_BE_INSIDE_OF_SPECIFIED_RANGE) { @@ -450,37 +502,51 @@ public abstract class Matcher extends IntHolder { if (regex.dMax != MinMaxLen.INFINITE_DISTANCE && (end - range) >= regex.thresholdLength) { do { int schStart = s + regex.dMax; - if (schStart > end) schStart = end; - if (!backwardSearchRange(chars, str, end, schStart, range, adjrange)) return mismatch(); // low, high - if (s > high) s = high; + if (schStart > end) { + schStart = end; + } + if (!backwardSearchRange(chars, str, end, schStart, range, adjrange)) + { + return mismatch(); // low, high + } + if (s > high) { + s = high; + } while (s != -1 && s >= low) { prev = EncodingHelper.prevCharHead(str, s); - if (matchCheck(origStart, s, prev)) return match(s); + if (matchCheck(origStart, s, prev)) { + return match(s); + } s = prev; } } while (s >= range); return mismatch(); - } else { /* check only. */ - if ((end - range) < regex.thresholdLength) return mismatch(); + } + if ((end - range) < regex.thresholdLength) { + return mismatch(); + } - int schStart = s; - if (regex.dMax != 0) { - if (regex.dMax == MinMaxLen.INFINITE_DISTANCE) { + int schStart = s; + if (regex.dMax != 0) { + if (regex.dMax == MinMaxLen.INFINITE_DISTANCE) { + schStart = end; + } else { + schStart += regex.dMax; + if (schStart > end) { schStart = end; - } else { - schStart += regex.dMax; - if (schStart > end) { - schStart = end; - } } } - if (!backwardSearchRange(chars, str, end, schStart, range, adjrange)) return mismatch(); + } + if (!backwardSearchRange(chars, str, end, schStart, range, adjrange)) { + return mismatch(); } } do { prev = EncodingHelper.prevCharHead(str, s); - if (matchCheck(origStart, s, prev)) return match(s); + if (matchCheck(origStart, s, prev)) { + return match(s); + } s = prev; } while (s >= range); @@ -488,8 +554,13 @@ public abstract class Matcher extends IntHolder { return mismatch(); } - private boolean endBuf(int start, int range, final int minSemiEnd, final int maxSemiEnd) { - if ((maxSemiEnd - str) < regex.anchorDmin) return true; // mismatch_no_msa; + private boolean endBuf(final int startp, final int rangep, final int minSemiEnd, final int maxSemiEnd) { + int start = startp; + int range = rangep; + + if ((maxSemiEnd - str) < regex.anchorDmin) { + return true; // mismatch_no_msa; + } if (range > start) { if ((minSemiEnd - start) > regex.anchorDmax) { @@ -502,7 +573,10 @@ public abstract class Matcher extends IntHolder { if ((maxSemiEnd - (range - 1)) < regex.anchorDmin) { range = maxSemiEnd - regex.anchorDmin + 1; } - if (start >= range) return true; // mismatch_no_msa; + if (start >= range) + { + return true; // mismatch_no_msa; + } } else { if ((minSemiEnd - range) > regex.anchorDmax) { range = minSemiEnd - regex.anchorDmax; @@ -510,7 +584,10 @@ public abstract class Matcher extends IntHolder { if ((maxSemiEnd - start) < regex.anchorDmin) { start = maxSemiEnd - regex.anchorDmin; } - if (range > start) return true; // mismatch_no_msa; + if (range > start) + { + return true; // mismatch_no_msa; + } } return false; } diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/MatcherFactory.java b/src/jdk/nashorn/internal/runtime/regexp/joni/MatcherFactory.java index df7167b1..70642d5e 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/MatcherFactory.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/MatcherFactory.java @@ -19,6 +19,7 @@ */ package jdk.nashorn.internal.runtime.regexp.joni; +@SuppressWarnings("javadoc") public abstract class MatcherFactory { public abstract Matcher create(Regex regex, char[] chars, int p, int end); diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/MinMaxLen.java b/src/jdk/nashorn/internal/runtime/regexp/joni/MinMaxLen.java index 6990f357..83a9e2dc 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/MinMaxLen.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/MinMaxLen.java @@ -46,24 +46,40 @@ final class MinMaxLen { }; int distanceValue() { - if (max == INFINITE_DISTANCE) return 0; + if (max == INFINITE_DISTANCE) { + return 0; + } final int d = max - min; /* return dist_vals[d] * 16 / (mm->min + 12); */ return d < distValues.length ? distValues[d] : 1; } - int compareDistanceValue(final MinMaxLen other, int v1, int v2) { - if (v2 <= 0) return -1; - if (v1 <= 0) return 1; + int compareDistanceValue(final MinMaxLen other, final int v1p, final int v2p) { + int v1 = v1p, v2 = v2p; + + if (v2 <= 0) { + return -1; + } + if (v1 <= 0) { + return 1; + } v1 *= distanceValue(); v2 *= other.distanceValue(); - if (v2 > v1) return 1; - if (v2 < v1) return -1; + if (v2 > v1) { + return 1; + } + if (v2 < v1) { + return -1; + } - if (other.min < min) return 1; - if (other.min > min) return -1; + if (other.min < min) { + return 1; + } + if (other.min > min) { + return -1; + } return 0; } @@ -96,27 +112,33 @@ final class MinMaxLen { } void altMerge(final MinMaxLen other) { - if (min > other.min) min = other.min; - if (max < other.max) max = other.max; + if (min > other.min) { + min = other.min; + } + if (max < other.max) { + max = other.max; + } } static final int INFINITE_DISTANCE = 0x7FFFFFFF; static int distanceAdd(final int d1, final int d2) { if (d1 == INFINITE_DISTANCE || d2 == INFINITE_DISTANCE) { return INFINITE_DISTANCE; - } else { - if (d1 <= INFINITE_DISTANCE - d2) return d1 + d2; - else return INFINITE_DISTANCE; } + if (d1 <= INFINITE_DISTANCE - d2) { + return d1 + d2; + } + return INFINITE_DISTANCE; } static int distanceMultiply(final int d, final int m) { - if (m == 0) return 0; + if (m == 0) { + return 0; + } if (d < INFINITE_DISTANCE / m) { return d * m; - } else { - return INFINITE_DISTANCE; } + return INFINITE_DISTANCE; } static String distanceRangeToString(final int a, final int b) { diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/NodeOptInfo.java b/src/jdk/nashorn/internal/runtime/regexp/joni/NodeOptInfo.java index e072641f..a5e569dc 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/NodeOptInfo.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/NodeOptInfo.java @@ -19,6 +19,7 @@ */ package jdk.nashorn.internal.runtime.regexp.joni; +@SuppressWarnings("javadoc") public final class NodeOptInfo { final MinMaxLen length = new MinMaxLen(); final OptAnchorInfo anchor = new OptAnchorInfo(); @@ -91,8 +92,12 @@ public final class NodeOptInfo { if (other.length.max > 0) { // TODO: make sure it is not an Oniguruma bug (casting unsigned int to int for arithmetic comparison) int otherLengthMax = other.length.max; - if (otherLengthMax == MinMaxLen.INFINITE_DISTANCE) otherLengthMax = -1; - if (expr.length > otherLengthMax) expr.length = otherLengthMax; + if (otherLengthMax == MinMaxLen.INFINITE_DISTANCE) { + otherLengthMax = -1; + } + if (expr.length > otherLengthMax) { + expr.length = otherLengthMax; + } if (expr.mmd.max == 0) { exb.select(expr); } else { diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/OptAnchorInfo.java b/src/jdk/nashorn/internal/runtime/regexp/joni/OptAnchorInfo.java index 599c0231..7c7f5140 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/OptAnchorInfo.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/OptAnchorInfo.java @@ -36,14 +36,20 @@ final class OptAnchorInfo implements AnchorType { void concat(final OptAnchorInfo left, final OptAnchorInfo right, final int leftLength, final int rightLength) { leftAnchor = left.leftAnchor; - if (leftLength == 0) leftAnchor |= right.leftAnchor; + if (leftLength == 0) { + leftAnchor |= right.leftAnchor; + } rightAnchor = right.rightAnchor; - if (rightLength == 0) rightAnchor |= left.rightAnchor; + if (rightLength == 0) { + rightAnchor |= left.rightAnchor; + } } boolean isSet(final int anchor) { - if ((leftAnchor & anchor) != 0) return true; + if ((leftAnchor & anchor) != 0) { + return true; + } return (rightAnchor & anchor) != 0; } @@ -77,14 +83,30 @@ final class OptAnchorInfo implements AnchorType { static String anchorToString(final int anchor) { final StringBuffer s = new StringBuffer("["); - if ((anchor & AnchorType.BEGIN_BUF) !=0 ) s.append("begin-buf "); - if ((anchor & AnchorType.BEGIN_LINE) !=0 ) s.append("begin-line "); - if ((anchor & AnchorType.BEGIN_POSITION) !=0 ) s.append("begin-pos "); - if ((anchor & AnchorType.END_BUF) !=0 ) s.append("end-buf "); - if ((anchor & AnchorType.SEMI_END_BUF) !=0 ) s.append("semi-end-buf "); - if ((anchor & AnchorType.END_LINE) !=0 ) s.append("end-line "); - if ((anchor & AnchorType.ANYCHAR_STAR) !=0 ) s.append("anychar-star "); - if ((anchor & AnchorType.ANYCHAR_STAR_ML) !=0 ) s.append("anychar-star-pl "); + if ((anchor & AnchorType.BEGIN_BUF) !=0 ) { + s.append("begin-buf "); + } + if ((anchor & AnchorType.BEGIN_LINE) !=0 ) { + s.append("begin-line "); + } + if ((anchor & AnchorType.BEGIN_POSITION) !=0 ) { + s.append("begin-pos "); + } + if ((anchor & AnchorType.END_BUF) !=0 ) { + s.append("end-buf "); + } + if ((anchor & AnchorType.SEMI_END_BUF) !=0 ) { + s.append("semi-end-buf "); + } + if ((anchor & AnchorType.END_LINE) !=0 ) { + s.append("end-line "); + } + if ((anchor & AnchorType.ANYCHAR_STAR) !=0 ) { + s.append("anychar-star "); + } + if ((anchor & AnchorType.ANYCHAR_STAR_ML) !=0 ) { + s.append("anychar-star-pl "); + } s.append("]"); return s.toString(); diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/OptExactInfo.java b/src/jdk/nashorn/internal/runtime/regexp/joni/OptExactInfo.java index 2fa91a30..cc2143de 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/OptExactInfo.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/OptExactInfo.java @@ -56,7 +56,9 @@ final class OptExactInfo { void concat(final OptExactInfo other) { if (!ignoreCase && other.ignoreCase) { - if (length >= other.length) return; /* avoid */ + if (length >= other.length) { + return; /* avoid */ + } ignoreCase = true; } @@ -65,7 +67,9 @@ final class OptExactInfo { int i; for (i = length; p < end;) { - if (i + 1 > OPT_EXACT_MAXLEN) break; + if (i + 1 > OPT_EXACT_MAXLEN) { + break; + } chars[i++] = other.chars[p++]; } @@ -74,15 +78,20 @@ final class OptExactInfo { final OptAnchorInfo tmp = new OptAnchorInfo(); tmp.concat(anchor, other.anchor, 1, 1); - if (!other.reachEnd) tmp.rightAnchor = 0; + if (!other.reachEnd) { + tmp.rightAnchor = 0; + } anchor.copy(tmp); } // ?? raw is not used here - void concatStr(final char[] lchars, int p, final int end, final boolean raw) { + void concatStr(final char[] lchars, final int pp, final int end, final boolean raw) { int i; + int p = pp; for (i = length; p < end && i < OPT_EXACT_MAXLEN;) { - if (i + 1 > OPT_EXACT_MAXLEN) break; + if (i + 1 > OPT_EXACT_MAXLEN) { + break; + } chars[i++] = lchars[p++]; } @@ -102,17 +111,23 @@ final class OptExactInfo { int i; for (i = 0; i < length && i < other.length; i++) { - if (chars[i] != other.chars[i]) break; + if (chars[i] != other.chars[i]) { + break; + } } - if (!other.reachEnd || i 1) v1 += 5; - if (alt.length > 1) v2 += 5; + if (length > 1) { + v1 += 5; + } + if (alt.length > 1) { + v2 += 5; + } } - if (!ignoreCase) v1 *= 2; - if (!alt.ignoreCase) v2 *= 2; + if (!ignoreCase) { + v1 *= 2; + } + if (!alt.ignoreCase) { + v2 *= 2; + } - if (mmd.compareDistanceValue(alt.mmd, v1, v2) > 0) copy(alt); + if (mmd.compareDistanceValue(alt.mmd, v1, v2) > 0) { + copy(alt); + } } // comp_opt_exact_or_map_info private static final int COMP_EM_BASE = 20; int compare(final OptMapInfo m) { - if (m.value <= 0) return -1; + if (m.value <= 0) { + return -1; + } final int ve = COMP_EM_BASE * length * (ignoreCase ? 1 : 2); final int vm = COMP_EM_BASE * 5 * 2 / m.value; diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/OptMapInfo.java b/src/jdk/nashorn/internal/runtime/regexp/joni/OptMapInfo.java index c4fd183b..a3c4c7c5 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/OptMapInfo.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/OptMapInfo.java @@ -31,7 +31,9 @@ final class OptMapInfo { mmd.clear(); anchor.clear(); value = 0; - for (int i=0; i 0) copy(alt); + if (mmd.compareDistanceValue(alt.mmd, v1, v2) > 0) { + copy(alt); + } } // alt_merge_opt_map_info void altMerge(final OptMapInfo other) { /* if (! is_equal_mml(&to->mmd, &add->mmd)) return ; */ - if (value == 0) return; + if (value == 0) { + return; + } if (other.value == 0 || mmd.max < other.mmd.max) { clear(); return; @@ -89,8 +96,12 @@ final class OptMapInfo { int val = 0; for (int i=0; i 0) { diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/Region.java b/src/jdk/nashorn/internal/runtime/regexp/joni/Region.java index ee3dc615..32db18e1 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/Region.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/Region.java @@ -19,6 +19,7 @@ */ package jdk.nashorn.internal.runtime.regexp.joni; +@SuppressWarnings("javadoc") public final class Region { static final int REGION_NOTPOS = -1; @@ -36,7 +37,9 @@ public final class Region { public String toString() { final StringBuilder sb = new StringBuilder(); sb.append("Region: \n"); - for (int i=0; i textRange) end = textRange; + if (end > textRange) { + end = textRange; + } int s = textP; @@ -71,11 +74,15 @@ public abstract class SearchAlgorithm { int p = s + 1; int t = targetP + 1; while (t < targetEnd) { - if (target[t] != text[p++]) break; + if (target[t] != text[p++]) { + break; + } t++; } - if (t == targetEnd) return s; + if (t == targetEnd) { + return s; + } } s++; } @@ -101,10 +108,14 @@ public abstract class SearchAlgorithm { int p = s + 1; int t = targetP + 1; while (t < targetEnd) { - if (target[t] != text[p++]) break; + if (target[t] != text[p++]) { + break; + } t++; } - if (t == targetEnd) return s; + if (t == targetEnd) { + return s; + } } // s = enc.prevCharHead or s = s <= adjustText ? -1 : s - 1; s--; @@ -114,10 +125,8 @@ public abstract class SearchAlgorithm { }; public static final class SLOW_IC extends SearchAlgorithm { - private final int caseFoldFlag; - public SLOW_IC(final Regex regex) { - this.caseFoldFlag = regex.caseFoldFlag; + //empty } @Override @@ -134,11 +143,15 @@ public abstract class SearchAlgorithm { int end = textEnd; end -= targetEnd - targetP - 1; - if (end > textRange) end = textRange; + if (end > textRange) { + end = textRange; + } int s = textP; while (s < end) { - if (lowerCaseMatch(target, targetP, targetEnd, text, s, textEnd)) return s; + if (lowerCaseMatch(target, targetP, targetEnd, text, s, textEnd)) { + return s; + } s++; } return -1; @@ -158,17 +171,21 @@ public abstract class SearchAlgorithm { } while (s >= textP) { - if (lowerCaseMatch(target, targetP, targetEnd, text, s, textEnd)) return s; + if (lowerCaseMatch(target, targetP, targetEnd, text, s, textEnd)) { + return s; + } s = EncodingHelper.prevCharHead(adjustText, s); } return -1; } - private boolean lowerCaseMatch(final char[] t, int tP, final int tEnd, - final char[] chars, int p, final int end) { + private static boolean lowerCaseMatch(final char[] t, final int tPp, final int tEnd, + final char[] chars, final int pp, final int end) { - while (tP < tEnd) { - if (t[tP++] != EncodingHelper.toLowerCase(chars[p++])) return false; + for (int tP = tPp, p = pp; tP < tEnd; ) { + if (t[tP++] != EncodingHelper.toLowerCase(chars[p++])) { + return false; + } } return true; } @@ -188,7 +205,9 @@ public abstract class SearchAlgorithm { final int targetEnd = regex.exactEnd; int end = textRange + (targetEnd - targetP) - 1; - if (end > textEnd) end = textEnd; + if (end > textEnd) { + end = textEnd; + } final int tail = targetEnd - 1; int s = textP + (targetEnd - targetP) - 1; @@ -199,7 +218,9 @@ public abstract class SearchAlgorithm { int t = tail; while (text[p] == target[t]) { - if (t == targetP) return p; + if (t == targetP) { + return p; + } p--; t--; } @@ -211,7 +232,9 @@ public abstract class SearchAlgorithm { int t = tail; while (text[p] == target[t]) { - if (t == targetP) return p; + if (t == targetP) { + return p; + } p--; t--; } @@ -249,7 +272,9 @@ public abstract class SearchAlgorithm { while (t < targetEnd && text[p] == target[t]) { p++; t++; } - if (t == targetEnd) return s; + if (t == targetEnd) { + return s; + } s -= regex.intMapBackward[text[s] & 0xff]; } @@ -268,8 +293,12 @@ public abstract class SearchAlgorithm { final int len = end - p; - for (int i=0; i0; i--) skip[chars[i] & 0xff] = i; + for (int i=0; i0; i--) { + skip[chars[i] & 0xff] = i; + } } }; @@ -286,7 +315,9 @@ public abstract class SearchAlgorithm { int s = textP; while (s < textRange) { - if (text[s] > 0xff || map[text[s]] != 0) return s; + if (text[s] > 0xff || map[text[s]] != 0) { + return s; + } s++; } return -1; @@ -297,9 +328,13 @@ public abstract class SearchAlgorithm { final byte[] map = regex.map; int s = textStart; - if (s >= textEnd) s = textEnd - 1; + if (s >= textEnd) { + s = textEnd - 1; + } while (s >= textP) { - if (text[s] > 0xff || map[text[s]] != 0) return s; + if (text[s] > 0xff || map[text[s]] != 0) { + return s; + } s--; } return -1; diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/StackMachine.java b/src/jdk/nashorn/internal/runtime/regexp/joni/StackMachine.java index 2ba5cfd6..fc498c45 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/StackMachine.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/StackMachine.java @@ -20,7 +20,6 @@ package jdk.nashorn.internal.runtime.regexp.joni; import static jdk.nashorn.internal.runtime.regexp.joni.BitStatus.bsAt; - import java.lang.ref.WeakReference; import jdk.nashorn.internal.runtime.regexp.joni.constants.StackPopLevel; import jdk.nashorn.internal.runtime.regexp.joni.constants.StackType; @@ -61,12 +60,14 @@ abstract class StackMachine extends Matcher implements StackType { static final ThreadLocal> stacks = new ThreadLocal>() { + @SuppressWarnings("unused") @Override protected WeakReference initialValue() { return new WeakReference(allocateStack()); } }; + @SuppressWarnings("unused") private static StackEntry[] fetchStack() { WeakReference ref = stacks.get(); StackEntry[] stack = ref.get(); @@ -78,7 +79,9 @@ abstract class StackMachine extends Matcher implements StackType { } protected final void init() { - if (stack != null) pushEnsured(ALT, regex.codeLength - 1); /* bottom stack */ + if (stack != null) { + pushEnsured(ALT, regex.codeLength - 1); /* bottom stack */ + } if (repeatStk != null) { for (int i=1; i<=regex.numMem; i++) { repeatStk[i + memStartStk] = repeatStk[i + memEndStk] = INVALID_INDEX; @@ -87,9 +90,13 @@ abstract class StackMachine extends Matcher implements StackType { } protected final StackEntry ensure1() { - if (stk >= stack.length) doubleStack(); + if (stk >= stack.length) { + doubleStack(); + } StackEntry e = stack[stk]; - if (e == null) stack[stk] = e = new StackEntry(); + if (e == null) { + stack[stk] = e = new StackEntry(); + } return e; } @@ -190,7 +197,9 @@ abstract class StackMachine extends Matcher implements StackType { if ((e.type & MASK_MEM_END_OR_MARK) != 0 && e.getMemNum() == mnum) { level++; } else if (e.type == MEM_START && e.getMemNum() == mnum) { - if (level == 0) break; + if (level == 0) { + break; + } level--; } } @@ -371,9 +380,8 @@ abstract class StackMachine extends Matcher implements StackType { if (e.getNullCheckNum() == id) { if (level == 0) { return e.getNullCheckPStr() == s ? 1 : 0; - } else { - level--; } + level--; } } else if (e.type == NULL_CHECK_END) { level++; @@ -393,32 +401,31 @@ abstract class StackMachine extends Matcher implements StackType { if (e.getNullCheckPStr() != s) { isNull = 0; break; - } else { - int endp; - isNull = 1; - while (k < stk) { - if (e.type == MEM_START) { - if (e.getMemEnd() == INVALID_INDEX) { - isNull = 0; - break; - } - if (bsAt(regex.btMemEnd, e.getMemNum())) { - endp = stack[e.getMemEnd()].getMemPStr(); - } else { - endp = e.getMemEnd(); - } - if (stack[e.getMemStart()].getMemPStr() != endp) { - isNull = 0; - break; - } else if (endp != s) { - isNull = -1; /* empty, but position changed */ - } + } + int endp; + isNull = 1; + while (k < stk) { + if (e.type == MEM_START) { + if (e.getMemEnd() == INVALID_INDEX) { + isNull = 0; + break; + } + if (bsAt(regex.btMemEnd, e.getMemNum())) { + endp = stack[e.getMemEnd()].getMemPStr(); + } else { + endp = e.getMemEnd(); + } + if (stack[e.getMemStart()].getMemPStr() != endp) { + isNull = 0; + break; + } else if (endp != s) { + isNull = -1; /* empty, but position changed */ } - k++; - e = stack[k]; // !! } - break; + k++; + e = stack[k]; // !! } + break; } } } @@ -439,38 +446,38 @@ abstract class StackMachine extends Matcher implements StackType { if (e.getNullCheckPStr() != s) { isNull = 0; break; - } else { - int endp; - isNull = 1; - while (k < stk) { - if (e.type == MEM_START) { - if (e.getMemEnd() == INVALID_INDEX) { - isNull = 0; - break; - } - if (bsAt(regex.btMemEnd, e.getMemNum())) { - endp = stack[e.getMemEnd()].getMemPStr(); - } else { - endp = e.getMemEnd(); - } - if (stack[e.getMemStart()].getMemPStr() != endp) { - isNull = 0; - break; - } else if (endp != s) { - isNull = -1; /* empty, but position changed */ - } + } + int endp; + isNull = 1; + while (k < stk) { + if (e.type == MEM_START) { + if (e.getMemEnd() == INVALID_INDEX) { + isNull = 0; + break; + } + if (bsAt(regex.btMemEnd, e.getMemNum())) { + endp = stack[e.getMemEnd()].getMemPStr(); + } else { + endp = e.getMemEnd(); + } + if (stack[e.getMemStart()].getMemPStr() != endp) { + isNull = 0; + break; + } else if (endp != s) { + isNull = -1; /* empty, but position changed */ } - k++; - e = stack[k]; } - break; + k++; + e = stack[k]; } - } else { - level--; + break; } + level--; } } else if (e.type == NULL_CHECK_END) { - if (e.getNullCheckNum() == id) level++; + if (e.getNullCheckNum() == id) { + level++; + } } } return isNull; @@ -485,7 +492,9 @@ abstract class StackMachine extends Matcher implements StackType { if (e.type == REPEAT) { if (level == 0) { - if (e.getRepeatNum() == id) return k; + if (e.getRepeatNum() == id) { + return k; + } } } else if (e.type == CALL_FRAME) { level--; @@ -505,9 +514,8 @@ abstract class StackMachine extends Matcher implements StackType { if (e.type == CALL_FRAME) { if (level == 0) { return e.getCallFrameRetAddr(); - } else { - level--; } + level--; } else if (e.type == RETURN) { level++; } diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/Syntax.java b/src/jdk/nashorn/internal/runtime/regexp/joni/Syntax.java index e20ff023..f58b85f5 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/Syntax.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/Syntax.java @@ -20,10 +20,10 @@ package jdk.nashorn.internal.runtime.regexp.joni; import static jdk.nashorn.internal.runtime.regexp.joni.constants.MetaChar.INEFFECTIVE_META_CHAR; - import jdk.nashorn.internal.runtime.regexp.joni.constants.SyntaxProperties; -public final class Syntax implements SyntaxProperties{ +@SuppressWarnings("javadoc") +public final class Syntax implements SyntaxProperties { private final int op; private final int op2; private final int behavior; diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/WarnCallback.java b/src/jdk/nashorn/internal/runtime/regexp/joni/WarnCallback.java index 87cb6dc5..2529684d 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/WarnCallback.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/WarnCallback.java @@ -22,6 +22,7 @@ package jdk.nashorn.internal.runtime.regexp.joni; /** * @author Ola Bini */ +@SuppressWarnings("javadoc") public interface WarnCallback { WarnCallback DEFAULT = new WarnCallback() { @Override diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/Warnings.java b/src/jdk/nashorn/internal/runtime/regexp/joni/Warnings.java index 890a0818..09708bcd 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/Warnings.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/Warnings.java @@ -19,6 +19,7 @@ */ package jdk.nashorn.internal.runtime.regexp.joni; +@SuppressWarnings("javadoc") public interface Warnings { final String INVALID_BACKREFERENCE = "invalid back reference"; final String INVALID_SUBEXP_CALL = "invalid subexp call"; diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/ast/AnchorNode.java b/src/jdk/nashorn/internal/runtime/regexp/joni/ast/AnchorNode.java index f4fd85a1..6583da3b 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/ast/AnchorNode.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/ast/AnchorNode.java @@ -21,6 +21,7 @@ package jdk.nashorn.internal.runtime.regexp.joni.ast; import jdk.nashorn.internal.runtime.regexp.joni.constants.AnchorType; +@SuppressWarnings("javadoc") public final class AnchorNode extends Node implements AnchorType { public int type; public Node target; @@ -65,28 +66,60 @@ public final class AnchorNode extends Node implements AnchorType { } public String typeToString() { - final StringBuilder type = new StringBuilder(); - if (isType(BEGIN_BUF)) type.append("BEGIN_BUF "); - if (isType(BEGIN_LINE)) type.append("BEGIN_LINE "); - if (isType(BEGIN_POSITION)) type.append("BEGIN_POSITION "); - if (isType(END_BUF)) type.append("END_BUF "); - if (isType(SEMI_END_BUF)) type.append("SEMI_END_BUF "); - if (isType(END_LINE)) type.append("END_LINE "); - if (isType(WORD_BOUND)) type.append("WORD_BOUND "); - if (isType(NOT_WORD_BOUND)) type.append("NOT_WORD_BOUND "); - if (isType(WORD_BEGIN)) type.append("WORD_BEGIN "); - if (isType(WORD_END)) type.append("WORD_END "); - if (isType(PREC_READ)) type.append("PREC_READ "); - if (isType(PREC_READ_NOT)) type.append("PREC_READ_NOT "); - if (isType(LOOK_BEHIND)) type.append("LOOK_BEHIND "); - if (isType(LOOK_BEHIND_NOT)) type.append("LOOK_BEHIND_NOT "); - if (isType(ANYCHAR_STAR)) type.append("ANYCHAR_STAR "); - if (isType(ANYCHAR_STAR_ML)) type.append("ANYCHAR_STAR_ML "); - return type.toString(); + final StringBuilder sb = new StringBuilder(); + if (isType(BEGIN_BUF)) { + sb.append("BEGIN_BUF "); + } + if (isType(BEGIN_LINE)) { + sb.append("BEGIN_LINE "); + } + if (isType(BEGIN_POSITION)) { + sb.append("BEGIN_POSITION "); + } + if (isType(END_BUF)) { + sb.append("END_BUF "); + } + if (isType(SEMI_END_BUF)) { + sb.append("SEMI_END_BUF "); + } + if (isType(END_LINE)) { + sb.append("END_LINE "); + } + if (isType(WORD_BOUND)) { + sb.append("WORD_BOUND "); + } + if (isType(NOT_WORD_BOUND)) { + sb.append("NOT_WORD_BOUND "); + } + if (isType(WORD_BEGIN)) { + sb.append("WORD_BEGIN "); + } + if (isType(WORD_END)) { + sb.append("WORD_END "); + } + if (isType(PREC_READ)) { + sb.append("PREC_READ "); + } + if (isType(PREC_READ_NOT)) { + sb.append("PREC_READ_NOT "); + } + if (isType(LOOK_BEHIND)) { + sb.append("LOOK_BEHIND "); + } + if (isType(LOOK_BEHIND_NOT)) { + sb.append("LOOK_BEHIND_NOT "); + } + if (isType(ANYCHAR_STAR)) { + sb.append("ANYCHAR_STAR "); + } + if (isType(ANYCHAR_STAR_ML)) { + sb.append("ANYCHAR_STAR_ML "); + } + return sb.toString(); } - private boolean isType(final int type) { - return (this.type & type) != 0; + private boolean isType(final int t) { + return (this.type & t) != 0; } } diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/ast/AnyCharNode.java b/src/jdk/nashorn/internal/runtime/regexp/joni/ast/AnyCharNode.java index 69659b7d..900932e3 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/ast/AnyCharNode.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/ast/AnyCharNode.java @@ -19,6 +19,7 @@ */ package jdk.nashorn.internal.runtime.regexp.joni.ast; +@SuppressWarnings("javadoc") public final class AnyCharNode extends Node { public AnyCharNode(){} diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/ast/BackRefNode.java b/src/jdk/nashorn/internal/runtime/regexp/joni/ast/BackRefNode.java index 75a9c6a0..573c1ec7 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/ast/BackRefNode.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/ast/BackRefNode.java @@ -21,6 +21,7 @@ package jdk.nashorn.internal.runtime.regexp.joni.ast; import jdk.nashorn.internal.runtime.regexp.joni.ScanEnvironment; +@SuppressWarnings("javadoc") public final class BackRefNode extends StateNode { public final int backRef; diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/ast/CClassNode.java b/src/jdk/nashorn/internal/runtime/regexp/joni/ast/CClassNode.java index ce3bef1b..bcf7aa07 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/ast/CClassNode.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/ast/CClassNode.java @@ -34,6 +34,7 @@ import jdk.nashorn.internal.runtime.regexp.joni.exception.InternalException; import jdk.nashorn.internal.runtime.regexp.joni.exception.SyntaxException; import jdk.nashorn.internal.runtime.regexp.joni.exception.ValueException; +@SuppressWarnings("javadoc") public final class CClassNode extends Node { private static final int FLAG_NCCLASS_NOT = 1<<0; private static final int FLAG_NCCLASS_SHARE = 1<<1; @@ -100,7 +101,9 @@ public final class CClassNode extends Node { @Override public boolean equals(final Object other) { - if (!(other instanceof CClassNode)) return false; + if (!(other instanceof CClassNode)) { + return false; + } final CClassNode cc = (CClassNode)other; return ctype == cc.ctype && isNot() == cc.isNot(); } @@ -110,11 +113,12 @@ public final class CClassNode extends Node { if (Config.USE_SHARED_CCLASS_TABLE) { int hash = 0; hash += ctype; - if (isNot()) hash++; + if (isNot()) { + hash++; + } return hash + (hash >> 5); - } else { - return super.hashCode(); } + return super.hashCode(); } @Override @@ -128,10 +132,14 @@ public final class CClassNode extends Node { } public String flagsToString() { - final StringBuilder flags = new StringBuilder(); - if (isNot()) flags.append("NOT "); - if (isShare()) flags.append("SHARE "); - return flags.toString(); + final StringBuilder f = new StringBuilder(); + if (isNot()) { + f.append("NOT "); + } + if (isShare()) { + f.append("SHARE "); + } + return f.toString(); } public boolean isEmpty() { @@ -251,7 +259,7 @@ public final class CClassNode extends Node { } // add_ctype_to_cc_by_range // Encoding out! - public void addCTypeByRange(final int ctype, final boolean not, final int sbOut, final int mbr[]) { + public void addCTypeByRange(final int ct, final boolean not, final int sbOut, final int mbr[]) { final int n = mbr[0]; if (!not) { @@ -294,10 +302,14 @@ public final class CClassNode extends Node { // !goto sb_end2!, remove duplication prev = sbOut; for (i=0; i 0xff) throw new ValueException(ErrorMessages.ERR_INVALID_CODE_POINT_VALUE); + if (arg.vs > 0xff) { + throw new ValueException(ErrorMessages.ERR_INVALID_CODE_POINT_VALUE); + } bs.set(arg.vs); } else if (arg.type == CCVALTYPE.CODE_POINT) { addCodeRange(env, arg.vs, arg.vs); @@ -450,16 +489,17 @@ public final class CClassNode extends Node { case RANGE: if (arg.inType == arg.type) { if (arg.inType == CCVALTYPE.SB) { - if (arg.vs > 0xff || arg.v > 0xff) throw new ValueException(ErrorMessages.ERR_INVALID_CODE_POINT_VALUE); + if (arg.vs > 0xff || arg.v > 0xff) { + throw new ValueException(ErrorMessages.ERR_INVALID_CODE_POINT_VALUE); + } if (arg.vs > arg.v) { if (env.syntax.allowEmptyRangeInCC()) { // goto ccs_range_end arg.state = CCSTATE.COMPLETE; break; - } else { - throw new ValueException(ErrorMessages.ERR_EMPTY_RANGE_IN_CHAR_CLASS); } + throw new ValueException(ErrorMessages.ERR_EMPTY_RANGE_IN_CHAR_CLASS); } bs.setRange(arg.vs, arg.v); } else { @@ -471,9 +511,8 @@ public final class CClassNode extends Node { // goto ccs_range_end arg.state = CCSTATE.COMPLETE; break; - } else { - throw new ValueException(ErrorMessages.ERR_EMPTY_RANGE_IN_CHAR_CLASS); } + throw new ValueException(ErrorMessages.ERR_EMPTY_RANGE_IN_CHAR_CLASS); } bs.setRange(arg.vs, arg.v < 0xff ? arg.v : 0xff); addCodeRange(env, arg.vs, arg.v); @@ -509,9 +548,8 @@ public final class CClassNode extends Node { if (isNot()) { return !found; - } else { - return found; } + return found; } // onig_is_code_in_cc diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/ast/ConsAltNode.java b/src/jdk/nashorn/internal/runtime/regexp/joni/ast/ConsAltNode.java index 45dc3860..c07bb369 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/ast/ConsAltNode.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/ast/ConsAltNode.java @@ -24,6 +24,7 @@ import jdk.nashorn.internal.runtime.regexp.joni.WarnCallback; import jdk.nashorn.internal.runtime.regexp.joni.exception.ErrorMessages; import jdk.nashorn.internal.runtime.regexp.joni.exception.InternalException; +@SuppressWarnings("javadoc") public final class ConsAltNode extends Node { public Node car; public ConsAltNode cdr; @@ -31,9 +32,13 @@ public final class ConsAltNode extends Node { private ConsAltNode(final Node car, final ConsAltNode cdr, final int type) { this.car = car; - if (car != null) car.parent = this; + if (car != null) { + car.parent = this; + } this.cdr = cdr; - if (cdr != null) cdr.parent = this; + if (cdr != null) { + cdr.parent = this; + } this.type = type; } @@ -46,8 +51,9 @@ public final class ConsAltNode extends Node { return new ConsAltNode(left, right, LIST); } - public static ConsAltNode listAdd(ConsAltNode list, final Node x) { + public static ConsAltNode listAdd(final ConsAltNode listp, final Node x) { final ConsAltNode n = newListNode(x, null); + ConsAltNode list = listp; if (list != null) { while (list.cdr != null) { diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/ast/EncloseNode.java b/src/jdk/nashorn/internal/runtime/regexp/joni/ast/EncloseNode.java index cd5a1e97..95110115 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/ast/EncloseNode.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/ast/EncloseNode.java @@ -22,6 +22,7 @@ package jdk.nashorn.internal.runtime.regexp.joni.ast; import jdk.nashorn.internal.runtime.regexp.joni.Option; import jdk.nashorn.internal.runtime.regexp.joni.constants.EncloseType; +@SuppressWarnings("javadoc") public final class EncloseNode extends StateNode implements EncloseType { public final int type; // enclose type diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/ast/Node.java b/src/jdk/nashorn/internal/runtime/regexp/joni/ast/Node.java index dbf812ea..9961432e 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/ast/Node.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/ast/Node.java @@ -24,6 +24,7 @@ import jdk.nashorn.internal.runtime.regexp.joni.Config; import jdk.nashorn.internal.runtime.regexp.joni.WarnCallback; import jdk.nashorn.internal.runtime.regexp.joni.constants.NodeType; +@SuppressWarnings("javadoc") public abstract class Node implements NodeType { public Node parent; @@ -33,8 +34,12 @@ public abstract class Node implements NodeType { return 1 << getType(); } - protected void setChild(final Node tgt){} // default definition - protected Node getChild(){return null;} // default definition + protected void setChild(final Node tgt) { + //empty, default definition + } + protected Node getChild() { + return null; // default definition + } public void swap(final Node with) { Node tmp; @@ -46,9 +51,13 @@ public abstract class Node implements NodeType { //setChild(with.getChild()); //with.setChild(tmp); - if (parent != null) parent.setChild(with); + if (parent != null) { + parent.setChild(with); + } - if (with.parent != null) with.parent.setChild(this); + if (with.parent != null) { + with.parent.setChild(this); + } tmp = parent; parent = with.parent; @@ -81,16 +90,22 @@ public abstract class Node implements NodeType { } protected static String pad(final Object value, final int level) { - if (value == null) return "NULL"; + if (value == null) { + return "NULL"; + } final StringBuilder pad = new StringBuilder(" "); - for (int i=0; i { public ObjPtr() { this(null); diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/exception/ErrorMessages.java b/src/jdk/nashorn/internal/runtime/regexp/joni/exception/ErrorMessages.java index 66ec0cfe..3c835d7b 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/exception/ErrorMessages.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/exception/ErrorMessages.java @@ -19,6 +19,7 @@ */ package jdk.nashorn.internal.runtime.regexp.joni.exception; +@SuppressWarnings("javadoc") public interface ErrorMessages { /* from jcodings */ diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/exception/InternalException.java b/src/jdk/nashorn/internal/runtime/regexp/joni/exception/InternalException.java index 6f2b024f..22642dd0 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/exception/InternalException.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/exception/InternalException.java @@ -19,6 +19,7 @@ */ package jdk.nashorn.internal.runtime.regexp.joni.exception; +@SuppressWarnings("javadoc") public class InternalException extends JOniException{ private static final long serialVersionUID = -3871816465397927992L; diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/exception/JOniException.java b/src/jdk/nashorn/internal/runtime/regexp/joni/exception/JOniException.java index 8024a567..537bf0f3 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/exception/JOniException.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/exception/JOniException.java @@ -19,6 +19,7 @@ */ package jdk.nashorn.internal.runtime.regexp.joni.exception; +@SuppressWarnings("javadoc") public class JOniException extends RuntimeException{ private static final long serialVersionUID = -6027192180014164667L; diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/exception/SyntaxException.java b/src/jdk/nashorn/internal/runtime/regexp/joni/exception/SyntaxException.java index 172e7880..4698ab76 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/exception/SyntaxException.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/exception/SyntaxException.java @@ -19,6 +19,7 @@ */ package jdk.nashorn.internal.runtime.regexp.joni.exception; +@SuppressWarnings("javadoc") public class SyntaxException extends JOniException{ private static final long serialVersionUID = 7862720128961874288L; diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/exception/ValueException.java b/src/jdk/nashorn/internal/runtime/regexp/joni/exception/ValueException.java index 1ed57d4e..75b590ec 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/exception/ValueException.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/exception/ValueException.java @@ -19,7 +19,8 @@ */ package jdk.nashorn.internal.runtime.regexp.joni.exception; -public class ValueException extends SyntaxException{ +@SuppressWarnings("javadoc") +public class ValueException extends SyntaxException { private static final long serialVersionUID = -196013852479929134L; public ValueException(final String message) { diff --git a/test/src/jdk/nashorn/api/javaaccess/ArrayConversionTest.java b/test/src/jdk/nashorn/api/javaaccess/ArrayConversionTest.java index 6997599e..1da767b7 100644 --- a/test/src/jdk/nashorn/api/javaaccess/ArrayConversionTest.java +++ b/test/src/jdk/nashorn/api/javaaccess/ArrayConversionTest.java @@ -29,7 +29,6 @@ import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertFalse; import static org.testng.AssertJUnit.assertNull; import static org.testng.AssertJUnit.assertTrue; - import java.util.Arrays; import java.util.List; import javax.script.ScriptContext; @@ -41,6 +40,7 @@ import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +@SuppressWarnings("javadoc") public class ArrayConversionTest { private static ScriptEngine e = null; @@ -49,7 +49,7 @@ public class ArrayConversionTest { } @BeforeClass - public static void setUpClass() throws ScriptException { + public static void setUpClass() { e = new ScriptEngineManager().getEngineByName("nashorn"); } @@ -205,7 +205,7 @@ public class ArrayConversionTest { assertEquals(Arrays.asList("apple", "orange"), array[1]); } - public static void assertVarArg_42_17(final Object... args) throws ScriptException { + public static void assertVarArg_42_17(final Object... args) { assertEquals(2, args.length); assertEquals(42, ((Number)args[0]).intValue()); assertEquals(17, ((Number)args[1]).intValue()); diff --git a/test/src/jdk/nashorn/api/javaaccess/BooleanAccessTest.java b/test/src/jdk/nashorn/api/javaaccess/BooleanAccessTest.java index 19873564..234484f7 100644 --- a/test/src/jdk/nashorn/api/javaaccess/BooleanAccessTest.java +++ b/test/src/jdk/nashorn/api/javaaccess/BooleanAccessTest.java @@ -27,7 +27,6 @@ package jdk.nashorn.api.javaaccess; import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertTrue; - import java.util.Arrays; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; @@ -42,6 +41,7 @@ import org.testng.annotations.Test; * @build jdk.nashorn.api.javaaccess.SharedObject jdk.nashorn.api.javaaccess.Person jdk.nashorn.api.javaaccess.BooleanAccessTest * @run testng/othervm jdk.nashorn.api.javaaccess.BooleanAccessTest */ +@SuppressWarnings("javadoc") public class BooleanAccessTest { private static ScriptEngine e = null; diff --git a/test/src/jdk/nashorn/api/javaaccess/ConsStringTest.java b/test/src/jdk/nashorn/api/javaaccess/ConsStringTest.java index 3b1fa2c7..2b12b046 100644 --- a/test/src/jdk/nashorn/api/javaaccess/ConsStringTest.java +++ b/test/src/jdk/nashorn/api/javaaccess/ConsStringTest.java @@ -26,7 +26,6 @@ package jdk.nashorn.api.javaaccess; import static org.testng.AssertJUnit.assertEquals; - import java.util.HashMap; import java.util.Map; import javax.script.Bindings; @@ -40,6 +39,7 @@ import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +@SuppressWarnings("javadoc") public class ConsStringTest { private static ScriptEngine e = null; @@ -48,7 +48,7 @@ public class ConsStringTest { } @BeforeClass - public static void setUpClass() throws ScriptException { + public static void setUpClass() { e = new ScriptEngineManager().getEngineByName("nashorn"); } @@ -69,7 +69,7 @@ public class ConsStringTest { @Test public void testConsStringFromMirror() throws ScriptException { final Bindings b = e.getBindings(ScriptContext.ENGINE_SCOPE); - final Map m = new HashMap<>(); + //final Map m = new HashMap<>(); e.eval("var x = 'f'; x += 'oo'; var obj = {x: x};"); assertEquals("foo", ((JSObject)b.get("obj")).getMember("x")); } diff --git a/test/src/jdk/nashorn/api/javaaccess/MethodAccessTest.java b/test/src/jdk/nashorn/api/javaaccess/MethodAccessTest.java index 4be66b81..8bac7e6a 100644 --- a/test/src/jdk/nashorn/api/javaaccess/MethodAccessTest.java +++ b/test/src/jdk/nashorn/api/javaaccess/MethodAccessTest.java @@ -28,7 +28,6 @@ package jdk.nashorn.api.javaaccess; import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertTrue; import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals; - import java.util.Arrays; import java.util.Calendar; import java.util.Locale; @@ -45,6 +44,7 @@ import org.testng.annotations.Test; * @build jdk.nashorn.api.javaaccess.SharedObject jdk.nashorn.api.javaaccess.Person jdk.nashorn.api.javaaccess.MethodAccessTest * @run testng/othervm jdk.nashorn.api.javaaccess.MethodAccessTest */ +@SuppressWarnings("javadoc") public class MethodAccessTest { private static ScriptEngine e = null; diff --git a/test/src/jdk/nashorn/api/javaaccess/NumberAccessTest.java b/test/src/jdk/nashorn/api/javaaccess/NumberAccessTest.java index 225891b7..fd4ab9da 100644 --- a/test/src/jdk/nashorn/api/javaaccess/NumberAccessTest.java +++ b/test/src/jdk/nashorn/api/javaaccess/NumberAccessTest.java @@ -28,7 +28,6 @@ package jdk.nashorn.api.javaaccess; import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertTrue; import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals; - import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; @@ -42,6 +41,7 @@ import org.testng.annotations.Test; * @build jdk.nashorn.api.javaaccess.SharedObject jdk.nashorn.api.javaaccess.Person jdk.nashorn.api.javaaccess.NumberAccessTest * @run testng/othervm jdk.nashorn.api.javaaccess.NumberAccessTest */ +@SuppressWarnings("javadoc") public class NumberAccessTest { private static ScriptEngine e; diff --git a/test/src/jdk/nashorn/api/javaaccess/NumberBoxingTest.java b/test/src/jdk/nashorn/api/javaaccess/NumberBoxingTest.java index 826368cd..40db6845 100644 --- a/test/src/jdk/nashorn/api/javaaccess/NumberBoxingTest.java +++ b/test/src/jdk/nashorn/api/javaaccess/NumberBoxingTest.java @@ -27,7 +27,6 @@ package jdk.nashorn.api.javaaccess; import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertTrue; - import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; @@ -41,6 +40,7 @@ import org.testng.annotations.Test; * @build jdk.nashorn.api.javaaccess.SharedObject jdk.nashorn.api.javaaccess.Person jdk.nashorn.api.javaaccess.NumberBoxingTest * @run testng/othervm jdk.nashorn.api.javaaccess.NumberBoxingTest */ +@SuppressWarnings("javadoc") public class NumberBoxingTest { private static ScriptEngine e; diff --git a/test/src/jdk/nashorn/api/javaaccess/ObjectAccessTest.java b/test/src/jdk/nashorn/api/javaaccess/ObjectAccessTest.java index 9c1fa114..00798a4e 100644 --- a/test/src/jdk/nashorn/api/javaaccess/ObjectAccessTest.java +++ b/test/src/jdk/nashorn/api/javaaccess/ObjectAccessTest.java @@ -27,7 +27,6 @@ package jdk.nashorn.api.javaaccess; import static org.testng.AssertJUnit.assertEquals; import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals; - import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; @@ -41,6 +40,7 @@ import org.testng.annotations.Test; * @build jdk.nashorn.api.javaaccess.SharedObject jdk.nashorn.api.javaaccess.Person jdk.nashorn.api.javaaccess.ObjectAccessTest * @run testng/othervm jdk.nashorn.api.javaaccess.ObjectAccessTest */ +@SuppressWarnings("javadoc") public class ObjectAccessTest { private static ScriptEngine e = null; diff --git a/test/src/jdk/nashorn/api/javaaccess/Person.java b/test/src/jdk/nashorn/api/javaaccess/Person.java index 9012e636..32b1c9b7 100644 --- a/test/src/jdk/nashorn/api/javaaccess/Person.java +++ b/test/src/jdk/nashorn/api/javaaccess/Person.java @@ -25,6 +25,7 @@ package jdk.nashorn.api.javaaccess; +@SuppressWarnings("javadoc") public class Person { public int id = 0; diff --git a/test/src/jdk/nashorn/api/javaaccess/SharedObject.java b/test/src/jdk/nashorn/api/javaaccess/SharedObject.java index b4003537..93c93e19 100644 --- a/test/src/jdk/nashorn/api/javaaccess/SharedObject.java +++ b/test/src/jdk/nashorn/api/javaaccess/SharedObject.java @@ -29,6 +29,7 @@ import javax.script.Invocable; import javax.script.ScriptEngine; import javax.script.ScriptException; +@SuppressWarnings("javadoc") public class SharedObject { // Public fields diff --git a/test/src/jdk/nashorn/api/javaaccess/StringAccessTest.java b/test/src/jdk/nashorn/api/javaaccess/StringAccessTest.java index 7b6a11f1..1e0a96aa 100644 --- a/test/src/jdk/nashorn/api/javaaccess/StringAccessTest.java +++ b/test/src/jdk/nashorn/api/javaaccess/StringAccessTest.java @@ -27,7 +27,6 @@ package jdk.nashorn.api.javaaccess; import static org.testng.AssertJUnit.assertEquals; import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals; - import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; @@ -41,6 +40,7 @@ import org.testng.annotations.Test; * @build jdk.nashorn.api.javaaccess.SharedObject jdk.nashorn.api.javaaccess.Person jdk.nashorn.api.javaaccess.StringAccessTest * @run testng/othervm jdk.nashorn.api.javaaccess.StringAccessTest */ +@SuppressWarnings("javadoc") public class StringAccessTest { private static ScriptEngine e = null; diff --git a/test/src/jdk/nashorn/api/scripting/InvocableTest.java b/test/src/jdk/nashorn/api/scripting/InvocableTest.java index d94aa464..4e44a296 100644 --- a/test/src/jdk/nashorn/api/scripting/InvocableTest.java +++ b/test/src/jdk/nashorn/api/scripting/InvocableTest.java @@ -27,7 +27,6 @@ package jdk.nashorn.api.scripting; import static org.testng.Assert.assertEquals; import static org.testng.Assert.fail; - import java.util.Objects; import java.util.function.Function; import javax.script.Invocable; @@ -42,9 +41,10 @@ import org.testng.annotations.Test; /** * Tests for javax.script.Invocable implementation of nashorn. */ +@SuppressWarnings("javadoc") public class InvocableTest { - private void log(final String msg) { + private static void log(final String msg) { org.testng.Reporter.log(msg, true); } @@ -100,7 +100,7 @@ public class InvocableTest { try { final Object obj = e.eval("({})"); - final Object res = ((Invocable) e).invokeMethod(obj, null); + ((Invocable) e).invokeMethod(obj, null); fail("should have thrown NPE"); } catch (final Exception exp) { if (!(exp instanceof NullPointerException)) { @@ -120,7 +120,7 @@ public class InvocableTest { try { final Object obj = e.eval("({})"); - final Object res = ((Invocable) e).invokeMethod(obj, "nonExistentMethod"); + ((Invocable) e).invokeMethod(obj, "nonExistentMethod"); fail("should have thrown NoSuchMethodException"); } catch (final Exception exp) { if (!(exp instanceof NoSuchMethodException)) { @@ -398,7 +398,7 @@ public class InvocableTest { final ScriptEngine e = m.getEngineByName("nashorn"); try { - final Object res = ((Invocable) e).invokeFunction(null); + ((Invocable)e).invokeFunction(null); fail("should have thrown NPE"); } catch (final Exception exp) { if (!(exp instanceof NullPointerException)) { @@ -418,7 +418,7 @@ public class InvocableTest { final ScriptEngine e = m.getEngineByName("nashorn"); try { - final Object res = ((Invocable) e).invokeFunction("NonExistentFunc"); + ((Invocable)e).invokeFunction("NonExistentFunc"); fail("should have thrown NoSuchMethodException"); } catch (final Exception exp) { if (!(exp instanceof NoSuchMethodException)) { @@ -439,7 +439,7 @@ public class InvocableTest { try { // define an object with method on it - final Object obj = e.eval("function hello() { return 'Hello World!'; }"); + e.eval("function hello() { return 'Hello World!'; }"); final ScriptContext ctxt = new SimpleScriptContext(); ctxt.setBindings(e.createBindings(), ScriptContext.ENGINE_SCOPE); // change engine's current context @@ -526,13 +526,13 @@ public class InvocableTest { } @Test - @SuppressWarnings("unchecked") public void defaultMethodTest() throws ScriptException { final ScriptEngineManager m = new ScriptEngineManager(); final ScriptEngine e = m.getEngineByName("nashorn"); final Invocable inv = (Invocable) e; final Object obj = e.eval("({ apply: function(arg) { return arg.toUpperCase(); }})"); + @SuppressWarnings("unchecked") final Function func = inv.getInterface(obj, Function.class); assertEquals(func.apply("hello"), "HELLO"); } diff --git a/test/src/jdk/nashorn/api/scripting/MultipleEngineTest.java b/test/src/jdk/nashorn/api/scripting/MultipleEngineTest.java index f72f8e61..218deff1 100644 --- a/test/src/jdk/nashorn/api/scripting/MultipleEngineTest.java +++ b/test/src/jdk/nashorn/api/scripting/MultipleEngineTest.java @@ -37,7 +37,7 @@ import org.testng.annotations.Test; * @test * @run testng jdk.nashorn.api.scripting.MultipleEngineTest */ - +@SuppressWarnings("javadoc") public class MultipleEngineTest { @Test public void createAndUseManyEngine() throws ScriptException { diff --git a/test/src/jdk/nashorn/api/scripting/PluggableJSObjectTest.java b/test/src/jdk/nashorn/api/scripting/PluggableJSObjectTest.java index 4e910ff9..b277bdef 100644 --- a/test/src/jdk/nashorn/api/scripting/PluggableJSObjectTest.java +++ b/test/src/jdk/nashorn/api/scripting/PluggableJSObjectTest.java @@ -44,6 +44,7 @@ import org.testng.annotations.Test; * JDK-8024615: Refactor ScriptObjectMirror and JSObject to support external * JSObject implementations. */ +@SuppressWarnings("javadoc") public class PluggableJSObjectTest { public static class MapWrapperObject extends AbstractJSObject { private final HashMap map = new LinkedHashMap<>(); @@ -202,6 +203,7 @@ public class PluggableJSObjectTest { } public static class Factory extends AbstractJSObject { + @SuppressWarnings("unused") @Override public Object newObject(final Object... args) { return new HashMap(); diff --git a/test/src/jdk/nashorn/api/scripting/ScopeTest.java b/test/src/jdk/nashorn/api/scripting/ScopeTest.java index 3e2a6b6e..4e1dfe78 100644 --- a/test/src/jdk/nashorn/api/scripting/ScopeTest.java +++ b/test/src/jdk/nashorn/api/scripting/ScopeTest.java @@ -28,7 +28,6 @@ import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; - import javax.script.Bindings; import javax.script.ScriptContext; import javax.script.ScriptEngine; @@ -42,6 +41,7 @@ import org.testng.annotations.Test; /** * Tests for jsr223 Bindings "scope" (engine, global scopes) */ +@SuppressWarnings("javadoc") public class ScopeTest { @Test @@ -655,6 +655,8 @@ public class ScopeTest { /** * Test "slow" scopes involving {@code with} and {@code eval} statements for shared script classes with multiple globals. + * @throws ScriptException + * @throws InterruptedException */ @Test public static void testSlowScope() throws ScriptException, InterruptedException { diff --git a/test/src/jdk/nashorn/api/scripting/ScriptEngineSecurityTest.java b/test/src/jdk/nashorn/api/scripting/ScriptEngineSecurityTest.java index 226832e7..06b89e83 100644 --- a/test/src/jdk/nashorn/api/scripting/ScriptEngineSecurityTest.java +++ b/test/src/jdk/nashorn/api/scripting/ScriptEngineSecurityTest.java @@ -26,12 +26,9 @@ package jdk.nashorn.api.scripting; import static org.testng.Assert.fail; - import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; -import java.util.Objects; -import javax.script.Invocable; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; @@ -40,9 +37,10 @@ import org.testng.annotations.Test; /** * jsr223 tests for security access checks. */ +@SuppressWarnings("javadoc") public class ScriptEngineSecurityTest { - private void log(final String msg) { + private static void log(final String msg) { org.testng.Reporter.log(msg, true); } @@ -169,6 +167,7 @@ public class ScriptEngineSecurityTest { } // @bug 8032948: Nashorn linkages awry + @SuppressWarnings("serial") public static class FakeProxy extends Proxy { public FakeProxy(final InvocationHandler ih) { super(ih); @@ -180,7 +179,7 @@ public class ScriptEngineSecurityTest { } @Test - public void fakeProxySubclassAccessCheckTest() throws ScriptException { + public void fakeProxySubclassAccessCheckTest() { if (System.getSecurityManager() == null) { // pass vacuously return; @@ -197,7 +196,7 @@ public class ScriptEngineSecurityTest { // Should not be able to call static methods of Proxy via fake subclass try { - final Class c = (Class)e.eval(getClass); + e.eval(getClass); fail("should have thrown SecurityException"); } catch (final Exception exp) { if (! (exp instanceof SecurityException)) { @@ -207,7 +206,7 @@ public class ScriptEngineSecurityTest { } @Test - public void fakeProxySubclassAccessCheckTest2() throws ScriptException { + public void fakeProxySubclassAccessCheckTest2() { if (System.getSecurityManager() == null) { // pass vacuously return; @@ -224,7 +223,7 @@ public class ScriptEngineSecurityTest { // Should not be able to call static methods of Proxy via fake subclass try { - final Class c = (Class)e.eval(getClass); + e.eval(getClass); fail("should have thrown SecurityException"); } catch (final Exception exp) { if (! (exp instanceof SecurityException)) { @@ -234,7 +233,7 @@ public class ScriptEngineSecurityTest { } @Test - public static void proxyStaticAccessCheckTest() throws ScriptException { + public static void proxyStaticAccessCheckTest() { if (System.getSecurityManager() == null) { // pass vacuously return; @@ -247,7 +246,7 @@ public class ScriptEngineSecurityTest { new Class[] { Runnable.class }, new InvocationHandler() { @Override - public Object invoke(final Object p, final Method m, final Object[] a) { + public Object invoke(final Object p, final Method mtd, final Object[] a) { return null; } }); @@ -284,7 +283,9 @@ public class ScriptEngineSecurityTest { } }); fail("SecurityException should have been thrown"); - } catch (final SecurityException exp) {} + } catch (final SecurityException e) { + //empty + } } @Test @@ -303,6 +304,8 @@ public class ScriptEngineSecurityTest { } }); fail("SecurityException should have been thrown"); - } catch (final SecurityException exp) {} + } catch (final SecurityException e) { + //empty + } } } diff --git a/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java b/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java index 124b5a92..a066d6b3 100644 --- a/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java +++ b/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java @@ -29,7 +29,6 @@ import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; - import java.io.StringReader; import java.io.StringWriter; import java.lang.reflect.InvocationHandler; @@ -54,9 +53,10 @@ import org.testng.annotations.Test; * @build jdk.nashorn.api.scripting.Window jdk.nashorn.api.scripting.WindowEventHandler jdk.nashorn.api.scripting.VariableArityTestInterface jdk.nashorn.api.scripting.ScriptEngineTest * @run testng/othervm jdk.nashorn.api.scripting.ScriptEngineTest */ +@SuppressWarnings("javadoc") public class ScriptEngineTest { - private void log(final String msg) { + private static void log(final String msg) { org.testng.Reporter.log(msg, true); } @@ -145,6 +145,8 @@ public class ScriptEngineTest { case "nashorn": seenNashorn = true; break; case "javascript": seenJavaScript = true; break; case "ECMAScript": seenECMAScript = true; break; + default: + break; } } @@ -159,6 +161,8 @@ public class ScriptEngineTest { case "application/ecmascript": seenAppECMA = true; break; case "text/javascript": seenTextJS = true; break; case "text/ecmascript": seenTextECMA = true; break; + default: + break; } } @@ -548,7 +552,7 @@ public class ScriptEngineTest { new Class[] { Runnable.class }, new InvocationHandler() { @Override - public Object invoke(final Object p, final Method m, final Object[] a) { + public Object invoke(final Object p, final Method mtd, final Object[] a) { reached[0] = true; return null; } @@ -633,7 +637,7 @@ public class ScriptEngineTest { public static class Context { private Object myobj; - public void set(Object o) { + public void set(final Object o) { myobj = o; } diff --git a/test/src/jdk/nashorn/api/scripting/ScriptObjectMirrorTest.java b/test/src/jdk/nashorn/api/scripting/ScriptObjectMirrorTest.java index dc347443..ce3b421c 100644 --- a/test/src/jdk/nashorn/api/scripting/ScriptObjectMirrorTest.java +++ b/test/src/jdk/nashorn/api/scripting/ScriptObjectMirrorTest.java @@ -46,6 +46,7 @@ import org.testng.annotations.Test; /** * Tests to check jdk.nashorn.api.scripting.ScriptObjectMirror API. */ +@SuppressWarnings("javadoc") public class ScriptObjectMirrorTest { @SuppressWarnings("unchecked") @@ -343,14 +344,13 @@ public class ScriptObjectMirrorTest { assertEquals(ScriptObjectMirror.class, value3.getClass()); assertEquals(ScriptObjectMirror.class, value4.getClass()); assertTrue((boolean)invocable.invokeFunction("compare", value1, value1)); - assertTrue((boolean)example.compare(value1, value1)); + assertTrue(example.compare(value1, value1)); assertTrue((boolean)invocable.invokeFunction("compare", value3, value4)); - assertTrue((boolean)example.compare(value3, value4)); + assertTrue(example.compare(value3, value4)); } // @bug 8053910: ScriptObjectMirror causing havoc with Invocation interface @Test - @SuppressWarnings("unchecked") public void mirrorUnwrapInterfaceMethod() throws Exception { final ScriptEngineManager engineManager = new ScriptEngineManager(); final ScriptEngine engine = engineManager.getEngineByName("nashorn"); @@ -358,6 +358,7 @@ public class ScriptObjectMirrorTest { engine.eval("function apply(obj) { " + " return obj instanceof Packages.jdk.nashorn.api.scripting.ScriptObjectMirror; " + "}"); + @SuppressWarnings("unchecked") final Function func = invocable.getInterface(Function.class); assertFalse((boolean)func.apply(engine.eval("({ x: 2 })"))); } diff --git a/test/src/jdk/nashorn/api/scripting/VariableArityTestInterface.java b/test/src/jdk/nashorn/api/scripting/VariableArityTestInterface.java index d3904522..8ce5e490 100644 --- a/test/src/jdk/nashorn/api/scripting/VariableArityTestInterface.java +++ b/test/src/jdk/nashorn/api/scripting/VariableArityTestInterface.java @@ -25,6 +25,7 @@ package jdk.nashorn.api.scripting; +@SuppressWarnings("javadoc") public interface VariableArityTestInterface { public String test1(int i, String... strings); public String test2(int i, String... strings); diff --git a/test/src/jdk/nashorn/api/scripting/Window.java b/test/src/jdk/nashorn/api/scripting/Window.java index 510c5dae..7a7476f5 100644 --- a/test/src/jdk/nashorn/api/scripting/Window.java +++ b/test/src/jdk/nashorn/api/scripting/Window.java @@ -28,6 +28,7 @@ package jdk.nashorn.api.scripting; import java.util.Map; import javax.script.Bindings; +@SuppressWarnings("javadoc") public class Window { private String location = "http://localhost:8080/window"; diff --git a/test/src/jdk/nashorn/api/scripting/WindowEventHandler.java b/test/src/jdk/nashorn/api/scripting/WindowEventHandler.java index 88892994..dfcad5a9 100644 --- a/test/src/jdk/nashorn/api/scripting/WindowEventHandler.java +++ b/test/src/jdk/nashorn/api/scripting/WindowEventHandler.java @@ -25,8 +25,7 @@ package jdk.nashorn.api.scripting; +@SuppressWarnings("javadoc") public interface WindowEventHandler { - public boolean loaded(); - } diff --git a/test/src/jdk/nashorn/internal/codegen/CompilerTest.java b/test/src/jdk/nashorn/internal/codegen/CompilerTest.java index dadeb15f..61d896b6 100644 --- a/test/src/jdk/nashorn/internal/codegen/CompilerTest.java +++ b/test/src/jdk/nashorn/internal/codegen/CompilerTest.java @@ -27,7 +27,6 @@ package jdk.nashorn.internal.codegen; import static jdk.nashorn.internal.runtime.Source.readFully; import static jdk.nashorn.internal.runtime.Source.sourceFor; - import java.io.File; import java.io.PrintWriter; import java.io.StringWriter; @@ -45,6 +44,7 @@ import org.testng.annotations.Test; /** * Tests to check Nashorn JS compiler - just compiler and not execution of scripts. */ +@SuppressWarnings("javadoc") public class CompilerTest { private static final boolean VERBOSE = Boolean.valueOf(System.getProperty("compilertest.verbose")); private static final boolean TEST262 = Boolean.valueOf(System.getProperty("compilertest.test262")); @@ -56,7 +56,7 @@ public class CompilerTest { public boolean exclude(File file, String content); } - private void log(final String msg) { + private static void log(final String msg) { org.testng.Reporter.log(msg, true); } diff --git a/test/src/jdk/nashorn/internal/parser/ParserTest.java b/test/src/jdk/nashorn/internal/parser/ParserTest.java index c9f6e417..110f6237 100644 --- a/test/src/jdk/nashorn/internal/parser/ParserTest.java +++ b/test/src/jdk/nashorn/internal/parser/ParserTest.java @@ -27,7 +27,6 @@ package jdk.nashorn.internal.parser; import static jdk.nashorn.internal.runtime.Source.readFully; import static jdk.nashorn.internal.runtime.Source.sourceFor; - import java.io.File; import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.ErrorManager; @@ -41,6 +40,7 @@ import org.testng.annotations.Test; /** * Run tests to check Nashorn's parser. */ +@SuppressWarnings("javadoc") public class ParserTest { private static final boolean VERBOSE = Boolean.valueOf(System.getProperty("parsertest.verbose")); private static final boolean TEST262 = Boolean.valueOf(System.getProperty("parsertest.test262")); diff --git a/test/src/jdk/nashorn/internal/performance/AuroraWrapper.java b/test/src/jdk/nashorn/internal/performance/AuroraWrapper.java index a3f4caa1..ccc3930e 100644 --- a/test/src/jdk/nashorn/internal/performance/AuroraWrapper.java +++ b/test/src/jdk/nashorn/internal/performance/AuroraWrapper.java @@ -43,6 +43,7 @@ import org.w3c.dom.Element; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; +@SuppressWarnings("javadoc") public class AuroraWrapper { public static String fileName = "report.xml"; diff --git a/test/src/jdk/nashorn/internal/performance/OctaneTest.java b/test/src/jdk/nashorn/internal/performance/OctaneTest.java index d1f79427..102ffc1a 100644 --- a/test/src/jdk/nashorn/internal/performance/OctaneTest.java +++ b/test/src/jdk/nashorn/internal/performance/OctaneTest.java @@ -40,6 +40,7 @@ import java.text.NumberFormat; import java.util.List; import org.testng.annotations.Test; +@SuppressWarnings("javadoc") public class OctaneTest { @Test @@ -72,7 +73,7 @@ public class OctaneTest { genericTest("GBEMU"); } - /* @Test +/* @Test public void mandreelTest() { genericTest("Mandreel"); }*/ @@ -107,10 +108,20 @@ public class OctaneTest { genericTest("Splay"); } + @Test +/* public void typeScriptTest() { + genericTest("TypeScript"); + } + + @Test + public void zlibTest() { + genericTest("zlib"); + }/*/ + public void genericTest(final String benchmark) { try { final String mainScript = "test/script/basic/run-octane.js"; - final String benchmarkScript = "test/script/external/octane/benchmarks/"+benchmark.toLowerCase() + ".js"; + final String benchmarkScript = "test/script/external/octane/benchmarks/" + benchmark.toLowerCase() + ".js"; final String[] args = { "--", benchmarkScript, diff --git a/test/src/jdk/nashorn/internal/performance/PerformanceWrapper.java b/test/src/jdk/nashorn/internal/performance/PerformanceWrapper.java index 2ffefbf1..cd3d322b 100644 --- a/test/src/jdk/nashorn/internal/performance/PerformanceWrapper.java +++ b/test/src/jdk/nashorn/internal/performance/PerformanceWrapper.java @@ -36,10 +36,7 @@ import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptRuntime; -/** - * - * @author Pavel Stepanov - */ +@SuppressWarnings("javadoc") public class PerformanceWrapper extends jdk.nashorn.tools.Shell { int _numberOfIterations; diff --git a/test/src/jdk/nashorn/internal/performance/SplayTest.java b/test/src/jdk/nashorn/internal/performance/SplayTest.java index e937a0f4..d80b1aa2 100644 --- a/test/src/jdk/nashorn/internal/performance/SplayTest.java +++ b/test/src/jdk/nashorn/internal/performance/SplayTest.java @@ -27,10 +27,7 @@ package jdk.nashorn.internal.performance; import org.testng.annotations.Test; -/** - * - * @author Pavel Stepanov - */ +@SuppressWarnings("javadoc") public class SplayTest { @Test diff --git a/test/src/jdk/nashorn/internal/runtime/ClassFilterTest.java b/test/src/jdk/nashorn/internal/runtime/ClassFilterTest.java index 7471731d..5c69141d 100644 --- a/test/src/jdk/nashorn/internal/runtime/ClassFilterTest.java +++ b/test/src/jdk/nashorn/internal/runtime/ClassFilterTest.java @@ -25,18 +25,17 @@ package jdk.nashorn.internal.runtime; +import static org.testng.Assert.fail; +import java.io.File; +import javax.script.ScriptEngine; +import javax.script.ScriptException; import jdk.nashorn.api.scripting.ClassFilter; import jdk.nashorn.api.scripting.NashornScriptEngineFactory; import jdk.nashorn.api.scripting.URLReader; import jdk.nashorn.internal.test.framework.TestFinder; import org.testng.annotations.Test; -import javax.script.ScriptEngine; -import javax.script.ScriptException; -import java.io.File; - -import static org.testng.Assert.fail; - +@SuppressWarnings("javadoc") public class ClassFilterTest { private static final String NASHORN_CODE_CACHE = "nashorn.persistent.code.cache"; private static final String CLASSFILTER_CODE_CACHE = "build/classfilter_nashorn_code_cache"; @@ -48,7 +47,7 @@ public class ClassFilterTest { // test contributes much. We need faster "ant clean test" cycle for // developers. public void runExternalJsTest() { - String[] paths = new String[]{ + final String[] paths = new String[]{ "test/script/basic/compile-octane.js", "test/script/basic/jquery.js", "test/script/basic/prototype.js", @@ -57,12 +56,12 @@ public class ClassFilterTest { "test/script/basic/yui.js", "test/script/basic/run-octane.js" }; - NashornScriptEngineFactory factory = new NashornScriptEngineFactory(); - for (String path : paths) { - ScriptEngine engine = factory.getScriptEngine(new String[]{"-scripting"}, getClass().getClassLoader(), getClassFilter()); + final NashornScriptEngineFactory factory = new NashornScriptEngineFactory(); + for (final String path : paths) { + final ScriptEngine engine = factory.getScriptEngine(new String[]{"-scripting"}, getClass().getClassLoader(), getClassFilter()); try { engine.eval(new URLReader(new File(path).toURI().toURL())); - } catch (Exception e) { + } catch (final Exception e) { fail("Script " + path + " fails with exception :" + e.getMessage()); } } @@ -70,12 +69,13 @@ public class ClassFilterTest { @Test public void noJavaOptionTest() { - NashornScriptEngineFactory factory = new NashornScriptEngineFactory(); - ScriptEngine engine = factory.getScriptEngine(new String[]{"--no-java"}, getClass().getClassLoader(), getClassFilter()); + final NashornScriptEngineFactory factory = new NashornScriptEngineFactory(); + final ScriptEngine engine = factory.getScriptEngine(new String[]{"--no-java"}, getClass().getClassLoader(), getClassFilter()); try { engine.eval("var str = Java.type('java.lang.String');"); fail("TypeError should have been thrown"); - } catch (ScriptException exc) { + } catch (final ScriptException e) { + //emtpy } } @@ -85,27 +85,31 @@ public class ClassFilterTest { return; } - NashornScriptEngineFactory factory = new NashornScriptEngineFactory(); - ScriptEngine engine = factory.getScriptEngine(getClassFilter()); + final NashornScriptEngineFactory factory = new NashornScriptEngineFactory(); + final ScriptEngine engine = factory.getScriptEngine(getClassFilter()); try { engine.eval("var thread = Java.type('sun.misc.Unsafe')"); fail("SecurityException should have been thrown"); - } catch (final Exception exc) { + } catch (final Exception e) { + //empty } try { engine.eval("var thread = new sun.misc.Unsafe()"); fail("SecurityException should have been thrown"); - } catch (final Exception exc) { + } catch (final Exception e) { + //empty } try { engine.eval("var thread = Java.extend(sun.misc.Unsafe, {})"); fail("TypeError should have been thrown"); - } catch (final Exception exc) { + } catch (final Exception e) { + //empty } try { engine.eval("java.lang.System.exit(0)"); fail("SecurityException should have been thrown"); - } catch (final Exception exc) { + } catch (final Exception e) { + //empty } } @@ -124,24 +128,24 @@ public class ClassFilterTest { } private void persistentCacheTestImpl() { - NashornScriptEngineFactory factory = new NashornScriptEngineFactory(); - ScriptEngine engine = factory.getScriptEngine( + final NashornScriptEngineFactory factory = new NashornScriptEngineFactory(); + final ScriptEngine engine = factory.getScriptEngine( TestFinder.addExplicitOptimisticTypes(new String[]{"--persistent-code-cache", "--optimistic-types=true"}), getClass().getClassLoader(), getClassFilter() ); - String testScript = "var a = Java.type('java.lang.String');" + generateCodeForPersistentStore(); + final String testScript = "var a = Java.type('java.lang.String');" + generateCodeForPersistentStore(); try { engine.eval(testScript); } catch (final ScriptException exc) { fail(exc.getMessage()); } - ScriptEngine engineSafe = factory.getScriptEngine( + final ScriptEngine engineSafe = factory.getScriptEngine( TestFinder.addExplicitOptimisticTypes(new String[]{"--persistent-code-cache", "--optimistic-types=true"}), getClass().getClassLoader(), new ClassFilter() { @Override - public boolean exposeToScripts(String s) { + public boolean exposeToScripts(final String s) { return false; } } @@ -156,8 +160,8 @@ public class ClassFilterTest { } } - private String generateCodeForPersistentStore() { - StringBuilder stringBuilder = new StringBuilder(); + private static String generateCodeForPersistentStore() { + final StringBuilder stringBuilder = new StringBuilder(); for (int i=0; i < 100; i++) { stringBuilder.append("function i") .append(i) @@ -170,10 +174,10 @@ public class ClassFilterTest { return stringBuilder.toString(); } - private ClassFilter getClassFilter() { + private static ClassFilter getClassFilter() { return new ClassFilter() { @Override - public boolean exposeToScripts(String s) { + public boolean exposeToScripts(final String s) { return true; } }; diff --git a/test/src/jdk/nashorn/internal/runtime/CodeStoreAndPathTest.java b/test/src/jdk/nashorn/internal/runtime/CodeStoreAndPathTest.java index 9175ef6d..4c069076 100644 --- a/test/src/jdk/nashorn/internal/runtime/CodeStoreAndPathTest.java +++ b/test/src/jdk/nashorn/internal/runtime/CodeStoreAndPathTest.java @@ -26,7 +26,6 @@ package jdk.nashorn.internal.runtime; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; - import java.io.File; import java.io.IOException; import java.nio.file.DirectoryStream; @@ -44,7 +43,7 @@ import org.testng.annotations.Test; * @summary Test for persistent code cache and path handling * @run testng jdk.nashorn.internal.runtime.CodeStoreAndPathTest */ - +@SuppressWarnings("javadoc") public class CodeStoreAndPathTest { final String code1 = "var code1; var x = 'Hello Script'; var x1 = 'Hello Script'; " @@ -98,19 +97,22 @@ public class CodeStoreAndPathTest { private static final String[] ENGINE_OPTIONS = new String[]{"--persistent-code-cache", "--optimistic-types=false", "--lazy-compilation=false"}; - public void checkCompiledScripts(final DirectoryStream stream, int numberOfScripts) throws IOException { - for (final Path file : stream) { - numberOfScripts--; + public void checkCompiledScripts(final DirectoryStream stream, final int numberOfScripts) throws IOException { + int n = numberOfScripts; + for (@SuppressWarnings("unused") final Path file : stream) { + n--; } stream.close(); - assertEquals(numberOfScripts,0); + assertEquals(n, 0); } @Test - public void pathHandlingTest() throws ScriptException, IOException { + public void pathHandlingTest() { System.setProperty("nashorn.persistent.code.cache", codeCache); final NashornScriptEngineFactory fac = new NashornScriptEngineFactory(); - final ScriptEngine e = fac.getScriptEngine(ENGINE_OPTIONS); + + fac.getScriptEngine(ENGINE_OPTIONS); + final Path expectedCodeCachePath = FileSystems.getDefault().getPath(oldUserDir + File.separator + codeCache); final Path actualCodeCachePath = FileSystems.getDefault().getPath(System.getProperty( "nashorn.persistent.code.cache")).toAbsolutePath(); diff --git a/test/src/jdk/nashorn/internal/runtime/ContextTest.java b/test/src/jdk/nashorn/internal/runtime/ContextTest.java index 8e17e34a..6770d7ec 100644 --- a/test/src/jdk/nashorn/internal/runtime/ContextTest.java +++ b/test/src/jdk/nashorn/internal/runtime/ContextTest.java @@ -29,7 +29,6 @@ import static jdk.nashorn.internal.runtime.Source.sourceFor; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; - import java.util.Map; import jdk.nashorn.internal.objects.Global; import jdk.nashorn.internal.runtime.options.Options; @@ -41,6 +40,7 @@ import org.testng.annotations.Test; * @test * @run testng jdk.nashorn.internal.runtime.ContextTest */ +@SuppressWarnings("javadoc") public class ContextTest { // basic context eval test @Test @@ -96,7 +96,7 @@ public class ContextTest { final String code = "var obj = { x: 344, y: 42 }"; eval(cx, "", code); - final Object obj = cx.getGlobal().get("obj"); + final Object obj = Context.getGlobal().get("obj"); assertTrue(obj instanceof ScriptObject); @@ -129,7 +129,7 @@ public class ContextTest { } } - private Object eval(final Context cx, final String name, final String code) { + private static Object eval(final Context cx, final String name, final String code) { final Source source = sourceFor(name, code); final ScriptObject global = Context.getGlobal(); final ScriptFunction func = cx.compileScript(source, global); diff --git a/test/src/jdk/nashorn/internal/runtime/ExceptionsNotSerializable.java b/test/src/jdk/nashorn/internal/runtime/ExceptionsNotSerializable.java index e00672a3..3b6d91b2 100644 --- a/test/src/jdk/nashorn/internal/runtime/ExceptionsNotSerializable.java +++ b/test/src/jdk/nashorn/internal/runtime/ExceptionsNotSerializable.java @@ -27,7 +27,6 @@ package jdk.nashorn.internal.runtime; import static org.testng.Assert.assertEquals; import static org.testng.Assert.fail; - import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.NotSerializableException; @@ -43,6 +42,7 @@ import org.testng.annotations.Test; * @test * @run testng jdk.nashorn.internal.runtime.ExceptionsNotSerializable */ +@SuppressWarnings("javadoc") public class ExceptionsNotSerializable { @Test public void rewriteExceptionNotSerializable() throws ScriptException { @@ -59,7 +59,7 @@ public class ExceptionsNotSerializable { } @Test - public void unwarrantedOptimismExceptionNotSerializable() throws IOException { + public void unwarrantedOptimismExceptionNotSerializable() { tryToSerialize(new UnwarrantedOptimismException(new Double(1.0), 128)); } diff --git a/test/src/jdk/nashorn/internal/runtime/NoPersistenceCachingTest.java b/test/src/jdk/nashorn/internal/runtime/NoPersistenceCachingTest.java index 3edf4c10..91f19606 100644 --- a/test/src/jdk/nashorn/internal/runtime/NoPersistenceCachingTest.java +++ b/test/src/jdk/nashorn/internal/runtime/NoPersistenceCachingTest.java @@ -25,7 +25,6 @@ package jdk.nashorn.internal.runtime; import static org.testng.Assert.fail; - import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.util.regex.Matcher; @@ -46,6 +45,7 @@ import org.testng.annotations.Test; * @summary Sanity tests for no persistence caching * @run testng/othervm jdk.nashorn.internal.runtime.NoPersistenceCachingTest */ +@SuppressWarnings("javadoc") public class NoPersistenceCachingTest { private ScriptEngine engine; @@ -102,6 +102,8 @@ public class NoPersistenceCachingTest { engine.eval(scriptThreeContexts, context2); engine.eval(scriptThreeContexts, context3); break; + default: + break; } } catch (final Exception se) { se.printStackTrace(); diff --git a/test/src/jdk/nashorn/internal/runtime/SourceTest.java b/test/src/jdk/nashorn/internal/runtime/SourceTest.java index eb837fb2..12645c05 100644 --- a/test/src/jdk/nashorn/internal/runtime/SourceTest.java +++ b/test/src/jdk/nashorn/internal/runtime/SourceTest.java @@ -29,7 +29,6 @@ import static jdk.nashorn.internal.runtime.Source.sourceFor; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; - import java.io.File; import java.io.IOException; import java.io.InputStreamReader; @@ -42,6 +41,7 @@ import org.testng.annotations.Test; /** * Tests different Source representations. */ +@SuppressWarnings("javadoc") public class SourceTest { final private static String SOURCE_NAME = "source.js"; @@ -104,11 +104,11 @@ public class SourceTest { } } - private Reader getReader(final String path) { + private static Reader getReader(final String path) { return new InputStreamReader(SourceTest.class.getResourceAsStream(path)); } - private void testSources(final Source source1, final Source source2) { + private static void testSources(final Source source1, final Source source2) { final char[] chars1 = source1.getContent(); final char[] chars2 = source2.getContent(); final String str1 = source1.getString(); diff --git a/test/src/jdk/nashorn/internal/runtime/TrustedScriptEngineTest.java b/test/src/jdk/nashorn/internal/runtime/TrustedScriptEngineTest.java index f7a18dcd..09c90dc6 100644 --- a/test/src/jdk/nashorn/internal/runtime/TrustedScriptEngineTest.java +++ b/test/src/jdk/nashorn/internal/runtime/TrustedScriptEngineTest.java @@ -28,7 +28,6 @@ package jdk.nashorn.internal.runtime; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; - import javax.script.ScriptContext; import javax.script.ScriptEngine; import javax.script.ScriptEngineFactory; @@ -42,6 +41,7 @@ import org.testng.annotations.Test; /** * Tests for trusted client usage of nashorn script engine factory extension API */ +@SuppressWarnings("javadoc") public class TrustedScriptEngineTest { @Test public void versionTest() { @@ -64,7 +64,7 @@ public class TrustedScriptEngineTest { public boolean reached() { return reached[0]; } - }; + } // These are for "private" extension API of NashornScriptEngineFactory that // accepts a ClassLoader and/or command line options. @@ -140,7 +140,8 @@ public class TrustedScriptEngineTest { // try nashorn specific extension e.eval("var f = funtion(x) 2*x;"); fail("should have thrown exception!"); - } catch (final ScriptException se) { + } catch (final Exception ex) { + //empty } return; } @@ -276,7 +277,9 @@ public class TrustedScriptEngineTest { try { fac.getScriptEngine((ClassFilter)null); fail("should have thrown NPE"); - } catch (NullPointerException npe) {} + } catch (final NullPointerException e) { + //empty + } } @Test @@ -285,7 +288,9 @@ public class TrustedScriptEngineTest { try { fac.getScriptEngine(new String[0], null, null); fail("should have thrown NPE"); - } catch (NullPointerException npe) {} + } catch (final NullPointerException e) { + //empty + } } @Test @@ -294,7 +299,9 @@ public class TrustedScriptEngineTest { try { fac.getScriptEngine((String[])null); fail("should have thrown NPE"); - } catch (NullPointerException npe) {} + } catch (final NullPointerException e) { + //empty + } } @Test @@ -308,7 +315,9 @@ public class TrustedScriptEngineTest { } }); fail("should have thrown NPE"); - } catch (NullPointerException npe) {} + } catch (final NullPointerException e) { + //empty + } } @Test diff --git a/test/src/jdk/nashorn/internal/runtime/regexp/joni/JoniTest.java b/test/src/jdk/nashorn/internal/runtime/regexp/joni/JoniTest.java index 7fb0d10e..616f769f 100644 --- a/test/src/jdk/nashorn/internal/runtime/regexp/joni/JoniTest.java +++ b/test/src/jdk/nashorn/internal/runtime/regexp/joni/JoniTest.java @@ -33,6 +33,7 @@ import org.testng.annotations.Test; * @test * @run testng jdk.nashorn.internal.runtime.regexp.joni.JoniTest */ +@SuppressWarnings("javadoc") public class JoniTest { @Test diff --git a/test/src/jdk/nashorn/internal/test/framework/AbstractScriptRunnable.java b/test/src/jdk/nashorn/internal/test/framework/AbstractScriptRunnable.java index 7dfb48d9..e8ca191d 100644 --- a/test/src/jdk/nashorn/internal/test/framework/AbstractScriptRunnable.java +++ b/test/src/jdk/nashorn/internal/test/framework/AbstractScriptRunnable.java @@ -34,7 +34,6 @@ import static jdk.nashorn.internal.test.framework.TestConfig.OPTIONS_IGNORE_STD_ import static jdk.nashorn.internal.test.framework.TestConfig.OPTIONS_RUN; import static jdk.nashorn.internal.test.framework.TestConfig.TEST_JS_FAIL_LIST; import static jdk.nashorn.internal.test.framework.TestConfig.TEST_JS_SHARED_CONTEXT; - import java.io.BufferedReader; import java.io.File; import java.io.IOException; @@ -50,6 +49,7 @@ import java.util.regex.Matcher; /** * Abstract class to compile and run one .js script file. */ +@SuppressWarnings("javadoc") public abstract class AbstractScriptRunnable { // some test scripts need a "framework" script - whose features are used // in the test script. This optional framework script can be null. @@ -274,14 +274,14 @@ public abstract class AbstractScriptRunnable { // compile and run this script protected abstract void execute(); - private boolean equalsCompilerMsgs(final String es, final String as) { + private static boolean equalsCompilerMsgs(final String es, final String as) { final int split = es.indexOf(':'); // Replace both types of separators ('/' and '\') with the one from // current environment return (split >= 0) && as.equals(es.substring(0, split).replaceAll("[/\\\\]", Matcher.quoteReplacement(File.separator)) + es.substring(split)); } - private void escape(final String value, final StringBuilder out) { + private static void escape(final String value, final StringBuilder out) { final int len = value.length(); for (int i = 0; i < len; i++) { final char ch = value.charAt(i); @@ -297,7 +297,7 @@ public abstract class AbstractScriptRunnable { } } - private String escape(final String value) { + private static String escape(final String value) { final StringBuilder sb = new StringBuilder(); escape(value, sb); return sb.toString(); diff --git a/test/src/jdk/nashorn/internal/test/framework/OrphanTestFinder.java b/test/src/jdk/nashorn/internal/test/framework/OrphanTestFinder.java index c9c567d9..74b5ccd7 100644 --- a/test/src/jdk/nashorn/internal/test/framework/OrphanTestFinder.java +++ b/test/src/jdk/nashorn/internal/test/framework/OrphanTestFinder.java @@ -34,6 +34,7 @@ import org.testng.annotations.Test; * Test case used by JSCompilerTest to complain if test files are marked as * neither test nor subtest. */ +@SuppressWarnings("javadoc") public final class OrphanTestFinder implements ITest { private final Set orphanFiles; diff --git a/test/src/jdk/nashorn/internal/test/framework/ParallelTestRunner.java b/test/src/jdk/nashorn/internal/test/framework/ParallelTestRunner.java index 0de5524a..2c206d7c 100644 --- a/test/src/jdk/nashorn/internal/test/framework/ParallelTestRunner.java +++ b/test/src/jdk/nashorn/internal/test/framework/ParallelTestRunner.java @@ -31,7 +31,6 @@ import static jdk.nashorn.internal.test.framework.TestConfig.TEST_JS_EXCLUDES_FI import static jdk.nashorn.internal.test.framework.TestConfig.TEST_JS_EXCLUDE_LIST; import static jdk.nashorn.internal.test.framework.TestConfig.TEST_JS_FRAMEWORK; import static jdk.nashorn.internal.test.framework.TestConfig.TEST_JS_ROOTS; - import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.File; @@ -73,6 +72,7 @@ import jdk.nashorn.internal.test.framework.TestFinder.TestFactory; * Parallel test runner runs tests in multiple threads - but avoids any dependency * on third-party test framework library such as TestNG. */ +@SuppressWarnings("javadoc") public class ParallelTestRunner { // ParallelTestRunner-specific @@ -247,7 +247,7 @@ public class ParallelTestRunner { } } - private void compare(final String outputFileName, final String expected, final boolean compareCompilerMsg) throws IOException { + private void compare(final String fileName, final String expected, final boolean compareCompilerMsg) throws IOException { final File expectedFile = new File(expected); BufferedReader expectedReader; @@ -257,7 +257,7 @@ public class ParallelTestRunner { expectedReader = new BufferedReader(new StringReader("")); } - final BufferedReader actual = new BufferedReader(new InputStreamReader(new FileInputStream(outputFileName))); + final BufferedReader actual = new BufferedReader(new InputStreamReader(new FileInputStream(fileName))); compare(actual, expectedReader, compareCompilerMsg); } @@ -434,8 +434,8 @@ public class ParallelTestRunner { public static void main(final String[] args) throws Exception { parseArgs(args); - while(new ParallelTestRunner().run()) { - ; + while (new ParallelTestRunner().run()) { + //empty } } diff --git a/test/src/jdk/nashorn/internal/test/framework/ScriptRunnable.java b/test/src/jdk/nashorn/internal/test/framework/ScriptRunnable.java index ee26061e..704b77c5 100644 --- a/test/src/jdk/nashorn/internal/test/framework/ScriptRunnable.java +++ b/test/src/jdk/nashorn/internal/test/framework/ScriptRunnable.java @@ -52,6 +52,7 @@ import org.testng.annotations.Test; * class. Optionally, output from running the script is compared against the * corresponding .EXPECTED file. */ +@SuppressWarnings("javadoc") public final class ScriptRunnable extends AbstractScriptRunnable implements ITest { public ScriptRunnable(final String framework, final File testFile, final List engineOptions, final Map testOptions, final List scriptArguments) { super(framework, testFile, engineOptions, testOptions, scriptArguments); diff --git a/test/src/jdk/nashorn/internal/test/framework/ScriptTest.java b/test/src/jdk/nashorn/internal/test/framework/ScriptTest.java index 219b3f99..70c2992f 100644 --- a/test/src/jdk/nashorn/internal/test/framework/ScriptTest.java +++ b/test/src/jdk/nashorn/internal/test/framework/ScriptTest.java @@ -26,7 +26,6 @@ package jdk.nashorn.internal.test.framework; import static jdk.nashorn.internal.test.framework.TestConfig.TEST_JS_INCLUDES; - import java.io.File; import java.util.ArrayList; import java.util.List; @@ -48,7 +47,9 @@ public final class ScriptTest { * Creates a test factory for the set of .js source tests. * * @return a Object[] of test objects. + * @throws Exception upon failure */ + @SuppressWarnings("static-method") @Factory public Object[] suite() throws Exception { Locale.setDefault(new Locale("")); diff --git a/test/src/jdk/nashorn/internal/test/framework/TestConfig.java b/test/src/jdk/nashorn/internal/test/framework/TestConfig.java index 3b623038..e539ee2a 100644 --- a/test/src/jdk/nashorn/internal/test/framework/TestConfig.java +++ b/test/src/jdk/nashorn/internal/test/framework/TestConfig.java @@ -28,6 +28,7 @@ package jdk.nashorn.internal.test.framework; /** * Configuration info for script tests. */ +@SuppressWarnings("javadoc") public interface TestConfig { // Test options inferred from various test @foo tags and passed to test factory. public static final String OPTIONS_RUN = "run"; diff --git a/test/src/jdk/nashorn/internal/test/framework/TestFinder.java b/test/src/jdk/nashorn/internal/test/framework/TestFinder.java index 018f4c7c..ab472d70 100644 --- a/test/src/jdk/nashorn/internal/test/framework/TestFinder.java +++ b/test/src/jdk/nashorn/internal/test/framework/TestFinder.java @@ -42,7 +42,6 @@ import static jdk.nashorn.internal.test.framework.TestConfig.TEST_JS_INCLUDES; import static jdk.nashorn.internal.test.framework.TestConfig.TEST_JS_LIST; import static jdk.nashorn.internal.test.framework.TestConfig.TEST_JS_ROOTS; import static jdk.nashorn.internal.test.framework.TestConfig.TEST_JS_UNCHECKED_DIR; - import java.io.BufferedReader; import java.io.File; import java.io.FileReader; @@ -76,6 +75,7 @@ import org.xml.sax.InputSource; * Utility class to find/parse script test files and to create 'test' instances. * Actual 'test' object type is decided by clients of this class. */ +@SuppressWarnings("javadoc") public final class TestFinder { private TestFinder() {} @@ -299,6 +299,8 @@ public final class TestFinder { case "@fork": fork = true; break; + default: + break; } // negative tests are expected to fail at runtime only @@ -377,7 +379,7 @@ public final class TestFinder { * * @args new argument list array */ - public static String[] addExplicitOptimisticTypes(String[] args) { + public static String[] addExplicitOptimisticTypes(final String[] args) { if (hasOptimisticOverride()) { final List newList = new ArrayList<>(Arrays.asList(args)); newList.add("--optimistic-types=" + Boolean.valueOf(OPTIMISTIC_OVERRIDE)); @@ -392,7 +394,7 @@ public final class TestFinder { * * @args argument list */ - public static void addExplicitOptimisticTypes(List args) { + public static void addExplicitOptimisticTypes(final List args) { if (hasOptimisticOverride()) { args.add("--optimistic-types=" + Boolean.valueOf(OPTIMISTIC_OVERRIDE)); } diff --git a/test/src/jdk/nashorn/internal/test/framework/TestHelper.java b/test/src/jdk/nashorn/internal/test/framework/TestHelper.java index bb16cf48..99e32802 100644 --- a/test/src/jdk/nashorn/internal/test/framework/TestHelper.java +++ b/test/src/jdk/nashorn/internal/test/framework/TestHelper.java @@ -36,6 +36,7 @@ import java.io.Reader; /** * Simple utilities to deal with build-dir, read/dump files etc. */ +@SuppressWarnings("javadoc") public abstract class TestHelper { public static final String TEST_ROOT = "test"; diff --git a/test/src/jdk/nashorn/internal/test/framework/TestReorderInterceptor.java b/test/src/jdk/nashorn/internal/test/framework/TestReorderInterceptor.java index 5efd6b9e..51da19c9 100644 --- a/test/src/jdk/nashorn/internal/test/framework/TestReorderInterceptor.java +++ b/test/src/jdk/nashorn/internal/test/framework/TestReorderInterceptor.java @@ -47,10 +47,9 @@ public final class TestReorderInterceptor implements IMethodInterceptor { final Object o2 = mi2.getInstance(); if (o1 instanceof ITest && o2 instanceof ITest) { return ((ITest)o1).getTestName().compareTo(((ITest)o2).getTestName()); - } else { - // something else, don't care about the order - return 0; } + // something else, don't care about the order + return 0; } }); diff --git a/test/src/jdk/nashorn/internal/test/models/InternalRunnable.java b/test/src/jdk/nashorn/internal/test/models/InternalRunnable.java index ed45139d..503d8f6e 100644 --- a/test/src/jdk/nashorn/internal/test/models/InternalRunnable.java +++ b/test/src/jdk/nashorn/internal/test/models/InternalRunnable.java @@ -28,6 +28,7 @@ package jdk.nashorn.internal.test.models; import java.io.PrintWriter; import java.io.StringWriter; +@SuppressWarnings("javadoc") public class InternalRunnable implements Runnable, RestrictedRunnable { // This is a public field in a restricted class; scripts should not see it. diff --git a/test/src/jdk/nashorn/internal/test/models/RestrictedRunnable.java b/test/src/jdk/nashorn/internal/test/models/RestrictedRunnable.java index 05fd52c0..aa5bfb77 100644 --- a/test/src/jdk/nashorn/internal/test/models/RestrictedRunnable.java +++ b/test/src/jdk/nashorn/internal/test/models/RestrictedRunnable.java @@ -27,8 +27,8 @@ package jdk.nashorn.internal.test.models; /** * Acts as a restricted interface implemented by a restricted class. - * */ +@SuppressWarnings("javadoc") public interface RestrictedRunnable { public void restrictedRun(); } diff --git a/test/src/jdk/nashorn/test/models/ClassWithFinalFinalizer.java b/test/src/jdk/nashorn/test/models/ClassWithFinalFinalizer.java index ba0d86d8..2d1906bf 100644 --- a/test/src/jdk/nashorn/test/models/ClassWithFinalFinalizer.java +++ b/test/src/jdk/nashorn/test/models/ClassWithFinalFinalizer.java @@ -25,7 +25,10 @@ package jdk.nashorn.test.models; +@SuppressWarnings("javadoc") public class ClassWithFinalFinalizer { + @Override protected final void finalize() { + //empty } } diff --git a/test/src/jdk/nashorn/test/models/ClassWithInheritedFinalFinalizer.java b/test/src/jdk/nashorn/test/models/ClassWithInheritedFinalFinalizer.java index 80393fbb..6a1f4d65 100644 --- a/test/src/jdk/nashorn/test/models/ClassWithInheritedFinalFinalizer.java +++ b/test/src/jdk/nashorn/test/models/ClassWithInheritedFinalFinalizer.java @@ -25,5 +25,7 @@ package jdk.nashorn.test.models; +@SuppressWarnings("javadoc") public class ClassWithInheritedFinalFinalizer extends ClassWithFinalFinalizer { + //empty } diff --git a/test/src/jdk/nashorn/test/models/ConstructorWithArgument.java b/test/src/jdk/nashorn/test/models/ConstructorWithArgument.java index f3985a22..1483a6e5 100644 --- a/test/src/jdk/nashorn/test/models/ConstructorWithArgument.java +++ b/test/src/jdk/nashorn/test/models/ConstructorWithArgument.java @@ -25,6 +25,7 @@ package jdk.nashorn.test.models; +@SuppressWarnings("javadoc") public abstract class ConstructorWithArgument { private final String token; diff --git a/test/src/jdk/nashorn/test/models/DessertTopping.java b/test/src/jdk/nashorn/test/models/DessertTopping.java index 591e032d..a4352499 100644 --- a/test/src/jdk/nashorn/test/models/DessertTopping.java +++ b/test/src/jdk/nashorn/test/models/DessertTopping.java @@ -25,6 +25,7 @@ package jdk.nashorn.test.models; +@SuppressWarnings("javadoc") public interface DessertTopping { public String pourOnDessert(); } diff --git a/test/src/jdk/nashorn/test/models/DessertToppingFloorWaxDriver.java b/test/src/jdk/nashorn/test/models/DessertToppingFloorWaxDriver.java index e3268544..f074ec3d 100644 --- a/test/src/jdk/nashorn/test/models/DessertToppingFloorWaxDriver.java +++ b/test/src/jdk/nashorn/test/models/DessertToppingFloorWaxDriver.java @@ -25,6 +25,7 @@ package jdk.nashorn.test.models; +@SuppressWarnings("javadoc") public class DessertToppingFloorWaxDriver { public void decorateDessert(final DessertTopping dt) { dt.pourOnDessert(); diff --git a/test/src/jdk/nashorn/test/models/FinalClass.java b/test/src/jdk/nashorn/test/models/FinalClass.java index 8a3e8432..3b759dd2 100644 --- a/test/src/jdk/nashorn/test/models/FinalClass.java +++ b/test/src/jdk/nashorn/test/models/FinalClass.java @@ -25,6 +25,7 @@ package jdk.nashorn.test.models; +@SuppressWarnings("javadoc") public final class FinalClass { //empty } diff --git a/test/src/jdk/nashorn/test/models/FloorWax.java b/test/src/jdk/nashorn/test/models/FloorWax.java index 44ac96e9..02439272 100644 --- a/test/src/jdk/nashorn/test/models/FloorWax.java +++ b/test/src/jdk/nashorn/test/models/FloorWax.java @@ -25,6 +25,7 @@ package jdk.nashorn.test.models; +@SuppressWarnings("javadoc") public interface FloorWax { public String shineUpTheFloor(); } diff --git a/test/src/jdk/nashorn/test/models/IntFloatOverloadSelection.java b/test/src/jdk/nashorn/test/models/IntFloatOverloadSelection.java index ed104ef3..52a74552 100644 --- a/test/src/jdk/nashorn/test/models/IntFloatOverloadSelection.java +++ b/test/src/jdk/nashorn/test/models/IntFloatOverloadSelection.java @@ -24,6 +24,7 @@ */ package jdk.nashorn.test.models; +@SuppressWarnings("javadoc") public class IntFloatOverloadSelection { public static String overloadedMethod(final int i) { diff --git a/test/src/jdk/nashorn/test/models/InternalRunnableSuperclass.java b/test/src/jdk/nashorn/test/models/InternalRunnableSuperclass.java index 24104c3d..3af717aa 100644 --- a/test/src/jdk/nashorn/test/models/InternalRunnableSuperclass.java +++ b/test/src/jdk/nashorn/test/models/InternalRunnableSuperclass.java @@ -30,8 +30,9 @@ import jdk.nashorn.internal.test.models.InternalRunnable; /** * Acts as a non-restricted superclass for a restricted class. - * */ + +@SuppressWarnings("javadoc") public class InternalRunnableSuperclass { public final int canSeeThisField = 19; diff --git a/test/src/jdk/nashorn/test/models/Jdk8011362TestSubject.java b/test/src/jdk/nashorn/test/models/Jdk8011362TestSubject.java index 99ab2581..d7f2a95f 100644 --- a/test/src/jdk/nashorn/test/models/Jdk8011362TestSubject.java +++ b/test/src/jdk/nashorn/test/models/Jdk8011362TestSubject.java @@ -26,8 +26,9 @@ package jdk.nashorn.test.models; /** - * Test class used by JDK-8011362.js. + * Test class used by JDK-8011362.js */ +@SuppressWarnings("javadoc") public class Jdk8011362TestSubject { // This is selected for overloaded("", null) public String overloaded(final String a, final String b) { diff --git a/test/src/jdk/nashorn/test/models/Nashorn401TestSubject.java b/test/src/jdk/nashorn/test/models/Nashorn401TestSubject.java index bffa2478..8d529442 100644 --- a/test/src/jdk/nashorn/test/models/Nashorn401TestSubject.java +++ b/test/src/jdk/nashorn/test/models/Nashorn401TestSubject.java @@ -25,6 +25,7 @@ package jdk.nashorn.test.models; +@SuppressWarnings("javadoc") public class Nashorn401TestSubject { public String method2(final int arg) { return "int method 2"; diff --git a/test/src/jdk/nashorn/test/models/NoAccessibleConstructorClass.java b/test/src/jdk/nashorn/test/models/NoAccessibleConstructorClass.java index f0ddb1aa..68ca4f88 100644 --- a/test/src/jdk/nashorn/test/models/NoAccessibleConstructorClass.java +++ b/test/src/jdk/nashorn/test/models/NoAccessibleConstructorClass.java @@ -25,6 +25,7 @@ package jdk.nashorn.test.models; +@SuppressWarnings("javadoc") public class NoAccessibleConstructorClass { NoAccessibleConstructorClass() { } } diff --git a/test/src/jdk/nashorn/test/models/OuterClass.java b/test/src/jdk/nashorn/test/models/OuterClass.java index fdfa5cd2..3d6f279a 100644 --- a/test/src/jdk/nashorn/test/models/OuterClass.java +++ b/test/src/jdk/nashorn/test/models/OuterClass.java @@ -25,6 +25,7 @@ package jdk.nashorn.test.models; +@SuppressWarnings("javadoc") public class OuterClass { private final String value; @@ -35,6 +36,7 @@ public class OuterClass { public static class InnerStaticClass { public static class InnerInnerStaticClass { + //empty } private final String value; @@ -50,15 +52,15 @@ public class OuterClass { } public class InnerNonStaticClass { - private final String value; + private final String val; public InnerNonStaticClass(final String value) { - this.value = value; + this.val = value; } @Override public String toString() { - return "InnerNonStaticClass[value=" + value + ", outer=" + OuterClass.this + "]"; + return "InnerNonStaticClass[value=" + val + ", outer=" + OuterClass.this + "]"; } } diff --git a/test/src/jdk/nashorn/test/models/OverloadedSam.java b/test/src/jdk/nashorn/test/models/OverloadedSam.java index 05736bca..b75f6b07 100644 --- a/test/src/jdk/nashorn/test/models/OverloadedSam.java +++ b/test/src/jdk/nashorn/test/models/OverloadedSam.java @@ -25,6 +25,7 @@ package jdk.nashorn.test.models; +@SuppressWarnings("javadoc") public interface OverloadedSam { public void sam(String s); public void sam(String s1, String s2); diff --git a/test/src/jdk/nashorn/test/models/OverrideObject.java b/test/src/jdk/nashorn/test/models/OverrideObject.java index 7e61e6d7..ed5a895e 100644 --- a/test/src/jdk/nashorn/test/models/OverrideObject.java +++ b/test/src/jdk/nashorn/test/models/OverrideObject.java @@ -25,6 +25,7 @@ package jdk.nashorn.test.models; +@SuppressWarnings("javadoc") public class OverrideObject { @Override public int hashCode() { diff --git a/test/src/jdk/nashorn/test/models/PropertyBind.java b/test/src/jdk/nashorn/test/models/PropertyBind.java index fb3f0981..09e85309 100644 --- a/test/src/jdk/nashorn/test/models/PropertyBind.java +++ b/test/src/jdk/nashorn/test/models/PropertyBind.java @@ -25,6 +25,7 @@ package jdk.nashorn.test.models; +@SuppressWarnings("javadoc") public class PropertyBind { public static int publicStaticInt; public static final int publicStaticFinalInt = 2112; diff --git a/test/src/jdk/nashorn/test/models/SourceHelper.java b/test/src/jdk/nashorn/test/models/SourceHelper.java index 7e90f304..d0525827 100644 --- a/test/src/jdk/nashorn/test/models/SourceHelper.java +++ b/test/src/jdk/nashorn/test/models/SourceHelper.java @@ -34,6 +34,7 @@ import jdk.nashorn.internal.runtime.Source; /** * Helper class to facilitate script access of nashorn Source class. */ +@SuppressWarnings("javadoc") public final class SourceHelper { private SourceHelper() {} diff --git a/test/src/jdk/nashorn/test/models/StringArgs.java b/test/src/jdk/nashorn/test/models/StringArgs.java index 2ea98033..d80480f5 100644 --- a/test/src/jdk/nashorn/test/models/StringArgs.java +++ b/test/src/jdk/nashorn/test/models/StringArgs.java @@ -27,6 +27,7 @@ package jdk.nashorn.test.models; import java.util.List; +@SuppressWarnings("javadoc") public class StringArgs { public static void checkString(final List list) { diff --git a/test/src/jdk/nashorn/test/models/Toothpaste.java b/test/src/jdk/nashorn/test/models/Toothpaste.java index 7eae95f3..747de89c 100644 --- a/test/src/jdk/nashorn/test/models/Toothpaste.java +++ b/test/src/jdk/nashorn/test/models/Toothpaste.java @@ -25,6 +25,7 @@ package jdk.nashorn.test.models; +@SuppressWarnings("javadoc") public abstract class Toothpaste { public void applyToBrush() { applyToBrushImpl(); diff --git a/test/src/jdk/nashorn/test/models/VarArgConstructor.java b/test/src/jdk/nashorn/test/models/VarArgConstructor.java index d218d983..6c31627f 100644 --- a/test/src/jdk/nashorn/test/models/VarArgConstructor.java +++ b/test/src/jdk/nashorn/test/models/VarArgConstructor.java @@ -27,6 +27,7 @@ package jdk.nashorn.test.models; import java.util.List; +@SuppressWarnings("javadoc") public class VarArgConstructor { private final String indicator; diff --git a/test/src/jdk/nashorn/test/tools/StaticTypeInspector.java b/test/src/jdk/nashorn/test/tools/StaticTypeInspector.java index 48655619..8a971f3d 100644 --- a/test/src/jdk/nashorn/test/tools/StaticTypeInspector.java +++ b/test/src/jdk/nashorn/test/tools/StaticTypeInspector.java @@ -26,6 +26,7 @@ package jdk.nashorn.test.tools; import jdk.nashorn.internal.runtime.Undefined; +@SuppressWarnings("javadoc") public class StaticTypeInspector { public static String inspect(final boolean x, final String w) { -- cgit v1.2.1 From ff74b1da4660e5ce4919bfdbb9a71e9be0c99299 Mon Sep 17 00:00:00 2001 From: lagergren Date: Mon, 3 Nov 2014 12:34:39 +0100 Subject: 8062381: Wrong index was used for linking charCodeAt specializations Reviewed-by: attila, hannesw --- src/jdk/nashorn/internal/objects/NativeString.java | 4 +- test/script/basic/JDK-8062381.js | 53 ++++++++++++++++++++++ test/script/basic/JDK-8062381.js.EXPECTED | 32 +++++++++++++ 3 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 test/script/basic/JDK-8062381.js create mode 100644 test/script/basic/JDK-8062381.js.EXPECTED diff --git a/src/jdk/nashorn/internal/objects/NativeString.java b/src/jdk/nashorn/internal/objects/NativeString.java index 850af622..3088e595 100644 --- a/src/jdk/nashorn/internal/objects/NativeString.java +++ b/src/jdk/nashorn/internal/objects/NativeString.java @@ -572,7 +572,7 @@ public final class NativeString extends ScriptObject implements OptimisticBuilti try { return ((CharSequence)self).charAt(pos); } catch (final IndexOutOfBoundsException e) { - throw new ClassCastException(); + throw new ClassCastException(); //invalid char, out of bounds, force relink } } @@ -1389,7 +1389,7 @@ public final class NativeString extends ScriptObject implements OptimisticBuilti //check that it's a char sequence or throw cce final CharSequence cs = (CharSequence)self; //check that the index, representable as an int, is inside the array - final int intIndex = JSType.toInteger(request.getArguments()[1]); + final int intIndex = JSType.toInteger(request.getArguments()[2]); return intIndex >= 0 && intIndex < cs.length(); //can link } catch (final ClassCastException | IndexOutOfBoundsException e) { //fallthru diff --git a/test/script/basic/JDK-8062381.js b/test/script/basic/JDK-8062381.js new file mode 100644 index 00000000..ef010f79 --- /dev/null +++ b/test/script/basic/JDK-8062381.js @@ -0,0 +1,53 @@ +/* + * 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. + */ + +/** + * JDK-8062381 wrong argument chosen for charCodeAt in linker logic + * + * @test + * @run + */ + +var s = "abcdef"; +var len = s.length + 1; + +function f1() { + for (var i = 0; i < len; i++) { + print(s.charCodeAt(i)); + } + print(s.charCodeAt()); +} + +function f2() { + for (var i = 0; i < len; i++) { + print(s.charCodeAt("" + i)); + } + print(s.charCodeAt()); +} + +f1(); +f2(); +f1(); +f2(); + + diff --git a/test/script/basic/JDK-8062381.js.EXPECTED b/test/script/basic/JDK-8062381.js.EXPECTED new file mode 100644 index 00000000..1692a50b --- /dev/null +++ b/test/script/basic/JDK-8062381.js.EXPECTED @@ -0,0 +1,32 @@ +97 +98 +99 +100 +101 +102 +NaN +97 +97 +98 +99 +100 +101 +102 +NaN +97 +97 +98 +99 +100 +101 +102 +NaN +97 +97 +98 +99 +100 +101 +102 +NaN +97 -- cgit v1.2.1 From a68d5e254221f6afa50d5bd09813a2eca99f5ca1 Mon Sep 17 00:00:00 2001 From: lagergren Date: Mon, 3 Nov 2014 13:58:52 +0100 Subject: 8061959: ArrayBuffer lacked static isViewMethod Reviewed-by: attila, sundar --- .../internal/objects/NativeArrayBuffer.java | 15 +++++++++- test/script/basic/JDK-8061959.js | 35 ++++++++++++++++++++++ test/script/basic/JDK-8061959.js.EXPECTED | 3 ++ 3 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 test/script/basic/JDK-8061959.js create mode 100644 test/script/basic/JDK-8061959.js.EXPECTED diff --git a/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java b/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java index 4d16ca54..e3c5c00d 100644 --- a/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java +++ b/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java @@ -26,7 +26,6 @@ package jdk.nashorn.internal.objects; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; - import java.nio.ByteBuffer; import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Constructor; @@ -34,6 +33,7 @@ import jdk.nashorn.internal.objects.annotations.Function; import jdk.nashorn.internal.objects.annotations.Getter; import jdk.nashorn.internal.objects.annotations.ScriptClass; import jdk.nashorn.internal.objects.annotations.SpecializedFunction; +import jdk.nashorn.internal.objects.annotations.Where; import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.PropertyMap; import jdk.nashorn.internal.runtime.ScriptObject; @@ -137,6 +137,19 @@ public final class NativeArrayBuffer extends ScriptObject { return ((NativeArrayBuffer)self).getByteLength(); } + /** + * Returns true if an object is an ArrayBufferView + * + * @param self self + * @param obj object to check + * + * @return true if obj is an ArrayBufferView + */ + @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) + public static boolean isView(final Object self, final Object obj) { + return obj instanceof ArrayBufferView; + } + /** * Slice function * @param self native array buffer diff --git a/test/script/basic/JDK-8061959.js b/test/script/basic/JDK-8061959.js new file mode 100644 index 00000000..a234a92b --- /dev/null +++ b/test/script/basic/JDK-8061959.js @@ -0,0 +1,35 @@ +/* + * 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. + */ + +/** + * JDK-8061959 - Checks for the existence of ArrayBufferView + * + * @test + * @run + */ + +print(ArrayBuffer.isView(new Int8Array(4))); +print(ArrayBuffer.isView("gorilla")); +print(ArrayBuffer.isView()); + + diff --git a/test/script/basic/JDK-8061959.js.EXPECTED b/test/script/basic/JDK-8061959.js.EXPECTED new file mode 100644 index 00000000..36bc6136 --- /dev/null +++ b/test/script/basic/JDK-8061959.js.EXPECTED @@ -0,0 +1,3 @@ +true +false +false -- cgit v1.2.1 From c6df9349f77eaef0e74369680c06bc33e219eb3b Mon Sep 17 00:00:00 2001 From: lagergren Date: Mon, 3 Nov 2014 14:59:34 +0100 Subject: 8062490: Out of memory problems, as untouched array datas didn't go directly to SparseArrayDatas, but dragged very large int arrays around. Reviewed-by: attila, sundar --- src/jdk/nashorn/internal/runtime/arrays/ArrayData.java | 4 ++++ src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java index dc41c4d9..dd27612b 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java +++ b/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java @@ -98,6 +98,10 @@ public abstract class ArrayData { @Override public ArrayData ensure(final long safeIndex) { if (safeIndex > 0L) { + if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH) { + return new SparseArrayData(this, safeIndex + 1); + } + //known to fit in int return toRealArrayData((int)safeIndex).ensure(safeIndex); } return this; diff --git a/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java index ef473451..61fb420f 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java +++ b/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java @@ -38,6 +38,11 @@ import jdk.nashorn.internal.runtime.ScriptRuntime; class SparseArrayData extends ArrayData { static final long MAX_DENSE_LENGTH = 16 * 512 * 1024; + static { + // we must break into sparse arrays before we require long indexes + assert MAX_DENSE_LENGTH <= Integer.MAX_VALUE; + } + /** Underlying array. */ private ArrayData underlying; -- cgit v1.2.1 From 166f97e903559c70a25445d418404d93547f4d7d Mon Sep 17 00:00:00 2001 From: lagergren Date: Wed, 5 Nov 2014 12:34:06 +0100 Subject: 8057825: Bug in apply specialization - if an apply specialization that is available doesn't fit, a new one wouldn't be installed, if the new code generated as a specialization didn't manage to do the apply specialization. Basically changing a conditional to an unconditional. Reviewed-by: attila, hannesw --- .../internal/codegen/ApplySpecialization.java | 210 +++++++++++++-------- .../nashorn/internal/codegen/CodeGenerator.java | 3 +- src/jdk/nashorn/internal/codegen/types/Type.java | 4 + src/jdk/nashorn/internal/objects/NativeString.java | 2 +- .../runtime/RecompilableScriptFunctionData.java | 15 +- .../internal/runtime/arrays/SparseArrayData.java | 7 +- .../runtime/events/RecompilationEvent.java | 2 +- test/script/basic/JDK-8057825.js | 45 +++++ test/script/basic/JDK-8057825.js.EXPECTED | 2 + .../dynalink/beans/CallerSensitiveTest.java | 1 + .../jdk/nashorn/test/models/ClassLoaderAware.java | 1 + 11 files changed, 200 insertions(+), 92 deletions(-) create mode 100644 test/script/basic/JDK-8057825.js create mode 100644 test/script/basic/JDK-8057825.js.EXPECTED diff --git a/src/jdk/nashorn/internal/codegen/ApplySpecialization.java b/src/jdk/nashorn/internal/codegen/ApplySpecialization.java index cdfe34f2..274afc84 100644 --- a/src/jdk/nashorn/internal/codegen/ApplySpecialization.java +++ b/src/jdk/nashorn/internal/codegen/ApplySpecialization.java @@ -29,6 +29,7 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.ARGUMENTS_VAR; import static jdk.nashorn.internal.codegen.CompilerConstants.EXPLODED_ARGUMENT_PREFIX; import java.lang.invoke.MethodType; +import java.net.URL; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; @@ -93,6 +94,8 @@ public final class ApplySpecialization extends NodeVisitor imple private final Deque> explodedArguments = new ArrayDeque<>(); + private final Deque callSiteTypes = new ArrayDeque<>(); + private static final String ARGUMENTS = ARGUMENTS_VAR.symbolName(); /** @@ -118,86 +121,108 @@ public final class ApplySpecialization extends NodeVisitor imple return context.getLogger(this.getClass()); } + @SuppressWarnings("serial") + private static class TransformFailedException extends RuntimeException { + TransformFailedException(final FunctionNode fn, final String message) { + super(massageURL(fn.getSource().getURL()) + '.' + fn.getName() + " => " + message, null, false, false); + } + } + + @SuppressWarnings("serial") + private static class AppliesFoundException extends RuntimeException { + AppliesFoundException() { + super("applies_found", null, false, false); + } + } + + private static final AppliesFoundException HAS_APPLIES = new AppliesFoundException(); + + private boolean hasApplies(final FunctionNode functionNode) { + try { + functionNode.accept(new NodeVisitor(new LexicalContext()) { + @Override + public boolean enterCallNode(final CallNode callNode) { + if (isApply(callNode)) { + throw HAS_APPLIES; + } + return true; + } + }); + } catch (final AppliesFoundException e) { + return true; + } + + log.fine("There are no applies in ", DebugLogger.quote(functionNode.getName()), " - nothing to do."); + return false; // no applies + } + /** * Arguments may only be used as args to the apply. Everything else is disqualified * We cannot control arguments if they escape from the method and go into an unknown * scope, thus we are conservative and treat any access to arguments outside the * apply call as a case of "we cannot apply the optimization". - * - * @return true if arguments escape */ - private boolean argumentsEscape(final FunctionNode functionNode) { - - @SuppressWarnings("serial") - final UnsupportedOperationException uoe = new UnsupportedOperationException() { - @Override - public synchronized Throwable fillInStackTrace() { - return null; - } - }; + private void checkValidTransform(final FunctionNode functionNode) { final Set argumentsFound = new HashSet<>(); final Deque> stack = new ArrayDeque<>(); + //ensure that arguments is only passed as arg to apply - try { - functionNode.accept(new NodeVisitor(new LexicalContext()) { - private boolean isCurrentArg(final Expression expr) { - return !stack.isEmpty() && stack.peek().contains(expr); //args to current apply call - } + functionNode.accept(new NodeVisitor(new LexicalContext()) { + + private boolean isCurrentArg(final Expression expr) { + return !stack.isEmpty() && stack.peek().contains(expr); //args to current apply call + } - private boolean isArguments(final Expression expr) { - if (expr instanceof IdentNode && ARGUMENTS.equals(((IdentNode)expr).getName())) { - argumentsFound.add(expr); + private boolean isArguments(final Expression expr) { + if (expr instanceof IdentNode && ARGUMENTS.equals(((IdentNode)expr).getName())) { + argumentsFound.add(expr); + return true; + } + return false; + } + + private boolean isParam(final String name) { + for (final IdentNode param : functionNode.getParameters()) { + if (param.getName().equals(name)) { return true; } - return false; } + return false; + } - private boolean isParam(final String name) { - for (final IdentNode param : functionNode.getParameters()) { - if (param.getName().equals(name)) { - return true; - } - } - return false; + @Override + public Node leaveIdentNode(final IdentNode identNode) { + if (isParam(identNode.getName())) { + throw new TransformFailedException(lc.getCurrentFunction(), "parameter: " + identNode.getName()); } - - @Override - public Node leaveIdentNode(final IdentNode identNode) { - if (isParam(identNode.getName()) || isArguments(identNode) && !isCurrentArg(identNode)) { - throw uoe; //avoid filling in stack trace - } - return identNode; + // it's OK if 'argument' occurs as the current argument of an apply + if (isArguments(identNode) && !isCurrentArg(identNode)) { + throw new TransformFailedException(lc.getCurrentFunction(), "is 'arguments': " + identNode.getName()); } + return identNode; + } - @Override - public boolean enterCallNode(final CallNode callNode) { - final Set callArgs = new HashSet<>(); - if (isApply(callNode)) { - final List argList = callNode.getArgs(); - if (argList.size() != 2 || !isArguments(argList.get(argList.size() - 1))) { - throw new UnsupportedOperationException(); - } - callArgs.addAll(callNode.getArgs()); + @Override + public boolean enterCallNode(final CallNode callNode) { + final Set callArgs = new HashSet<>(); + if (isApply(callNode)) { + final List argList = callNode.getArgs(); + if (argList.size() != 2 || !isArguments(argList.get(argList.size() - 1))) { + throw new TransformFailedException(lc.getCurrentFunction(), "argument pattern not matched: " + argList); } - stack.push(callArgs); - return true; - } - - @Override - public Node leaveCallNode(final CallNode callNode) { - stack.pop(); - return callNode; + callArgs.addAll(callNode.getArgs()); } - }); - } catch (final UnsupportedOperationException e) { - if (!argumentsFound.isEmpty()) { - log.fine("'arguments' is used but escapes, or is reassigned in '" + functionNode.getName() + "'. Aborting"); + stack.push(callArgs); + return true; } - return true; //bad - } - return false; + @Override + public Node leaveCallNode(final CallNode callNode) { + stack.pop(); + return callNode; + } + }); } @Override @@ -224,12 +249,14 @@ public final class ApplySpecialization extends NodeVisitor imple final CallNode newCallNode = callNode.setArgs(newArgs).setIsApplyToCall(); - log.fine("Transformed ", - callNode, - " from apply to call => ", - newCallNode, - " in ", - DebugLogger.quote(lc.getCurrentFunction().getName())); + if (log.isEnabled()) { + log.fine("Transformed ", + callNode, + " from apply to call => ", + newCallNode, + " in ", + DebugLogger.quote(lc.getCurrentFunction().getName())); + } return newCallNode; } @@ -237,12 +264,12 @@ public final class ApplySpecialization extends NodeVisitor imple return callNode; } - private boolean pushExplodedArgs(final FunctionNode functionNode) { + private void pushExplodedArgs(final FunctionNode functionNode) { int start = 0; final MethodType actualCallSiteType = compiler.getCallSiteType(functionNode); if (actualCallSiteType == null) { - return false; + throw new TransformFailedException(lc.getCurrentFunction(), "No callsite type"); } assert actualCallSiteType.parameterType(actualCallSiteType.parameterCount() - 1) != Object[].class : "error vararg callsite passed to apply2call " + functionNode.getName() + " " + actualCallSiteType; @@ -264,8 +291,8 @@ public final class ApplySpecialization extends NodeVisitor imple } } + callSiteTypes.push(actualCallSiteType); explodedArguments.push(newParams); - return true; } @Override @@ -288,11 +315,30 @@ public final class ApplySpecialization extends NodeVisitor imple return false; } - if (argumentsEscape(functionNode)) { + if (!hasApplies(functionNode)) { return false; } - return pushExplodedArgs(functionNode); + if (log.isEnabled()) { + log.info("Trying to specialize apply to call in '", + functionNode.getName(), + "' params=", + functionNode.getParameters(), + " id=", + functionNode.getId(), + " source=", + massageURL(functionNode.getSource().getURL())); + } + + try { + checkValidTransform(functionNode); + pushExplodedArgs(functionNode); + } catch (final TransformFailedException e) { + log.info("Failure: ", e.getMessage()); + return false; + } + + return true; } /** @@ -300,8 +346,8 @@ public final class ApplySpecialization extends NodeVisitor imple * @return true if successful, false otherwise */ @Override - public Node leaveFunctionNode(final FunctionNode functionNode0) { - FunctionNode newFunctionNode = functionNode0; + public Node leaveFunctionNode(final FunctionNode functionNode) { + FunctionNode newFunctionNode = functionNode; final String functionName = newFunctionNode.getName(); if (changed.contains(newFunctionNode.getId())) { @@ -310,17 +356,18 @@ public final class ApplySpecialization extends NodeVisitor imple setParameters(lc, explodedArguments.peek()); if (log.isEnabled()) { - log.info("Successfully specialized apply to call in '", + log.info("Success: ", + massageURL(newFunctionNode.getSource().getURL()), + '.', functionName, - " params=", - explodedArguments.peek(), "' id=", newFunctionNode.getId(), - " source=", - newFunctionNode.getSource().getURL()); + " params=", + callSiteTypes.peek()); } } + callSiteTypes.pop(); explodedArguments.pop(); return newFunctionNode.setState(lc, CompilationState.BUILTINS_TRANSFORMED); @@ -331,4 +378,15 @@ public final class ApplySpecialization extends NodeVisitor imple return f instanceof AccessNode && "apply".equals(((AccessNode)f).getProperty()); } + private static String massageURL(final URL url) { + if (url == null) { + return ""; + } + final String str = url.toString(); + final int slash = str.lastIndexOf('/'); + if (slash == -1) { + return str; + } + return str.substring(slash + 1); + } } diff --git a/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/src/jdk/nashorn/internal/codegen/CodeGenerator.java index 28b08098..6e84dd89 100644 --- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java @@ -615,7 +615,6 @@ final class CodeGenerator extends NodeOperatorVisitor)rhs).getValue()); } private void loadBIT_XOR(final BinaryNode binaryNode) { diff --git a/src/jdk/nashorn/internal/codegen/types/Type.java b/src/jdk/nashorn/internal/codegen/types/Type.java index 2b9ccd82..2cf2d9b8 100644 --- a/src/jdk/nashorn/internal/codegen/types/Type.java +++ b/src/jdk/nashorn/internal/codegen/types/Type.java @@ -1155,6 +1155,10 @@ public abstract class Type implements Comparable, BytecodeOps, Serializabl return type; } + /** + * Read resolve + * @return resolved type + */ protected final Object readResolve() { return Type.typeFor(clazz); } diff --git a/src/jdk/nashorn/internal/objects/NativeString.java b/src/jdk/nashorn/internal/objects/NativeString.java index 3088e595..7fb86a4a 100644 --- a/src/jdk/nashorn/internal/objects/NativeString.java +++ b/src/jdk/nashorn/internal/objects/NativeString.java @@ -29,6 +29,7 @@ import static jdk.nashorn.internal.lookup.Lookup.MH; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; import static jdk.nashorn.internal.runtime.JSType.isRepresentableAsInt; import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; + import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; @@ -1380,7 +1381,6 @@ public final class NativeString extends ScriptObject implements OptimisticBuilti * sequence and that we are in range */ private static final class CharCodeAtLinkLogic extends SpecializedFunction.LinkLogic { - private static final CharCodeAtLinkLogic INSTANCE = new CharCodeAtLinkLogic(); @Override diff --git a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java index 9f666c01..fd381675 100644 --- a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java +++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java @@ -26,6 +26,7 @@ package jdk.nashorn.internal.runtime; import static jdk.nashorn.internal.lookup.Lookup.MH; + import java.io.IOException; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; @@ -727,7 +728,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp assert existingBest != null; //we are calling a vararg method with real args - boolean applyToCall = existingBest.isVarArg() && !CompiledFunction.isVarArgsType(callSiteType); + boolean varArgWithRealArgs = existingBest.isVarArg() && !CompiledFunction.isVarArgsType(callSiteType); //if the best one is an apply to call, it has to match the callsite exactly //or we need to regenerate @@ -736,14 +737,16 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp if (best != null) { return best; } - applyToCall = true; + varArgWithRealArgs = true; } - if (applyToCall) { + if (varArgWithRealArgs) { + // special case: we had an apply to call, but we failed to make it fit. + // Try to generate a specialized one for this callsite. It may + // be another apply to call specialization, or it may not, but whatever + // it is, it is a specialization that is guaranteed to fit final FunctionInitializer fnInit = compileTypeSpecialization(callSiteType, runtimeScope, false); - if ((fnInit.getFlags() & FunctionNode.HAS_APPLY_TO_CALL_SPECIALIZATION) != 0) { //did the specialization work - existingBest = addCode(fnInit, callSiteType); - } + existingBest = addCode(fnInit, callSiteType); } return existingBest; diff --git a/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java index 61fb420f..fd058286 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java +++ b/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java @@ -36,12 +36,7 @@ import jdk.nashorn.internal.runtime.ScriptRuntime; * Handle arrays where the index is very large. */ class SparseArrayData extends ArrayData { - static final long MAX_DENSE_LENGTH = 16 * 512 * 1024; - - static { - // we must break into sparse arrays before we require long indexes - assert MAX_DENSE_LENGTH <= Integer.MAX_VALUE; - } + static final int MAX_DENSE_LENGTH = 8 * 1024 * 1024; /** Underlying array. */ private ArrayData underlying; diff --git a/src/jdk/nashorn/internal/runtime/events/RecompilationEvent.java b/src/jdk/nashorn/internal/runtime/events/RecompilationEvent.java index db28012b..8b2ff471 100644 --- a/src/jdk/nashorn/internal/runtime/events/RecompilationEvent.java +++ b/src/jdk/nashorn/internal/runtime/events/RecompilationEvent.java @@ -47,7 +47,7 @@ public final class RecompilationEvent extends RuntimeEvent { * @param level logging level * @param rewriteException rewriteException wrapped by this RuntimEvent * @param returnValue rewriteException return value - as we don't want to make - * {@link RewriteException#getReturnValueNonDestructive()} public, we pass it as + * {@code RewriteException.getReturnValueNonDestructive()} public, we pass it as * an extra parameter, rather than querying the getter from another package. */ public RecompilationEvent(final Level level, final RewriteException rewriteException, final Object returnValue) { diff --git a/test/script/basic/JDK-8057825.js b/test/script/basic/JDK-8057825.js new file mode 100644 index 00000000..256e2fbf --- /dev/null +++ b/test/script/basic/JDK-8057825.js @@ -0,0 +1,45 @@ +/* + * 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. + */ + +/** + * JDK-8057825 : A failed apply to call generation should NOT reuse the + * best apply to call generation so far - because it may not fit!!! + * + * @test + * @run + */ + +function createApplier(f) { + function applier() { + f.apply(this, arguments); // no transform applied here + } + return applier; +} + +function printer(x,y) { + print(x + " and " + y); +} + +var printerApplier = createApplier(printer); +printerApplier(); +printerApplier.apply(this, ["foo", "bar"]); diff --git a/test/script/basic/JDK-8057825.js.EXPECTED b/test/script/basic/JDK-8057825.js.EXPECTED new file mode 100644 index 00000000..87acc7c4 --- /dev/null +++ b/test/script/basic/JDK-8057825.js.EXPECTED @@ -0,0 +1,2 @@ +undefined and undefined +foo and bar diff --git a/test/src/jdk/internal/dynalink/beans/CallerSensitiveTest.java b/test/src/jdk/internal/dynalink/beans/CallerSensitiveTest.java index 44039320..d9a44551 100644 --- a/test/src/jdk/internal/dynalink/beans/CallerSensitiveTest.java +++ b/test/src/jdk/internal/dynalink/beans/CallerSensitiveTest.java @@ -28,6 +28,7 @@ package jdk.internal.dynalink.beans; import jdk.nashorn.test.models.ClassLoaderAware; import org.testng.annotations.Test; +@SuppressWarnings("javadoc") public class CallerSensitiveTest { @Test public void testCallerSensitive() { diff --git a/test/src/jdk/nashorn/test/models/ClassLoaderAware.java b/test/src/jdk/nashorn/test/models/ClassLoaderAware.java index 18629914..491e9db2 100644 --- a/test/src/jdk/nashorn/test/models/ClassLoaderAware.java +++ b/test/src/jdk/nashorn/test/models/ClassLoaderAware.java @@ -25,6 +25,7 @@ package jdk.nashorn.test.models; +@SuppressWarnings("javadoc") public interface ClassLoaderAware { public ClassLoader getContextClassLoader(); public void checkMemberAccess(Class clazz, int which); -- cgit v1.2.1 From 38a38eb57e58a248fde3eb7732a5e882bdcfab14 Mon Sep 17 00:00:00 2001 From: hannesw Date: Wed, 5 Nov 2014 17:07:26 +0100 Subject: 8062386: Different versions of nashorn use same code cache directory Reviewed-by: lagergren, attila --- .../codegen/OptimisticTypesPersistence.java | 6 ++- src/jdk/nashorn/internal/runtime/CodeStore.java | 26 +++++++--- src/jdk/nashorn/internal/runtime/Context.java | 5 +- .../internal/runtime/CodeStoreAndPathTest.java | 60 ++++++++++++++++------ 4 files changed, 68 insertions(+), 29 deletions(-) diff --git a/src/jdk/nashorn/internal/codegen/OptimisticTypesPersistence.java b/src/jdk/nashorn/internal/codegen/OptimisticTypesPersistence.java index 05a76872..6ca50899 100644 --- a/src/jdk/nashorn/internal/codegen/OptimisticTypesPersistence.java +++ b/src/jdk/nashorn/internal/codegen/OptimisticTypesPersistence.java @@ -323,9 +323,11 @@ public final class OptimisticTypesPersistence { * per-code-version directory. Normally, this will create the SHA-1 digest of the nashorn.jar. In case the classpath * for nashorn is local directory (e.g. during development), this will create the string "dev-" followed by the * timestamp of the most recent .class file. - * @return + * + * @return digest of currently running nashorn + * @throws Exception if digest could not be created */ - private static String getVersionDirName() throws Exception { + public static String getVersionDirName() throws Exception { final URL url = OptimisticTypesPersistence.class.getResource(""); final String protocol = url.getProtocol(); if (protocol.equals("jar")) { diff --git a/src/jdk/nashorn/internal/runtime/CodeStore.java b/src/jdk/nashorn/internal/runtime/CodeStore.java index 0748ccc3..0e85beeb 100644 --- a/src/jdk/nashorn/internal/runtime/CodeStore.java +++ b/src/jdk/nashorn/internal/runtime/CodeStore.java @@ -41,6 +41,7 @@ import java.security.PrivilegedExceptionAction; import java.util.Iterator; import java.util.Map; import java.util.ServiceLoader; +import jdk.nashorn.internal.codegen.OptimisticTypesPersistence; import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.runtime.logging.DebugLogger; import jdk.nashorn.internal.runtime.logging.Loggable; @@ -102,7 +103,7 @@ public abstract class CodeStore implements Loggable { } catch (final AccessControlException e) { context.getLogger(CodeStore.class).warning("failed to load code store provider ", e); } - final CodeStore store = new DirectoryCodeStore(); + final CodeStore store = new DirectoryCodeStore(context); store.initLogger(context); return store; } @@ -210,32 +211,34 @@ public abstract class CodeStore implements Loggable { /** * Constructor * + * @param context the current context * @throws IOException if there are read/write problems with the cache and cache directory */ - public DirectoryCodeStore() throws IOException { - this(Options.getStringProperty("nashorn.persistent.code.cache", "nashorn_code_cache"), false, DEFAULT_MIN_SIZE); + public DirectoryCodeStore(final Context context) throws IOException { + this(context, Options.getStringProperty("nashorn.persistent.code.cache", "nashorn_code_cache"), false, DEFAULT_MIN_SIZE); } /** * Constructor * + * @param context the current context * @param path directory to store code in * @param readOnly is this a read only code store * @param minSize minimum file size for caching scripts * @throws IOException if there are read/write problems with the cache and cache directory */ - public DirectoryCodeStore(final String path, final boolean readOnly, final int minSize) throws IOException { - this.dir = checkDirectory(path, readOnly); + public DirectoryCodeStore(final Context context, final String path, final boolean readOnly, final int minSize) throws IOException { + this.dir = checkDirectory(path, context.getEnv(), readOnly); this.readOnly = readOnly; this.minSize = minSize; } - private static File checkDirectory(final String path, final boolean readOnly) throws IOException { + private static File checkDirectory(final String path, final ScriptEnvironment env, final boolean readOnly) throws IOException { try { return AccessController.doPrivileged(new PrivilegedExceptionAction() { @Override public File run() throws IOException { - final File dir = new File(path).getAbsoluteFile(); + final File dir = new File(path, getVersionDir(env)).getAbsoluteFile(); if (readOnly) { if (!dir.exists() || !dir.isDirectory()) { throw new IOException("Not a directory: " + dir.getPath()); @@ -257,6 +260,15 @@ public abstract class CodeStore implements Loggable { } } + private static String getVersionDir(final ScriptEnvironment env) throws IOException { + try { + final String versionDir = OptimisticTypesPersistence.getVersionDirName(); + return env._optimistic_types ? versionDir + "_opt" : versionDir; + } catch (final Exception e) { + throw new IOException(e); + } + } + @Override public StoredScript load(final Source source, final String functionKey) { if (source.getLength() < minSize) { diff --git a/src/jdk/nashorn/internal/runtime/Context.java b/src/jdk/nashorn/internal/runtime/Context.java index 23f0e3ab..09785ff5 100644 --- a/src/jdk/nashorn/internal/runtime/Context.java +++ b/src/jdk/nashorn/internal/runtime/Context.java @@ -1150,9 +1150,8 @@ public final class Context { StoredScript storedScript = null; FunctionNode functionNode = null; - // We only use the code store here if optimistic types are disabled. With optimistic types, - // code is stored per function in RecompilableScriptFunctionData. - // TODO: This should really be triggered by lazy compilation, not optimistic types. + // We only use the code store here if optimistic types are disabled. With optimistic types, initial compilation + // just creates a thin wrapper, and actual code is stored per function in RecompilableScriptFunctionData. final boolean useCodeStore = env._persistent_cache && !env._parse_only && !env._optimistic_types; final String cacheKey = useCodeStore ? CodeStore.getCacheKey(0, null) : null; diff --git a/test/src/jdk/nashorn/internal/runtime/CodeStoreAndPathTest.java b/test/src/jdk/nashorn/internal/runtime/CodeStoreAndPathTest.java index 4c069076..2ca4820b 100644 --- a/test/src/jdk/nashorn/internal/runtime/CodeStoreAndPathTest.java +++ b/test/src/jdk/nashorn/internal/runtime/CodeStoreAndPathTest.java @@ -95,23 +95,15 @@ public class CodeStoreAndPathTest { final String codeCache = "build/nashorn_code_cache"; final String oldUserDir = System.getProperty("user.dir"); - private static final String[] ENGINE_OPTIONS = new String[]{"--persistent-code-cache", "--optimistic-types=false", "--lazy-compilation=false"}; - - public void checkCompiledScripts(final DirectoryStream stream, final int numberOfScripts) throws IOException { - int n = numberOfScripts; - for (@SuppressWarnings("unused") final Path file : stream) { - n--; - } - stream.close(); - assertEquals(n, 0); - } + private static final String[] ENGINE_OPTIONS_OPT = new String[]{"--persistent-code-cache", "--optimistic-types=true"}; + private static final String[] ENGINE_OPTIONS_NOOPT = new String[]{"--persistent-code-cache", "--optimistic-types=false"}; @Test public void pathHandlingTest() { System.setProperty("nashorn.persistent.code.cache", codeCache); final NashornScriptEngineFactory fac = new NashornScriptEngineFactory(); - fac.getScriptEngine(ENGINE_OPTIONS); + fac.getScriptEngine(ENGINE_OPTIONS_NOOPT); final Path expectedCodeCachePath = FileSystems.getDefault().getPath(oldUserDir + File.separator + codeCache); final Path actualCodeCachePath = FileSystems.getDefault().getPath(System.getProperty( @@ -128,9 +120,8 @@ public class CodeStoreAndPathTest { public void changeUserDirTest() throws ScriptException, IOException { System.setProperty("nashorn.persistent.code.cache", codeCache); final NashornScriptEngineFactory fac = new NashornScriptEngineFactory(); - final ScriptEngine e = fac.getScriptEngine(ENGINE_OPTIONS); - final Path codeCachePath = FileSystems.getDefault().getPath(System.getProperty( - "nashorn.persistent.code.cache")).toAbsolutePath(); + final ScriptEngine e = fac.getScriptEngine(ENGINE_OPTIONS_NOOPT); + final Path codeCachePath = getCodeCachePath(false); final String newUserDir = "build/newUserDir"; // Now changing current working directory System.setProperty("user.dir", System.getProperty("user.dir") + File.separator + newUserDir); @@ -149,9 +140,8 @@ public class CodeStoreAndPathTest { public void codeCacheTest() throws ScriptException, IOException { System.setProperty("nashorn.persistent.code.cache", codeCache); final NashornScriptEngineFactory fac = new NashornScriptEngineFactory(); - final ScriptEngine e = fac.getScriptEngine(ENGINE_OPTIONS); - final Path codeCachePath = FileSystems.getDefault().getPath(System.getProperty( - "nashorn.persistent.code.cache")).toAbsolutePath(); + final ScriptEngine e = fac.getScriptEngine(ENGINE_OPTIONS_NOOPT); + final Path codeCachePath = getCodeCachePath(false); e.eval(code1); e.eval(code2); e.eval(code3);// less than minimum size for storing @@ -159,4 +149,40 @@ public class CodeStoreAndPathTest { final DirectoryStream stream = Files.newDirectoryStream(codeCachePath); checkCompiledScripts(stream, 2); } + + @Test + public void codeCacheTestOpt() throws ScriptException, IOException { + System.setProperty("nashorn.persistent.code.cache", codeCache); + final NashornScriptEngineFactory fac = new NashornScriptEngineFactory(); + final ScriptEngine e = fac.getScriptEngine(ENGINE_OPTIONS_OPT); + final Path codeCachePath = getCodeCachePath(true); + e.eval(code1); + e.eval(code2); + e.eval(code3);// less than minimum size for storing + // adding code1 and code2. + final DirectoryStream stream = Files.newDirectoryStream(codeCachePath); + checkCompiledScripts(stream, 2); + } + + private static Path getCodeCachePath(final boolean optimistic) { + final String codeCache = System.getProperty("nashorn.persistent.code.cache"); + final Path codeCachePath = FileSystems.getDefault().getPath(codeCache).toAbsolutePath(); + final String[] files = codeCachePath.toFile().list(); + for (final String file : files) { + if (file.endsWith("_opt") == optimistic) { + return codeCachePath.resolve(file); + } + } + throw new AssertionError("Code cache path not found"); + } + + private static void checkCompiledScripts(final DirectoryStream stream, final int numberOfScripts) throws IOException { + int n = numberOfScripts; + for (@SuppressWarnings("unused") final Path file : stream) { + n--; + } + stream.close(); + assertEquals(n, 0); + } + } -- cgit v1.2.1 From daa7a819119074c969b041db548cbda067ebfe16 Mon Sep 17 00:00:00 2001 From: hannesw Date: Thu, 6 Nov 2014 13:15:52 +0100 Subject: 8062624: java.lang.String methods not available on concatenated strings Reviewed-by: lagergren, attila --- .../runtime/linker/NashornBeansLinker.java | 32 +++++++++++++-- test/script/basic/JDK-8062624.js | 45 ++++++++++++++++++++++ test/script/basic/JDK-8062624.js.EXPECTED | 16 ++++++++ 3 files changed, 89 insertions(+), 4 deletions(-) create mode 100644 test/script/basic/JDK-8062624.js create mode 100644 test/script/basic/JDK-8062624.js.EXPECTED diff --git a/src/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java b/src/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java index 25ba619b..d5133cb3 100644 --- a/src/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java +++ b/src/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java @@ -53,15 +53,34 @@ public class NashornBeansLinker implements GuardingDynamicLinker { // Object type arguments of Java method calls, field set and array set. private static final boolean MIRROR_ALWAYS = Options.getBooleanProperty("nashorn.mirror.always", true); - private static final MethodHandle EXPORT_ARGUMENT = new Lookup(MethodHandles.lookup()).findOwnStatic("exportArgument", Object.class, Object.class); - private static final MethodHandle EXPORT_NATIVE_ARRAY = new Lookup(MethodHandles.lookup()).findOwnStatic("exportNativeArray", Object.class, NativeArray.class); - private static final MethodHandle EXPORT_SCRIPT_OBJECT = new Lookup(MethodHandles.lookup()).findOwnStatic("exportScriptObject", Object.class, ScriptObject.class); - private static final MethodHandle IMPORT_RESULT = new Lookup(MethodHandles.lookup()).findOwnStatic("importResult", Object.class, Object.class); + private static final MethodHandle EXPORT_ARGUMENT; + private static final MethodHandle EXPORT_NATIVE_ARRAY; + private static final MethodHandle EXPORT_SCRIPT_OBJECT; + private static final MethodHandle IMPORT_RESULT; + private static final MethodHandle FILTER_CONSSTRING; + + static { + final Lookup lookup = new Lookup(MethodHandles.lookup()); + EXPORT_ARGUMENT = lookup.findOwnStatic("exportArgument", Object.class, Object.class); + EXPORT_NATIVE_ARRAY = lookup.findOwnStatic("exportNativeArray", Object.class, NativeArray.class); + EXPORT_SCRIPT_OBJECT = lookup.findOwnStatic("exportScriptObject", Object.class, ScriptObject.class); + IMPORT_RESULT = lookup.findOwnStatic("importResult", Object.class, Object.class); + FILTER_CONSSTRING = lookup.findOwnStatic("consStringFilter", Object.class, Object.class); + } private final BeansLinker beansLinker = new BeansLinker(); @Override public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception { + if (linkRequest.getReceiver() instanceof ConsString) { + // In order to treat ConsString like a java.lang.String we need a link request with a string receiver. + final Object[] arguments = linkRequest.getArguments(); + arguments[0] = ""; + final LinkRequest forgedLinkRequest = linkRequest.replaceArguments(linkRequest.getCallSiteDescriptor(), arguments); + final GuardedInvocation invocation = getGuardedInvocation(beansLinker, forgedLinkRequest, linkerServices); + // If an invocation is found we add a filter that makes it work for both Strings and ConsStrings. + return invocation == null ? null : invocation.filterArguments(0, FILTER_CONSSTRING); + } return getGuardedInvocation(beansLinker, linkRequest, linkerServices); } @@ -113,6 +132,11 @@ public class NashornBeansLinker implements GuardingDynamicLinker { return ScriptUtils.unwrap(arg); } + @SuppressWarnings("unused") + private static Object consStringFilter(final Object arg) { + return arg instanceof ConsString ? arg.toString() : arg; + } + private static class NashornBeansLinkerServices implements LinkerServices { private final LinkerServices linkerServices; diff --git a/test/script/basic/JDK-8062624.js b/test/script/basic/JDK-8062624.js new file mode 100644 index 00000000..c5ecb963 --- /dev/null +++ b/test/script/basic/JDK-8062624.js @@ -0,0 +1,45 @@ +/* + * 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-8062624: java.lang.String methods not available on concatenated strings + * + * @test + * @run + */ + +function testStringMethods(s) { + print(s.startsWith("f")); + print(s.endsWith("r")); + print(Java.from(s.getBytes())); + print(Java.from(s.bytes)); +} + +var s = "f"; +testStringMethods(s); +s = s + "oo"; +testStringMethods(s); +testStringMethods("abc"); +s += "bar"; +s = "baz" + s; +testStringMethods(s); diff --git a/test/script/basic/JDK-8062624.js.EXPECTED b/test/script/basic/JDK-8062624.js.EXPECTED new file mode 100644 index 00000000..2d6dea36 --- /dev/null +++ b/test/script/basic/JDK-8062624.js.EXPECTED @@ -0,0 +1,16 @@ +true +false +102 +102 +true +false +102,111,111 +102,111,111 +false +false +97,98,99 +97,98,99 +false +true +98,97,122,102,111,111,98,97,114 +98,97,122,102,111,111,98,97,114 -- cgit v1.2.1 From b97fabe4326aabe101d76f31f0650ce997f567b7 Mon Sep 17 00:00:00 2001 From: attila Date: Thu, 6 Nov 2014 17:06:56 +0100 Subject: 8062308: Incorrect constant linkage with multiple Globals in a Context Reviewed-by: lagergren, sundar --- src/jdk/nashorn/internal/objects/Global.java | 20 +-- src/jdk/nashorn/internal/runtime/Context.java | 54 +++++- .../nashorn/internal/runtime/GlobalConstants.java | 189 +++++++++++++-------- src/jdk/nashorn/internal/runtime/ScriptObject.java | 29 +++- 4 files changed, 189 insertions(+), 103 deletions(-) diff --git a/src/jdk/nashorn/internal/objects/Global.java b/src/jdk/nashorn/internal/objects/Global.java index eb56de0e..6a978627 100644 --- a/src/jdk/nashorn/internal/objects/Global.java +++ b/src/jdk/nashorn/internal/objects/Global.java @@ -29,6 +29,7 @@ import static jdk.nashorn.internal.lookup.Lookup.MH; import static jdk.nashorn.internal.runtime.ECMAErrors.referenceError; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; + import java.io.IOException; import java.io.PrintWriter; import java.lang.invoke.MethodHandle; @@ -41,7 +42,6 @@ import java.util.List; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicReference; import javax.script.ScriptContext; import javax.script.ScriptEngine; import jdk.internal.dynalink.linker.GuardedInvocation; @@ -54,7 +54,6 @@ import jdk.nashorn.internal.objects.annotations.Property; import jdk.nashorn.internal.objects.annotations.ScriptClass; import jdk.nashorn.internal.runtime.ConsString; import jdk.nashorn.internal.runtime.Context; -import jdk.nashorn.internal.runtime.GlobalConstants; import jdk.nashorn.internal.runtime.GlobalFunctions; import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.NativeJavaPackage; @@ -438,9 +437,6 @@ public final class Global extends ScriptObject implements Scope { this.scontext = scontext; } - // global constants for this global - they can be replaced with MethodHandle.constant until invalidated - private static AtomicReference gcsInstance = new AtomicReference<>(); - @Override protected Context getContext() { return context; @@ -470,11 +466,6 @@ public final class Global extends ScriptObject implements Scope { super(checkAndGetMap(context)); this.context = context; this.setIsScope(); - //we can only share one instance of Global constants between globals, or we consume way too much - //memory - this is good enough for most programs - while (gcsInstance.get() == null) { - gcsInstance.compareAndSet(null, new GlobalConstants(context.getLogger(GlobalConstants.class))); - } } /** @@ -492,15 +483,6 @@ public final class Global extends ScriptObject implements Scope { return self instanceof Global? (Global)self : instance(); } - /** - * Return the global constants map for fields that - * can be accessed as MethodHandle.constant - * @return constant map - */ - public static GlobalConstants getConstants() { - return gcsInstance.get(); - } - /** * Check if we have a Global instance * @return true if one exists diff --git a/src/jdk/nashorn/internal/runtime/Context.java b/src/jdk/nashorn/internal/runtime/Context.java index 09785ff5..86369ab7 100644 --- a/src/jdk/nashorn/internal/runtime/Context.java +++ b/src/jdk/nashorn/internal/runtime/Context.java @@ -33,6 +33,7 @@ import static jdk.nashorn.internal.runtime.CodeStore.newCodeStore; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; import static jdk.nashorn.internal.runtime.Source.sourceFor; + import java.io.File; import java.io.IOException; import java.io.PrintWriter; @@ -60,6 +61,7 @@ import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import java.util.function.Supplier; import java.util.logging.Level; @@ -262,6 +264,10 @@ public final class Context { // persistent code store private CodeStore codeStore; + // A factory for linking global properties as constant method handles. It is created when the first Global + // is created, and invalidated forever once the second global is created. + private final AtomicReference globalConstantsRef = new AtomicReference<>(); + /** * Get the current global scope * @return the current global scope @@ -293,7 +299,10 @@ public final class Context { assert getGlobal() != global; //same code can be cached between globals, then we need to invalidate method handle constants if (global != null) { - Global.getConstants().invalidateAll(); + final GlobalConstants globalConstants = getContext(global).getGlobalConstants(); + if (globalConstants != null) { + globalConstants.invalidateAll(); + } } currentGlobal.set(global); } @@ -528,6 +537,15 @@ public final class Context { return classFilter; } + /** + * Returns the factory for constant method handles for global properties. The returned factory can be + * invalidated if this Context has more than one Global. + * @return the factory for constant method handles for global properties. + */ + GlobalConstants getGlobalConstants() { + return globalConstantsRef.get(); + } + /** * Get the error manager for this context * @return error manger @@ -1016,9 +1034,32 @@ public final class Context { * @return the global script object */ public Global newGlobal() { + createOrInvalidateGlobalConstants(); return new Global(this); } + private void createOrInvalidateGlobalConstants() { + for (;;) { + final GlobalConstants currentGlobalConstants = getGlobalConstants(); + if (currentGlobalConstants != null) { + // Subsequent invocation; we're creating our second or later Global. GlobalConstants is not safe to use + // with more than one Global, as the constant method handle linkages it creates create a coupling + // between the Global and the call sites in the compiled code. + currentGlobalConstants.invalidateForever(); + return; + } + final GlobalConstants newGlobalConstants = new GlobalConstants(getLogger(GlobalConstants.class)); + if (globalConstantsRef.compareAndSet(null, newGlobalConstants)) { + // First invocation; we're creating the first Global in this Context. Create the GlobalConstants object + // for this Context. + return; + } + + // If we reach here, then we started out as the first invocation, but another concurrent invocation won the + // CAS race. We'll just let the loop repeat and invalidate the CAS race winner. + } + } + /** * Initialize given global scope object. * @@ -1057,12 +1098,19 @@ public final class Context { * @return current global's context */ static Context getContextTrusted() { - return ((ScriptObject)Context.getGlobal()).getContext(); + return getContext(getGlobal()); } static Context getContextTrustedOrNull() { final Global global = Context.getGlobal(); - return global == null ? null : ((ScriptObject)global).getContext(); + return global == null ? null : getContext(global); + } + + private static Context getContext(final Global global) { + // We can't invoke Global.getContext() directly, as it's a protected override, and Global isn't in our package. + // In order to access the method, we must cast it to ScriptObject first (which is in our package) and then let + // virtual invocation do its thing. + return ((ScriptObject)global).getContext(); } /** diff --git a/src/jdk/nashorn/internal/runtime/GlobalConstants.java b/src/jdk/nashorn/internal/runtime/GlobalConstants.java index c6f9b964..cd1061c2 100644 --- a/src/jdk/nashorn/internal/runtime/GlobalConstants.java +++ b/src/jdk/nashorn/internal/runtime/GlobalConstants.java @@ -31,12 +31,14 @@ import static jdk.nashorn.internal.lookup.Lookup.MH; import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT; import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.getProgramPoint; import static jdk.nashorn.internal.runtime.logging.DebugLogger.quote; + import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.SwitchPoint; import java.util.Arrays; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import jdk.internal.dynalink.CallSiteDescriptor; import jdk.internal.dynalink.DynamicLinker; @@ -50,7 +52,7 @@ import jdk.nashorn.internal.runtime.logging.Loggable; import jdk.nashorn.internal.runtime.logging.Logger; /** - * Each global owns one of these. This is basically table of accessors + * Each context owns one of these. This is basically table of accessors * for global properties. A global constant is evaluated to a MethodHandle.constant * for faster access and to avoid walking to proto chain looking for it. * @@ -67,12 +69,19 @@ import jdk.nashorn.internal.runtime.logging.Logger; * reregister the switchpoint. Set twice or more - don't try again forever, or we'd * just end up relinking our way into megamorphisism. * + * Also it has to be noted that this kind of linking creates a coupling between a Global + * and the call sites in compiled code belonging to the Context. For this reason, the + * linkage becomes incorrect as soon as the Context has more than one Global. The + * {@link #invalidateForever()} is invoked by the Context to invalidate all linkages and + * turn off the functionality of this object as soon as the Context's {@link Context#newGlobal()} is invoked + * for second time. + * * We can extend this to ScriptObjects in general (GLOBAL_ONLY=false), which requires * a receiver guard on the constant getter, but it currently leaks memory and its benefits * have not yet been investigated property. * - * As long as all Globals share the same constant instance, we need synchronization - * whenever we access the instance. + * As long as all Globals in a Context share the same GlobalConstants instance, we need synchronization + * whenever we access it. */ @Logger(name="const") public final class GlobalConstants implements Loggable { @@ -82,7 +91,7 @@ public final class GlobalConstants implements Loggable { * Script objects require a receiver guard, which is memory intensive, so this is currently * disabled. We might implement a weak reference based approach to this later. */ - private static final boolean GLOBAL_ONLY = true; + public static final boolean GLOBAL_ONLY = true; private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); @@ -98,6 +107,8 @@ public final class GlobalConstants implements Loggable { */ private final Map map = new HashMap<>(); + private final AtomicBoolean invalidatedForever = new AtomicBoolean(false); + /** * Constructor - used only by global * @param log logger, or null if none @@ -216,10 +227,34 @@ public final class GlobalConstants implements Loggable { * the same class for a new global, but the builtins and global scoped variables * will have changed. */ - public synchronized void invalidateAll() { - log.info("New global created - invalidating all constant callsites without increasing invocation count."); - for (final Access acc : map.values()) { - acc.invalidateUncounted(); + public void invalidateAll() { + if (!invalidatedForever.get()) { + log.info("New global created - invalidating all constant callsites without increasing invocation count."); + synchronized (this) { + for (final Access acc : map.values()) { + acc.invalidateUncounted(); + } + } + } + } + + /** + * To avoid an expensive global guard "is this the same global", similar to the + * receiver guard on the ScriptObject level, we invalidate all getters when the + * second Global is created by the Context owning this instance. After this + * method is invoked, this GlobalConstants instance will both invalidate all the + * switch points it produced, and it will stop handing out new method handles + * altogether. + */ + public void invalidateForever() { + if (invalidatedForever.compareAndSet(false, true)) { + log.info("New global created - invalidating all constant callsites."); + synchronized (this) { + for (final Access acc : map.values()) { + acc.invalidateForever(); + } + map.clear(); + } } } @@ -251,7 +286,7 @@ public final class GlobalConstants implements Loggable { return obj; } - private synchronized Access getOrCreateSwitchPoint(final String name) { + private Access getOrCreateSwitchPoint(final String name) { Access acc = map.get(name); if (acc != null) { return acc; @@ -267,9 +302,13 @@ public final class GlobalConstants implements Loggable { * @param name name of property */ void delete(final String name) { - final Access acc = map.get(name); - if (acc != null) { - acc.invalidateForever(); + if (!invalidatedForever.get()) { + synchronized (this) { + final Access acc = map.get(name); + if (acc != null) { + acc.invalidateForever(); + } + } } } @@ -313,45 +352,45 @@ public final class GlobalConstants implements Loggable { * * @return null if failed to set up constant linkage */ - synchronized GuardedInvocation findSetMethod(final FindProperty find, final ScriptObject receiver, final GuardedInvocation inv, final CallSiteDescriptor desc, final LinkRequest request) { - if (GLOBAL_ONLY && !isGlobalSetter(receiver, find)) { + GuardedInvocation findSetMethod(final FindProperty find, final ScriptObject receiver, final GuardedInvocation inv, final CallSiteDescriptor desc, final LinkRequest request) { + if (invalidatedForever.get() || (GLOBAL_ONLY && !isGlobalSetter(receiver, find))) { return null; } final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND); - final Access acc = getOrCreateSwitchPoint(name); - - if (log.isEnabled()) { - log.fine("Trying to link constant SETTER ", acc); - } + synchronized (this) { + final Access acc = getOrCreateSwitchPoint(name); - if (!acc.mayRetry()) { if (log.isEnabled()) { - log.fine("*** SET: Giving up on " + quote(name) + " - retry count has exceeded " + DynamicLinker.getLinkedCallSiteLocation()); + log.fine("Trying to link constant SETTER ", acc); } - return null; - } - assert acc.mayRetry(); + if (!acc.mayRetry() || invalidatedForever.get()) { + if (log.isEnabled()) { + log.fine("*** SET: Giving up on " + quote(name) + " - retry count has exceeded " + DynamicLinker.getLinkedCallSiteLocation()); + } + return null; + } - if (acc.hasBeenInvalidated()) { - log.info("New chance for " + acc); - acc.newSwitchPoint(); - } + if (acc.hasBeenInvalidated()) { + log.info("New chance for " + acc); + acc.newSwitchPoint(); + } - assert !acc.hasBeenInvalidated(); + assert !acc.hasBeenInvalidated(); - // if we haven't given up on this symbol, add a switchpoint invalidation filter to the receiver parameter - final MethodHandle target = inv.getInvocation(); - final Class receiverType = target.type().parameterType(0); - final MethodHandle boundInvalidator = MH.bindTo(INVALIDATE_SP, this); - final MethodHandle invalidator = MH.asType(boundInvalidator, boundInvalidator.type().changeParameterType(0, receiverType).changeReturnType(receiverType)); - final MethodHandle mh = MH.filterArguments(inv.getInvocation(), 0, MH.insertArguments(invalidator, 1, acc)); + // if we haven't given up on this symbol, add a switchpoint invalidation filter to the receiver parameter + final MethodHandle target = inv.getInvocation(); + final Class receiverType = target.type().parameterType(0); + final MethodHandle boundInvalidator = MH.bindTo(INVALIDATE_SP, this); + final MethodHandle invalidator = MH.asType(boundInvalidator, boundInvalidator.type().changeParameterType(0, receiverType).changeReturnType(receiverType)); + final MethodHandle mh = MH.filterArguments(inv.getInvocation(), 0, MH.insertArguments(invalidator, 1, acc)); - assert inv.getSwitchPoints() == null : Arrays.asList(inv.getSwitchPoints()); - log.info("Linked setter " + quote(name) + " " + acc.getSwitchPoint()); - return new GuardedInvocation(mh, inv.getGuard(), acc.getSwitchPoint(), inv.getException()); + assert inv.getSwitchPoints() == null : Arrays.asList(inv.getSwitchPoints()); + log.info("Linked setter " + quote(name) + " " + acc.getSwitchPoint()); + return new GuardedInvocation(mh, inv.getGuard(), acc.getSwitchPoint(), inv.getException()); + } } /** @@ -380,11 +419,11 @@ public final class GlobalConstants implements Loggable { * * @return resulting getter, or null if failed to create constant */ - synchronized GuardedInvocation findGetMethod(final FindProperty find, final ScriptObject receiver, final CallSiteDescriptor desc) { + GuardedInvocation findGetMethod(final FindProperty find, final ScriptObject receiver, final CallSiteDescriptor desc) { // Only use constant getter for fast scope access, because the receiver may change between invocations // for slow-scope and non-scope callsites. // Also return null for user accessor properties as they may have side effects. - if (!NashornCallSiteDescriptor.isFastScope(desc) + if (invalidatedForever.get() || !NashornCallSiteDescriptor.isFastScope(desc) || (GLOBAL_ONLY && !find.getOwner().isGlobal()) || find.getProperty() instanceof UserAccessorProperty) { return null; @@ -395,51 +434,53 @@ public final class GlobalConstants implements Loggable { final Class retType = desc.getMethodType().returnType(); final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND); - final Access acc = getOrCreateSwitchPoint(name); - - log.fine("Starting to look up object value " + name); - final Object c = find.getObjectValue(); + synchronized (this) { + final Access acc = getOrCreateSwitchPoint(name); - if (log.isEnabled()) { - log.fine("Trying to link constant GETTER " + acc + " value = " + c); - } + log.fine("Starting to look up object value " + name); + final Object c = find.getObjectValue(); - if (acc.hasBeenInvalidated() || acc.guardFailed()) { if (log.isEnabled()) { - log.info("*** GET: Giving up on " + quote(name) + " - retry count has exceeded " + DynamicLinker.getLinkedCallSiteLocation()); + log.fine("Trying to link constant GETTER " + acc + " value = " + c); } - return null; - } - final MethodHandle cmh = constantGetter(c); + if (acc.hasBeenInvalidated() || acc.guardFailed() || invalidatedForever.get()) { + if (log.isEnabled()) { + log.info("*** GET: Giving up on " + quote(name) + " - retry count has exceeded " + DynamicLinker.getLinkedCallSiteLocation()); + } + return null; + } - MethodHandle mh; - MethodHandle guard; + final MethodHandle cmh = constantGetter(c); - if (isOptimistic) { - if (JSType.getAccessorTypeIndex(cmh.type().returnType()) <= JSType.getAccessorTypeIndex(retType)) { - //widen return type - this is pessimistic, so it will always work - mh = MH.asType(cmh, cmh.type().changeReturnType(retType)); + MethodHandle mh; + MethodHandle guard; + + if (isOptimistic) { + if (JSType.getAccessorTypeIndex(cmh.type().returnType()) <= JSType.getAccessorTypeIndex(retType)) { + //widen return type - this is pessimistic, so it will always work + mh = MH.asType(cmh, cmh.type().changeReturnType(retType)); + } else { + //immediately invalidate - we asked for a too wide constant as a narrower one + mh = MH.dropArguments(MH.insertArguments(JSType.THROW_UNWARRANTED.methodHandle(), 0, c, programPoint), 0, Object.class); + } } else { - //immediately invalidate - we asked for a too wide constant as a narrower one - mh = MH.dropArguments(MH.insertArguments(JSType.THROW_UNWARRANTED.methodHandle(), 0, c, programPoint), 0, Object.class); + //pessimistic return type filter + mh = Lookup.filterReturnType(cmh, retType); } - } else { - //pessimistic return type filter - mh = Lookup.filterReturnType(cmh, retType); - } - if (find.getOwner().isGlobal()) { - guard = null; - } else { - guard = MH.insertArguments(RECEIVER_GUARD, 0, acc, receiver); - } + if (find.getOwner().isGlobal()) { + guard = null; + } else { + guard = MH.insertArguments(RECEIVER_GUARD, 0, acc, receiver); + } - if (log.isEnabled()) { - log.info("Linked getter " + quote(name) + " as MethodHandle.constant() -> " + c + " " + acc.getSwitchPoint()); - mh = MethodHandleFactory.addDebugPrintout(log, Level.FINE, mh, "get const " + acc); - } + if (log.isEnabled()) { + log.info("Linked getter " + quote(name) + " as MethodHandle.constant() -> " + c + " " + acc.getSwitchPoint()); + mh = MethodHandleFactory.addDebugPrintout(log, Level.FINE, mh, "get const " + acc); + } - return new GuardedInvocation(mh, guard, acc.getSwitchPoint(), null); + return new GuardedInvocation(mh, guard, acc.getSwitchPoint(), null); + } } } diff --git a/src/jdk/nashorn/internal/runtime/ScriptObject.java b/src/jdk/nashorn/internal/runtime/ScriptObject.java index a76703cf..dcc0b522 100644 --- a/src/jdk/nashorn/internal/runtime/ScriptObject.java +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java @@ -47,6 +47,7 @@ import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid; import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndex; import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex; import static jdk.nashorn.internal.runtime.linker.NashornGuards.explicitInstanceOfCheck; + import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; @@ -922,7 +923,10 @@ public abstract class ScriptObject implements PropertyAccess { if (property instanceof UserAccessorProperty) { ((UserAccessorProperty)property).setAccessors(this, getMap(), null); } - Global.getConstants().delete(property.getKey()); + final GlobalConstants globalConstants = getGlobalConstants(); + if (globalConstants != null) { + globalConstants.delete(property.getKey()); + } return true; } } @@ -1983,9 +1987,12 @@ public abstract class ScriptObject implements PropertyAccess { } } - final GuardedInvocation cinv = Global.getConstants().findGetMethod(find, this, desc); - if (cinv != null) { - return cinv; + final GlobalConstants globalConstants = getGlobalConstants(); + if (globalConstants != null) { + final GuardedInvocation cinv = globalConstants.findGetMethod(find, this, desc); + if (cinv != null) { + return cinv; + } } final Class returnType = desc.getMethodType().returnType(); @@ -2183,14 +2190,22 @@ public abstract class ScriptObject implements PropertyAccess { final GuardedInvocation inv = new SetMethodCreator(this, find, desc, request).createGuardedInvocation(findBuiltinSwitchPoint(name)); - final GuardedInvocation cinv = Global.getConstants().findSetMethod(find, this, inv, desc, request); - if (cinv != null) { - return cinv; + final GlobalConstants globalConstants = getGlobalConstants(); + if (globalConstants != null) { + final GuardedInvocation cinv = globalConstants.findSetMethod(find, this, inv, desc, request); + if (cinv != null) { + return cinv; + } } return inv; } + private GlobalConstants getGlobalConstants() { + // Avoid hitting getContext() which might be costly for a non-Global unless needed. + return GlobalConstants.GLOBAL_ONLY && !isGlobal() ? null : getContext().getGlobalConstants(); + } + private GuardedInvocation createEmptySetMethod(final CallSiteDescriptor desc, final boolean explicitInstanceOfCheck, final String strictErrorMessage, final boolean canBeFastScope) { final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND); if (NashornCallSiteDescriptor.isStrict(desc)) { -- cgit v1.2.1 From 9107fc634616b6c88635f93c98c9eede5ccf12f1 Mon Sep 17 00:00:00 2001 From: attila Date: Mon, 3 Nov 2014 09:49:52 +0100 Subject: 8059443: NPE when unboxing return values Reviewed-by: lagergren, sundar --- .../internal/dynalink/DynamicLinkerFactory.java | 32 ++++++- .../linker/MethodTypeConversionStrategy.java | 100 +++++++++++++++++++++ .../dynalink/support/TypeConverterFactory.java | 44 +++++++-- .../internal/dynalink/support/TypeUtilities.java | 9 ++ .../nashorn/internal/runtime/linker/Bootstrap.java | 33 +++++++ test/script/basic/JDK-8059443.js | 39 ++++++++ test/script/basic/JDK-8059443.js.EXPECTED | 4 + test/src/jdk/nashorn/test/models/NullProvider.java | 34 +++++++ 8 files changed, 283 insertions(+), 12 deletions(-) create mode 100644 src/jdk/internal/dynalink/linker/MethodTypeConversionStrategy.java create mode 100644 test/script/basic/JDK-8059443.js create mode 100644 test/script/basic/JDK-8059443.js.EXPECTED create mode 100644 test/src/jdk/nashorn/test/models/NullProvider.java diff --git a/src/jdk/internal/dynalink/DynamicLinkerFactory.java b/src/jdk/internal/dynalink/DynamicLinkerFactory.java index af5eb119..2f4e5f33 100644 --- a/src/jdk/internal/dynalink/DynamicLinkerFactory.java +++ b/src/jdk/internal/dynalink/DynamicLinkerFactory.java @@ -97,6 +97,7 @@ import jdk.internal.dynalink.beans.BeansLinker; import jdk.internal.dynalink.linker.GuardingDynamicLinker; import jdk.internal.dynalink.linker.GuardingTypeConverterFactory; import jdk.internal.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.linker.MethodTypeConversionStrategy; import jdk.internal.dynalink.support.AutoDiscovery; import jdk.internal.dynalink.support.BottomGuardingDynamicLinker; import jdk.internal.dynalink.support.ClassLoaderGetterContextProvider; @@ -105,6 +106,7 @@ import jdk.internal.dynalink.support.CompositeTypeBasedGuardingDynamicLinker; import jdk.internal.dynalink.support.DefaultPrelinkFilter; import jdk.internal.dynalink.support.LinkerServicesImpl; import jdk.internal.dynalink.support.TypeConverterFactory; +import jdk.internal.dynalink.support.TypeUtilities; /** * A factory class for creating {@link DynamicLinker}s. The most usual dynamic linker is a linker that is a composition @@ -115,7 +117,6 @@ import jdk.internal.dynalink.support.TypeConverterFactory; * @author Attila Szegedi */ public class DynamicLinkerFactory { - /** * Default value for {@link #setUnstableRelinkThreshold(int) unstable relink threshold}. */ @@ -130,6 +131,7 @@ public class DynamicLinkerFactory { private boolean syncOnRelink = false; private int unstableRelinkThreshold = DEFAULT_UNSTABLE_RELINK_THRESHOLD; private GuardedInvocationFilter prelinkFilter; + private MethodTypeConversionStrategy autoConversionStrategy; /** * Sets the class loader for automatic discovery of available linkers. If not set explicitly, then the thread @@ -258,6 +260,29 @@ public class DynamicLinkerFactory { this.prelinkFilter = prelinkFilter; } + /** + * Sets an object representing the conversion strategy for automatic type conversions. After + * {@link TypeConverterFactory#asType(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType)} has + * applied all custom conversions to a method handle, it still needs to effect + * {@link TypeUtilities#isMethodInvocationConvertible(Class, Class) method invocation conversions} that + * can usually be automatically applied as per + * {@link java.lang.invoke.MethodHandle#asType(java.lang.invoke.MethodType)}. + * However, sometimes language runtimes will want to customize even those conversions for their own call + * sites. A typical example is allowing unboxing of null return values, which is by default prohibited by + * ordinary {@code MethodHandles.asType}. In this case, a language runtime can install its own custom + * automatic conversion strategy, that can deal with null values. Note that when the strategy's + * {@link MethodTypeConversionStrategy#asType(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType)} + * is invoked, the custom language conversions will already have been applied to the method handle, so by + * design the difference between the handle's current method type and the desired final type will always + * only be ones that can be subjected to method invocation conversions. The strategy also doesn't need to + * invoke a final {@code MethodHandle.asType()} as the converter factory will do that as the final step. + * @param autoConversionStrategy the strategy for applying method invocation conversions for the linker + * created by this factory. + */ + public void setAutoConversionStrategy(final MethodTypeConversionStrategy autoConversionStrategy) { + this.autoConversionStrategy = autoConversionStrategy; + } + /** * Creates a new dynamic linker consisting of all the prioritized, autodiscovered, and fallback linkers as well as * the pre-link filter. @@ -324,8 +349,9 @@ public class DynamicLinkerFactory { prelinkFilter = new DefaultPrelinkFilter(); } - return new DynamicLinker(new LinkerServicesImpl(new TypeConverterFactory(typeConverters), composite), - prelinkFilter, runtimeContextArgCount, syncOnRelink, unstableRelinkThreshold); + return new DynamicLinker(new LinkerServicesImpl(new TypeConverterFactory(typeConverters, + autoConversionStrategy), composite), prelinkFilter, runtimeContextArgCount, syncOnRelink, + unstableRelinkThreshold); } private static ClassLoader getThreadContextClassLoader() { diff --git a/src/jdk/internal/dynalink/linker/MethodTypeConversionStrategy.java b/src/jdk/internal/dynalink/linker/MethodTypeConversionStrategy.java new file mode 100644 index 00000000..f270c5fc --- /dev/null +++ b/src/jdk/internal/dynalink/linker/MethodTypeConversionStrategy.java @@ -0,0 +1,100 @@ +/* + * 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. 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2014 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.linker; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; + +/** + * Interface for objects representing a strategy for converting a method handle to a new type. + */ +public interface MethodTypeConversionStrategy { + /** + * Converts a method handle to a new type. + * @param target target method handle + * @param newType new type + * @return target converted to the new type. + */ + public MethodHandle asType(final MethodHandle target, final MethodType newType); +} diff --git a/src/jdk/internal/dynalink/support/TypeConverterFactory.java b/src/jdk/internal/dynalink/support/TypeConverterFactory.java index 79f6549b..736b787c 100644 --- a/src/jdk/internal/dynalink/support/TypeConverterFactory.java +++ b/src/jdk/internal/dynalink/support/TypeConverterFactory.java @@ -97,6 +97,7 @@ import jdk.internal.dynalink.linker.GuardedInvocation; import jdk.internal.dynalink.linker.GuardedTypeConversion; import jdk.internal.dynalink.linker.GuardingTypeConverterFactory; import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.linker.MethodTypeConversionStrategy; /** * A factory for type converters. This class is the main implementation behind the @@ -109,6 +110,7 @@ public class TypeConverterFactory { private final GuardingTypeConverterFactory[] factories; private final ConversionComparator[] comparators; + private final MethodTypeConversionStrategy autoConversionStrategy; private final ClassValue> converterMap = new ClassValue>() { @Override @@ -177,8 +179,24 @@ public class TypeConverterFactory { * Creates a new type converter factory from the available {@link GuardingTypeConverterFactory} instances. * * @param factories the {@link GuardingTypeConverterFactory} instances to compose. + * @param autoConversionStrategy conversion strategy for automatic type conversions. After + * {@link #asType(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType)} has applied all custom + * conversions to a method handle, it still needs to effect + * {@link TypeUtilities#isMethodInvocationConvertible(Class, Class) method invocation conversions} that + * can usually be automatically applied as per + * {@link java.lang.invoke.MethodHandle#asType(java.lang.invoke.MethodType)}. + * However, sometimes language runtimes will want to customize even those conversions for their own call + * sites. A typical example is allowing unboxing of null return values, which is by default prohibited by + * ordinary {@code MethodHandles.asType}. In this case, a language runtime can install its own custom + * automatic conversion strategy, that can deal with null values. Note that when the strategy's + * {@link MethodTypeConversionStrategy#asType(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType)} + * is invoked, the custom language conversions will already have been applied to the method handle, so by + * design the difference between the handle's current method type and the desired final type will always + * only be ones that can be subjected to method invocation conversions. Can be null, in which case no + * custom strategy is employed. */ - public TypeConverterFactory(final Iterable factories) { + public TypeConverterFactory(final Iterable factories, + final MethodTypeConversionStrategy autoConversionStrategy) { final List l = new LinkedList<>(); final List c = new LinkedList<>(); for(final GuardingTypeConverterFactory factory: factories) { @@ -189,20 +207,24 @@ public class TypeConverterFactory { } this.factories = l.toArray(new GuardingTypeConverterFactory[l.size()]); this.comparators = c.toArray(new ConversionComparator[c.size()]); - + this.autoConversionStrategy = autoConversionStrategy; } /** * Similar to {@link MethodHandle#asType(MethodType)} except it also hooks in method handles produced by * {@link GuardingTypeConverterFactory} implementations, providing for language-specific type coercing of - * parameters. It will apply {@link MethodHandle#asType(MethodType)} for all primitive-to-primitive, - * wrapper-to-primitive, primitive-to-wrapper conversions as well as for all upcasts. For all other conversions, - * it'll insert {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)} with composite filters - * provided by {@link GuardingTypeConverterFactory} implementations. + * parameters. For all conversions that are not a JLS method invocation conversion it'll insert + * {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)} with composite filters + * provided by {@link GuardingTypeConverterFactory} implementations. For the remaining JLS method invocation + * conversions, it will invoke {@link MethodTypeConversionStrategy#asType(MethodHandle, MethodType)} first + * if an automatic conversion strategy was specified in the + * {@link #TypeConverterFactory(Iterable, MethodTypeConversionStrategy) constructor}, and finally apply + * {@link MethodHandle#asType(MethodType)} for any remaining conversions. * * @param handle target method handle * @param fromType the types of source arguments - * @return a method handle that is a suitable combination of {@link MethodHandle#asType(MethodType)} and + * @return a method handle that is a suitable combination of {@link MethodHandle#asType(MethodType)}, + * {@link MethodTypeConversionStrategy#asType(MethodHandle, MethodType)}, and * {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)} with * {@link GuardingTypeConverterFactory} produced type converters as filters. */ @@ -246,8 +268,12 @@ public class TypeConverterFactory { } } - // Take care of automatic conversions - return newHandle.asType(fromType); + // Give change to automatic conversion strategy, if one is present. + final MethodHandle autoConvertedHandle = + autoConversionStrategy != null ? autoConversionStrategy.asType(newHandle, fromType) : newHandle; + + // Do a final asType for any conversions that remain. + return autoConvertedHandle.asType(fromType); } private static MethodHandle applyConverters(final MethodHandle handle, final int pos, final List converters) { diff --git a/src/jdk/internal/dynalink/support/TypeUtilities.java b/src/jdk/internal/dynalink/support/TypeUtilities.java index 6403f3d5..bf4771b2 100644 --- a/src/jdk/internal/dynalink/support/TypeUtilities.java +++ b/src/jdk/internal/dynalink/support/TypeUtilities.java @@ -520,4 +520,13 @@ public class TypeUtilities { public static Class getWrapperType(final Class primitiveType) { return WRAPPER_TYPES.get(primitiveType); } + + /** + * Returns true if the passed type is a wrapper for a primitive type. + * @param type the examined type + * @return true if the passed type is a wrapper for a primitive type. + */ + public static boolean isWrapperType(final Class type) { + return PRIMITIVE_TYPES.containsKey(type); + } } diff --git a/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java b/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java index a0842f2d..8c270fb8 100644 --- a/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java +++ b/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java @@ -42,6 +42,8 @@ import jdk.internal.dynalink.beans.StaticClass; import jdk.internal.dynalink.linker.GuardedInvocation; import jdk.internal.dynalink.linker.LinkRequest; import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.linker.MethodTypeConversionStrategy; +import jdk.internal.dynalink.support.TypeUtilities; import jdk.nashorn.api.scripting.JSObject; import jdk.nashorn.internal.codegen.CompilerConstants.Call; import jdk.nashorn.internal.codegen.ObjectClassGenerator; @@ -106,6 +108,12 @@ public final class Bootstrap { return OptimisticReturnFilters.filterOptimisticReturnValue(inv, desc).asType(linkerServices, desc.getMethodType()); } }); + factory.setAutoConversionStrategy(new MethodTypeConversionStrategy() { + @Override + public MethodHandle asType(final MethodHandle target, final MethodType newType) { + return unboxReturnType(target, newType); + } + }); final int relinkThreshold = Options.getIntProperty("nashorn.unstable.relink.threshold", NASHORN_DEFAULT_UNSTABLE_RELINK_THRESHOLD); if (relinkThreshold > -1) { factory.setUnstableRelinkThreshold(relinkThreshold); @@ -420,4 +428,29 @@ public final class Bootstrap { static GuardedInvocation asTypeSafeReturn(final GuardedInvocation inv, final LinkerServices linkerServices, final CallSiteDescriptor desc) { return inv == null ? null : inv.asTypeSafeReturn(linkerServices, desc.getMethodType()); } + + /** + * Adapts the return type of the method handle with {@code explicitCastArguments} when it is an unboxing + * conversion. This will ensure that nulls are unwrapped to false or 0. + * @param target the target method handle + * @param newType the desired new type. Note that this method does not adapt the method handle completely to the + * new type, it only adapts the return type; this is allowed as per + * {@link DynamicLinkerFactory#setAutoConversionStrategy(MethodTypeConversionStrategy)}, which is what this method + * is used for. + * @return the method handle with adapted return type, if it required an unboxing conversion. + */ + private static MethodHandle unboxReturnType(final MethodHandle target, final MethodType newType) { + final MethodType targetType = target.type(); + final Class oldReturnType = targetType.returnType(); + if (TypeUtilities.isWrapperType(oldReturnType)) { + final Class newReturnType = newType.returnType(); + if (newReturnType.isPrimitive()) { + // The contract of setAutoConversionStrategy is such that the difference between newType and targetType + // can only be JLS method invocation conversions. + assert TypeUtilities.isMethodInvocationConvertible(oldReturnType, newReturnType); + return MethodHandles.explicitCastArguments(target, targetType.changeReturnType(newReturnType)); + } + } + return target; + } } diff --git a/test/script/basic/JDK-8059443.js b/test/script/basic/JDK-8059443.js new file mode 100644 index 00000000..e0d2b0f8 --- /dev/null +++ b/test/script/basic/JDK-8059443.js @@ -0,0 +1,39 @@ +/* + * 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. + */ + +/** + * JDK-8059443: NPE when unboxing return values + * + * NOTE: this test can only pass when running with a JDK where + * JDK-8060483 is also fixed (9b37 or later). + * + * @test + * @run + */ + +var NullProvider = Java.type("jdk.nashorn.test.models.NullProvider"); + +if (!NullProvider.getBoolean()) { print("yay"); } +print(NullProvider.getLong() * (1 << 33)); +print(NullProvider.getDouble() / 2.5); +print(NullProvider.getInteger() << 1); diff --git a/test/script/basic/JDK-8059443.js.EXPECTED b/test/script/basic/JDK-8059443.js.EXPECTED new file mode 100644 index 00000000..dc60c976 --- /dev/null +++ b/test/script/basic/JDK-8059443.js.EXPECTED @@ -0,0 +1,4 @@ +yay +0 +0 +0 diff --git a/test/src/jdk/nashorn/test/models/NullProvider.java b/test/src/jdk/nashorn/test/models/NullProvider.java new file mode 100644 index 00000000..128d1198 --- /dev/null +++ b/test/src/jdk/nashorn/test/models/NullProvider.java @@ -0,0 +1,34 @@ +/* + * 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. 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.test.models; + + +public class NullProvider { + public static Integer getInteger() { return null; } + public static Long getLong() { return null; } + public static Double getDouble() { return null; } + public static Boolean getBoolean() { return null; } +} -- cgit v1.2.1 From 16e835ac344d7dfa3808e2df9f7bab92c948159d Mon Sep 17 00:00:00 2001 From: asaha Date: Mon, 3 Nov 2014 12:35:17 -0800 Subject: Added tag jdk8u31-b07 for changeset 5ed4fa732b26 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 6e5ae4f8..a710bd75 100644 --- a/.hgtags +++ b/.hgtags @@ -329,3 +329,4 @@ cdbf34dbef404b47805c8c85b11c65c2afaa6674 jdk8u25-b18 96acff2ad9e19aa80c4f7ed60d87a422bca1ea91 jdk8u31-b04 5fc3f210872d365c57ed4e8dba3926d9ed5c7e45 jdk8u31-b05 99a3333f7f8489bb3c80f0c0643ae19e549a0941 jdk8u31-b06 +5ed4fa732b26b6d8e37dfc5bbd00047c5352719b jdk8u31-b07 -- cgit v1.2.1 From 20ff91c22183f34eea12e7573e77140cbffedc34 Mon Sep 17 00:00:00 2001 From: katleman Date: Wed, 5 Nov 2014 12:54:12 -0800 Subject: Added tag jdk8u40-b13 for changeset d60fbb5343c1 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index dde92efc..f1e34539 100644 --- a/.hgtags +++ b/.hgtags @@ -332,3 +332,4 @@ a2e0a985764b5afd5f316429bfab4f44bf150f7f jdk8u40-b03 076b1f38a5ccd4692a6f93939a7fc03bc1a1bbb4 jdk8u40-b10 57c7b273277e00f7a98fafb18ff07aa3245808f0 jdk8u40-b11 375a3a3256d041fe7334638a95e69b4c11d6104b jdk8u40-b12 +d60fbb5343c186abbf92b0259e67efb3b71377b4 jdk8u40-b13 -- cgit v1.2.1 From d710cf0d43b60bae7ce6e89fcbd789a9bd12cb60 Mon Sep 17 00:00:00 2001 From: asaha Date: Mon, 10 Nov 2014 11:52:28 -0800 Subject: Added tag jdk8u31-b08 for changeset b17ecf341ee5 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index a710bd75..5fca6fbd 100644 --- a/.hgtags +++ b/.hgtags @@ -330,3 +330,4 @@ cdbf34dbef404b47805c8c85b11c65c2afaa6674 jdk8u25-b18 5fc3f210872d365c57ed4e8dba3926d9ed5c7e45 jdk8u31-b05 99a3333f7f8489bb3c80f0c0643ae19e549a0941 jdk8u31-b06 5ed4fa732b26b6d8e37dfc5bbd00047c5352719b jdk8u31-b07 +b17ecf341ee544cc5507b9b586c14a13c3adc058 jdk8u31-b08 -- cgit v1.2.1 From b7994c3ee6e44cd312160ac83904df3cc2b7e4ae Mon Sep 17 00:00:00 2001 From: attila Date: Tue, 11 Nov 2014 16:17:37 +0100 Subject: 8064467: type info persistence failed to calculate directory name Reviewed-by: hannesw, lagergren --- make/build.xml | 1 + .../codegen/OptimisticTypesPersistence.java | 43 +++++++++++++++++++--- src/jdk/nashorn/internal/codegen/anchor.properties | 27 ++++++++++++++ 3 files changed, 66 insertions(+), 5 deletions(-) create mode 100644 src/jdk/nashorn/internal/codegen/anchor.properties diff --git a/make/build.xml b/make/build.xml index f6de5589..a7539f48 100644 --- a/make/build.xml +++ b/make/build.xml @@ -155,6 +155,7 @@ + ${line.separator} diff --git a/src/jdk/nashorn/internal/codegen/OptimisticTypesPersistence.java b/src/jdk/nashorn/internal/codegen/OptimisticTypesPersistence.java index 6ca50899..53a107e6 100644 --- a/src/jdk/nashorn/internal/codegen/OptimisticTypesPersistence.java +++ b/src/jdk/nashorn/internal/codegen/OptimisticTypesPersistence.java @@ -33,6 +33,8 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.PrintWriter; +import java.io.StringWriter; import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; @@ -221,11 +223,37 @@ public final class OptimisticTypesPersistence { private static void reportError(final String msg, final File file, final Exception e) { final long now = System.currentTimeMillis(); if(now - lastReportedError > ERROR_REPORT_THRESHOLD) { - getLogger().warning(String.format("Failed to %s %s", msg, file), e); + reportError(String.format("Failed to %s %s", msg, file), e); lastReportedError = now; } } + /** + * Logs an error message with warning severity (reasoning being that we're reporting an error that'll disable the + * type info cache, but it's only logged as a warning because that doesn't prevent Nashorn from running, it just + * disables a performance-enhancing cache). + * @param msg the message to log + * @param e the exception that represents the error. + */ + private static void reportError(final String msg, final Exception e) { + getLogger().warning(msg, "\n", exceptionToString(e)); + } + + /** + * A helper that prints an exception stack trace into a string. We have to do this as if we just pass the exception + * to {@link DebugLogger#warning(Object...)}, it will only log the exception message and not the stack, making + * problems harder to diagnose. + * @param e the exception + * @return the string representation of {@link Exception#printStackTrace()} output. + */ + private static String exceptionToString(final Exception e) { + final StringWriter sw = new StringWriter(); + final PrintWriter pw = new PrintWriter(sw, false); + e.printStackTrace(pw); + pw.flush(); + return sw.toString(); + } + private static File createBaseCacheDir() { if(MAX_FILES == 0 || Options.getBooleanProperty("nashorn.typeInfo.disabled")) { return null; @@ -233,7 +261,7 @@ public final class OptimisticTypesPersistence { try { return createBaseCacheDirPrivileged(); } catch(final Exception e) { - getLogger().warning("Failed to create cache dir", e); + reportError("Failed to create cache dir", e); return null; } } @@ -267,7 +295,7 @@ public final class OptimisticTypesPersistence { try { return createCacheDirPrivileged(baseDir); } catch(final Exception e) { - getLogger().warning("Failed to create cache dir", e); + reportError("Failed to create cache dir", e); return null; } } @@ -280,7 +308,7 @@ public final class OptimisticTypesPersistence { try { versionDirName = getVersionDirName(); } catch(final Exception e) { - getLogger().warning("Failed to calculate version dir name", e); + reportError("Failed to calculate version dir name", e); return null; } final File versionDir = new File(baseDir, versionDirName); @@ -328,7 +356,12 @@ public final class OptimisticTypesPersistence { * @throws Exception if digest could not be created */ public static String getVersionDirName() throws Exception { - final URL url = OptimisticTypesPersistence.class.getResource(""); + // NOTE: getResource("") won't work if the JAR file doesn't have directory entries (and JAR files in JDK distro + // don't, or at least it's a bad idea counting on it). Alternatively, we could've tried + // getResource("OptimisticTypesPersistence.class") but behavior of getResource with regard to its willingness + // to hand out URLs to .class files is also unspecified. Therefore, the most robust way to obtain an URL to our + // package is to have a small non-class anchor file and start out from its URL. + final URL url = OptimisticTypesPersistence.class.getResource("anchor.properties"); final String protocol = url.getProtocol(); if (protocol.equals("jar")) { // Normal deployment: nashorn.jar diff --git a/src/jdk/nashorn/internal/codegen/anchor.properties b/src/jdk/nashorn/internal/codegen/anchor.properties new file mode 100644 index 00000000..1a930682 --- /dev/null +++ b/src/jdk/nashorn/internal/codegen/anchor.properties @@ -0,0 +1,27 @@ +# +# 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. 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. +# + + +# This file exists only so OptimisticTypesPersistence.getVersionDirName() can take its URL. -- cgit v1.2.1 From 3eb1beae3365dd083fb9f60958208a63a4d9d446 Mon Sep 17 00:00:00 2001 From: attila Date: Tue, 11 Nov 2014 17:27:44 +0100 Subject: 8062799: Binary logical expressions can have numeric types Reviewed-by: lagergren, sundar --- src/jdk/nashorn/internal/ir/BinaryNode.java | 4 ++ test/script/basic/JDK-8062799.js | 103 ++++++++++++++++++++++++++++ test/script/basic/JDK-8062799.js.EXPECTED | 50 ++++++++++++++ 3 files changed, 157 insertions(+) create mode 100644 test/script/basic/JDK-8062799.js create mode 100644 test/script/basic/JDK-8062799.js.EXPECTED diff --git a/src/jdk/nashorn/internal/ir/BinaryNode.java b/src/jdk/nashorn/internal/ir/BinaryNode.java index c2456363..cb8cc918 100644 --- a/src/jdk/nashorn/internal/ir/BinaryNode.java +++ b/src/jdk/nashorn/internal/ir/BinaryNode.java @@ -264,6 +264,10 @@ public final class BinaryNode extends Expression implements Assignment Date: Wed, 12 Nov 2014 14:54:40 +0100 Subject: 8063037: ApplySpecialization.hasApplies shouuld not descend into nested functions Reviewed-by: hannesw, lagergren --- src/jdk/nashorn/internal/codegen/ApplySpecialization.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/jdk/nashorn/internal/codegen/ApplySpecialization.java b/src/jdk/nashorn/internal/codegen/ApplySpecialization.java index 274afc84..62e58f46 100644 --- a/src/jdk/nashorn/internal/codegen/ApplySpecialization.java +++ b/src/jdk/nashorn/internal/codegen/ApplySpecialization.java @@ -140,6 +140,11 @@ public final class ApplySpecialization extends NodeVisitor imple private boolean hasApplies(final FunctionNode functionNode) { try { functionNode.accept(new NodeVisitor(new LexicalContext()) { + @Override + public boolean enterFunctionNode(final FunctionNode fn) { + return fn == functionNode; + } + @Override public boolean enterCallNode(final CallNode callNode) { if (isApply(callNode)) { @@ -162,7 +167,7 @@ public final class ApplySpecialization extends NodeVisitor imple * scope, thus we are conservative and treat any access to arguments outside the * apply call as a case of "we cannot apply the optimization". */ - private void checkValidTransform(final FunctionNode functionNode) { + private static void checkValidTransform(final FunctionNode functionNode) { final Set argumentsFound = new HashSet<>(); final Deque> stack = new ArrayDeque<>(); -- cgit v1.2.1 From d8e6197d4b2278ce3788366a0516165b8612dce2 Mon Sep 17 00:00:00 2001 From: lagergren Date: Wed, 12 Nov 2014 14:12:01 +0100 Subject: 8035312: Various array and ScriptObject length issues for non writable length fields Reviewed-by: hannesw, attila --- src/jdk/nashorn/internal/objects/NativeArray.java | 270 +++++++-------------- src/jdk/nashorn/internal/objects/NativeDebug.java | 31 +++ .../objects/annotations/SpecializedFunction.java | 129 ---------- .../nashorn/internal/runtime/ScriptFunction.java | 10 - src/jdk/nashorn/internal/runtime/ScriptObject.java | 14 +- .../nashorn/internal/runtime/arrays/ArrayData.java | 141 ++++++++--- .../internal/runtime/arrays/ArrayFilter.java | 34 +-- .../runtime/arrays/ContinuousArrayData.java | 4 +- .../runtime/arrays/DeletedArrayFilter.java | 27 +-- .../runtime/arrays/DeletedRangeArrayFilter.java | 10 +- .../internal/runtime/arrays/FrozenArrayFilter.java | 13 +- .../internal/runtime/arrays/IntArrayData.java | 65 ++--- .../runtime/arrays/LengthNotWritableFilter.java | 198 +++++++++++++++ .../internal/runtime/arrays/LongArrayData.java | 62 ++--- .../runtime/arrays/NonExtensibleArrayFilter.java | 4 +- .../internal/runtime/arrays/NumberArrayData.java | 54 +++-- .../internal/runtime/arrays/ObjectArrayData.java | 45 ++-- .../internal/runtime/arrays/SparseArrayData.java | 78 +++--- .../internal/runtime/arrays/TypedArrayData.java | 4 +- .../runtime/arrays/UndefinedArrayFilter.java | 19 +- test/script/basic/JDK-8035312.js | 225 +++++++++++++++++ test/script/basic/JDK-8035312.js.EXPECTED | 186 ++++++++++++++ test/script/basic/JDK-8035312_2.js | 65 +++++ test/script/basic/JDK-8035312_2.js.EXPECTED | 47 ++++ test/script/basic/JDK-8035312_3.js | 43 ++++ test/script/basic/JDK-8035312_3.js.EXPECTED | 3 + test/script/basic/JDK-8035312_4.js | 59 +++++ test/script/basic/JDK-8035312_4.js.EXPECTED | 23 ++ test/script/basic/JDK-8035312_5.js | 60 +++++ test/script/basic/JDK-8035312_5.js.EXPECTED | 6 + test/script/basic/fastpushpop.js.EXPECTED | 4 +- 31 files changed, 1354 insertions(+), 579 deletions(-) create mode 100644 src/jdk/nashorn/internal/runtime/arrays/LengthNotWritableFilter.java create mode 100644 test/script/basic/JDK-8035312.js create mode 100644 test/script/basic/JDK-8035312.js.EXPECTED create mode 100644 test/script/basic/JDK-8035312_2.js create mode 100644 test/script/basic/JDK-8035312_2.js.EXPECTED create mode 100644 test/script/basic/JDK-8035312_3.js create mode 100644 test/script/basic/JDK-8035312_3.js.EXPECTED create mode 100644 test/script/basic/JDK-8035312_4.js create mode 100644 test/script/basic/JDK-8035312_4.js.EXPECTED create mode 100644 test/script/basic/JDK-8035312_5.js create mode 100644 test/script/basic/JDK-8035312_5.js.EXPECTED diff --git a/src/jdk/nashorn/internal/objects/NativeArray.java b/src/jdk/nashorn/internal/objects/NativeArray.java index da07432d..40835758 100644 --- a/src/jdk/nashorn/internal/objects/NativeArray.java +++ b/src/jdk/nashorn/internal/objects/NativeArray.java @@ -33,9 +33,7 @@ import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex; 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; import java.util.Arrays; import java.util.Collections; @@ -93,17 +91,10 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin 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 ConcatLinkLogic concatLinkLogic; - /** - * Index for the modification SwitchPoint that triggers when length - * becomes not writable - */ - private static final int LENGTH_NOT_WRITABLE_SWITCHPOINT = 0; - /* * Constructors. */ @@ -271,12 +262,83 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin @Override public Object getLength() { final long length = JSType.toUint32(getArray().length()); - if(length < Integer.MAX_VALUE) { + if (length < Integer.MAX_VALUE) { return (int)length; } return length; } + private boolean defineLength(final long oldLen, final PropertyDescriptor oldLenDesc, final PropertyDescriptor desc, final boolean reject) { + // Step 3a + if (!desc.has(VALUE)) { + return super.defineOwnProperty("length", desc, reject); + } + + // Step 3b + final PropertyDescriptor newLenDesc = desc; + + // Step 3c and 3d - get new length and convert to long + final long newLen = NativeArray.validLength(newLenDesc.getValue(), true); + + // Step 3e + newLenDesc.setValue(newLen); + + // Step 3f + // increasing array length - just need to set new length value (and attributes if any) and return + if (newLen >= oldLen) { + return super.defineOwnProperty("length", newLenDesc, reject); + } + + // Step 3g + if (!oldLenDesc.isWritable()) { + if (reject) { + throw typeError("property.not.writable", "length", ScriptRuntime.safeToString(this)); + } + return false; + } + + // Step 3h and 3i + final boolean newWritable = !newLenDesc.has(WRITABLE) || newLenDesc.isWritable(); + if (!newWritable) { + newLenDesc.setWritable(true); + } + + // Step 3j and 3k + final boolean succeeded = super.defineOwnProperty("length", newLenDesc, reject); + if (!succeeded) { + return false; + } + + // Step 3l + // make sure that length is set till the point we can delete the old elements + long o = oldLen; + while (newLen < o) { + o--; + final boolean deleteSucceeded = delete(o, false); + if (!deleteSucceeded) { + newLenDesc.setValue(o + 1); + if (!newWritable) { + newLenDesc.setWritable(false); + } + super.defineOwnProperty("length", newLenDesc, false); + if (reject) { + throw typeError("property.not.writable", "length", ScriptRuntime.safeToString(this)); + } + return false; + } + } + + // Step 3m + if (!newWritable) { + // make 'length' property not writable + final ScriptObject newDesc = Global.newEmptyInstance(); + newDesc.set(WRITABLE, false, 0); + return super.defineOwnProperty("length", newDesc, false); + } + + return true; + } + /** * ECMA 15.4.5.1 [[DefineOwnProperty]] ( P, Desc, Throw ) */ @@ -290,82 +352,16 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin // Step 2 // get old length and convert to long - long oldLen = NativeArray.validLength(oldLenDesc.getValue(), true); + final long oldLen = NativeArray.validLength(oldLenDesc.getValue(), true); // Step 3 if ("length".equals(key)) { // check for length being made non-writable + final boolean result = defineLength(oldLen, oldLenDesc, desc, reject); if (desc.has(WRITABLE) && !desc.isWritable()) { setIsLengthNotWritable(); } - - // Step 3a - if (!desc.has(VALUE)) { - return super.defineOwnProperty("length", desc, reject); - } - - // Step 3b - final PropertyDescriptor newLenDesc = desc; - - // Step 3c and 3d - get new length and convert to long - final long newLen = NativeArray.validLength(newLenDesc.getValue(), true); - - // Step 3e - newLenDesc.setValue(newLen); - - // Step 3f - // increasing array length - just need to set new length value (and attributes if any) and return - if (newLen >= oldLen) { - return super.defineOwnProperty("length", newLenDesc, reject); - } - - // Step 3g - if (!oldLenDesc.isWritable()) { - if (reject) { - throw typeError("property.not.writable", "length", ScriptRuntime.safeToString(this)); - } - return false; - } - - // Step 3h and 3i - final boolean newWritable = !newLenDesc.has(WRITABLE) || newLenDesc.isWritable(); - if (!newWritable) { - newLenDesc.setWritable(true); - } - - // Step 3j and 3k - final boolean succeeded = super.defineOwnProperty("length", newLenDesc, reject); - if (!succeeded) { - return false; - } - - // Step 3l - // make sure that length is set till the point we can delete the old elements - while (newLen < oldLen) { - oldLen--; - final boolean deleteSucceeded = delete(oldLen, false); - if (!deleteSucceeded) { - newLenDesc.setValue(oldLen + 1); - if (!newWritable) { - newLenDesc.setWritable(false); - } - super.defineOwnProperty("length", newLenDesc, false); - if (reject) { - throw typeError("property.not.writable", "length", ScriptRuntime.safeToString(this)); - } - return false; - } - } - - // Step 3m - if (!newWritable) { - // make 'length' property not writable - final ScriptObject newDesc = Global.newEmptyInstance(); - newDesc.set(WRITABLE, false, 0); - return super.defineOwnProperty("length", newDesc, false); - } - - return true; + return result; } // Step 4a @@ -441,23 +437,7 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin @Override public void setIsLengthNotWritable() { super.setIsLengthNotWritable(); - /* - * Switchpoints are created lazily. If we link any push or pop site, - * we need to create the "length made not writable" switchpoint, if it - * doesn't exist. - * - * If the switchpoint already exists, we will find it here, and invalidate - * it, invalidating all previous callsites that use it. - * - * If the switchpoint doesn't exist, no push/pop has been linked so far, - * because that would create it too. We invalidate it immediately and the - * check link logic for all future callsites will fail immediately at link - * time - */ - if (lengthMadeNotWritableSwitchPoint == null) { - lengthMadeNotWritableSwitchPoint = new SwitchPoint(); - } - SwitchPoint.invalidateAll(new SwitchPoint[] { lengthMadeNotWritableSwitchPoint }); + setArray(ArrayData.setIsLengthNotWritable(getArray())); } /** @@ -494,7 +474,7 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin @Setter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE) public static void length(final Object self, final Object length) { if (isArray(self)) { - ((ScriptObject) self).setLength(validLength(length, true)); + ((ScriptObject)self).setLength(validLength(length, true)); } } @@ -1306,10 +1286,13 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin // Get only non-missing elements. Missing elements go at the end // of the sorted array. So, just don't copy these to sort input. final ArrayList src = new ArrayList<>(); - for (long i = 0; i < len; i = array.nextIndex(i)) { - if (array.has((int) i)) { - src.add(array.getObject((int) i)); + + for (final Iterator iter = array.indexIterator(); iter.hasNext(); ) { + final long index = iter.next(); + if (index >= len) { + break; } + src.add(array.getObject((int)index)); } final Object[] sorted = sort(src.toArray(), comparefn); @@ -1767,11 +1750,11 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin @Override public SpecializedFunction.LinkLogic getLinkLogic(final Class clazz) { if (clazz == PushLinkLogic.class) { - return pushLinkLogic == null ? new PushLinkLogic(this) : pushLinkLogic; + return pushLinkLogic == null ? new PushLinkLogic() : pushLinkLogic; } else if (clazz == PopLinkLogic.class) { - return popLinkLogic == null ? new PopLinkLogic(this) : pushLinkLogic; + return popLinkLogic == null ? new PopLinkLogic() : pushLinkLogic; } else if (clazz == ConcatLinkLogic.class) { - return concatLinkLogic == null ? new ConcatLinkLogic(this) : concatLinkLogic; + return concatLinkLogic == null ? new ConcatLinkLogic() : concatLinkLogic; } return null; } @@ -1787,21 +1770,7 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin * modification switchpoint which is touched when length is written. */ private static abstract class ArrayLinkLogic extends SpecializedFunction.LinkLogic { - private final NativeArray array; - - protected ArrayLinkLogic(final NativeArray array) { - this.array = array; - } - - private SwitchPoint getSwitchPoint() { - return array.lengthMadeNotWritableSwitchPoint; - } - - private SwitchPoint newSwitchPoint() { - assert array.lengthMadeNotWritableSwitchPoint == null; - final SwitchPoint sp = new SwitchPoint(); - array.lengthMadeNotWritableSwitchPoint = sp; - return sp; + protected ArrayLinkLogic() { } protected static ContinuousArrayData getContinuousArrayData(final Object self) { @@ -1822,69 +1791,12 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin public Class getRelinkException() { return ClassCastException.class; } - - @Override - public boolean hasModificationSwitchPoints() { - return getSwitchPoint() != null; - } - - @Override - public boolean hasModificationSwitchPoint(final int index) { - assert index == LENGTH_NOT_WRITABLE_SWITCHPOINT; - return hasModificationSwitchPoints(); - } - - @Override - public SwitchPoint getOrCreateModificationSwitchPoint(final int index) { - assert index == LENGTH_NOT_WRITABLE_SWITCHPOINT; - SwitchPoint sp = getSwitchPoint(); - if (sp == null) { - sp = newSwitchPoint(); - } - return sp; - } - - @Override - public SwitchPoint[] getOrCreateModificationSwitchPoints() { - return new SwitchPoint[] { getOrCreateModificationSwitchPoint(LENGTH_NOT_WRITABLE_SWITCHPOINT) }; - } - - @Override - public void invalidateModificationSwitchPoint(final int index) { - assert index == LENGTH_NOT_WRITABLE_SWITCHPOINT; - invalidateModificationSwitchPoints(); - } - - @Override - public void invalidateModificationSwitchPoints() { - final SwitchPoint sp = getSwitchPoint(); - assert sp != null : "trying to invalidate non-existant modified SwitchPoint"; - if (!sp.hasBeenInvalidated()) { - SwitchPoint.invalidateAll(new SwitchPoint[] { sp }); - } - } - - @Override - public boolean hasInvalidatedModificationSwitchPoint(final int index) { - assert index == LENGTH_NOT_WRITABLE_SWITCHPOINT; - return hasInvalidatedModificationSwitchPoints(); - } - - @Override - public boolean hasInvalidatedModificationSwitchPoints() { - final SwitchPoint sp = getSwitchPoint(); - return sp != null && !sp.hasBeenInvalidated(); - } } /** * 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(); @@ -1915,10 +1827,6 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin * This is linker logic for optimistic pushes */ private static final class PushLinkLogic extends ArrayLinkLogic { - private PushLinkLogic(final NativeArray array) { - super(array); - } - @Override public boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request) { return getContinuousArrayData(self) != null; @@ -1929,10 +1837,6 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin * This is linker logic for optimistic pops */ private static final class PopLinkLogic extends ArrayLinkLogic { - private PopLinkLogic(final NativeArray array) { - super(array); - } - /** * We need to check if we are dealing with a continuous non empty array data here, * as pop with a primitive return value returns undefined for arrays with length 0 diff --git a/src/jdk/nashorn/internal/objects/NativeDebug.java b/src/jdk/nashorn/internal/objects/NativeDebug.java index 3d8f1095..c42e7843 100644 --- a/src/jdk/nashorn/internal/objects/NativeDebug.java +++ b/src/jdk/nashorn/internal/objects/NativeDebug.java @@ -39,6 +39,7 @@ import jdk.nashorn.internal.runtime.PropertyListeners; import jdk.nashorn.internal.runtime.PropertyMap; import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptObject; +import jdk.nashorn.internal.runtime.ScriptRuntime; import jdk.nashorn.internal.runtime.events.RuntimeEvent; import jdk.nashorn.internal.runtime.linker.LinkerCallSite; import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor; @@ -65,6 +66,36 @@ public final class NativeDebug extends ScriptObject { return "Debug"; } + /** + * Return the ArrayData class for this ScriptObject + * @param self self + * @param obj script object to check + * @return ArrayData class, or undefined if no ArrayData is present + */ + @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) + public static Object getArrayDataClass(final Object self, final Object obj) { + try { + return ((ScriptObject)obj).getArray().getClass(); + } catch (final ClassCastException e) { + return ScriptRuntime.UNDEFINED; + } + } + + /** + * Return the ArrayData for this ScriptObject + * @param self self + * @param obj script object to check + * @return ArrayData, ArrayDatas have toString methods, return Undefined if data missing + */ + @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) + public static Object getArrayData(final Object self, final Object obj) { + try { + return ((ScriptObject)obj).getArray(); + } catch (final ClassCastException e) { + return ScriptRuntime.UNDEFINED; + } + } + /** * Nashorn extension: get context, context utility * diff --git a/src/jdk/nashorn/internal/objects/annotations/SpecializedFunction.java b/src/jdk/nashorn/internal/objects/annotations/SpecializedFunction.java index 36f47b27..62e6e99f 100644 --- a/src/jdk/nashorn/internal/objects/annotations/SpecializedFunction.java +++ b/src/jdk/nashorn/internal/objects/annotations/SpecializedFunction.java @@ -30,7 +30,6 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.invoke.MethodHandle; -import java.lang.invoke.SwitchPoint; import jdk.internal.dynalink.CallSiteDescriptor; import jdk.internal.dynalink.linker.LinkRequest; import jdk.nashorn.internal.runtime.ScriptFunction; @@ -62,10 +61,6 @@ public @interface SpecializedFunction { */ public static final LinkLogic EMPTY_INSTANCE = new Empty(); - private static final SwitchPoint[] INVALIDATED_SWITCHPOINTS = new SwitchPoint[0]; - - private SwitchPoint[] modificationSwitchPoints; //cache - /** Empty link logic class - allow all linking, no guards */ private static final class Empty extends LinkLogic { @Override @@ -166,92 +161,6 @@ public @interface SpecializedFunction { return null; } - /** - * Return the modification SwitchPoint of a particular index from this OptimisticBuiltins - * If none exists, one is created and that one is return. - * - * The implementor must map indexes to specific SwitchPoints for specific events and keep - * track of what they mean, for example NativeArray.LENGTH_NOT_WRITABLE_SWITCHPOINT - * might be a useful index mapping - * - * @param index index for SwitchPoint to get or create - * @return modification SwitchPoint of particular index for the receiver - */ - public SwitchPoint getOrCreateModificationSwitchPoint(final int index) { - return null; - } - - /** - * Return the modification SwitchPoint from this OptimisticBuiltins. If none - * exists, one is created and that one is return. - * - * @return modification SwitchPoint for the receiver - */ - public SwitchPoint[] getOrCreateModificationSwitchPoints() { - return null; - } - - /** - * Hook to invalidate a modification SwitchPoint by index. - * - * @param index index for SwitchPoint to invalidate - */ - public void invalidateModificationSwitchPoint(final int index) { - //empty - } - - /** - * Hook to invalidate all modification SwitchPoints for a receiver - */ - public void invalidateModificationSwitchPoints() { - //empty - } - - /** - * Check whether the receiver has an invalidated modification SwitchPoint. - * - * @param index index for the modification SwitchPoint - * @return true if the particular SwitchPoint at the index is invalidated - */ - public boolean hasInvalidatedModificationSwitchPoint(final int index) { - return false; - } - - /** - * Check whether at least one of the modification SwitchPoints has been - * invalidated - * @return true if one of the SwitchPoints has been invalidated - */ - public boolean hasInvalidatedModificationSwitchPoints() { - return false; - } - - /** - * Check whether this OptimisticBuiltins has a SwitchPoints of particular - * index. - * - * As creation overhead for a SwitchPoint is non-zero, we have to create them lazily instead of, - * e.g. in the constructor of every subclass. - * - * @param index index for the modification SwitchPoint - * @return true if a modification SwitchPoint exists, no matter if it has been invalidated or not - */ - public boolean hasModificationSwitchPoint(final int index) { - return false; - } - - /** - * Check whether this OptimisticBuiltins has SwitchPoints. - * - * As creation overhead for a SwitchPoint is non-zero, we have to create them lazily instead of, - * e.g. in the constructor of every subclass. - * - * @return true if a modification SwitchPoint exists, no matter if it has been invalidated or not - */ - public boolean hasModificationSwitchPoints() { - return false; - } - /** * Check, given a link request and a receiver, if this specialization * fits This is used by the linker in {@link ScriptFunction} to figure @@ -265,47 +174,9 @@ public @interface SpecializedFunction { * pick a non specialized target */ public boolean checkLinkable(final Object self, final CallSiteDescriptor desc, final LinkRequest request) { - // no matter what the modification switchpoints are, if any of them are invalidated, - // we can't link. Side effect is that if it's the first time we see this callsite, - // we have to create the SwitchPoint(s) so future modification switchpoint invalidations - // relink it - final SwitchPoint[] sps = getOrCreateModificationSwitchPoints(self); - if (sps == INVALIDATED_SWITCHPOINTS) { - // nope, can't do the fast link as this assumption - // has been invalidated already, e.g. length of an - // array set to not writable - return false; - } - modificationSwitchPoints = sps; //cache - // check the link guard, if it says we can link, go ahead return canLink(self, desc, request); } - - private SwitchPoint[] getOrCreateModificationSwitchPoints(final Object self) { - final SwitchPoint[] sps = getOrCreateModificationSwitchPoints(); //ask for all my switchpoints - if (sps != null) { //switchpoint exists, but some may be invalidated - for (final SwitchPoint sp : sps) { - if (sp.hasBeenInvalidated()) { - return INVALIDATED_SWITCHPOINTS; - } - } - } - return sps; - } - - /** - * Get the cached modification switchpoints. Only possible to do after a link - * check call has been performed, one that has answered "true", or you will get the - * wrong information. - * - * Should be used only from {@link ScriptFunction#findCallMethod} - * - * @return cached modification switchpoints for this callsite, null if none - */ - public SwitchPoint[] getModificationSwitchPoints() { - return modificationSwitchPoints == null ? null : modificationSwitchPoints.clone(); - } } /** diff --git a/src/jdk/nashorn/internal/runtime/ScriptFunction.java b/src/jdk/nashorn/internal/runtime/ScriptFunction.java index 0ba06b3a..d999c118 100644 --- a/src/jdk/nashorn/internal/runtime/ScriptFunction.java +++ b/src/jdk/nashorn/internal/runtime/ScriptFunction.java @@ -603,16 +603,6 @@ public abstract class ScriptFunction extends ScriptObject { log.info("Linking optimistic builtin function: '", name, "' args=", Arrays.toString(request.getArguments()), " desc=", desc); } - final SwitchPoint[] msps = linkLogic.getModificationSwitchPoints(); - if (msps != null) { - for (final SwitchPoint sp : msps) { - if (sp != null) { - assert !sp.hasBeenInvalidated(); - sps.add(sp); - } - } - } - exceptionGuard = linkLogic.getRelinkException(); break; diff --git a/src/jdk/nashorn/internal/runtime/ScriptObject.java b/src/jdk/nashorn/internal/runtime/ScriptObject.java index dcc0b522..23d8ca09 100644 --- a/src/jdk/nashorn/internal/runtime/ScriptObject.java +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java @@ -1352,12 +1352,9 @@ public abstract class ScriptObject implements PropertyAccess { final PropertyMap selfMap = this.getMap(); final ArrayData array = getArray(); - final long length = array.length(); - for (long i = 0; i < length; i = array.nextIndex(i)) { - if (array.has((int)i)) { - keys.add(JSType.toString(i)); - } + for (final Iterator iter = array.indexIterator(); iter.hasNext(); ) { + keys.add(JSType.toString(iter.next().longValue())); } for (final Property property : selfMap.getProperties()) { @@ -1516,12 +1513,12 @@ public abstract class ScriptObject implements PropertyAccess { * * @return {@code true} if 'length' property is non-writable */ - public final boolean isLengthNotWritable() { + public boolean isLengthNotWritable() { return (flags & IS_LENGTH_NOT_WRITABLE) != 0; } /** - * Flag this object as having non-writable length property + * Flag this object as having non-writable length property. */ public void setIsLengthNotWritable() { flags |= IS_LENGTH_NOT_WRITABLE; @@ -3151,7 +3148,6 @@ public abstract class ScriptObject implements PropertyAccess { */ public final void setObject(final FindProperty find, final int callSiteFlags, final String key, final Object value) { FindProperty f = find; - if (f != null && f.isInherited() && !(f.getProperty() instanceof UserAccessorProperty)) { final boolean isScope = NashornCallSiteDescriptor.isScopeFlag(callSiteFlags); // If the start object of the find is not this object it means the property was found inside a @@ -3177,7 +3173,6 @@ public abstract class ScriptObject implements PropertyAccess { if (NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)) { throw typeError("property.not.writable", key, ScriptRuntime.safeToString(this)); } - return; } @@ -3588,7 +3583,6 @@ public abstract class ScriptObject implements PropertyAccess { } return false; } - return deleteObject(JSType.toObject(key), strict); } diff --git a/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java index dd27612b..b018596f 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java +++ b/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java @@ -30,6 +30,9 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.reflect.Array; import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; import jdk.internal.dynalink.CallSiteDescriptor; import jdk.internal.dynalink.linker.GuardedInvocation; import jdk.internal.dynalink.linker.LinkRequest; @@ -55,6 +58,21 @@ public abstract class ArrayData { * a proper ArrayData when we try to write to it */ public static final ArrayData EMPTY_ARRAY = new UntouchedArrayData(); + /** + * Length of the array data. Not necessarily length of the wrapped array. + * This is private to ensure that no one in a subclass is able to touch the length + * without going through {@link setLength}. This is used to implement + * {@link LengthNotWritableFilter}s, ensuring that there are no ways past + * a {@link setLength} function replaced by a nop + */ + private long length; + + /** + * Method handle to throw an {@link UnwarrantedOptimismException} when getting an element + * of the wrong type + */ + protected static final CompilerConstants.Call THROW_UNWARRANTED = staticCall(MethodHandles.lookup(), ArrayData.class, "throwUnwarranted", void.class, ArrayData.class, int.class, int.class); + /** * Immutable empty array to get ScriptObjects started. * Use the same array and convert it to mutable as soon as it is modified @@ -82,7 +100,7 @@ public abstract class ArrayData { @Override public ContinuousArrayData copy() { - return new UntouchedArrayData((int)length); + return new UntouchedArrayData((int)length()); } @Override @@ -112,6 +130,16 @@ public abstract class ArrayData { return toRealArrayData(0).convert(type); } + @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 void shiftLeft(final int by) { //nop, always empty or we wouldn't be of this class @@ -172,16 +200,6 @@ public abstract class ArrayData { 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; @@ -230,17 +248,6 @@ public abstract class ArrayData { } }; - /** - * Length of the array data. Not necessarily length of the wrapped array. - */ - protected long length; - - /** - * Method handle to throw an {@link UnwarrantedOptimismException} when getting an element - * of the wrong type - */ - protected static final CompilerConstants.Call THROW_UNWARRANTED = staticCall(MethodHandles.lookup(), ArrayData.class, "throwUnwarranted", void.class, ArrayData.class, int.class, int.class); - /** * Constructor * @param length Virtual length of the array. @@ -393,6 +400,16 @@ public abstract class ArrayData { return new NonExtensibleArrayFilter(underlying); } + /** + * Prevent this array from having its length reset + * + * @param underlying the underlying ArrayDAta to wrap in the non extensible filter + * @return new array data, filtered + */ + public static final ArrayData setIsLengthNotWritable(final ArrayData underlying) { + return new LengthNotWritableFilter(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 @@ -445,6 +462,22 @@ public abstract class ArrayData { this.length = length; } + /** + * Increase length by 1 + * @return the new length, not the old one (i.e. pre-increment) + */ + protected final long increaseLength() { + return ++this.length; + } + + /** + * Decrease length by 1. + * @return the new length, not the old one (i.e. pre-decrement) + */ + protected final long decreaseLength() { + return --this.length; + } + /** * Shift the array data left * @@ -454,7 +487,7 @@ public abstract class ArrayData { * * @param by offset to shift */ - public abstract void shiftLeft(int by); + public abstract void shiftLeft(final int by); /** * Shift the array right @@ -463,7 +496,7 @@ public abstract class ArrayData { * @return New arraydata (or same) */ - public abstract ArrayData shiftRight(int by); + public abstract ArrayData shiftRight(final int by); /** * Ensure that the given index exists and won't fail subsequent @@ -471,7 +504,7 @@ public abstract class ArrayData { * @param safeIndex the index to ensure wont go out of bounds * @return new array data (or same) */ - public abstract ArrayData ensure(long safeIndex); + public abstract ArrayData ensure(final long safeIndex); /** * Shrink the array to a new length, may or may not retain the @@ -481,7 +514,7 @@ public abstract class ArrayData { * * @return new array data (or same) */ - public abstract ArrayData shrink(long newLength); + public abstract ArrayData shrink(final long newLength); /** * Set an object value at a given index @@ -491,7 +524,7 @@ public abstract class ArrayData { * @param strict are we in strict mode * @return new array data (or same) */ - public abstract ArrayData set(int index, Object value, boolean strict); + public abstract ArrayData set(final int index, final Object value, final boolean strict); /** * Set an int value at a given index @@ -501,7 +534,7 @@ public abstract class ArrayData { * @param strict are we in strict mode * @return new array data (or same) */ - public abstract ArrayData set(int index, int value, boolean strict); + public abstract ArrayData set(final int index, final int value, final boolean strict); /** * Set a long value at a given index @@ -511,7 +544,7 @@ public abstract class ArrayData { * @param strict are we in strict mode * @return new array data (or same) */ - public abstract ArrayData set(int index, long value, boolean strict); + public abstract ArrayData set(final int index, final long value, final boolean strict); /** * Set an double value at a given index @@ -521,7 +554,7 @@ public abstract class ArrayData { * @param strict are we in strict mode * @return new array data (or same) */ - public abstract ArrayData set(int index, double value, boolean strict); + public abstract ArrayData set(final int index, final double value, final boolean strict); /** * Set an empty value at a given index. Should only affect Object array. @@ -552,7 +585,7 @@ public abstract class ArrayData { * @param index the index * @return the value */ - public abstract int getInt(int index); + public abstract int getInt(final int index); /** * Returns the optimistic type of this array data. Basically, when an array data object needs to throw an @@ -581,7 +614,7 @@ public abstract class ArrayData { * @param index the index * @return the value */ - public abstract long getLong(int index); + public abstract long getLong(final int index); /** * Get optimistic long - default is that it's impossible. Overridden @@ -601,7 +634,7 @@ public abstract class ArrayData { * @param index the index * @return the value */ - public abstract double getDouble(int index); + public abstract double getDouble(final int index); /** * Get optimistic double - default is that it's impossible. Overridden @@ -621,14 +654,14 @@ public abstract class ArrayData { * @param index the index * @return the value */ - public abstract Object getObject(int index); + public abstract Object getObject(final int index); /** * Tests to see if an entry exists (avoids boxing.) * @param index the index * @return true if entry exists */ - public abstract boolean has(int index); + public abstract boolean has(final int index); /** * Returns if element at specific index can be deleted or not. @@ -674,7 +707,7 @@ public abstract class ArrayData { * @param index the index * @return new array data (or same) */ - public abstract ArrayData delete(int index); + public abstract ArrayData delete(final int index); /** * Delete a given range from this array; @@ -684,7 +717,7 @@ public abstract class ArrayData { * * @return new ArrayData after deletion */ - public abstract ArrayData delete(long fromIndex, long toIndex); + public abstract ArrayData delete(final long fromIndex, final long toIndex); /** * Convert the ArrayData to one with a different element type @@ -694,7 +727,7 @@ public abstract class ArrayData { * @param type new element type * @return new array data */ - public abstract ArrayData convert(Class type); + public abstract ArrayData convert(final Class type); /** * Push an array of items to the end of the array @@ -778,7 +811,7 @@ public abstract class ArrayData { * @param to end index + 1 * @return new array data */ - public abstract ArrayData slice(long from, long to); + public abstract ArrayData slice(final long from, final long to); /** * Fast splice operation. This just modifies the array according to the number of @@ -822,6 +855,34 @@ public abstract class ArrayData { return widest; } + /** + * Return a list of keys in the array for the iterators + * @return iterator key list + */ + protected List computeIteratorKeys() { + final List keys = new ArrayList<>(); + + final long len = length(); + for (long i = 0L; i < len; i = nextIndex(i)) { + if (has((int)i)) { + keys.add(i); + } + } + + return keys; + } + + /** + * Return an iterator that goes through all indexes of elements + * in this array. This includes those after array.length if + * they exist + * + * @return iterator + */ + public Iterator indexIterator() { + return computeIteratorKeys().iterator(); + } + /** * Exponential growth function for array size when in * need of resizing. @@ -841,7 +902,7 @@ public abstract class ArrayData { * * @return the next index */ - public long nextIndex(final long index) { + long nextIndex(final long index) { return index + 1; } diff --git a/src/jdk/nashorn/internal/runtime/arrays/ArrayFilter.java b/src/jdk/nashorn/internal/runtime/arrays/ArrayFilter.java index 8d71cc04..9c24a9bf 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/ArrayFilter.java +++ b/src/jdk/nashorn/internal/runtime/arrays/ArrayFilter.java @@ -39,7 +39,7 @@ abstract class ArrayFilter extends ArrayData { protected ArrayData underlying; ArrayFilter(final ArrayData underlying) { - super(underlying.length); + super(underlying.length()); this.underlying = underlying; } @@ -70,62 +70,55 @@ abstract class ArrayFilter extends ArrayData { @Override public void shiftLeft(final int by) { underlying.shiftLeft(by); - setLength(underlying.length); + setLength(underlying.length()); } @Override public ArrayData shiftRight(final int by) { underlying = underlying.shiftRight(by); - setLength(underlying.length); - + setLength(underlying.length()); return this; } @Override public ArrayData ensure(final long safeIndex) { underlying = underlying.ensure(safeIndex); - setLength(underlying.length); - + setLength(underlying.length()); return this; } @Override public ArrayData shrink(final long newLength) { underlying = underlying.shrink(newLength); - setLength(underlying.length); - + setLength(underlying.length()); return this; } @Override public ArrayData set(final int index, final Object value, final boolean strict) { underlying = underlying.set(index, value, strict); - setLength(underlying.length); - + setLength(underlying.length()); return this; } @Override public ArrayData set(final int index, final int value, final boolean strict) { underlying = underlying.set(index, value, strict); - setLength(underlying.length); - + setLength(underlying.length()); return this; } @Override public ArrayData set(final int index, final long value, final boolean strict) { underlying = underlying.set(index, value, strict); - setLength(underlying.length); - + setLength(underlying.length()); return this; } @Override public ArrayData set(final int index, final double value, final boolean strict) { underlying = underlying.set(index, value, strict); - setLength(underlying.length); - + setLength(underlying.length()); return this; } @@ -189,29 +182,28 @@ abstract class ArrayFilter extends ArrayData { @Override public ArrayData delete(final int index) { underlying = underlying.delete(index); - setLength(underlying.length); + setLength(underlying.length()); return this; } @Override public ArrayData delete(final long from, final long to) { underlying = underlying.delete(from, to); - setLength(underlying.length); + setLength(underlying.length()); return this; } @Override public ArrayData convert(final Class type) { underlying = underlying.convert(type); - setLength(underlying.length); + setLength(underlying.length()); return this; } @Override public Object pop() { final Object value = underlying.pop(); - setLength(underlying.length); - + setLength(underlying.length()); return value; } diff --git a/src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java index 56840da9..2fdd184e 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java +++ b/src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java @@ -65,7 +65,7 @@ public abstract class ContinuousArrayData extends ArrayData { * @return true if we don't need to do any array reallocation to fit an element at index */ public final boolean hasRoomFor(final int index) { - return has(index) || (index == length && ensure(index) == this); + return has(index) || (index == length() && ensure(index) == this); } /** @@ -73,7 +73,7 @@ public abstract class ContinuousArrayData extends ArrayData { * @return true if empty */ public boolean isEmpty() { - return length == 0L; + return length() == 0L; } /** diff --git a/src/jdk/nashorn/internal/runtime/arrays/DeletedArrayFilter.java b/src/jdk/nashorn/internal/runtime/arrays/DeletedArrayFilter.java index 4f54b639..4fa89f7d 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/DeletedArrayFilter.java +++ b/src/jdk/nashorn/internal/runtime/arrays/DeletedArrayFilter.java @@ -38,8 +38,7 @@ final class DeletedArrayFilter extends ArrayFilter { DeletedArrayFilter(final ArrayData underlying) { super(underlying); - - this.deleted = new BitVector(underlying.length); + this.deleted = new BitVector(underlying.length()); } @Override @@ -79,25 +78,24 @@ final class DeletedArrayFilter extends ArrayFilter { @Override public void shiftLeft(final int by) { super.shiftLeft(by); - deleted.shiftLeft(by, length); + deleted.shiftLeft(by, length()); } @Override public ArrayData shiftRight(final int by) { super.shiftRight(by); - deleted.shiftRight(by, length); - + deleted.shiftRight(by, length()); return this; } @Override public ArrayData ensure(final long safeIndex) { - if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= length) { + if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= length()) { return new SparseArrayData(this, safeIndex + 1); } super.ensure(safeIndex); - deleted.resize(length); + deleted.resize(length()); return this; } @@ -105,36 +103,31 @@ final class DeletedArrayFilter extends ArrayFilter { @Override public ArrayData shrink(final long newLength) { super.shrink(newLength); - deleted.resize(length); - + deleted.resize(length()); return this; } @Override public ArrayData set(final int index, final Object value, final boolean strict) { deleted.clear(ArrayIndex.toLongIndex(index)); - return super.set(index, value, strict); } @Override public ArrayData set(final int index, final int value, final boolean strict) { deleted.clear(ArrayIndex.toLongIndex(index)); - return super.set(index, value, strict); } @Override public ArrayData set(final int index, final long value, final boolean strict) { deleted.clear(ArrayIndex.toLongIndex(index)); - return super.set(index, value, strict); } @Override public ArrayData set(final int index, final double value, final boolean strict) { deleted.clear(ArrayIndex.toLongIndex(index)); - return super.set(index, value, strict); } @@ -146,7 +139,7 @@ final class DeletedArrayFilter extends ArrayFilter { @Override public ArrayData delete(final int index) { final long longIndex = ArrayIndex.toLongIndex(index); - assert longIndex >= 0 && longIndex < length; + assert longIndex >= 0 && longIndex < length(); deleted.set(longIndex); underlying.setEmpty(index); return this; @@ -154,7 +147,7 @@ final class DeletedArrayFilter extends ArrayFilter { @Override public ArrayData delete(final long fromIndex, final long toIndex) { - assert fromIndex >= 0 && fromIndex <= toIndex && toIndex < length; + assert fromIndex >= 0 && fromIndex <= toIndex && toIndex < length(); deleted.setRange(fromIndex, toIndex + 1); underlying.setEmpty(fromIndex, toIndex); return this; @@ -162,7 +155,7 @@ final class DeletedArrayFilter extends ArrayFilter { @Override public Object pop() { - final long index = length - 1; + final long index = length() - 1; if (super.has((int)index)) { final boolean isDeleted = deleted.isSet(index); @@ -179,7 +172,7 @@ final class DeletedArrayFilter extends ArrayFilter { final ArrayData newArray = underlying.slice(from, to); final DeletedArrayFilter newFilter = new DeletedArrayFilter(newArray); newFilter.getDeleted().copy(deleted); - newFilter.getDeleted().shiftLeft(from, newFilter.length); + newFilter.getDeleted().shiftLeft(from, newFilter.length()); return newFilter; } diff --git a/src/jdk/nashorn/internal/runtime/arrays/DeletedRangeArrayFilter.java b/src/jdk/nashorn/internal/runtime/arrays/DeletedRangeArrayFilter.java index cd5cadb9..953b9213 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/DeletedRangeArrayFilter.java +++ b/src/jdk/nashorn/internal/runtime/arrays/DeletedRangeArrayFilter.java @@ -42,10 +42,10 @@ final class DeletedRangeArrayFilter extends ArrayFilter { } private static ArrayData maybeSparse(final ArrayData underlying, final long hi) { - if(hi < SparseArrayData.MAX_DENSE_LENGTH || underlying instanceof SparseArrayData) { + if (hi < SparseArrayData.MAX_DENSE_LENGTH || underlying instanceof SparseArrayData) { return underlying; } - return new SparseArrayData(underlying, underlying.length); + return new SparseArrayData(underlying, underlying.length()); } private boolean isEmpty() { @@ -93,7 +93,7 @@ final class DeletedRangeArrayFilter extends ArrayFilter { @Override public ArrayData ensure(final long safeIndex) { - if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= length) { + if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= length()) { return new SparseArrayData(this, safeIndex + 1); } @@ -110,7 +110,7 @@ final class DeletedRangeArrayFilter extends ArrayFilter { @Override public ArrayData shiftRight(final int by) { super.shiftRight(by); - final long len = length; + final long len = length(); lo = Math.min(len, lo + by); hi = Math.min(len - 1, hi + by); @@ -238,7 +238,7 @@ final class DeletedRangeArrayFilter extends ArrayFilter { @Override public Object pop() { - final int index = (int)length - 1; + final int index = (int)length() - 1; if (super.has(index)) { final boolean isDeleted = isDeleted(index); final Object value = super.pop(); diff --git a/src/jdk/nashorn/internal/runtime/arrays/FrozenArrayFilter.java b/src/jdk/nashorn/internal/runtime/arrays/FrozenArrayFilter.java index ccf1d882..1e71b44d 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/FrozenArrayFilter.java +++ b/src/jdk/nashorn/internal/runtime/arrays/FrozenArrayFilter.java @@ -26,9 +26,9 @@ 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.PropertyDescriptor; +import jdk.nashorn.internal.runtime.ScriptRuntime; /** * ArrayData after the array has been frozen by Object.freeze call. @@ -79,4 +79,15 @@ final class FrozenArrayFilter extends SealedArrayFilter { } return this; } + + @Override + public ArrayData push(final boolean strict, final Object... items) { + return this; //nop + } + + @Override + public Object pop() { + final int len = (int)underlying.length(); + return len == 0 ? ScriptRuntime.UNDEFINED : underlying.getObject(len - 1); + } } diff --git a/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java index b74b6419..381390ce 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java +++ b/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java @@ -119,22 +119,24 @@ final class IntArrayData extends ContinuousArrayData implements IntElements { @Override public IntArrayData copy() { - return new IntArrayData(array.clone(), (int)length); + return new IntArrayData(array.clone(), (int)length()); } @Override public Object asArrayOfType(final Class componentType) { if (componentType == int.class) { - return array.length == length ? array.clone() : Arrays.copyOf(array, (int)length); + final int len = (int)length(); + return array.length == len ? array.clone() : Arrays.copyOf(array, len); } return super.asArrayOfType(componentType); } private Object[] toObjectArray(final boolean trim) { - assert length <= array.length : "length exceeds internal array size"; - final Object[] oarray = new Object[trim ? (int)length : array.length]; + assert length() <= array.length : "length exceeds internal array size"; + final int len = (int)length(); + final Object[] oarray = new Object[trim ? len : array.length]; - for (int index = 0; index < length; index++) { + for (int index = 0; index < len; index++) { oarray[index] = Integer.valueOf(array[index]); } @@ -142,10 +144,11 @@ final class IntArrayData extends ContinuousArrayData implements IntElements { } private double[] toDoubleArray() { - assert length <= array.length : "length exceeds internal array size"; + assert length() <= array.length : "length exceeds internal array size"; + final int len = (int)length(); final double[] darray = new double[array.length]; - for (int index = 0; index < length; index++) { + for (int index = 0; index < len; index++) { darray[index] = array[index]; } @@ -153,10 +156,11 @@ final class IntArrayData extends ContinuousArrayData implements IntElements { } private long[] toLongArray() { - assert length <= array.length : "length exceeds internal array size"; + assert length() <= array.length : "length exceeds internal array size"; + final int len = (int)length(); final long[] larray = new long[array.length]; - for (int index = 0; index < length; index++) { + for (int index = 0; index < len; index++) { larray[index] = array[index]; } @@ -164,15 +168,15 @@ final class IntArrayData extends ContinuousArrayData implements IntElements { } private LongArrayData convertToLong() { - return new LongArrayData(toLongArray(), (int)length); + return new LongArrayData(toLongArray(), (int)length()); } private NumberArrayData convertToDouble() { - return new NumberArrayData(toDoubleArray(), (int)length); + return new NumberArrayData(toDoubleArray(), (int)length()); } private ObjectArrayData convertToObject() { - return new ObjectArrayData(toObjectArray(false), (int)length); + return new ObjectArrayData(toObjectArray(false), (int)length()); } @Override @@ -196,7 +200,7 @@ final class IntArrayData extends ContinuousArrayData implements IntElements { @Override public ArrayData shiftRight(final int by) { - final ArrayData newData = ensure(by + length - 1); + final ArrayData newData = ensure(by + length() - 1); if (newData != this) { newData.shiftRight(by); return newData; @@ -241,7 +245,7 @@ final class IntArrayData extends ContinuousArrayData implements IntElements { @Override public ArrayData set(final int index, final int value, final boolean strict) { array[index] = value; - setLength(Math.max(index + 1, length)); + setLength(Math.max(index + 1, length())); return this; } @@ -250,7 +254,7 @@ final class IntArrayData extends ContinuousArrayData implements IntElements { public ArrayData set(final int index, final long value, final boolean strict) { if (JSType.isRepresentableAsInt(value)) { array[index] = JSType.toInt32(value); - setLength(Math.max(index + 1, length)); + setLength(Math.max(index + 1, length())); return this; } @@ -261,7 +265,7 @@ final class IntArrayData extends ContinuousArrayData implements IntElements { public ArrayData set(final int index, final double value, final boolean strict) { if (JSType.isRepresentableAsInt(value)) { array[index] = (int)(long)value; - setLength(Math.max(index + 1, length)); + setLength(Math.max(index + 1, length())); return this; } @@ -305,7 +309,7 @@ final class IntArrayData extends ContinuousArrayData implements IntElements { @Override public boolean has(final int index) { - return 0 <= index && index < length; + return 0 <= index && index < length(); } @Override @@ -320,11 +324,12 @@ final class IntArrayData extends ContinuousArrayData implements IntElements { @Override public Object pop() { - if (length == 0) { + final int len = (int)length(); + if (len == 0) { return ScriptRuntime.UNDEFINED; } - final int newLength = (int)length - 1; + final int newLength = len - 1; final int elem = array[newLength]; array[newLength] = 0; setLength(newLength); @@ -334,12 +339,12 @@ final class IntArrayData extends ContinuousArrayData implements IntElements { @Override public ArrayData slice(final long from, final long to) { - return new IntArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)(to - (from < 0 ? from + length : from))); + return new IntArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)(to - (from < 0 ? from + length() : from))); } @Override public final ArrayData push(final boolean strict, final int item) { - final long len = length; + final long len = length(); final ArrayData newData = ensure(len); if (newData == this) { array[(int)len] = item; @@ -350,7 +355,7 @@ final class IntArrayData extends ContinuousArrayData implements IntElements { @Override public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException { - final long oldLength = length; + final long oldLength = length(); final long newLength = oldLength - removed + added; if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) { throw new UnsupportedOperationException(); @@ -384,21 +389,21 @@ final class IntArrayData extends ContinuousArrayData implements IntElements { @Override public long fastPush(final int arg) { - final int len = (int)length; + final int len = (int)length(); if (len == array.length) { array = Arrays.copyOf(array, nextSize(len)); } array[len] = arg; - return ++length; + return increaseLength(); } //length must not be zero @Override public int fastPopInt() { - if (length == 0) { + if (length() == 0) { throw new ClassCastException(); //relink } - final int newLength = (int)--length; + final int newLength = (int)decreaseLength(); final int elem = array[newLength]; array[newLength] = 0; return elem; @@ -421,8 +426,8 @@ final class IntArrayData extends ContinuousArrayData implements IntElements { @Override public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) { - final int otherLength = (int)otherData.length; - final int thisLength = (int)length; + final int otherLength = (int)otherData.length(); + final int thisLength = (int)length(); assert otherLength > 0 && thisLength > 0; final int[] otherArray = ((IntArrayData)otherData).array; @@ -437,7 +442,7 @@ final class IntArrayData extends ContinuousArrayData implements IntElements { @Override public String toString() { - assert length <= array.length : length + " > " + array.length; - return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length)); + assert length() <= array.length : length() + " > " + array.length; + return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length())); } } diff --git a/src/jdk/nashorn/internal/runtime/arrays/LengthNotWritableFilter.java b/src/jdk/nashorn/internal/runtime/arrays/LengthNotWritableFilter.java new file mode 100644 index 00000000..945d80d2 --- /dev/null +++ b/src/jdk/nashorn/internal/runtime/arrays/LengthNotWritableFilter.java @@ -0,0 +1,198 @@ +package jdk.nashorn.internal.runtime.arrays; + +import java.util.Iterator; +import java.util.List; +import java.util.SortedMap; +import java.util.TreeMap; +import jdk.nashorn.internal.runtime.JSType; +import jdk.nashorn.internal.runtime.ScriptRuntime; + +/** + * Filter to use for ArrayData where the length is not writable. + * The default behavior is just to ignore {@link ArrayData#setLength} + */ +final class LengthNotWritableFilter extends ArrayFilter { + private final SortedMap extraElements; //elements with index >= length + + /** + * Constructor + * @param underlying array + */ + LengthNotWritableFilter(final ArrayData underlying) { + this(underlying, new TreeMap()); + } + + private LengthNotWritableFilter(final ArrayData underlying, final SortedMap extraElements) { + super(underlying); + this.extraElements = extraElements; + } + + @Override + public ArrayData copy() { + return new LengthNotWritableFilter(underlying.copy(), new TreeMap<>(extraElements)); + } + + @Override + public boolean has(final int index) { + return super.has(index) || extraElements.containsKey((long)index); + } + + /** + * Set the length of the data array + * + * @param length the new length for the data array + */ + @Override + public void setLength(final long length) { + //empty - setting length for a LengthNotWritableFilter is always a nop + } + + @Override + public ArrayData ensure(final long index) { + return this; + } + + @Override + public ArrayData slice(final long from, final long to) { + //return array[from...to), or array[from...length] if undefined, in this case not as we are an ArrayData + return new LengthNotWritableFilter(underlying.slice(from, to), extraElements.subMap(from, to)); + } + + private boolean checkAdd(final long index, final Object value) { + if (index >= length()) { + extraElements.put(index, value); + return true; + } + return false; + } + + private Object get(final long index) { + final Object obj = extraElements.get(index); + if (obj == null) { + return ScriptRuntime.UNDEFINED; + } + return obj; + } + + @Override + public int getInt(final int index) { + if (index >= length()) { + return JSType.toInt32(get(index)); + } + return underlying.getInt(index); + } + + @Override + public int getIntOptimistic(final int index, final int programPoint) { + if (index >= length()) { + return JSType.toInt32Optimistic(get(index), programPoint); + } + return underlying.getIntOptimistic(index, programPoint); + } + + @Override + public long getLong(final int index) { + if (index >= length()) { + return JSType.toLong(get(index)); + } + return underlying.getLong(index); + } + + @Override + public long getLongOptimistic(final int index, final int programPoint) { + if (index >= length()) { + return JSType.toLongOptimistic(get(index), programPoint); + } + return underlying.getLongOptimistic(index, programPoint); + } + + @Override + public double getDouble(final int index) { + if (index >= length()) { + return JSType.toNumber(get(index)); + } + return underlying.getDouble(index); + } + + @Override + public double getDoubleOptimistic(final int index, final int programPoint) { + if (index >= length()) { + return JSType.toNumberOptimistic(get(index), programPoint); + } + return underlying.getDoubleOptimistic(index, programPoint); + } + + @Override + public Object getObject(final int index) { + if (index >= length()) { + return get(index); + } + return underlying.getObject(index); + } + + @Override + public ArrayData set(final int index, final Object value, final boolean strict) { + if (checkAdd(index, value)) { + return this; + } + underlying = underlying.set(index, value, strict); + return this; + } + + @Override + public ArrayData set(final int index, final int value, final boolean strict) { + if (checkAdd(index, value)) { + return this; + } + underlying = underlying.set(index, value, strict); + return this; + } + + @Override + public ArrayData set(final int index, final long value, final boolean strict) { + if (checkAdd(index, value)) { + return this; + } + underlying = underlying.set(index, value, strict); + return this; + } + + @Override + public ArrayData set(final int index, final double value, final boolean strict) { + if (checkAdd(index, value)) { + return this; + } + underlying = underlying.set(index, value, strict); + return this; + } + + @Override + public ArrayData delete(final int index) { + extraElements.remove(index); + underlying = underlying.delete(index); + return this; + } + + @Override + public ArrayData delete(final long fromIndex, final long toIndex) { + for (final Iterator iter = extraElements.keySet().iterator(); iter.hasNext();) { + final long next = iter.next(); + if (next >= fromIndex && next <= toIndex) { + iter.remove(); + } + if (next > toIndex) { //ordering guaranteed because TreeSet + break; + } + } + underlying = underlying.delete(fromIndex, toIndex); + return this; + } + + @Override + public Iterator indexIterator() { + final List keys = computeIteratorKeys(); + keys.addAll(extraElements.keySet()); //even if they are outside length this is fine + return keys.iterator(); + } + +} diff --git a/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java index cbe507b8..0437cdfe 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java +++ b/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java @@ -27,7 +27,6 @@ package jdk.nashorn.internal.runtime.arrays; import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall; import static jdk.nashorn.internal.lookup.Lookup.MH; - import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.util.Arrays; @@ -77,7 +76,7 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen @Override public LongArrayData copy() { - return new LongArrayData(array.clone(), (int)length); + return new LongArrayData(array.clone(), (int)length()); } @Override @@ -86,10 +85,11 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen } private Object[] toObjectArray(final boolean trim) { - assert length <= array.length : "length exceeds internal array size"; - final Object[] oarray = new Object[trim ? (int)length : array.length]; + assert length() <= array.length : "length exceeds internal array size"; + final int len = (int)length(); + final Object[] oarray = new Object[trim ? len : array.length]; - for (int index = 0; index < length; index++) { + for (int index = 0; index < len; index++) { oarray[index] = Long.valueOf(array[index]); } @@ -99,16 +99,18 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen @Override public Object asArrayOfType(final Class componentType) { if (componentType == long.class) { - return array.length == length ? array.clone() : Arrays.copyOf(array, (int)length); + final int len = (int)length(); + return array.length == len ? array.clone() : Arrays.copyOf(array, len); } return super.asArrayOfType(componentType); } private double[] toDoubleArray() { - assert length <= array.length : "length exceeds internal array size"; + assert length() <= array.length : "length exceeds internal array size"; + final int len = (int)length(); final double[] darray = new double[array.length]; - for (int index = 0; index < length; index++) { + for (int index = 0; index < len; index++) { darray[index] = array[index]; } @@ -120,7 +122,7 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen if (type == Integer.class || type == Long.class) { return this; } - final int len = (int)length; + final int len = (int)length(); if (type == Double.class) { return new NumberArrayData(toDoubleArray(), len); } @@ -134,7 +136,7 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen @Override public ArrayData shiftRight(final int by) { - final ArrayData newData = ensure(by + length - 1); + final ArrayData newData = ensure(by + length() - 1); if (newData != this) { newData.shiftRight(by); return newData; @@ -179,14 +181,14 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen @Override public ArrayData set(final int index, final int value, final boolean strict) { array[index] = value; - setLength(Math.max(index + 1, length)); + setLength(Math.max(index + 1, length())); return this; } @Override public ArrayData set(final int index, final long value, final boolean strict) { array[index] = value; - setLength(Math.max(index + 1, length)); + setLength(Math.max(index + 1, length())); return this; } @@ -194,7 +196,7 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen public ArrayData set(final int index, final double value, final boolean strict) { if (JSType.isRepresentableAsLong(value)) { array[index] = (long)value; - setLength(Math.max(index + 1, length)); + setLength(Math.max(index + 1, length())); return this; } return convert(Double.class).set(index, value, strict); @@ -265,7 +267,7 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen @Override public boolean has(final int index) { - return 0 <= index && index < length; + return 0 <= index && index < length(); } @Override @@ -280,11 +282,12 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen @Override public Object pop() { - if (length == 0) { + final int len = (int)length(); + if (len == 0) { return ScriptRuntime.UNDEFINED; } - final int newLength = (int)length - 1; + final int newLength = len - 1; final long elem = array[newLength]; array[newLength] = 0; setLength(newLength); @@ -294,14 +297,14 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen @Override public ArrayData slice(final long from, final long to) { - final long start = from < 0 ? from + length : from; + final long start = from < 0 ? from + length() : from; final long newLength = to - start; return new LongArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength); } @Override public final ArrayData push(final boolean strict, final long item) { - final long len = length; + final long len = length(); final ArrayData newData = ensure(len); if (newData == this) { array[(int)len] = item; @@ -312,7 +315,7 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen @Override public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException { - final long oldLength = length; + final long oldLength = length(); final long newLength = oldLength - removed + added; if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) { throw new UnsupportedOperationException(); @@ -345,20 +348,20 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen @Override public long fastPush(final long arg) { - final int len = (int)length; + final int len = (int)length(); if (len == array.length) { array = Arrays.copyOf(array, nextSize(len)); } array[len] = arg; - return ++length; + return increaseLength(); } @Override public long fastPopLong() { - if (length == 0) { - throw new ClassCastException(); + if (length() == 0) { + throw new ClassCastException(); //undefined result } - final int newLength = (int)--length; + final int newLength = (int)decreaseLength(); final long elem = array[newLength]; array[newLength] = 0; return elem; @@ -376,8 +379,8 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen @Override public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) { - final int otherLength = (int)otherData.length; - final int thisLength = (int)length; + final int otherLength = (int)otherData.length(); + final int thisLength = (int)length(); assert otherLength > 0 && thisLength > 0; final long[] otherArray = ((LongArrayData)otherData).array; @@ -392,13 +395,14 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen @Override public String toString() { - assert length <= array.length : length + " > " + array.length; + assert length() <= array.length : length() + " > " + array.length; final StringBuilder sb = new StringBuilder(getClass().getSimpleName()). append(": ["); - for (int i = 0; i < length; i++) { + final int len = (int)length(); + for (int i = 0; i < len; i++) { sb.append(array[i]).append('L'); //make sure L suffix is on elements, to discriminate this from IntArrayData.toString() - if (i + 1 < length) { + if (i + 1 < len) { sb.append(", "); } } diff --git a/src/jdk/nashorn/internal/runtime/arrays/NonExtensibleArrayFilter.java b/src/jdk/nashorn/internal/runtime/arrays/NonExtensibleArrayFilter.java index bb73b89f..7e0f3c63 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/NonExtensibleArrayFilter.java +++ b/src/jdk/nashorn/internal/runtime/arrays/NonExtensibleArrayFilter.java @@ -7,13 +7,13 @@ import jdk.nashorn.internal.runtime.ScriptRuntime; /** * Filter class that wrap arrays that have been tagged non extensible */ -public class NonExtensibleArrayFilter extends ArrayFilter { +final class NonExtensibleArrayFilter extends ArrayFilter { /** * Constructor * @param underlying array */ - public NonExtensibleArrayFilter(final ArrayData underlying) { + NonExtensibleArrayFilter(final ArrayData underlying) { super(underlying); } diff --git a/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java index f43c25af..2522b979 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java +++ b/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java @@ -28,7 +28,6 @@ package jdk.nashorn.internal.runtime.arrays; import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall; import static jdk.nashorn.internal.lookup.Lookup.MH; import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; - import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.util.Arrays; @@ -76,7 +75,7 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen @Override public NumberArrayData copy() { - return new NumberArrayData(array.clone(), (int)length); + return new NumberArrayData(array.clone(), (int)length()); } @Override @@ -85,10 +84,11 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen } private Object[] toObjectArray(final boolean trim) { - assert length <= array.length : "length exceeds internal array size"; - final Object[] oarray = new Object[trim ? (int)length : array.length]; + assert length() <= array.length : "length exceeds internal array size"; + final int len = (int)length(); + final Object[] oarray = new Object[trim ? len : array.length]; - for (int index = 0; index < length; index++) { + for (int index = 0; index < len; index++) { oarray[index] = Double.valueOf(array[index]); } return oarray; @@ -96,8 +96,9 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen @Override public Object asArrayOfType(final Class componentType) { - if(componentType == double.class) { - return array.length == length ? array.clone() : Arrays.copyOf(array, (int)length); + if (componentType == double.class) { + final int len = (int)length(); + return array.length == len ? array.clone() : Arrays.copyOf(array, len); } return super.asArrayOfType(componentType); } @@ -105,7 +106,7 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen @Override public ContinuousArrayData convert(final Class type) { if (type != Double.class && type != Integer.class && type != Long.class) { - final int len = (int)length; + final int len = (int)length(); return new ObjectArrayData(toObjectArray(false), len); } return this; @@ -118,7 +119,7 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen @Override public ArrayData shiftRight(final int by) { - final ArrayData newData = ensure(by + length - 1); + final ArrayData newData = ensure(by + length() - 1); if (newData != this) { newData.shiftRight(by); return newData; @@ -163,21 +164,21 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen @Override public ArrayData set(final int index, final int value, final boolean strict) { array[index] = value; - setLength(Math.max(index + 1, length)); + setLength(Math.max(index + 1, length())); return this; } @Override public ArrayData set(final int index, final long value, final boolean strict) { array[index] = value; - setLength(Math.max(index + 1, length)); + setLength(Math.max(index + 1, length())); return this; } @Override public ArrayData set(final int index, final double value, final boolean strict) { array[index] = value; - setLength(Math.max(index + 1, length)); + setLength(Math.max(index + 1, length())); return this; } @@ -241,7 +242,7 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen @Override public boolean has(final int index) { - return 0 <= index && index < length; + return 0 <= index && index < length(); } @Override @@ -256,11 +257,12 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen @Override public Object pop() { - if (length == 0) { + final int len = (int)length(); + if (len == 0) { return UNDEFINED; } - final int newLength = (int)length - 1; + final int newLength = len - 1; final double elem = array[newLength]; array[newLength] = 0; setLength(newLength); @@ -269,14 +271,14 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen @Override public ArrayData slice(final long from, final long to) { - final long start = from < 0 ? from + length : from; + final long start = from < 0 ? from + length() : from; final long newLength = to - start; return new NumberArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength); } @Override public final ArrayData push(final boolean strict, final double item) { - final long len = length; + final long len = length(); final ArrayData newData = ensure(len); if (newData == this) { array[(int)len] = item; @@ -287,7 +289,7 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen @Override public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException { - final long oldLength = length; + final long oldLength = length(); final long newLength = oldLength - removed + added; if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) { throw new UnsupportedOperationException(); @@ -325,21 +327,21 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen @Override public long fastPush(final double arg) { - final int len = (int)length; + final int len = (int)length(); if (len == array.length) { //note that fastpush never creates spares arrays, there is nothing to gain by that - it will just use even more memory array = Arrays.copyOf(array, nextSize(len)); } array[len] = arg; - return ++length; + return increaseLength(); } @Override public double fastPopDouble() { - if (length == 0) { + if (length() == 0) { throw new ClassCastException(); } - final int newLength = (int)--length; + final int newLength = (int)decreaseLength(); final double elem = array[newLength]; array[newLength] = 0; return elem; @@ -352,8 +354,8 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen @Override public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) { - final int otherLength = (int)otherData.length; - final int thisLength = (int)length; + final int otherLength = (int)otherData.length(); + final int thisLength = (int)length(); assert otherLength > 0 && thisLength > 0; final double[] otherArray = ((NumberArrayData)otherData).array; @@ -368,7 +370,7 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen @Override public String toString() { - assert length <= array.length : length + " > " + array.length; - return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length)); + assert length() <= array.length : length() + " > " + array.length; + return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length())); } } diff --git a/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java index 0c7f54d0..ebaa3d6d 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java +++ b/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java @@ -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; @@ -77,16 +76,16 @@ final class ObjectArrayData extends ContinuousArrayData implements AnyElements { @Override public ObjectArrayData copy() { - return new ObjectArrayData(array.clone(), (int)length); + return new ObjectArrayData(array.clone(), (int)length()); } @Override public Object[] asObjectArray() { - return array.length == length ? array.clone() : asObjectArrayCopy(); + return array.length == length() ? array.clone() : asObjectArrayCopy(); } private Object[] asObjectArrayCopy() { - final long len = length; + final long len = length(); assert len <= Integer.MAX_VALUE; final Object[] copy = new Object[(int)len]; System.arraycopy(array, 0, copy, 0, (int)len); @@ -105,7 +104,7 @@ final class ObjectArrayData extends ContinuousArrayData implements AnyElements { @Override public ArrayData shiftRight(final int by) { - final ArrayData newData = ensure(by + length - 1); + final ArrayData newData = ensure(by + length() - 1); if (newData != this) { newData.shiftRight(by); return newData; @@ -137,28 +136,28 @@ final class ObjectArrayData extends ContinuousArrayData implements AnyElements { @Override public ArrayData set(final int index, final Object value, final boolean strict) { array[index] = value; - setLength(Math.max(index + 1, length)); + setLength(Math.max(index + 1, length())); return this; } @Override public ArrayData set(final int index, final int value, final boolean strict) { array[index] = value; - setLength(Math.max(index + 1, length)); + setLength(Math.max(index + 1, length())); return this; } @Override public ArrayData set(final int index, final long value, final boolean strict) { array[index] = value; - setLength(Math.max(index + 1, length)); + setLength(Math.max(index + 1, length())); return this; } @Override public ArrayData set(final int index, final double value, final boolean strict) { array[index] = value; - setLength(Math.max(index + 1, length)); + setLength(Math.max(index + 1, length())); return this; } @@ -231,7 +230,7 @@ final class ObjectArrayData extends ContinuousArrayData implements AnyElements { @Override public boolean has(final int index) { - return 0 <= index && index < length; + return 0 <= index && index < length(); } @Override @@ -263,20 +262,20 @@ final class ObjectArrayData extends ContinuousArrayData implements AnyElements { @Override public long fastPush(final Object arg) { - final int len = (int)length; + final int len = (int)length(); if (len == array.length) { array = Arrays.copyOf(array, nextSize(len)); } array[len] = arg; - return ++length; + return increaseLength(); } @Override public Object fastPopObject() { - if (length == 0) { + if (length() == 0) { return ScriptRuntime.UNDEFINED; } - final int newLength = (int)--length; + final int newLength = (int)decreaseLength(); final Object elem = array[newLength]; array[newLength] = ScriptRuntime.EMPTY; return elem; @@ -284,11 +283,11 @@ final class ObjectArrayData extends ContinuousArrayData implements AnyElements { @Override public Object pop() { - if (length == 0) { + if (length() == 0) { return ScriptRuntime.UNDEFINED; } - final int newLength = (int)length - 1; + final int newLength = (int)length() - 1; final Object elem = array[newLength]; setEmpty(newLength); setLength(newLength); @@ -297,14 +296,14 @@ final class ObjectArrayData extends ContinuousArrayData implements AnyElements { @Override public ArrayData slice(final long from, final long to) { - final long start = from < 0 ? from + length : from; + final long start = from < 0 ? from + length() : from; final long newLength = to - start; return new ObjectArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength); } @Override public ArrayData push(final boolean strict, final Object item) { - final long len = length; + final long len = length(); final ArrayData newData = ensure(len); if (newData == this) { array[(int)len] = item; @@ -315,7 +314,7 @@ final class ObjectArrayData extends ContinuousArrayData implements AnyElements { @Override public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException { - final long oldLength = length; + final long oldLength = length(); final long newLength = oldLength - removed + added; if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) { throw new UnsupportedOperationException(); @@ -343,8 +342,8 @@ final class ObjectArrayData extends ContinuousArrayData implements AnyElements { @Override public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) { - final int otherLength = (int)otherData.length; - final int thisLength = (int)length; + final int otherLength = (int)otherData.length(); + final int thisLength = (int)length(); assert otherLength > 0 && thisLength > 0; final Object[] otherArray = ((ObjectArrayData)otherData).array; @@ -359,7 +358,7 @@ final class ObjectArrayData extends ContinuousArrayData implements AnyElements { @Override public String toString() { - assert length <= array.length : length + " > " + array.length; - return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length)); + assert length() <= array.length : length() + " > " + array.length; + return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length())); } } diff --git a/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java index fd058286..ff569d44 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java +++ b/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java @@ -53,21 +53,21 @@ class SparseArrayData extends ArrayData { SparseArrayData(final ArrayData underlying, final long length, final TreeMap sparseMap) { super(length); - assert underlying.length <= length; + assert underlying.length() <= length; this.underlying = underlying; - this.maxDenseLength = Math.max(MAX_DENSE_LENGTH, underlying.length); + this.maxDenseLength = Math.max(MAX_DENSE_LENGTH, underlying.length()); this.sparseMap = sparseMap; } @Override public ArrayData copy() { - return new SparseArrayData(underlying.copy(), length, new TreeMap<>(sparseMap)); + return new SparseArrayData(underlying.copy(), length(), new TreeMap<>(sparseMap)); } @Override public Object[] asObjectArray() { - final int len = (int)Math.min(length, Integer.MAX_VALUE); - final int underlyingLength = (int)Math.min(len, underlying.length); + final int len = (int)Math.min(length(), Integer.MAX_VALUE); + final int underlyingLength = (int)Math.min(len, underlying.length()); final Object[] objArray = new Object[len]; for (int i = 0; i < underlyingLength; i++) { @@ -104,14 +104,15 @@ class SparseArrayData extends ArrayData { } sparseMap = newSparseMap; - setLength(Math.max(length - by, 0)); + setLength(Math.max(length() - by, 0)); } @Override public ArrayData shiftRight(final int by) { final TreeMap newSparseMap = new TreeMap<>(); - if (underlying.length + by > maxDenseLength) { - for (long i = maxDenseLength - by; i < underlying.length; i++) { + final long len = underlying.length(); + if (len + by > maxDenseLength) { + for (long i = maxDenseLength - by; i < len; i++) { if (underlying.has((int) i)) { newSparseMap.put(Long.valueOf(i + by), underlying.getObject((int) i)); } @@ -127,23 +128,23 @@ class SparseArrayData extends ArrayData { } sparseMap = newSparseMap; - setLength(length + by); + setLength(length() + by); return this; } @Override public ArrayData ensure(final long safeIndex) { - if (safeIndex < maxDenseLength && underlying.length <= safeIndex) { + if (safeIndex < maxDenseLength && underlying.length() <= safeIndex) { underlying = underlying.ensure(safeIndex); } - setLength(Math.max(safeIndex + 1, length)); + setLength(Math.max(safeIndex + 1, length())); return this; } @Override public ArrayData shrink(final long newLength) { - if (newLength < underlying.length) { + if (newLength < underlying.length()) { underlying = underlying.shrink(newLength); underlying.setLength(newLength); sparseMap.clear(); @@ -160,11 +161,11 @@ class SparseArrayData extends ArrayData { if (index >= 0 && index < maxDenseLength) { ensure(index); underlying = underlying.set(index, value, strict); - setLength(Math.max(underlying.length, length)); + setLength(Math.max(underlying.length(), length())); } else { final Long longIndex = indexToKey(index); sparseMap.put(longIndex, value); - setLength(Math.max(longIndex + 1, length)); + setLength(Math.max(longIndex + 1, length())); } return this; @@ -175,11 +176,11 @@ class SparseArrayData extends ArrayData { if (index >= 0 && index < maxDenseLength) { ensure(index); underlying = underlying.set(index, value, strict); - setLength(Math.max(underlying.length, length)); + setLength(Math.max(underlying.length(), length())); } else { final Long longIndex = indexToKey(index); sparseMap.put(longIndex, value); - setLength(Math.max(longIndex + 1, length)); + setLength(Math.max(longIndex + 1, length())); } return this; } @@ -189,11 +190,11 @@ class SparseArrayData extends ArrayData { if (index >= 0 && index < maxDenseLength) { ensure(index); underlying = underlying.set(index, value, strict); - setLength(Math.max(underlying.length, length)); + setLength(Math.max(underlying.length(), length())); } else { final Long longIndex = indexToKey(index); sparseMap.put(longIndex, value); - setLength(Math.max(longIndex + 1, length)); + setLength(Math.max(longIndex + 1, length())); } return this; } @@ -203,11 +204,11 @@ class SparseArrayData extends ArrayData { if (index >= 0 && index < maxDenseLength) { ensure(index); underlying = underlying.set(index, value, strict); - setLength(Math.max(underlying.length, length)); + setLength(Math.max(underlying.length(), length())); } else { final Long longIndex = indexToKey(index); sparseMap.put(longIndex, value); - setLength(Math.max(longIndex + 1, length)); + setLength(Math.max(longIndex + 1, length())); } return this; } @@ -294,7 +295,7 @@ class SparseArrayData extends ArrayData { @Override public boolean has(final int index) { if (index >= 0 && index < maxDenseLength) { - return index < underlying.length && underlying.has(index); + return index < underlying.length() && underlying.has(index); } return sparseMap.containsKey(indexToKey(index)); @@ -303,7 +304,7 @@ class SparseArrayData extends ArrayData { @Override public ArrayData delete(final int index) { if (index >= 0 && index < maxDenseLength) { - if (index < underlying.length) { + if (index < underlying.length()) { underlying = underlying.delete(index); } } else { @@ -315,8 +316,8 @@ class SparseArrayData extends ArrayData { @Override public ArrayData delete(final long fromIndex, final long toIndex) { - if (fromIndex < maxDenseLength && fromIndex < underlying.length) { - underlying = underlying.delete(fromIndex, Math.min(toIndex, underlying.length - 1)); + if (fromIndex < maxDenseLength && fromIndex < underlying.length()) { + underlying = underlying.delete(fromIndex, Math.min(toIndex, underlying.length() - 1)); } if (toIndex >= maxDenseLength) { sparseMap.subMap(fromIndex, true, toIndex, true).clear(); @@ -336,30 +337,34 @@ class SparseArrayData extends ArrayData { @Override public Object pop() { - if (length == 0) { + final long len = length(); + final long underlyingLen = underlying.length(); + if (len == 0) { return ScriptRuntime.UNDEFINED; } - if (length == underlying.length) { + if (len == underlyingLen) { final Object result = underlying.pop(); - setLength(underlying.length); + setLength(underlying.length()); return result; } - setLength(length - 1); - final Long key = Long.valueOf(length); + setLength(len - 1); + final Long key = Long.valueOf(len - 1); return sparseMap.containsKey(key) ? sparseMap.remove(key) : ScriptRuntime.UNDEFINED; } @Override public ArrayData slice(final long from, final long to) { - assert to <= length; - final long start = from < 0 ? (from + length) : from; + assert to <= length(); + final long start = from < 0 ? (from + length()) : from; final long newLength = to - start; + final long underlyingLength = underlying.length(); + if (start >= 0 && to <= maxDenseLength) { - if (newLength <= underlying.length) { + if (newLength <= underlyingLength) { return underlying.slice(from, to); } - return underlying.slice(from, to).ensure(newLength - 1).delete(underlying.length, newLength); + return underlying.slice(from, to).ensure(newLength - 1).delete(underlyingLength, newLength); } ArrayData sliced = EMPTY_ARRAY; @@ -369,13 +374,13 @@ class SparseArrayData extends ArrayData { sliced = sliced.set((int)(i - start), getObject((int)i), false); } } - assert sliced.length == newLength; + assert sliced.length() == newLength; return sliced; } @Override public long nextIndex(final long index) { - if (index < underlying.length - 1) { + if (index < underlying.length() - 1) { return underlying.nextIndex(index); } @@ -383,6 +388,7 @@ class SparseArrayData extends ArrayData { if (nextKey != null) { return nextKey; } - return length; + + return length(); } } diff --git a/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java index 405ff028..40b3210b 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java +++ b/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java @@ -58,7 +58,7 @@ public abstract class TypedArrayData extends ContinuousArrayDa * @return element length */ public final int getElementLength() { - return (int)length; + return (int)length(); } /** @@ -119,7 +119,7 @@ public abstract class TypedArrayData extends ContinuousArrayDa @Override public final boolean has(final int index) { - return 0 <= index && index < length; + return 0 <= index && index < length(); } @Override diff --git a/src/jdk/nashorn/internal/runtime/arrays/UndefinedArrayFilter.java b/src/jdk/nashorn/internal/runtime/arrays/UndefinedArrayFilter.java index f744aacd..9865dcbb 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/UndefinedArrayFilter.java +++ b/src/jdk/nashorn/internal/runtime/arrays/UndefinedArrayFilter.java @@ -39,8 +39,7 @@ final class UndefinedArrayFilter extends ArrayFilter { UndefinedArrayFilter(final ArrayData underlying) { super(underlying); - - this.undefined = new BitVector(underlying.length); + this.undefined = new BitVector(underlying.length()); } @Override @@ -80,25 +79,24 @@ final class UndefinedArrayFilter extends ArrayFilter { @Override public void shiftLeft(final int by) { super.shiftLeft(by); - undefined.shiftLeft(by, length); + undefined.shiftLeft(by, length()); } @Override public ArrayData shiftRight(final int by) { super.shiftRight(by); - undefined.shiftRight(by, length); - + undefined.shiftRight(by, length()); return this; } @Override public ArrayData ensure(final long safeIndex) { - if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= length) { + if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= length()) { return new SparseArrayData(this, safeIndex + 1); } super.ensure(safeIndex); - undefined.resize(length); + undefined.resize(length()); return this; } @@ -106,8 +104,7 @@ final class UndefinedArrayFilter extends ArrayFilter { @Override public ArrayData shrink(final long newLength) { super.shrink(newLength); - undefined.resize(length); - + undefined.resize(length()); return this; } @@ -216,7 +213,7 @@ final class UndefinedArrayFilter extends ArrayFilter { @Override public Object pop() { - final long index = length - 1; + final long index = length() - 1; if (super.has((int)index)) { final boolean isUndefined = undefined.isSet(index); @@ -233,7 +230,7 @@ final class UndefinedArrayFilter extends ArrayFilter { final ArrayData newArray = underlying.slice(from, to); final UndefinedArrayFilter newFilter = new UndefinedArrayFilter(newArray); newFilter.getUndefined().copy(undefined); - newFilter.getUndefined().shiftLeft(from, newFilter.length); + newFilter.getUndefined().shiftLeft(from, newFilter.length()); return newFilter; } diff --git a/test/script/basic/JDK-8035312.js b/test/script/basic/JDK-8035312.js new file mode 100644 index 00000000..b027f2ec --- /dev/null +++ b/test/script/basic/JDK-8035312.js @@ -0,0 +1,225 @@ +/* + * 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. + */ + +/** + * JDK-8035312 push to frozen array must not increase length property + * + * @test + * @run + * @fork + * @option -Dnashorn.debug=true + */ + +function printArrayDataClass(x) { + if (typeof Debug !== 'undefined') { + print(Debug.getArrayDataClass(x)); + } +} + +function gpush(x, elem) { + try { + print("Pushing " + elem + " to " + x); + x.push(elem); + } catch (e) { + print("caught error" + e); + } + print("\tarray is now [" + x + "] length is = " + x.length); + print(); + printArrayDataClass(x); +} + +function gpop(x) { + try { + print("Popping from " + x); + x.pop(); + } catch (e) { + if (!(e instanceof TypeError)) { + print("e of wrong type " + e); + } + } + print("\tarray is now [" + x + "] length is = " + x.length); + print(); + printArrayDataClass(x); +} + +function checkArray(x) { + print(); + print(">>> Push test"); + + var olen = x.length; + gpush(x, 0); + + print("x.length === " + x.length + " (should be " + olen + ")"); + print("x[3] === " + x[3] + " (should be 0)"); + print("x[4] === " + x[4] + " (should be undefined)"); + + print(); + print(">>> Pop test"); + gpop(x); + gpop(x); + print("x.length === " + x.length + " (should be " + olen + ")"); + print("x === " + x); + + for (var i = 0 ; i < 5; i++) { + gpop(x); + } + + print("x.length === " + x.length + " (should be " + olen + ")"); + print("x === " + x); +} + +print("*** Freezing"); +var frozen = [1,2,3]; +Object.freeze(frozen); +checkArray(frozen); +printArrayDataClass(frozen); + +//so far so good + +print(); +print("*** Other length not writable issues"); +var lengthNotWritable = [1,2,3]; +Object.defineProperty(lengthNotWritable, "length", { writable: false }); +checkArray(lengthNotWritable); +printArrayDataClass(lengthNotWritable); + +function set(array, from, to, stride) { + //add three elements + for (var i = from; i < to; i+=stride) { + try { + print("Writing " + i); + array[i] = i; + printArrayDataClass(array); + } catch (e) { + print(e instanceof TypeError); + } + } +} + +//define empty array with non writable length +var arr = [1]; +Object.defineProperty(arr, "length", { writable: false }); + +var olen2 = arr.length; + +set(arr, 0, 3, 1); + +if (arr.length != olen2) { + throw new ("error: " + arr.length + " != " + olen2); +} + +print(); +print("array writing 0-3, with 1 stride, array = " + arr); +print("length = " + arr.length + ", but elements are: " + arr[0] + " " + arr[1] + " " + arr[2]); +print(); + +//do the same but sparse/deleted range +var arr2 = [1]; +Object.defineProperty(arr2, "length", { writable: false }); + +print("initial length = " + arr2.length); +var olen3 = arr2.length; + +set(arr2, 0, 30, 3); + +if (arr2.length != olen3) { + throw new ("error: " + arr2.length + " != " + olen3); +} + +print(); +var larger = 20; +print("array writing 0-" + larger + ", with 3 stride, array = " + arr2); +print("length = " + arr2.length + ", but elements are: " + arr2[0] + " " + arr2[1] + " " + arr2[2]); + +for (var i = 0; i < larger; i++) { + if (arr2[i] === undefined) { + continue; + } + print(arr2[i] + " has length " + arr2.length); +} + +print(); +var elem = 0x7fffffff - 10; +printArrayDataClass(arr2); +print("adding a new element high up in the array"); +print("length before element was added " + arr2.length); +print("putting sparse at " + elem); +arr2[elem] = "sparse"; +print("length after element was added " + arr2.length + " should be the same"); +printArrayDataClass(arr2); + +print(); +print("Printing arr2 - this will fail if length is > 28 and it is " + arr2.length); +print("arr2 = [" + arr2 + "]"); +print("new length that should not be writable = " + arr2.length); +print(arr2[elem] === "sparse"); +print(arr2[elem]); +for (var i = 0; i < larger; i++) { + print(arr2[i]); +} +for (var key in arr2) { + print(key + ":" + arr2[key]); +} + +//issues reported by sundar - generic setter doesn't go through push/pop bulkable + +function sundarExample2(arr, _writable) { + print("Checking if push works for bulkable non bulkable arrays - Setting length property not allowed"); + arr[0] = "bar"; + print(arr.length + " should be 1"); // should be 1 + print(arr[0] + " should be bar"); + print("["+ arr + "] should be [bar]"); + + // Object.defineProperty(arr, "length", { configurable: _writable }); + Object.defineProperty(arr, "length", { writable: _writable }); + arr[1] = "baz"; + + if (_writable) { + print(arr.length + " should be 2"); + print(arr[0] + " should be bar"); + print(arr[1] + " should be baz"); + print("["+ arr + "] should be [bar,baz]"); + } else { + print(arr.length + " should STILL be 1"); + print(arr[0] + " should be bar"); + print(arr[1] + " should be baz"); + print("["+ arr + "] should be [bar]"); + } +} + +var newArr1 = []; +sundarExample2(newArr1, false); +print(); +try { + sundarExample2(newArr1, true); + print("should not get here"); +} catch (e) { + if (!(e instanceof TypeError)) { + print("Wrong exception"); + } + print("got TypeError when redefining length, as expected") +} +print(); + +sundarExample2([], true); +print("Done"); diff --git a/test/script/basic/JDK-8035312.js.EXPECTED b/test/script/basic/JDK-8035312.js.EXPECTED new file mode 100644 index 00000000..07d576f1 --- /dev/null +++ b/test/script/basic/JDK-8035312.js.EXPECTED @@ -0,0 +1,186 @@ +*** Freezing + +>>> Push test +Pushing 0 to 1,2,3 + array is now [1,2,3] length is = 3 + +class jdk.nashorn.internal.runtime.arrays.FrozenArrayFilter +x.length === 3 (should be 3) +x[3] === undefined (should be 0) +x[4] === undefined (should be undefined) + +>>> Pop test +Popping from 1,2,3 + array is now [1,2,3] length is = 3 + +class jdk.nashorn.internal.runtime.arrays.FrozenArrayFilter +Popping from 1,2,3 + array is now [1,2,3] length is = 3 + +class jdk.nashorn.internal.runtime.arrays.FrozenArrayFilter +x.length === 3 (should be 3) +x === 1,2,3 +Popping from 1,2,3 + array is now [1,2,3] length is = 3 + +class jdk.nashorn.internal.runtime.arrays.FrozenArrayFilter +Popping from 1,2,3 + array is now [1,2,3] length is = 3 + +class jdk.nashorn.internal.runtime.arrays.FrozenArrayFilter +Popping from 1,2,3 + array is now [1,2,3] length is = 3 + +class jdk.nashorn.internal.runtime.arrays.FrozenArrayFilter +Popping from 1,2,3 + array is now [1,2,3] length is = 3 + +class jdk.nashorn.internal.runtime.arrays.FrozenArrayFilter +Popping from 1,2,3 + array is now [1,2,3] length is = 3 + +class jdk.nashorn.internal.runtime.arrays.FrozenArrayFilter +x.length === 3 (should be 3) +x === 1,2,3 +class jdk.nashorn.internal.runtime.arrays.FrozenArrayFilter + +*** Other length not writable issues + +>>> Push test +Pushing 0 to 1,2,3 +caught errorTypeError: "length" is not a writable property of [object Array] + array is now [1,2,3] length is = 3 + +class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter +x.length === 3 (should be 3) +x[3] === 0 (should be 0) +x[4] === undefined (should be undefined) + +>>> Pop test +Popping from 1,2,3 + array is now [1,2,3] length is = 3 + +class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter +Popping from 1,2,3 + array is now [1,2,3] length is = 3 + +class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter +x.length === 3 (should be 3) +x === 1,2,3 +Popping from 1,2,3 + array is now [1,2,3] length is = 3 + +class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter +Popping from 1,2,3 + array is now [1,2,3] length is = 3 + +class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter +Popping from 1,2,3 + array is now [1,2,3] length is = 3 + +class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter +Popping from 1,2,3 + array is now [1,2,3] length is = 3 + +class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter +Popping from 1,2,3 + array is now [1,2,3] length is = 3 + +class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter +x.length === 3 (should be 3) +x === 1,2,3 +class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter +Writing 0 +class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter +Writing 1 +class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter +Writing 2 +class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter + +array writing 0-3, with 1 stride, array = 0 +length = 1, but elements are: 0 undefined 2 + +initial length = 1 +Writing 0 +class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter +Writing 3 +class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter +Writing 6 +class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter +Writing 9 +class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter +Writing 12 +class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter +Writing 15 +class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter +Writing 18 +class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter +Writing 21 +class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter +Writing 24 +class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter +Writing 27 +class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter + +array writing 0-20, with 3 stride, array = 0 +length = 1, but elements are: 0 undefined undefined +0 has length 1 + +class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter +adding a new element high up in the array +length before element was added 1 +putting sparse at 2147483637 +length after element was added 1 should be the same +class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter + +Printing arr2 - this will fail if length is > 28 and it is 1 +arr2 = [0] +new length that should not be writable = 1 +true +sparse +0 +undefined +undefined +undefined +undefined +undefined +undefined +undefined +undefined +undefined +undefined +undefined +undefined +undefined +undefined +undefined +undefined +undefined +undefined +undefined +0:0 +2147483637:sparse +Checking if push works for bulkable non bulkable arrays - Setting length property not allowed +1 should be 1 +bar should be bar +[bar] should be [bar] +1 should STILL be 1 +bar should be bar +baz should be baz +[bar] should be [bar] + +Checking if push works for bulkable non bulkable arrays - Setting length property not allowed +1 should be 1 +bar should be bar +[bar] should be [bar] +got TypeError when redefining length, as expected + +Checking if push works for bulkable non bulkable arrays - Setting length property not allowed +1 should be 1 +bar should be bar +[bar] should be [bar] +2 should be 2 +bar should be bar +baz should be baz +[bar,baz] should be [bar,baz] +Done diff --git a/test/script/basic/JDK-8035312_2.js b/test/script/basic/JDK-8035312_2.js new file mode 100644 index 00000000..a7da0b0d --- /dev/null +++ b/test/script/basic/JDK-8035312_2.js @@ -0,0 +1,65 @@ +/* + * 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. + */ + +/** + * JDK-8035312_2 - length setter and iterators + * + * @test + * @run + */ + +"use strict" + +function printArray(a,n) { + print("PRINT_ARRAY CALLED: length = " + a.length); + print(); + + print("INDEXED"); + for (var x = 0; x list = new ArrayList<>(); for (final Iterator> iter = ipp.entrySet().iterator(); iter.hasNext(); ) { final Map.Entry entry = iter.next(); final char bct = entry.getValue().getBytecodeStackType(); + final String type; + + switch (entry.getValue().getBytecodeStackType()) { + case 'A': + type = "object"; + break; + case 'I': + type = "int"; + break; + case 'J': + type = "long"; + break; + case 'D': + type = "double"; + break; + default: + type = String.valueOf(bct); + break; + } + final StringBuilder sb = new StringBuilder(); sb.append('['). + append("program point: "). append(entry.getKey()). - append("->"). - append(bct == 'A' ? 'O' : bct). + append(" -> "). + append(type). append(']'); - if (iter.hasNext()) { - sb.append(' '); - } + list.add(sb.toString()); } - return sb.toString(); + return list; } private void logRecompile(final String reason, final FunctionNode fn, final MethodType type, final Map ipp) { if (log.isEnabled()) { - log.info(reason, DebugLogger.quote(fn.getName()), " signature: ", type, " ", toStringInvalidations(ipp)); + log.info(reason, DebugLogger.quote(fn.getName()), " signature: ", type); + log.indent(); + for (final String str : toStringInvalidations(ipp)) { + log.fine(str); + } + log.unindent(); } } @@ -769,7 +795,14 @@ final class CompiledFunction { */ private synchronized MethodHandle handleRewriteException(final OptimismInfo oldOptInfo, final RewriteException re) { if (log.isEnabled()) { - log.info(new RecompilationEvent(Level.INFO, re, re.getReturnValueNonDestructive()), "RewriteException ", re.getMessageShort()); + log.info( + new RecompilationEvent( + Level.INFO, + re, + re.getReturnValueNonDestructive()), + "caught RewriteException ", + re.getMessageShort()); + log.indent(); } final MethodType type = type(); @@ -799,7 +832,7 @@ final class CompiledFunction { logRecompile("Deoptimizing recompilation (up to bytecode) ", fn, ct, effectiveOptInfo.invalidatedProgramPoints); fn = compiler.compile(fn, serialized ? CompilationPhases.RECOMPILE_SERIALIZED_UPTO_BYTECODE : CompilationPhases.COMPILE_UPTO_BYTECODE); - log.info("Reusable IR generated"); + log.fine("Reusable IR generated"); // compile the rest of the function, and install it log.info("Generating and installing bytecode from reusable IR..."); @@ -815,15 +848,15 @@ final class CompiledFunction { compiler.persistClassInfo(cacheKey, normalFn); } - log.info("Done."); - final boolean canBeDeoptimized = normalFn.canBeDeoptimized(); if (log.isEnabled()) { - log.info("Recompiled '", fn.getName(), "' (", Debug.id(this), ") ", canBeDeoptimized ? " can still be deoptimized." : " is completely deoptimized."); - } + log.unindent(); + log.info("Done."); - log.info("Looking up invoker..."); + log.info("Recompiled '", fn.getName(), "' (", Debug.id(this), ") ", canBeDeoptimized ? "can still be deoptimized." : " is completely deoptimized."); + log.finest("Looking up invoker..."); + } final MethodHandle newInvoker = effectiveOptInfo.data.lookup(fn); invoker = newInvoker.asType(type.changeReturnType(newInvoker.type().returnType())); @@ -870,7 +903,6 @@ final class CompiledFunction { private SwitchPoint optimisticAssumptions; private final DebugLogger log; - @SuppressWarnings("unused") OptimismInfo(final RecompilableScriptFunctionData data, final Map invalidatedProgramPoints) { this.data = data; this.log = data.getLogger(); diff --git a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java index fd381675..06414edb 100644 --- a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java +++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java @@ -26,7 +26,6 @@ package jdk.nashorn.internal.runtime; import static jdk.nashorn.internal.lookup.Lookup.MH; - import java.io.IOException; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; @@ -620,20 +619,25 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp return f; } - MethodHandle lookup(final FunctionInitializer fnInit) { + private void logLookup(final boolean shouldLog, final MethodType targetType) { + if (shouldLog && log.isEnabled()) { + log.info("Looking up ", DebugLogger.quote(functionName), " type=", targetType); + } + } + + private MethodHandle lookup(final FunctionInitializer fnInit, final boolean shouldLog) { final MethodType type = fnInit.getMethodType(); + logLookup(shouldLog, type); return lookupCodeMethod(fnInit.getCode(), type); } MethodHandle lookup(final FunctionNode fn) { final MethodType type = new FunctionSignature(fn).getMethodType(); + logLookup(true, type); return lookupCodeMethod(fn.getCompileUnit().getCode(), type); } MethodHandle lookupCodeMethod(final Class codeClass, final MethodType targetType) { - if (log.isEnabled()) { - log.info("Looking up ", DebugLogger.quote(functionName), " type=", targetType); - } return MH.findStatic(LOOKUP, codeClass, functionName, targetType); } @@ -649,7 +653,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp if(!code.isEmpty()) { throw new IllegalStateException(name); } - addCode(lookup(initializer), null, null, initializer.getFlags()); + addCode(lookup(initializer, true), null, null, initializer.getFlags()); } private CompiledFunction addCode(final MethodHandle target, final Map invalidatedProgramPoints, @@ -671,10 +675,10 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp */ private CompiledFunction addCode(final FunctionInitializer fnInit, final MethodType callSiteType) { if (isVariableArity()) { - return addCode(lookup(fnInit), fnInit.getInvalidatedProgramPoints(), callSiteType, fnInit.getFlags()); + return addCode(lookup(fnInit, true), fnInit.getInvalidatedProgramPoints(), callSiteType, fnInit.getFlags()); } - final MethodHandle handle = lookup(fnInit); + final MethodHandle handle = lookup(fnInit, true); final MethodType fromType = handle.type(); MethodType toType = needsCallee(fromType) ? callSiteType.changeParameterType(0, ScriptFunction.class) : callSiteType.dropParameterTypes(0, 1); toType = toType.changeReturnType(fromType.returnType()); @@ -699,7 +703,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp toType = toType.dropParameterTypes(fromCount, toCount); } - return addCode(lookup(fnInit).asType(toType), fnInit.getInvalidatedProgramPoints(), callSiteType, fnInit.getFlags()); + return addCode(lookup(fnInit, false).asType(toType), fnInit.getInvalidatedProgramPoints(), callSiteType, fnInit.getFlags()); } /** -- cgit v1.2.1 From b48633e84c4774ae5acf3c7fe4ce74f93f46c8d6 Mon Sep 17 00:00:00 2001 From: lagergren Date: Thu, 13 Nov 2014 16:59:03 +0100 Subject: 8062937: Need to block constant assumption for index setters and defineOwnProperty, not just delete Reviewed-by: hannesw, jlaskey --- src/jdk/nashorn/internal/runtime/ScriptObject.java | 18 +++++++-- test/script/basic/JDK-8062937.js | 46 ++++++++++++++++++++++ test/script/basic/JDK-8062937.js.EXPECTED | 9 +++++ 3 files changed, 69 insertions(+), 4 deletions(-) create mode 100644 test/script/basic/JDK-8062937.js create mode 100644 test/script/basic/JDK-8062937.js.EXPECTED diff --git a/src/jdk/nashorn/internal/runtime/ScriptObject.java b/src/jdk/nashorn/internal/runtime/ScriptObject.java index 23d8ca09..89246241 100644 --- a/src/jdk/nashorn/internal/runtime/ScriptObject.java +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java @@ -510,6 +510,13 @@ public abstract class ScriptObject implements PropertyAccess { } } + private void invalidateGlobalConstant(final String key) { + final GlobalConstants globalConstants = getGlobalConstants(); + if (globalConstants != null) { + globalConstants.delete(key); + } + } + /** * ECMA 8.12.9 [[DefineOwnProperty]] (P, Desc, Throw) * @@ -525,6 +532,8 @@ public abstract class ScriptObject implements PropertyAccess { final Object current = getOwnPropertyDescriptor(key); final String name = JSType.toString(key); + invalidateGlobalConstant(key); + if (current == UNDEFINED) { if (isExtensible()) { // add a new own property @@ -923,10 +932,8 @@ public abstract class ScriptObject implements PropertyAccess { if (property instanceof UserAccessorProperty) { ((UserAccessorProperty)property).setAccessors(this, getMap(), null); } - final GlobalConstants globalConstants = getGlobalConstants(); - if (globalConstants != null) { - globalConstants.delete(property.getKey()); - } + + invalidateGlobalConstant(property.getKey()); return true; } } @@ -3148,6 +3155,9 @@ public abstract class ScriptObject implements PropertyAccess { */ public final void setObject(final FindProperty find, final int callSiteFlags, final String key, final Object value) { FindProperty f = find; + + invalidateGlobalConstant(key); + if (f != null && f.isInherited() && !(f.getProperty() instanceof UserAccessorProperty)) { final boolean isScope = NashornCallSiteDescriptor.isScopeFlag(callSiteFlags); // If the start object of the find is not this object it means the property was found inside a diff --git a/test/script/basic/JDK-8062937.js b/test/script/basic/JDK-8062937.js new file mode 100644 index 00000000..d38161a7 --- /dev/null +++ b/test/script/basic/JDK-8062937.js @@ -0,0 +1,46 @@ +/* + * 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. + */ + +/** + * JDK-8062937 - GlobalConstants produces wrong result with defineProperty and index setters + * + * @test + * @run + */ + +var x = 1; +for (var i = 2; i < 5; i++) { + print(x); + Object.defineProperty(this, "x", {value: i}); +} +print(x); + +print(); + +var name = "y"; +var y = 1; +for (var i = 2; i < 5; i++) { + print(y); + this[name] = i; +} +print(y); diff --git a/test/script/basic/JDK-8062937.js.EXPECTED b/test/script/basic/JDK-8062937.js.EXPECTED new file mode 100644 index 00000000..4b6f9b6c --- /dev/null +++ b/test/script/basic/JDK-8062937.js.EXPECTED @@ -0,0 +1,9 @@ +1 +2 +3 +4 + +1 +2 +3 +4 -- cgit v1.2.1 From af65a8486fed53447d38c4bea6e2a97bc00c1322 Mon Sep 17 00:00:00 2001 From: attila Date: Wed, 12 Nov 2014 15:13:08 +0100 Subject: 8064707: Remove NativeArray link logic fields Reviewed-by: hannesw, lagergren --- src/jdk/nashorn/internal/objects/NativeArray.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/jdk/nashorn/internal/objects/NativeArray.java b/src/jdk/nashorn/internal/objects/NativeArray.java index 40835758..047d612a 100644 --- a/src/jdk/nashorn/internal/objects/NativeArray.java +++ b/src/jdk/nashorn/internal/objects/NativeArray.java @@ -33,6 +33,7 @@ import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex; 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.util.ArrayList; import java.util.Arrays; @@ -91,10 +92,6 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin private static final Object CALL_CMP = new Object(); private static final Object TO_LOCALE_STRING = new Object(); - private PushLinkLogic pushLinkLogic; - private PopLinkLogic popLinkLogic; - private ConcatLinkLogic concatLinkLogic; - /* * Constructors. */ @@ -1750,11 +1747,11 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin @Override public SpecializedFunction.LinkLogic getLinkLogic(final Class clazz) { if (clazz == PushLinkLogic.class) { - return pushLinkLogic == null ? new PushLinkLogic() : pushLinkLogic; + return PushLinkLogic.INSTANCE; } else if (clazz == PopLinkLogic.class) { - return popLinkLogic == null ? new PopLinkLogic() : pushLinkLogic; + return PopLinkLogic.INSTANCE; } else if (clazz == ConcatLinkLogic.class) { - return concatLinkLogic == null ? new ConcatLinkLogic() : concatLinkLogic; + return ConcatLinkLogic.INSTANCE; } return null; } @@ -1797,6 +1794,8 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin * This is linker logic for optimistic concatenations */ private static final class ConcatLinkLogic extends ArrayLinkLogic { + private static final LinkLogic INSTANCE = new ConcatLinkLogic(); + @Override public boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request) { final Object[] args = request.getArguments(); @@ -1827,6 +1826,8 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin * This is linker logic for optimistic pushes */ private static final class PushLinkLogic extends ArrayLinkLogic { + private static final LinkLogic INSTANCE = new PushLinkLogic(); + @Override public boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request) { return getContinuousArrayData(self) != null; @@ -1837,6 +1838,8 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin * This is linker logic for optimistic pops */ private static final class PopLinkLogic extends ArrayLinkLogic { + private static final LinkLogic INSTANCE = new PopLinkLogic(); + /** * We need to check if we are dealing with a continuous non empty array data here, * as pop with a primitive return value returns undefined for arrays with length 0 -- cgit v1.2.1 From 42eafef631e290847a3b99d9204f8064b2dc433e Mon Sep 17 00:00:00 2001 From: katleman Date: Wed, 12 Nov 2014 13:47:23 -0800 Subject: Added tag jdk8u40-b14 for changeset 7e34104c55ca --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index f1e34539..861910b7 100644 --- a/.hgtags +++ b/.hgtags @@ -333,3 +333,4 @@ a2e0a985764b5afd5f316429bfab4f44bf150f7f jdk8u40-b03 57c7b273277e00f7a98fafb18ff07aa3245808f0 jdk8u40-b11 375a3a3256d041fe7334638a95e69b4c11d6104b jdk8u40-b12 d60fbb5343c186abbf92b0259e67efb3b71377b4 jdk8u40-b13 +7e34104c55cafa0b579be3a480dda383c616a378 jdk8u40-b14 -- cgit v1.2.1 From 0c6c3fa370d97964decd95f232d6cae700998268 Mon Sep 17 00:00:00 2001 From: lagergren Date: Mon, 17 Nov 2014 14:36:15 +0100 Subject: 8049407: Endianness problem with TypedArrays Reviewed-by: hannesw, sundar --- test/script/basic/JDK-8049407-big-endian.js | 33 +++ .../basic/JDK-8049407-big-endian.js.EXPECTED | 1 + test/script/basic/JDK-8049407-payload.js | 37 ++++ test/script/basic/JDK-8049407.js | 33 +++ test/script/basic/JDK-8049407.js.EXPECTED | 1 + test/script/basic/NASHORN-377-big-endian.js | 33 +++ .../basic/NASHORN-377-big-endian.js.EXPECTED | 34 ++++ test/script/basic/NASHORN-377-payload.js | 226 +++++++++++++++++++++ test/script/basic/NASHORN-377.js | 199 +----------------- .../internal/test/framework/TestFinder.java | 7 + 10 files changed, 408 insertions(+), 196 deletions(-) create mode 100644 test/script/basic/JDK-8049407-big-endian.js create mode 100644 test/script/basic/JDK-8049407-big-endian.js.EXPECTED create mode 100644 test/script/basic/JDK-8049407-payload.js create mode 100644 test/script/basic/JDK-8049407.js create mode 100644 test/script/basic/JDK-8049407.js.EXPECTED create mode 100644 test/script/basic/NASHORN-377-big-endian.js create mode 100644 test/script/basic/NASHORN-377-big-endian.js.EXPECTED create mode 100644 test/script/basic/NASHORN-377-payload.js diff --git a/test/script/basic/JDK-8049407-big-endian.js b/test/script/basic/JDK-8049407-big-endian.js new file mode 100644 index 00000000..323c4540 --- /dev/null +++ b/test/script/basic/JDK-8049407-big-endian.js @@ -0,0 +1,33 @@ +/* + * 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. + */ + +/** + * Verify DataView behavior with little/big endian + * + * @test + * @run + * @bigendian + */ + +var dir = typeof(__DIR__) == 'undefined' ? "test/script/basic/" : __DIR__; +load(dir + "JDK-8049407-payload.js"); diff --git a/test/script/basic/JDK-8049407-big-endian.js.EXPECTED b/test/script/basic/JDK-8049407-big-endian.js.EXPECTED new file mode 100644 index 00000000..c508d536 --- /dev/null +++ b/test/script/basic/JDK-8049407-big-endian.js.EXPECTED @@ -0,0 +1 @@ +false diff --git a/test/script/basic/JDK-8049407-payload.js b/test/script/basic/JDK-8049407-payload.js new file mode 100644 index 00000000..467d4bb7 --- /dev/null +++ b/test/script/basic/JDK-8049407-payload.js @@ -0,0 +1,37 @@ +/* + * 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. + */ + +/** + * Verify DataView behavior with little/big endian + * + * @subtest + * @run + */ + +var littleEndian = (function() { + var buffer = new ArrayBuffer(2); + new DataView(buffer).setInt16(0, 256, true); + return new Int16Array(buffer)[0] === 256; + })(); + +print(littleEndian); diff --git a/test/script/basic/JDK-8049407.js b/test/script/basic/JDK-8049407.js new file mode 100644 index 00000000..4bfcd26c --- /dev/null +++ b/test/script/basic/JDK-8049407.js @@ -0,0 +1,33 @@ +/* + * 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. + */ + +/** + * Verify DataView behavior with little/big endian + * + * @test + * @run + * @littleendian + */ + +var dir = typeof(__DIR__) == 'undefined' ? "test/script/basic/" : __DIR__; +load(dir + "JDK-8049407-payload.js"); diff --git a/test/script/basic/JDK-8049407.js.EXPECTED b/test/script/basic/JDK-8049407.js.EXPECTED new file mode 100644 index 00000000..27ba77dd --- /dev/null +++ b/test/script/basic/JDK-8049407.js.EXPECTED @@ -0,0 +1 @@ +true diff --git a/test/script/basic/NASHORN-377-big-endian.js b/test/script/basic/NASHORN-377-big-endian.js new file mode 100644 index 00000000..30f0cc3e --- /dev/null +++ b/test/script/basic/NASHORN-377-big-endian.js @@ -0,0 +1,33 @@ +/* + * 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. + */ + +/* + * NASHORN-377: Typed arrays. + * + * @test + * @run + * @bigendian + */ + +var dir = typeof(__DIR__) == 'undefined' ? "test/script/basic/" : __DIR__; +load(dir + "NASHORN-377-payload.js"); diff --git a/test/script/basic/NASHORN-377-big-endian.js.EXPECTED b/test/script/basic/NASHORN-377-big-endian.js.EXPECTED new file mode 100644 index 00000000..ed3f19ab --- /dev/null +++ b/test/script/basic/NASHORN-377-big-endian.js.EXPECTED @@ -0,0 +1,34 @@ +8 8 true undefined +[object ArrayBuffer] [object ArrayBuffer] [object Int8Array] +0 8 8 1 +0 8 8 1 +0 8 8 1 +0 8 4 2 +0 8 4 2 +0 8 2 4 +0 8 2 4 +0 8 2 4 +0 8 1 8 +7071727374-807677 7071727374807677 +727374-807677 2 6 +72737480 2 4 +71727374 1 4 +717273748076 +7071727374807677 1886483059 1954575991 +70717273-1020305 1886483059 -16909061 +70717273fefdfcfb 1886483059 4278058235 +40490fdafefdfcfb 2 +400921fb4d12d84a 1 +400921fb4d12d84a 1074340347 1293080650 +00000000400921fb4d12d84a +400921fb4d12-27b6 400921fb4d12d84a +00-100804d12-27b6 ffff00804d12d84a +0 1 2 3 4 5 6 7 +0102030405060708 +subarray(2,4)=0304 subarray(-6,-4)=0304 +010203040506 +03040506 0405 +0102030405060708090a0b0c0d0e0f10 +slice(4,8)=05060708 slice(-8,-4)=090a0b0c +0102030405060708090a0b0c +060708090a0b diff --git a/test/script/basic/NASHORN-377-payload.js b/test/script/basic/NASHORN-377-payload.js new file mode 100644 index 00000000..b47fb7cf --- /dev/null +++ b/test/script/basic/NASHORN-377-payload.js @@ -0,0 +1,226 @@ +/* + * 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. + */ + +/* + * NASHORN-377: Typed arrays. Payload for litte and big endian platforms. + * + * @subtest + * @run + */ + +var types = [Int8Array,Uint8Array,Uint8ClampedArray,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array]; + +//--------------------------------------------------------------------------- +// utility functions +//--------------------------------------------------------------------------- +function tohex(d, w) { + var hex = Number(d).toString(16); + var pad = (w ? w : 8) - hex.length; + hex = "00000000".substr(0, pad) + hex; + return hex; +} + +function arrstr(a, n, w) { + var s = ""; + if (typeof n == "undefined") n = a.length; + if (typeof w == "undefined") w = a.constructor.BYTES_PER_ELEMENT * 2; + for (var i = 0; i < n; i++) { + s += tohex(a[i], w); + } + return s; +} +function bufstr(b) { + if (b.buffer !== undefined) { + b = b.buffer; + } + return arrstr(new Uint8Array(b)); +} + +function assertFail(f) { + try { + f(); + } catch (e) { + //print(e); + return; + } + throw "assertion failed: expected exception"; +} + +function assertTrue(f) { + if (f() !== true) throw "assertion failed: " + f; +} + +function isUndefined(x) { + return typeof x === "undefined"; +} + +function fillArray(a, start) { + if (typeof start == "undefined") start = 1; + for (var i = 0; i < a.length; i++) { + a[i] = i + start; + } + return a; +} + +//--------------------------------------------------------------------------- +// tests +//--------------------------------------------------------------------------- +(function() { + var b = new ArrayBuffer(8); + var i8 = new Int8Array(b); + print(i8.buffer.byteLength, b.byteLength, i8.buffer === b, b.length); + print(b, i8.buffer, i8); +})(); + +(function test_attributes() { + var b = new ArrayBuffer(8); + for (var i in types) { + var x = new types[i](b); + print(x.byteOffset, x.byteLength, x.length, x.constructor.BYTES_PER_ELEMENT); + assertTrue(function(){ return x.constructor === types[i] }); + } +})(); + +(function() { + var b = new ArrayBuffer(8); + var i8 = new Int8Array(b); + fillArray(i8, 0x70); + + var i8_2 = new Int8Array(b, 2); + var i8_2_4 = new Uint8Array(b, 2, 4); + + i8_2_4[3] = 0x80; + + print(arrstr(i8, 8, 2) + " " + bufstr(i8)); + print(arrstr(i8_2, 6) + " " + i8_2.byteOffset + " " + i8_2.byteLength); + print(arrstr(i8_2_4, 4) + " " + i8_2_4.byteOffset + " " + i8_2_4.byteLength); + + var i8_1_5 = i8.subarray(1, 5); + i8_2_4.subarray(1, 5); + print(arrstr(i8_1_5, 4) + " " + i8_1_5.byteOffset + " " + i8_1_5.byteLength); + + print(bufstr(b.slice(1,7))); +})(); + +(function() { + var b = new ArrayBuffer(8); + fillArray(new Int8Array(b), 0x70); + new Int8Array(b)[5] = 0x80; + + var i32 = new Int32Array(b); + var u32 = new Uint32Array(b); + print(arrstr(i32), i32[0], i32[1]); + i32[1] = 0xfefdfcfb; + print(arrstr(i32), i32[0], i32[1]); + print(arrstr(u32), u32[0], u32[1]); + + var pi = 3.1415926; + var f32 = new Float32Array(b); + var f64 = new Float64Array(b); + f32[0] = pi; + print(bufstr(b), f32.length); + f64[0] = pi; + print(bufstr(b), f64.length); + print(arrstr(u32), u32[0], u32[1]); + + var d = new Int32Array(3); + d.set(i32,1); + print(bufstr(d)); + + var s = new Int16Array(b); + var t = new Uint16Array(b); + print(arrstr(s), arrstr(t)); + s[0] = -1; s[1] = 0x80; + print(arrstr(s), arrstr(t)); +})(); + +(function enumerate_properties() { + var i8 = new Int8Array(new ArrayBuffer(8)); + var s = ""; for (var i in i8) { s += i + " "; } print(s.trim()); +})(); + +// check that ScriptObject fallback is still working +// DISABLED because correct behavior is unclear +(function() { + // NB: firefox will never set any out-of-bounds or non-array values although it does get both from prototype. + var z = new Uint8Array(4); + z["asdf"] = "asdf"; print(z["asdf"]); + z[0x100000000] = "asdf"; print(z[0x100000000]); + z[-1] = "asdf"; print(z[-1]); + + // v8 and nashorn disagree on out-of-bounds uint32 indices: v8 won't go to the prototype. + z[0xf0000000] = "asdf"; print(z[0xf0000000]); + z[0xffffffff] = "asdf"; print(z[0xffffffff]); + z[0x70000000] = "asdf"; print(z[0x70000000]); + + // this will work in firefox and nashorn (not in v8). + Uint8Array.prototype[4] = "asdf"; print(z[4]); +}); + +(function test_exceptions() { + assertFail(function() { new Int32Array(new ArrayBuffer(7)); }); + assertFail(function() { new Int32Array(new ArrayBuffer(8), 0, 4); }); + assertFail(function() { new Int32Array(new ArrayBuffer(8),-1, 2); }); + assertFail(function() { new Int32Array(new ArrayBuffer(8), 0,-1); }); +})(); + +(function test_subarray() { + var x = fillArray(new Int8Array(8)); + print(arrstr(x)); + print("subarray(2,4)=" + arrstr(x.subarray(2, 4)), "subarray(-6,-4)=" + arrstr(x.subarray(-6, -4))); // negative index refers from the end of the array + print(arrstr(x.subarray(-10, -2))); // negative index clamped to 0 + assertTrue(function(){ return arrstr(x.subarray(6, 4)) === ""; }); // negative length clamped to 0 + print(arrstr(x.subarray(1,-1).subarray(1,-1)), arrstr(x.subarray(1,-1).subarray(1,-1).subarray(1,-1))); // subarray of subarray +})(); + +(function test_slice() { + var b = new ArrayBuffer(16); + fillArray(new Int8Array(b)); + print(bufstr(b)); + print("slice(4,8)=" + bufstr(b.slice(4, 8)), "slice(-8,-4)=" + bufstr(b.slice(-8, -4))); // negative index refers from the end of the array + print(bufstr(b.slice(-20, -4))); // negative index clamped to 0 + assertTrue(function(){ return bufstr(b.slice(8, 4)) === ""; }); // negative length clamped to 0 + print(arrstr(new Int16Array(b.slice(1,-1).slice(2,-1).slice(1,-2).slice(1,-1)))); // slice of slice +})(); + +(function test_clamped() { + var a = new Uint8ClampedArray(10); + a[0] = -17; // clamped to 0 + a[1] = 4711; // clamped to 255 + a[2] = 17.5; // clamped to 18 + a[3] = 16.5; // clamped to 16 + a[4] = 255.9; // clamped to 255 + a[5] = Infinity; // clamped to 255 + a[6] = -Infinity; // clamped to 0 + a[7] = NaN; // 0 + assertTrue(function(){ return a[0] === 0 && a[1] === 255 && a[2] === 18 && a[3] === 16 && a[4] === 255 && a[5] === 255 && a[6] === 0 && a[7] === 0; }); +})(); + +(function test_out_of_bounds() { + var a = new Int32Array(10); + a[10] = 10; + a[100] = 100; + a[1000] = 1000; + assertTrue(function(){ return isUndefined(a[10]) && isUndefined(a[11]) && isUndefined(a[100]) && isUndefined(a[123]) && isUndefined(a[1000]); }); +})(); + diff --git a/test/script/basic/NASHORN-377.js b/test/script/basic/NASHORN-377.js index 968e46e8..3484223f 100644 --- a/test/script/basic/NASHORN-377.js +++ b/test/script/basic/NASHORN-377.js @@ -26,201 +26,8 @@ * * @test * @run + * @littleendian */ -var types = [Int8Array,Uint8Array,Uint8ClampedArray,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array]; - -//--------------------------------------------------------------------------- -// utility functions -//--------------------------------------------------------------------------- -function tohex(d, w) { - var hex = Number(d).toString(16); - var pad = (w ? w : 8) - hex.length; - hex = "00000000".substr(0, pad) + hex; - return hex; -} - -function arrstr(a, n, w) { - var s = ""; - if (typeof n == "undefined") n = a.length; - if (typeof w == "undefined") w = a.constructor.BYTES_PER_ELEMENT * 2; - for (var i = 0; i < n; i++) { - s += tohex(a[i], w); - } - return s; -} -function bufstr(b) { - if (b.buffer !== undefined) { - b = b.buffer; - } - return arrstr(new Uint8Array(b)); -} - -function assertFail(f) { - try { - f(); - } catch (e) { - //print(e); - return; - } - throw "assertion failed: expected exception"; -} - -function assertTrue(f) { - if (f() !== true) throw "assertion failed: " + f; -} - -function isUndefined(x) { - return typeof x === "undefined"; -} - -function fillArray(a, start) { - if (typeof start == "undefined") start = 1; - for (var i = 0; i < a.length; i++) { - a[i] = i + start; - } - return a; -} - -//--------------------------------------------------------------------------- -// tests -//--------------------------------------------------------------------------- -(function() { - var b = new ArrayBuffer(8); - var i8 = new Int8Array(b); - print(i8.buffer.byteLength, b.byteLength, i8.buffer === b, b.length); - print(b, i8.buffer, i8); -})(); - -(function test_attributes() { - var b = new ArrayBuffer(8); - for (var i in types) { - var x = new types[i](b); - print(x.byteOffset, x.byteLength, x.length, x.constructor.BYTES_PER_ELEMENT); - assertTrue(function(){ return x.constructor === types[i] }); - } -})(); - -(function() { - var b = new ArrayBuffer(8); - var i8 = new Int8Array(b); - fillArray(i8, 0x70); - - var i8_2 = new Int8Array(b, 2); - var i8_2_4 = new Uint8Array(b, 2, 4); - - i8_2_4[3] = 0x80; - - print(arrstr(i8, 8, 2) + " " + bufstr(i8)); - print(arrstr(i8_2, 6) + " " + i8_2.byteOffset + " " + i8_2.byteLength); - print(arrstr(i8_2_4, 4) + " " + i8_2_4.byteOffset + " " + i8_2_4.byteLength); - - var i8_1_5 = i8.subarray(1, 5); - i8_2_4.subarray(1, 5); - print(arrstr(i8_1_5, 4) + " " + i8_1_5.byteOffset + " " + i8_1_5.byteLength); - - print(bufstr(b.slice(1,7))); -})(); - -(function() { - var b = new ArrayBuffer(8); - fillArray(new Int8Array(b), 0x70); - new Int8Array(b)[5] = 0x80; - - var i32 = new Int32Array(b); - var u32 = new Uint32Array(b); - print(arrstr(i32), i32[0], i32[1]); - i32[1] = 0xfefdfcfb; - print(arrstr(i32), i32[0], i32[1]); - print(arrstr(u32), u32[0], u32[1]); - - var pi = 3.1415926; - var f32 = new Float32Array(b); - var f64 = new Float64Array(b); - f32[0] = pi; - print(bufstr(b), f32.length); - f64[0] = pi; - print(bufstr(b), f64.length); - print(arrstr(u32), u32[0], u32[1]); - - var d = new Int32Array(3); - d.set(i32,1); - print(bufstr(d)); - - var s = new Int16Array(b); - var t = new Uint16Array(b); - print(arrstr(s), arrstr(t)); - s[0] = -1; s[1] = 0x80; - print(arrstr(s), arrstr(t)); -})(); - -(function enumerate_properties() { - var i8 = new Int8Array(new ArrayBuffer(8)); - var s = ""; for (var i in i8) { s += i + " "; } print(s.trim()); -})(); - -// check that ScriptObject fallback is still working -// DISABLED because correct behavior is unclear -(function() { - // NB: firefox will never set any out-of-bounds or non-array values although it does get both from prototype. - var z = new Uint8Array(4); - z["asdf"] = "asdf"; print(z["asdf"]); - z[0x100000000] = "asdf"; print(z[0x100000000]); - z[-1] = "asdf"; print(z[-1]); - - // v8 and nashorn disagree on out-of-bounds uint32 indices: v8 won't go to the prototype. - z[0xf0000000] = "asdf"; print(z[0xf0000000]); - z[0xffffffff] = "asdf"; print(z[0xffffffff]); - z[0x70000000] = "asdf"; print(z[0x70000000]); - - // this will work in firefox and nashorn (not in v8). - Uint8Array.prototype[4] = "asdf"; print(z[4]); -}); - -(function test_exceptions() { - assertFail(function() { new Int32Array(new ArrayBuffer(7)); }); - assertFail(function() { new Int32Array(new ArrayBuffer(8), 0, 4); }); - assertFail(function() { new Int32Array(new ArrayBuffer(8),-1, 2); }); - assertFail(function() { new Int32Array(new ArrayBuffer(8), 0,-1); }); -})(); - -(function test_subarray() { - var x = fillArray(new Int8Array(8)); - print(arrstr(x)); - print("subarray(2,4)=" + arrstr(x.subarray(2, 4)), "subarray(-6,-4)=" + arrstr(x.subarray(-6, -4))); // negative index refers from the end of the array - print(arrstr(x.subarray(-10, -2))); // negative index clamped to 0 - assertTrue(function(){ return arrstr(x.subarray(6, 4)) === ""; }); // negative length clamped to 0 - print(arrstr(x.subarray(1,-1).subarray(1,-1)), arrstr(x.subarray(1,-1).subarray(1,-1).subarray(1,-1))); // subarray of subarray -})(); - -(function test_slice() { - var b = new ArrayBuffer(16); - fillArray(new Int8Array(b)); - print(bufstr(b)); - print("slice(4,8)=" + bufstr(b.slice(4, 8)), "slice(-8,-4)=" + bufstr(b.slice(-8, -4))); // negative index refers from the end of the array - print(bufstr(b.slice(-20, -4))); // negative index clamped to 0 - assertTrue(function(){ return bufstr(b.slice(8, 4)) === ""; }); // negative length clamped to 0 - print(arrstr(new Int16Array(b.slice(1,-1).slice(2,-1).slice(1,-2).slice(1,-1)))); // slice of slice -})(); - -(function test_clamped() { - var a = new Uint8ClampedArray(10); - a[0] = -17; // clamped to 0 - a[1] = 4711; // clamped to 255 - a[2] = 17.5; // clamped to 18 - a[3] = 16.5; // clamped to 16 - a[4] = 255.9; // clamped to 255 - a[5] = Infinity; // clamped to 255 - a[6] = -Infinity; // clamped to 0 - a[7] = NaN; // 0 - assertTrue(function(){ return a[0] === 0 && a[1] === 255 && a[2] === 18 && a[3] === 16 && a[4] === 255 && a[5] === 255 && a[6] === 0 && a[7] === 0; }); -})(); - -(function test_out_of_bounds() { - var a = new Int32Array(10); - a[10] = 10; - a[100] = 100; - a[1000] = 1000; - assertTrue(function(){ return isUndefined(a[10]) && isUndefined(a[11]) && isUndefined(a[100]) && isUndefined(a[123]) && isUndefined(a[1000]); }); -})(); - +var dir = typeof(__DIR__) == 'undefined' ? "test/script/basic/" : __DIR__; +load(dir + "NASHORN-377-payload.js"); diff --git a/test/src/jdk/nashorn/internal/test/framework/TestFinder.java b/test/src/jdk/nashorn/internal/test/framework/TestFinder.java index ab472d70..32b1cbd5 100644 --- a/test/src/jdk/nashorn/internal/test/framework/TestFinder.java +++ b/test/src/jdk/nashorn/internal/test/framework/TestFinder.java @@ -46,6 +46,7 @@ import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; +import java.nio.ByteOrder; import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.nio.file.FileVisitOption; @@ -264,6 +265,12 @@ public final class TestFinder { isTest = false; isNotTest = true; break; + case "@bigendian": + shouldRun = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN; + break; + case "@littleendian": + shouldRun = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN; + break; case "@runif": { final String prop = scanner.next(); if (System.getProperty(prop) != null) { -- cgit v1.2.1 From cd4128794031bedeaa6f1680b1dfd7417bd2f1d5 Mon Sep 17 00:00:00 2001 From: asaha Date: Mon, 17 Nov 2014 12:40:54 -0800 Subject: Added tag jdk8u31-b09 for changeset 762eaacc45ce --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 5fca6fbd..90b524f6 100644 --- a/.hgtags +++ b/.hgtags @@ -331,3 +331,4 @@ cdbf34dbef404b47805c8c85b11c65c2afaa6674 jdk8u25-b18 99a3333f7f8489bb3c80f0c0643ae19e549a0941 jdk8u31-b06 5ed4fa732b26b6d8e37dfc5bbd00047c5352719b jdk8u31-b07 b17ecf341ee544cc5507b9b586c14a13c3adc058 jdk8u31-b08 +762eaacc45cec3f7d593bedd08fb8de478d4415b jdk8u31-b09 -- cgit v1.2.1 From 0ddce13dc33a759420614c0c372b28cd93ccdacb Mon Sep 17 00:00:00 2001 From: katleman Date: Wed, 19 Nov 2014 11:29:48 -0800 Subject: Added tag jdk8u40-b15 for changeset fc37699ddc0e --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 861910b7..d31293a6 100644 --- a/.hgtags +++ b/.hgtags @@ -334,3 +334,4 @@ a2e0a985764b5afd5f316429bfab4f44bf150f7f jdk8u40-b03 375a3a3256d041fe7334638a95e69b4c11d6104b jdk8u40-b12 d60fbb5343c186abbf92b0259e67efb3b71377b4 jdk8u40-b13 7e34104c55cafa0b579be3a480dda383c616a378 jdk8u40-b14 +fc37699ddc0ed41d4ab5da821211a6d2648c8883 jdk8u40-b15 -- cgit v1.2.1 From 422aa12f3ece2332330f86c1666ae223a3ab8bba Mon Sep 17 00:00:00 2001 From: hannesw Date: Fri, 21 Nov 2014 20:17:02 +0100 Subject: 8064789: Nashorn should just warn on code store instantiation error Reviewed-by: attila, lagergren --- src/jdk/nashorn/internal/runtime/CodeStore.java | 16 ++++++++++------ src/jdk/nashorn/internal/runtime/Context.java | 8 ++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/jdk/nashorn/internal/runtime/CodeStore.java b/src/jdk/nashorn/internal/runtime/CodeStore.java index 0e85beeb..4e745ff4 100644 --- a/src/jdk/nashorn/internal/runtime/CodeStore.java +++ b/src/jdk/nashorn/internal/runtime/CodeStore.java @@ -82,10 +82,9 @@ public abstract class CodeStore implements Loggable { * Returns a new code store instance. * * @param context the current context - * @return The instance - * @throws IOException If an error occurs + * @return The instance, or null if code store could not be created */ - public static CodeStore newCodeStore(final Context context) throws IOException { + public static CodeStore newCodeStore(final Context context) { final Class baseClass = CodeStore.class; try { // security check first @@ -103,9 +102,14 @@ public abstract class CodeStore implements Loggable { } catch (final AccessControlException e) { context.getLogger(CodeStore.class).warning("failed to load code store provider ", e); } - final CodeStore store = new DirectoryCodeStore(context); - store.initLogger(context); - return store; + try { + final CodeStore store = new DirectoryCodeStore(context); + store.initLogger(context); + return store; + } catch (final IOException e) { + context.getLogger(CodeStore.class).warning("failed to create cache directory ", e); + return null; + } } diff --git a/src/jdk/nashorn/internal/runtime/Context.java b/src/jdk/nashorn/internal/runtime/Context.java index 86369ab7..9e851998 100644 --- a/src/jdk/nashorn/internal/runtime/Context.java +++ b/src/jdk/nashorn/internal/runtime/Context.java @@ -509,11 +509,7 @@ public final class Context { } if (env._persistent_cache) { - try { - codeStore = newCodeStore(this); - } catch (final IOException e) { - throw new RuntimeException("Error initializing code cache", e); - } + codeStore = newCodeStore(this); } // print version info if asked. @@ -1200,7 +1196,7 @@ public final class Context { FunctionNode functionNode = null; // We only use the code store here if optimistic types are disabled. With optimistic types, initial compilation // just creates a thin wrapper, and actual code is stored per function in RecompilableScriptFunctionData. - final boolean useCodeStore = env._persistent_cache && !env._parse_only && !env._optimistic_types; + final boolean useCodeStore = codeStore != null && !env._parse_only && !env._optimistic_types; final String cacheKey = useCodeStore ? CodeStore.getCacheKey(0, null) : null; if (useCodeStore) { -- cgit v1.2.1 From 9e84bddace10ff39aabfa7dbcdcc16cb0c9e656c Mon Sep 17 00:00:00 2001 From: hannesw Date: Mon, 24 Nov 2014 12:03:15 +0100 Subject: 8057691: Nashorn: let & const declarations are not shared between scripts Reviewed-by: lagergren, attila --- .../nashorn/internal/codegen/AssignSymbols.java | 6 +- src/jdk/nashorn/internal/codegen/MapCreator.java | 4 + src/jdk/nashorn/internal/objects/Global.java | 188 +++++++++++++++++- src/jdk/nashorn/internal/parser/Parser.java | 15 +- src/jdk/nashorn/internal/runtime/Property.java | 17 +- src/jdk/nashorn/internal/runtime/ScriptObject.java | 59 ++++-- .../basic/es6/const-redeclare-extra.js.EXPECTED | 12 +- test/script/basic/es6/let-load.js | 3 +- test/script/basic/es6/let-load.js.EXPECTED | 4 +- .../basic/es6/let-redeclare-extra.js.EXPECTED | 10 +- test/script/basic/es6/lexical-toplevel-def.js | 34 ++++ test/script/basic/es6/lexical-toplevel-print.js | 51 +++++ .../es6/lexical-toplevel-redeclare-func-on-let.js | 31 +++ .../lexical-toplevel-redeclare-let-on-builtin.js | 30 +++ .../es6/lexical-toplevel-redeclare-let-on-func.js | 31 +++ .../lexical-toplevel-redeclare-let-on-global.js | 30 +++ .../es6/lexical-toplevel-redeclare-let-on-var.js | 31 +++ .../es6/lexical-toplevel-redeclare-var-on-let.js | 31 +++ .../script/basic/es6/lexical-toplevel-redeclare.js | 78 ++++++++ .../es6/lexical-toplevel-redeclare.js.EXPECTED | 100 ++++++++++ test/script/basic/es6/lexical-toplevel.js | 35 ++++ test/script/basic/es6/lexical-toplevel.js.EXPECTED | 30 +++ .../internal/runtime/LexicalBindingTest.java | 212 +++++++++++++++++++++ 23 files changed, 983 insertions(+), 59 deletions(-) create mode 100644 test/script/basic/es6/lexical-toplevel-def.js create mode 100644 test/script/basic/es6/lexical-toplevel-print.js create mode 100644 test/script/basic/es6/lexical-toplevel-redeclare-func-on-let.js create mode 100644 test/script/basic/es6/lexical-toplevel-redeclare-let-on-builtin.js create mode 100644 test/script/basic/es6/lexical-toplevel-redeclare-let-on-func.js create mode 100644 test/script/basic/es6/lexical-toplevel-redeclare-let-on-global.js create mode 100644 test/script/basic/es6/lexical-toplevel-redeclare-let-on-var.js create mode 100644 test/script/basic/es6/lexical-toplevel-redeclare-var-on-let.js create mode 100644 test/script/basic/es6/lexical-toplevel-redeclare.js create mode 100644 test/script/basic/es6/lexical-toplevel-redeclare.js.EXPECTED create mode 100644 test/script/basic/es6/lexical-toplevel.js create mode 100644 test/script/basic/es6/lexical-toplevel.js.EXPECTED create mode 100644 test/src/jdk/nashorn/internal/runtime/LexicalBindingTest.java diff --git a/src/jdk/nashorn/internal/codegen/AssignSymbols.java b/src/jdk/nashorn/internal/codegen/AssignSymbols.java index 88fd89bb..ad0f13c7 100644 --- a/src/jdk/nashorn/internal/codegen/AssignSymbols.java +++ b/src/jdk/nashorn/internal/codegen/AssignSymbols.java @@ -356,6 +356,10 @@ final class AssignSymbols extends NodeVisitor implements Loggabl throwParserException(ECMAErrors.getMessage("syntax.error.redeclare.variable", name), origin); } else { symbol.setHasBeenDeclared(); + // Set scope flag on top-level block scoped symbols + if (function.isProgram() && function.getBody() == block) { + symbol.setIsScope(); + } } } else if ((flags & IS_INTERNAL) != 0) { // Always create a new definition. @@ -540,7 +544,7 @@ final class AssignSymbols extends NodeVisitor implements Loggabl final int flags; if (varNode.isAnonymousFunctionDeclaration()) { flags = IS_INTERNAL; - } else if (lc.getCurrentFunction().isProgram()) { + } else if (!varNode.isBlockScoped() && lc.getCurrentFunction().isProgram()) { flags = IS_SCOPE; } else { flags = 0; diff --git a/src/jdk/nashorn/internal/codegen/MapCreator.java b/src/jdk/nashorn/internal/codegen/MapCreator.java index 3ba3f630..1bec86fc 100644 --- a/src/jdk/nashorn/internal/codegen/MapCreator.java +++ b/src/jdk/nashorn/internal/codegen/MapCreator.java @@ -152,6 +152,10 @@ public class MapCreator { flags |= Property.NOT_WRITABLE; } + if (symbol.isBlockScoped()) { + flags |= Property.IS_LEXICAL_BINDING; + } + // Mark symbol as needing declaration. Access before declaration will throw a ReferenceError. if (symbol.isBlockScoped() && symbol.isScope()) { flags |= Property.NEEDS_DECLARATION; diff --git a/src/jdk/nashorn/internal/objects/Global.java b/src/jdk/nashorn/internal/objects/Global.java index 6a978627..bb3e13d2 100644 --- a/src/jdk/nashorn/internal/objects/Global.java +++ b/src/jdk/nashorn/internal/objects/Global.java @@ -34,6 +34,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; import java.lang.invoke.SwitchPoint; import java.lang.reflect.Field; import java.util.ArrayList; @@ -44,6 +45,7 @@ import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import javax.script.ScriptContext; import javax.script.ScriptEngine; +import jdk.internal.dynalink.CallSiteDescriptor; import jdk.internal.dynalink.linker.GuardedInvocation; import jdk.internal.dynalink.linker.LinkRequest; import jdk.nashorn.api.scripting.ClassFilter; @@ -54,6 +56,8 @@ import jdk.nashorn.internal.objects.annotations.Property; import jdk.nashorn.internal.objects.annotations.ScriptClass; import jdk.nashorn.internal.runtime.ConsString; import jdk.nashorn.internal.runtime.Context; +import jdk.nashorn.internal.runtime.ECMAErrors; +import jdk.nashorn.internal.runtime.GlobalConstants; import jdk.nashorn.internal.runtime.GlobalFunctions; import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.NativeJavaPackage; @@ -69,6 +73,7 @@ import jdk.nashorn.internal.runtime.Specialization; import jdk.nashorn.internal.runtime.arrays.ArrayData; import jdk.nashorn.internal.runtime.linker.Bootstrap; import jdk.nashorn.internal.runtime.linker.InvokeByName; +import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor; import jdk.nashorn.internal.runtime.regexp.RegExpResult; import jdk.nashorn.internal.scripts.JO; @@ -410,13 +415,14 @@ public final class Global extends ScriptObject implements Scope { // Used to store the last RegExp result to support deprecated RegExp constructor properties private RegExpResult lastRegExpResult; - private static final MethodHandle EVAL = findOwnMH_S("eval", Object.class, Object.class, Object.class); - private static final MethodHandle NO_SUCH_PROPERTY = findOwnMH_S(NO_SUCH_PROPERTY_NAME, Object.class, Object.class, Object.class); - private static final MethodHandle PRINT = findOwnMH_S("print", Object.class, Object.class, Object[].class); - private static final MethodHandle PRINTLN = findOwnMH_S("println", Object.class, Object.class, Object[].class); - private static final MethodHandle LOAD = findOwnMH_S("load", Object.class, Object.class, Object.class); - private static final MethodHandle LOADWITHNEWGLOBAL = findOwnMH_S("loadWithNewGlobal", Object.class, Object.class, Object[].class); - private static final MethodHandle EXIT = findOwnMH_S("exit", Object.class, Object.class, Object.class); + private static final MethodHandle EVAL = findOwnMH_S("eval", Object.class, Object.class, Object.class); + private static final MethodHandle NO_SUCH_PROPERTY = findOwnMH_S(NO_SUCH_PROPERTY_NAME, Object.class, Object.class, Object.class); + private static final MethodHandle PRINT = findOwnMH_S("print", Object.class, Object.class, Object[].class); + private static final MethodHandle PRINTLN = findOwnMH_S("println", Object.class, Object.class, Object[].class); + private static final MethodHandle LOAD = findOwnMH_S("load", Object.class, Object.class, Object.class); + private static final MethodHandle LOAD_WITH_NEW_GLOBAL = findOwnMH_S("loadWithNewGlobal", Object.class, Object.class, Object[].class); + private static final MethodHandle EXIT = findOwnMH_S("exit", Object.class, Object.class, Object.class); + private static final MethodHandle LEXICAL_SCOPE_FILTER = findOwnMH_S("lexicalScopeFilter", Object.class, Object.class); // initialized by nasgen private static PropertyMap $nasgenmap$; @@ -429,6 +435,12 @@ public final class Global extends ScriptObject implements Scope { // current ScriptEngine associated - can be null. private ScriptEngine engine; + // ES6 global lexical scope. + private final LexicalScope lexicalScope; + + // Switchpoint for non-constant global callsites in the presence of ES6 lexical scope. + private SwitchPoint lexicalScopeSwitchPoint; + /** * Set the current script context * @param scontext script context @@ -466,6 +478,7 @@ public final class Global extends ScriptObject implements Scope { super(checkAndGetMap(context)); this.context = context; this.setIsScope(); + this.lexicalScope = context.getEnv()._es6 ? new LexicalScope(this) : null; } /** @@ -1694,6 +1707,133 @@ public final class Global extends ScriptObject implements Scope { splitState = state; } + /** + * Return the ES6 global scope for lexically declared bindings. + * @return the ES6 lexical global scope. + */ + public final ScriptObject getLexicalScope() { + assert context.getEnv()._es6; + return lexicalScope; + } + + @Override + public void addBoundProperties(final ScriptObject source, final jdk.nashorn.internal.runtime.Property[] properties) { + PropertyMap ownMap = getMap(); + LexicalScope lexicalScope = null; + PropertyMap lexicalMap = null; + boolean hasLexicalDefinitions = false; + + if (context.getEnv()._es6) { + lexicalScope = (LexicalScope) getLexicalScope(); + lexicalMap = lexicalScope.getMap(); + + for (final jdk.nashorn.internal.runtime.Property property : properties) { + if (property.isLexicalBinding()) { + hasLexicalDefinitions = true; + } + // ES6 15.1.8 steps 6. and 7. + final jdk.nashorn.internal.runtime.Property globalProperty = ownMap.findProperty(property.getKey()); + if (globalProperty != null && !globalProperty.isConfigurable() && property.isLexicalBinding()) { + throw ECMAErrors.syntaxError("redeclare.variable", property.getKey()); + } + final jdk.nashorn.internal.runtime.Property lexicalProperty = lexicalMap.findProperty(property.getKey()); + if (lexicalProperty != null && !property.isConfigurable()) { + throw ECMAErrors.syntaxError("redeclare.variable", property.getKey()); + } + } + } + + for (final jdk.nashorn.internal.runtime.Property property : properties) { + if (property.isLexicalBinding()) { + assert lexicalScope != null; + lexicalMap = lexicalScope.addBoundProperty(lexicalMap, source, property); + + if (ownMap.findProperty(property.getKey()) != null) { + // If property exists in the global object invalidate any global constant call sites. + invalidateGlobalConstant(property.getKey()); + } + } else { + ownMap = addBoundProperty(ownMap, source, property); + } + } + + setMap(ownMap); + + if (hasLexicalDefinitions) { + lexicalScope.setMap(lexicalMap); + invalidateLexicalSwitchPoint(); + } + } + + @Override + public GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) { + final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND); + final boolean isScope = NashornCallSiteDescriptor.isScope(desc); + + if (lexicalScope != null && isScope && !NashornCallSiteDescriptor.isApplyToCall(desc)) { + if (lexicalScope.hasOwnProperty(name)) { + return lexicalScope.findGetMethod(desc, request, operator); + } + } + + final GuardedInvocation invocation = super.findGetMethod(desc, request, operator); + + // We want to avoid adding our generic lexical scope switchpoint to global constant invocations, + // because those are invalidated per-key in the addBoundProperties method above. + // We therefor check if the invocation does already have a switchpoint and the property is non-inherited, + // assuming this only applies to global constants. If other non-inherited properties will + // start using switchpoints some time in the future we'll have to revisit this. + if (isScope && context.getEnv()._es6 && (invocation.getSwitchPoints() == null || !hasOwnProperty(name))) { + return invocation.addSwitchPoint(getLexicalScopeSwitchPoint()); + } + + return invocation; + } + + @Override + public GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final LinkRequest request) { + final boolean isScope = NashornCallSiteDescriptor.isScope(desc); + + if (lexicalScope != null && isScope) { + final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND); + if (lexicalScope.hasOwnProperty(name)) { + return lexicalScope.findSetMethod(desc, request); + } + } + + final GuardedInvocation invocation = super.findSetMethod(desc, request); + + if (isScope && context.getEnv()._es6) { + return invocation.addSwitchPoint(getLexicalScopeSwitchPoint()); + } + + return invocation; + } + + private synchronized SwitchPoint getLexicalScopeSwitchPoint() { + SwitchPoint switchPoint = lexicalScopeSwitchPoint; + if (switchPoint == null || switchPoint.hasBeenInvalidated()) { + switchPoint = lexicalScopeSwitchPoint = new SwitchPoint(); + } + return switchPoint; + } + + private synchronized void invalidateLexicalSwitchPoint() { + if (lexicalScopeSwitchPoint != null) { + context.getLogger(GlobalConstants.class).info("Invalidating non-constant globals on lexical scope update"); + SwitchPoint.invalidateAll(new SwitchPoint[]{ lexicalScopeSwitchPoint }); + } + } + + + @SuppressWarnings("unused") + private static Object lexicalScopeFilter(final Object self) { + if (self instanceof Global) { + return ((Global) self).getLexicalScope(); + } + return self; + } + private T initConstructorAndSwitchPoint(final String name, final Class clazz) { final T func = initConstructor(name, clazz); tagBuiltinProperties(name, func); @@ -1739,7 +1879,7 @@ public final class Global extends ScriptObject implements Scope { this.unescape = ScriptFunctionImpl.makeFunction("unescape", GlobalFunctions.UNESCAPE); this.print = ScriptFunctionImpl.makeFunction("print", env._print_no_newline ? PRINT : PRINTLN); this.load = ScriptFunctionImpl.makeFunction("load", LOAD); - this.loadWithNewGlobal = ScriptFunctionImpl.makeFunction("loadWithNewGlobal", LOADWITHNEWGLOBAL); + this.loadWithNewGlobal = ScriptFunctionImpl.makeFunction("loadWithNewGlobal", LOAD_WITH_NEW_GLOBAL); this.exit = ScriptFunctionImpl.makeFunction("exit", EXIT); this.quit = ScriptFunctionImpl.makeFunction("quit", EXIT); @@ -2205,4 +2345,36 @@ public final class Global extends ScriptObject implements Scope { protected boolean isGlobal() { return true; } + + /** + * A class representing the ES6 global lexical scope. + */ + private static class LexicalScope extends ScriptObject { + + LexicalScope(final ScriptObject proto) { + super(proto, PropertyMap.newMap()); + } + + @Override + protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) { + return filterInvocation(super.findGetMethod(desc, request, operator)); + } + + @Override + protected GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final LinkRequest request) { + return filterInvocation(super.findSetMethod(desc, request)); + } + + @Override + protected PropertyMap addBoundProperty(final PropertyMap propMap, final ScriptObject source, final jdk.nashorn.internal.runtime.Property property) { + // We override this method just to make it callable by Global + return super.addBoundProperty(propMap, source, property); + } + + private static GuardedInvocation filterInvocation(final GuardedInvocation invocation) { + final MethodType type = invocation.getInvocation().type(); + return invocation.asType(type.changeParameterType(0, Object.class)).filterArguments(0, LEXICAL_SCOPE_FILTER); + } + } + } diff --git a/src/jdk/nashorn/internal/parser/Parser.java b/src/jdk/nashorn/internal/parser/Parser.java index 3162e184..ed11a18b 100644 --- a/src/jdk/nashorn/internal/parser/Parser.java +++ b/src/jdk/nashorn/internal/parser/Parser.java @@ -707,20 +707,9 @@ loop: FunctionNode.Kind.SCRIPT, functionLine); - // If ES6 block scope is enabled add a per-script block for top-level LET and CONST declarations. - final int startLine = start; - Block outer = useBlockScope() ? newBlock() : null; functionDeclarations = new ArrayList<>(); - - try { - sourceElements(allowPropertyFunction); - addFunctionDeclarations(script); - } finally { - if (outer != null) { - outer = restoreBlock(outer); - appendStatement(new BlockStatement(startLine, outer)); - } - } + sourceElements(allowPropertyFunction); + addFunctionDeclarations(script); functionDeclarations = null; expect(EOF); diff --git a/src/jdk/nashorn/internal/runtime/Property.java b/src/jdk/nashorn/internal/runtime/Property.java index 41baa642..4225c251 100644 --- a/src/jdk/nashorn/internal/runtime/Property.java +++ b/src/jdk/nashorn/internal/runtime/Property.java @@ -84,14 +84,17 @@ public abstract class Property implements Serializable { public static final int IS_NASGEN_PRIMITIVE = 1 << 6; /** Is this a builtin property, e.g. Function.prototype.apply */ - public static final int IS_BUILTIN = 1 << 7; + public static final int IS_BUILTIN = 1 << 7; /** Is this property bound to a receiver? This means get/set operations will be delegated to * a statically defined object instead of the object passed as callsite parameter. */ - public static final int IS_BOUND = 1 << 7; + public static final int IS_BOUND = 1 << 8; /** Is this a lexically scoped LET or CONST variable that is dead until it is declared. */ - public static final int NEEDS_DECLARATION = 1 << 8; + public static final int NEEDS_DECLARATION = 1 << 9; + + /** Is this property an ES6 lexical binding? */ + public static final int IS_LEXICAL_BINDING = 1 << 10; /** Property key. */ private final String key; @@ -714,4 +717,12 @@ public abstract class Property implements Serializable { public boolean isFunctionDeclaration() { return (flags & IS_FUNCTION_DECLARATION) == IS_FUNCTION_DECLARATION; } + + /** + * Is this a property defined by ES6 let or const? + * @return true if this property represents a lexical binding. + */ + public boolean isLexicalBinding() { + return (flags & IS_LEXICAL_BINDING) == IS_LEXICAL_BINDING; + } } diff --git a/src/jdk/nashorn/internal/runtime/ScriptObject.java b/src/jdk/nashorn/internal/runtime/ScriptObject.java index 89246241..f87af8ee 100644 --- a/src/jdk/nashorn/internal/runtime/ScriptObject.java +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java @@ -304,29 +304,44 @@ public abstract class ScriptObject implements PropertyAccess { PropertyMap newMap = this.getMap(); for (final Property property : properties) { - final String key = property.getKey(); - final Property oldProp = newMap.findProperty(key); - if (oldProp == null) { - if (property instanceof UserAccessorProperty) { - // Note: we copy accessor functions to this object which is semantically different from binding. - final UserAccessorProperty prop = this.newUserAccessors(key, property.getFlags(), property.getGetterFunction(source), property.getSetterFunction(source)); - newMap = newMap.addPropertyNoHistory(prop); - } else { - newMap = newMap.addPropertyBind((AccessorProperty)property, source); - } + newMap = addBoundProperty(newMap, source, property); + } + + this.setMap(newMap); + } + + /** + * Add a bound property from {@code source}, using the interim property map {@code propMap}, and return the + * new interim property map. + * + * @param propMap the property map + * @param source the source object + * @param property the property to be added + * @return the new property map + */ + protected PropertyMap addBoundProperty(final PropertyMap propMap, final ScriptObject source, final Property property) { + PropertyMap newMap = propMap; + final String key = property.getKey(); + final Property oldProp = newMap.findProperty(key); + if (oldProp == null) { + if (property instanceof UserAccessorProperty) { + // Note: we copy accessor functions to this object which is semantically different from binding. + final UserAccessorProperty prop = this.newUserAccessors(key, property.getFlags(), property.getGetterFunction(source), property.getSetterFunction(source)); + newMap = newMap.addPropertyNoHistory(prop); } else { - // See ECMA section 10.5 Declaration Binding Instantiation - // step 5 processing each function declaration. - if (property.isFunctionDeclaration() && !oldProp.isConfigurable()) { - if (oldProp instanceof UserAccessorProperty || - !(oldProp.isWritable() && oldProp.isEnumerable())) { - throw typeError("cant.redefine.property", key, ScriptRuntime.safeToString(this)); - } + newMap = newMap.addPropertyBind((AccessorProperty)property, source); + } + } else { + // See ECMA section 10.5 Declaration Binding Instantiation + // step 5 processing each function declaration. + if (property.isFunctionDeclaration() && !oldProp.isConfigurable()) { + if (oldProp instanceof UserAccessorProperty || + !(oldProp.isWritable() && oldProp.isEnumerable())) { + throw typeError("cant.redefine.property", key, ScriptRuntime.safeToString(this)); } } } - - this.setMap(newMap); + return newMap; } /** @@ -510,7 +525,11 @@ public abstract class ScriptObject implements PropertyAccess { } } - private void invalidateGlobalConstant(final String key) { + /** + * Invalidate any existing global constant method handles that may exist for {@code key}. + * @param key the property name + */ + protected void invalidateGlobalConstant(final String key) { final GlobalConstants globalConstants = getGlobalConstants(); if (globalConstants != null) { globalConstants.delete(key); diff --git a/test/script/basic/es6/const-redeclare-extra.js.EXPECTED b/test/script/basic/es6/const-redeclare-extra.js.EXPECTED index 754a75c6..06af782e 100644 --- a/test/script/basic/es6/const-redeclare-extra.js.EXPECTED +++ b/test/script/basic/es6/const-redeclare-extra.js.EXPECTED @@ -1,9 +1,9 @@ SyntaxError: test/script/basic/es6/const-redeclare-extra.js#36:8:3:8 Variable "x" has already been declared var x = {}; ^ -SyntaxError: test/script/basic/es6/const-redeclare-extra.js#36:8:2:8 Variable "x" has already been declared - var x = 2; - ^ -SyntaxError: test/script/basic/es6/const-redeclare-extra.js#36:8:2:13 Variable "x" has already been declared - function x () {} - ^ +SyntaxError: test/script/basic/es6/const-redeclare-extra.js#36:8:3:10 Variable "x" has already been declared + const x = {}; + ^ +SyntaxError: test/script/basic/es6/const-redeclare-extra.js#36:8:3:10 Variable "x" has already been declared + const x = 5; + ^ diff --git a/test/script/basic/es6/let-load.js b/test/script/basic/es6/let-load.js index b4c29465..57667543 100644 --- a/test/script/basic/es6/let-load.js +++ b/test/script/basic/es6/let-load.js @@ -26,7 +26,8 @@ * * @test * @run - * @option --language=es6 */ + * @option --language=es6 + */ "use strict"; diff --git a/test/script/basic/es6/let-load.js.EXPECTED b/test/script/basic/es6/let-load.js.EXPECTED index 510da6e6..f92f84c1 100644 --- a/test/script/basic/es6/let-load.js.EXPECTED +++ b/test/script/basic/es6/let-load.js.EXPECTED @@ -2,7 +2,7 @@ top level function block function print local defs: 20 30 imported var: 1 -ReferenceError: "b" is not defined -ReferenceError: "c" is not defined +imported let: 2 +imported const: 3 top level function ReferenceError: "block" is not defined diff --git a/test/script/basic/es6/let-redeclare-extra.js.EXPECTED b/test/script/basic/es6/let-redeclare-extra.js.EXPECTED index 5e43b694..e0e1afec 100644 --- a/test/script/basic/es6/let-redeclare-extra.js.EXPECTED +++ b/test/script/basic/es6/let-redeclare-extra.js.EXPECTED @@ -4,12 +4,12 @@ SyntaxError: test/script/basic/es6/let-redeclare-extra.js#35:8:2:8 Variabl SyntaxError: test/script/basic/es6/let-redeclare-extra.js#35:8:3:8 Variable "x" has already been declared var x = 2; ^ -SyntaxError: test/script/basic/es6/let-redeclare-extra.js#35:8:2:8 Variable "x" has already been declared - var x = 2; +SyntaxError: test/script/basic/es6/let-redeclare-extra.js#35:8:3:8 Variable "x" has already been declared + let x = undefined; ^ SyntaxError: test/script/basic/es6/let-redeclare-extra.js#35:8:2:10 Variable "x" has already been declared const x = function (){}; ^ -SyntaxError: test/script/basic/es6/let-redeclare-extra.js#35:8:3:13 Variable "a" has already been declared - function a () {}; - ^ +SyntaxError: test/script/basic/es6/let-redeclare-extra.js#35:8:2:8 Variable "a" has already been declared + let a = 2; + ^ diff --git a/test/script/basic/es6/lexical-toplevel-def.js b/test/script/basic/es6/lexical-toplevel-def.js new file mode 100644 index 00000000..c9a44f70 --- /dev/null +++ b/test/script/basic/es6/lexical-toplevel-def.js @@ -0,0 +1,34 @@ +/* + * 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-8057691: Nashorn: let & const declarations are not shared between scripts + * + * @subtest + */ + +var VAR = "VAR"; +let LET = "LET"; +const CONST = "CONST"; +function FUNC() {} +this.GLOBAL = "GLOBAL"; diff --git a/test/script/basic/es6/lexical-toplevel-print.js b/test/script/basic/es6/lexical-toplevel-print.js new file mode 100644 index 00000000..eef030ac --- /dev/null +++ b/test/script/basic/es6/lexical-toplevel-print.js @@ -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-8057691: Nashorn: let & const declarations are not shared between scripts + * + * @subtest + */ + +print(VAR); +print(LET); +print(CONST); +print(FUNC); +print(GLOBAL); +print(this.VAR); +print(this.LET); // undefined +print(this.CONST); // undefined +print(this.FUNC); +print(this.GLOBAL); +print("VAR" in this); +print("LET" in this); // false +print("CONST" in this); // false +print("FUNC" in this); +print("GLOBAL" in this); + +try { + LET = LET + "LET"; + CONST = CONST + "CONST"; +} catch (e) { + print(String(e).replace(/\\/g, "/")); +} diff --git a/test/script/basic/es6/lexical-toplevel-redeclare-func-on-let.js b/test/script/basic/es6/lexical-toplevel-redeclare-func-on-let.js new file mode 100644 index 00000000..bfe7af35 --- /dev/null +++ b/test/script/basic/es6/lexical-toplevel-redeclare-func-on-let.js @@ -0,0 +1,31 @@ +/* + * 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-8057691: Nashorn: let & const declarations are not shared between scripts + * + * @subtest + */ + +function LET() {} +var SHOULD_NOT_EXIST = 10; diff --git a/test/script/basic/es6/lexical-toplevel-redeclare-let-on-builtin.js b/test/script/basic/es6/lexical-toplevel-redeclare-let-on-builtin.js new file mode 100644 index 00000000..64360142 --- /dev/null +++ b/test/script/basic/es6/lexical-toplevel-redeclare-let-on-builtin.js @@ -0,0 +1,30 @@ +/* + * 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-8057691: Nashorn: let & const declarations are not shared between scripts + * + * @subtest + */ + +let Object = "LEXICAL BUILTIN"; diff --git a/test/script/basic/es6/lexical-toplevel-redeclare-let-on-func.js b/test/script/basic/es6/lexical-toplevel-redeclare-let-on-func.js new file mode 100644 index 00000000..44c83964 --- /dev/null +++ b/test/script/basic/es6/lexical-toplevel-redeclare-let-on-func.js @@ -0,0 +1,31 @@ +/* + * 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-8057691: Nashorn: let & const declarations are not shared between scripts + * + * @subtest + */ + +let FUNC = 10; +var SHOULD_NOT_EXIST = 10; diff --git a/test/script/basic/es6/lexical-toplevel-redeclare-let-on-global.js b/test/script/basic/es6/lexical-toplevel-redeclare-let-on-global.js new file mode 100644 index 00000000..a742fad3 --- /dev/null +++ b/test/script/basic/es6/lexical-toplevel-redeclare-let-on-global.js @@ -0,0 +1,30 @@ +/* + * 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-8057691: Nashorn: let & const declarations are not shared between scripts + * + * @subtest + */ + +let GLOBAL = "LEXICAL GLOBAL"; diff --git a/test/script/basic/es6/lexical-toplevel-redeclare-let-on-var.js b/test/script/basic/es6/lexical-toplevel-redeclare-let-on-var.js new file mode 100644 index 00000000..630741f0 --- /dev/null +++ b/test/script/basic/es6/lexical-toplevel-redeclare-let-on-var.js @@ -0,0 +1,31 @@ +/* + * 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-8057691: Nashorn: let & const declarations are not shared between scripts + * + * @subtest + */ + +let VAR = 10; +var SHOULD_NOT_EXIST = 10; diff --git a/test/script/basic/es6/lexical-toplevel-redeclare-var-on-let.js b/test/script/basic/es6/lexical-toplevel-redeclare-var-on-let.js new file mode 100644 index 00000000..cb4b3822 --- /dev/null +++ b/test/script/basic/es6/lexical-toplevel-redeclare-var-on-let.js @@ -0,0 +1,31 @@ +/* + * 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-8057691: Nashorn: let & const declarations are not shared between scripts + * + * @subtest + */ + +var LET = 10; +var SHOULD_NOT_EXIST = 10; diff --git a/test/script/basic/es6/lexical-toplevel-redeclare.js b/test/script/basic/es6/lexical-toplevel-redeclare.js new file mode 100644 index 00000000..6a76622f --- /dev/null +++ b/test/script/basic/es6/lexical-toplevel-redeclare.js @@ -0,0 +1,78 @@ +/* + * 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-8057691: Nashorn: let & const declarations are not shared between scripts + * + * @test + * @run + * @option -scripting + * @option --language=es6 + */ + +load(__DIR__ + "lexical-toplevel-def.js"); + +var global = this; + +function tryIt (code) { + try { + eval(code) + } catch (e) { + print(String(e).replace(/\\/g, "/")) + } +} + +function loadScript(script) { + print(script); + try { + load(__DIR__ + script); + } catch (e) { + print(String(e).replace(/\\/g, "/")); + } + print(VAR); + print(LET); + print(CONST); + print(FUNC); + print(GLOBAL); + print(global.VAR); + print(global.LET); + print(global.CONST); + print(global.FUNC); + print(global.GLOBAL); + try { + print(SHOULD_NOT_EXIST); + } catch (e) { + print(String(e).replace(/\\/g, "/")); + } + print(global.SHOULD_NOT_EXIST); + print(Object); + print(global.Object); + print(); +} + +loadScript("lexical-toplevel-redeclare-var-on-let.js"); +loadScript("lexical-toplevel-redeclare-func-on-let.js"); +loadScript("lexical-toplevel-redeclare-let-on-var.js"); +loadScript("lexical-toplevel-redeclare-let-on-func.js"); +loadScript("lexical-toplevel-redeclare-let-on-builtin.js"); +loadScript("lexical-toplevel-redeclare-let-on-global.js"); diff --git a/test/script/basic/es6/lexical-toplevel-redeclare.js.EXPECTED b/test/script/basic/es6/lexical-toplevel-redeclare.js.EXPECTED new file mode 100644 index 00000000..d1471c80 --- /dev/null +++ b/test/script/basic/es6/lexical-toplevel-redeclare.js.EXPECTED @@ -0,0 +1,100 @@ +lexical-toplevel-redeclare-var-on-let.js +SyntaxError: Variable "LET" has already been declared +VAR +LET +CONST +function FUNC() {} +GLOBAL +VAR +undefined +undefined +function FUNC() {} +GLOBAL +ReferenceError: "SHOULD_NOT_EXIST" is not defined +undefined +function Object() { [native code] } +function Object() { [native code] } + +lexical-toplevel-redeclare-func-on-let.js +SyntaxError: Variable "LET" has already been declared +VAR +LET +CONST +function FUNC() {} +GLOBAL +VAR +undefined +undefined +function FUNC() {} +GLOBAL +ReferenceError: "SHOULD_NOT_EXIST" is not defined +undefined +function Object() { [native code] } +function Object() { [native code] } + +lexical-toplevel-redeclare-let-on-var.js +SyntaxError: Variable "VAR" has already been declared +VAR +LET +CONST +function FUNC() {} +GLOBAL +VAR +undefined +undefined +function FUNC() {} +GLOBAL +ReferenceError: "SHOULD_NOT_EXIST" is not defined +undefined +function Object() { [native code] } +function Object() { [native code] } + +lexical-toplevel-redeclare-let-on-func.js +SyntaxError: Variable "FUNC" has already been declared +VAR +LET +CONST +function FUNC() {} +GLOBAL +VAR +undefined +undefined +function FUNC() {} +GLOBAL +ReferenceError: "SHOULD_NOT_EXIST" is not defined +undefined +function Object() { [native code] } +function Object() { [native code] } + +lexical-toplevel-redeclare-let-on-builtin.js +VAR +LET +CONST +function FUNC() {} +GLOBAL +VAR +undefined +undefined +function FUNC() {} +GLOBAL +ReferenceError: "SHOULD_NOT_EXIST" is not defined +undefined +LEXICAL BUILTIN +function Object() { [native code] } + +lexical-toplevel-redeclare-let-on-global.js +VAR +LET +CONST +function FUNC() {} +LEXICAL GLOBAL +VAR +undefined +undefined +function FUNC() {} +GLOBAL +ReferenceError: "SHOULD_NOT_EXIST" is not defined +undefined +LEXICAL BUILTIN +function Object() { [native code] } + diff --git a/test/script/basic/es6/lexical-toplevel.js b/test/script/basic/es6/lexical-toplevel.js new file mode 100644 index 00000000..fc272a8a --- /dev/null +++ b/test/script/basic/es6/lexical-toplevel.js @@ -0,0 +1,35 @@ +/* + * 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-8057691: Nashorn: let & const declarations are not shared between scripts + * + * @test + * @run + * @option --language=es6 + */ + +load(__DIR__ + "lexical-toplevel-def.js"); + +load(__DIR__ + "lexical-toplevel-print.js"); +load(__DIR__ + "lexical-toplevel-print.js"); diff --git a/test/script/basic/es6/lexical-toplevel.js.EXPECTED b/test/script/basic/es6/lexical-toplevel.js.EXPECTED new file mode 100644 index 00000000..804e7506 --- /dev/null +++ b/test/script/basic/es6/lexical-toplevel.js.EXPECTED @@ -0,0 +1,30 @@ +VAR +LET +CONST +function FUNC() {} +GLOBAL +VAR +undefined +undefined +function FUNC() {} +GLOBAL +true +false +false +true +true +VAR +LETLET +CONST +function FUNC() {} +GLOBAL +VAR +undefined +undefined +function FUNC() {} +GLOBAL +true +false +false +true +true diff --git a/test/src/jdk/nashorn/internal/runtime/LexicalBindingTest.java b/test/src/jdk/nashorn/internal/runtime/LexicalBindingTest.java new file mode 100644 index 00000000..2cd0bf01 --- /dev/null +++ b/test/src/jdk/nashorn/internal/runtime/LexicalBindingTest.java @@ -0,0 +1,212 @@ +/* + * 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. 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; + +import jdk.nashorn.api.scripting.NashornScriptEngineFactory; +import org.testng.annotations.Test; + +import javax.script.Bindings; +import javax.script.ScriptContext; +import javax.script.ScriptEngine; +import javax.script.ScriptException; +import javax.script.SimpleScriptContext; + +import static org.testng.Assert.assertEquals; + +/** + * Top-level lexical binding tests. + * + * @test + * @run testng jdk.nashorn.internal.runtime.LexicalBindingTest + */ +@SuppressWarnings("javadoc") +public class LexicalBindingTest { + + final static String LANGUAGE_ES6 = "--language=es6"; + final static int NUMBER_OF_CONTEXTS = 20; + final static int MEGAMORPHIC_LOOP_COUNT = 20; + + /** + * Test access to global var-declared variables for shared script classes with multiple globals. + */ + @Test + public static void megamorphicVarTest() throws ScriptException, InterruptedException { + final NashornScriptEngineFactory factory = new NashornScriptEngineFactory(); + final ScriptEngine e = factory.getScriptEngine(); + final ScriptContext[] contexts = new ScriptContext[NUMBER_OF_CONTEXTS]; + final String sharedScript = "foo"; + + + for (int i = 0; i < NUMBER_OF_CONTEXTS; i++) { + final ScriptContext context = contexts[i] = new SimpleScriptContext(); + final Bindings b = e.createBindings(); + context.setBindings(b, ScriptContext.ENGINE_SCOPE); + assertEquals(e.eval("var foo = '" + i + "';", context), null); + } + + for (int i = 0; i < NUMBER_OF_CONTEXTS; i++) { + final ScriptContext context = contexts[i]; + assertEquals(e.eval(sharedScript, context), String.valueOf(i)); + } + } + + /** + * Test access to global lexically declared variables for shared script classes with multiple globals. + */ + @Test + public static void megamorphicMultiGlobalLetTest() throws ScriptException, InterruptedException { + final NashornScriptEngineFactory factory = new NashornScriptEngineFactory(); + final ScriptEngine e = factory.getScriptEngine(LANGUAGE_ES6); + final ScriptContext[] contexts = new ScriptContext[NUMBER_OF_CONTEXTS]; + final String sharedScript = "foo"; + + + for (int i = 0; i < NUMBER_OF_CONTEXTS; i++) { + final ScriptContext context = contexts[i] = new SimpleScriptContext(); + final Bindings b = e.createBindings(); + context.setBindings(b, ScriptContext.ENGINE_SCOPE); + assertEquals(e.eval("let foo = '" + i + "';", context), null); + } + + for (int i = 0; i < NUMBER_OF_CONTEXTS; i++) { + final ScriptContext context = contexts[i]; + assertEquals(e.eval(sharedScript, context), String.valueOf(i)); + } + } + + + /** + * Test access to global lexically declared variables for shared script classes with single global. + */ + @Test + public static void megamorphicSingleGlobalLetTest() throws ScriptException, InterruptedException { + final NashornScriptEngineFactory factory = new NashornScriptEngineFactory(); + final ScriptEngine e = factory.getScriptEngine(LANGUAGE_ES6); + final String sharedGetterScript = "foo"; + final String sharedSetterScript = "foo = 1"; + + for (int i = 0; i < MEGAMORPHIC_LOOP_COUNT; i++) { + assertEquals(e.eval(sharedSetterScript), 1); + assertEquals(e.eval(sharedGetterScript), 1); + assertEquals(e.eval("delete foo; a" + i + " = 1; foo = " + i + ";"), i); + assertEquals(e.eval(sharedGetterScript), i); + } + + assertEquals(e.eval("let foo = 'foo';"), null); + assertEquals(e.eval(sharedGetterScript), "foo"); + assertEquals(e.eval(sharedSetterScript), 1); + assertEquals(e.eval(sharedGetterScript), 1); + assertEquals(e.eval("this.foo"), MEGAMORPHIC_LOOP_COUNT - 1); + } + + /** + * Test access to global lexically declared variables for shared script classes with single global. + */ + @Test + public static void megamorphicInheritedGlobalLetTest() throws ScriptException, InterruptedException { + final NashornScriptEngineFactory factory = new NashornScriptEngineFactory(); + final ScriptEngine e = factory.getScriptEngine(LANGUAGE_ES6); + final String sharedGetterScript = "foo"; + final String sharedSetterScript = "foo = 1"; + + for (int i = 0; i < MEGAMORPHIC_LOOP_COUNT; i++) { + assertEquals(e.eval(sharedSetterScript), 1); + assertEquals(e.eval(sharedGetterScript), 1); + assertEquals(e.eval("delete foo; a" + i + " = 1; Object.prototype.foo = " + i + ";"), i); + assertEquals(e.eval(sharedGetterScript), i); + } + + assertEquals(e.eval("let foo = 'foo';"), null); + assertEquals(e.eval(sharedGetterScript), "foo"); + assertEquals(e.eval(sharedSetterScript), 1); + assertEquals(e.eval(sharedGetterScript), 1); + assertEquals(e.eval("this.foo"), MEGAMORPHIC_LOOP_COUNT - 1); + } + + /** + * Test multi-threaded access to global lexically declared variables for shared script classes with multiple globals. + */ + @Test + public static void multiThreadedLetTest() throws ScriptException, InterruptedException { + final NashornScriptEngineFactory factory = new NashornScriptEngineFactory(); + final ScriptEngine e = factory.getScriptEngine(LANGUAGE_ES6); + final Bindings b = e.createBindings(); + final ScriptContext origContext = e.getContext(); + final ScriptContext newCtxt = new SimpleScriptContext(); + newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE); + final String sharedScript = "foo"; + + assertEquals(e.eval("let foo = 'original context';", origContext), null); + assertEquals(e.eval("let foo = 'new context';", newCtxt), null); + + final Thread t1 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000)); + final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "new context", 1000)); + t1.start(); + t2.start(); + t1.join(); + t2.join(); + + assertEquals(e.eval("foo = 'newer context';", newCtxt), "newer context"); + final Thread t3 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000)); + final Thread t4 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "newer context", 1000)); + + t3.start(); + t4.start(); + t3.join(); + t4.join(); + + assertEquals(e.eval(sharedScript), "original context"); + assertEquals(e.eval(sharedScript, newCtxt), "newer context"); + } + + private static class ScriptRunner implements Runnable { + + final ScriptEngine engine; + final ScriptContext context; + final String source; + final Object expected; + final int iterations; + + ScriptRunner(final ScriptEngine engine, final ScriptContext context, final String source, final Object expected, final int iterations) { + this.engine = engine; + this.context = context; + this.source = source; + this.expected = expected; + this.iterations = iterations; + } + + @Override + public void run() { + try { + for (int i = 0; i < iterations; i++) { + assertEquals(engine.eval(source, context), expected); + } + } catch (final ScriptException se) { + throw new RuntimeException(se); + } + } + } +} -- cgit v1.2.1 From d5c6520928cb0bd5b37556f9c2999ee7760aa900 Mon Sep 17 00:00:00 2001 From: asaha Date: Mon, 24 Nov 2014 13:36:38 -0800 Subject: Added tag jdk8u31-b10 for changeset c68ba913a0ee --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 90b524f6..8a271cfe 100644 --- a/.hgtags +++ b/.hgtags @@ -332,3 +332,4 @@ cdbf34dbef404b47805c8c85b11c65c2afaa6674 jdk8u25-b18 5ed4fa732b26b6d8e37dfc5bbd00047c5352719b jdk8u31-b07 b17ecf341ee544cc5507b9b586c14a13c3adc058 jdk8u31-b08 762eaacc45cec3f7d593bedd08fb8de478d4415b jdk8u31-b09 +c68ba913a0eeea6eb94d9568e9985505ec3408a3 jdk8u31-b10 -- cgit v1.2.1 From 32204ed3e66f63ae6b696b5dea90d1db780abbc5 Mon Sep 17 00:00:00 2001 From: slugovoy Date: Tue, 25 Nov 2014 14:57:01 +0300 Subject: 8062638: RuntimeException when run command from js with -scripting on Cygwin 8054343: Nashorn: Some tests fails on windows with AccessControlException Reviewed-by: coffeys --- test/script/basic/compile-octane-normal.js | 4 ++-- test/script/basic/compile-octane-splitter.js | 4 ++-- test/script/basic/compile-octane.js | 2 +- test/script/nosecurity/JDK-8050964.js | 1 + test/script/nosecurity/JDK-8055034.js | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/test/script/basic/compile-octane-normal.js b/test/script/basic/compile-octane-normal.js index 769f00b5..c671d572 100644 --- a/test/script/basic/compile-octane-normal.js +++ b/test/script/basic/compile-octane-normal.js @@ -38,5 +38,5 @@ */ var fn = __DIR__ + 'compile-octane.js'; -var url = "file://" + fn; -loadWithNewGlobal(new java.net.URL(url)); +var url = new java.io.File(fn).toURL(); +loadWithNewGlobal(url); diff --git a/test/script/basic/compile-octane-splitter.js b/test/script/basic/compile-octane-splitter.js index 5b4f0e15..58c5966a 100644 --- a/test/script/basic/compile-octane-splitter.js +++ b/test/script/basic/compile-octane-splitter.js @@ -40,5 +40,5 @@ */ var fn = __DIR__ + 'compile-octane.js'; -var url = "file://" + fn; -loadWithNewGlobal(new java.net.URL(url)); +var url = new java.io.File(fn).toURL(); +loadWithNewGlobal(url); diff --git a/test/script/basic/compile-octane.js b/test/script/basic/compile-octane.js index aee105a0..b37038f9 100644 --- a/test/script/basic/compile-octane.js +++ b/test/script/basic/compile-octane.js @@ -132,7 +132,7 @@ for (var j in tests) { str2 += " processing file: " + file + "..."; print_if_verbose(str2); } - newGlobal.load("file://" + path + file); + newGlobal.load(new java.io.File(path + file).toURL()); } } print("Done."); diff --git a/test/script/nosecurity/JDK-8050964.js b/test/script/nosecurity/JDK-8050964.js index 486948aa..eda3d1b6 100644 --- a/test/script/nosecurity/JDK-8050964.js +++ b/test/script/nosecurity/JDK-8050964.js @@ -50,6 +50,7 @@ var javahome = System.getProperty("java.home"); var jdepsPath = javahome + "/../bin/jdeps".replaceAll(/\//g, File.separater); // run jdep on nashorn.jar - only summary but print profile info +$ENV.PWD=System.getProperty("user.dir") // to avoid RE on Cygwin `${jdepsPath} -s -P ${nashornJar.absolutePath}` // check for "(compact1)" in output from jdep tool diff --git a/test/script/nosecurity/JDK-8055034.js b/test/script/nosecurity/JDK-8055034.js index 76f24be7..a0e5057e 100644 --- a/test/script/nosecurity/JDK-8055034.js +++ b/test/script/nosecurity/JDK-8055034.js @@ -49,7 +49,7 @@ var nashornJarDir = nashornJar.parentFile.absolutePath; var jjsCmd = javahome + "/../bin/jjs"; jjsCmd += " -J-Djava.ext.dirs=" + nashornJarDir; jjsCmd = jjsCmd.toString().replaceAll(/\//g, File.separater); - +$ENV.PWD=System.getProperty("user.dir") // to avoid RE on Cygwin $EXEC(jjsCmd, "var x = Object.create(null);\nx;\nprint('PASSED');\nexit(0)"); // $ERR has all interactions including prompts! Just check for error substring. -- cgit v1.2.1 From 54712185f895296b14b6a63f61374a2b883a63f6 Mon Sep 17 00:00:00 2001 From: asaha Date: Wed, 26 Nov 2014 08:00:20 -0800 Subject: Added tag jdk8u40-b16 for changeset e079f3f6d536 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index d31293a6..2941d00d 100644 --- a/.hgtags +++ b/.hgtags @@ -335,3 +335,4 @@ a2e0a985764b5afd5f316429bfab4f44bf150f7f jdk8u40-b03 d60fbb5343c186abbf92b0259e67efb3b71377b4 jdk8u40-b13 7e34104c55cafa0b579be3a480dda383c616a378 jdk8u40-b14 fc37699ddc0ed41d4ab5da821211a6d2648c8883 jdk8u40-b15 +e079f3f6d536510b1ab3589b1038d893d78302ac jdk8u40-b16 -- cgit v1.2.1 From f3e4fff787c43bba0e454663a770e028df9e3fae Mon Sep 17 00:00:00 2001 From: vlivanov Date: Thu, 27 Nov 2014 17:14:01 +0400 Subject: 8065985: Inlining failure of Number.doubleValue() in JSType.toNumeric() causes 15% peak perf regresion on Box2D Reviewed-by: lagergren, hannesw --- src/jdk/nashorn/internal/runtime/JSType.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/jdk/nashorn/internal/runtime/JSType.java b/src/jdk/nashorn/internal/runtime/JSType.java index 75395ea4..7e54b1e2 100644 --- a/src/jdk/nashorn/internal/runtime/JSType.java +++ b/src/jdk/nashorn/internal/runtime/JSType.java @@ -714,6 +714,9 @@ public enum JSType { * @return a number */ public static double toNumber(final Object obj) { + if (obj instanceof Double) { + return (Double)obj; + } if (obj instanceof Number) { return ((Number)obj).doubleValue(); } -- cgit v1.2.1 From df1ab7ee4dd024358de71e9877155c7d8f542c32 Mon Sep 17 00:00:00 2001 From: hannesw Date: Thu, 27 Nov 2014 18:02:28 +0100 Subject: 8057980: let & const: remaining issues with lexical scoping Reviewed-by: lagergren, attila --- .../nashorn/internal/codegen/AssignSymbols.java | 30 +++++--- .../nashorn/internal/codegen/CodeGenerator.java | 7 ++ src/jdk/nashorn/internal/codegen/Lower.java | 2 +- src/jdk/nashorn/internal/ir/ForNode.java | 24 +++++-- src/jdk/nashorn/internal/ir/LexicalContext.java | 14 ++++ src/jdk/nashorn/internal/ir/LoopNode.java | 6 ++ src/jdk/nashorn/internal/ir/VarNode.java | 19 ++--- src/jdk/nashorn/internal/ir/WhileNode.java | 5 ++ src/jdk/nashorn/internal/parser/Parser.java | 43 ++++++----- src/jdk/nashorn/internal/runtime/ScriptObject.java | 83 +++++++++++++++------- .../nashorn/internal/runtime/arrays/ArrayData.java | 15 ++-- .../internal/runtime/resources/Messages.properties | 2 + test/script/basic/es6/for-let.js | 37 ++++++++++ test/script/basic/es6/for-let.js.EXPECTED | 22 ++++++ .../basic/es6/let-const-statement-context.js | 49 +++++++++++++ .../es6/let-const-statement-context.js.EXPECTED | 30 ++++++++ test/script/basic/es6/let-const-switch.js | 45 ++++++++++++ test/script/basic/es6/let-const-switch.js.EXPECTED | 12 ++++ test/script/basic/es6/let-load.js | 15 ++-- test/script/basic/es6/let-load.js.EXPECTED | 1 + .../script/basic/es6/let_const_closure.js.EXPECTED | 6 +- test/script/basic/es6/lexical-toplevel.js.EXPECTED | 2 + 22 files changed, 372 insertions(+), 97 deletions(-) create mode 100644 test/script/basic/es6/let-const-statement-context.js create mode 100644 test/script/basic/es6/let-const-statement-context.js.EXPECTED create mode 100644 test/script/basic/es6/let-const-switch.js create mode 100644 test/script/basic/es6/let-const-switch.js.EXPECTED diff --git a/src/jdk/nashorn/internal/codegen/AssignSymbols.java b/src/jdk/nashorn/internal/codegen/AssignSymbols.java index ad0f13c7..6eb89a16 100644 --- a/src/jdk/nashorn/internal/codegen/AssignSymbols.java +++ b/src/jdk/nashorn/internal/codegen/AssignSymbols.java @@ -189,7 +189,7 @@ final class AssignSymbols extends NodeVisitor implements Loggabl * @param body the body of the FunctionNode we are entering */ private void acceptDeclarations(final FunctionNode functionNode, final Block body) { - // This visitor will assign symbol to all declared variables, except "var" declarations in for loop initializers. + // This visitor will assign symbol to all declared variables. body.accept(new NodeVisitor(new LexicalContext()) { @Override protected boolean enterDefault(final Node node) { @@ -200,16 +200,17 @@ final class AssignSymbols extends NodeVisitor implements Loggabl @Override public Node leaveVarNode(final VarNode varNode) { - if (varNode.isStatement()) { - final IdentNode ident = varNode.getName(); - final Block block = varNode.isBlockScoped() ? getLexicalContext().getCurrentBlock() : body; - final Symbol symbol = defineSymbol(block, ident.getName(), ident, varNode.getSymbolFlags()); - if (varNode.isFunctionDeclaration()) { - symbol.setIsFunctionDeclaration(); - } - return varNode.setName(ident.setSymbol(symbol)); + final IdentNode ident = varNode.getName(); + final boolean blockScoped = varNode.isBlockScoped(); + if (blockScoped && lc.inUnprotectedSwitchContext()) { + throwUnprotectedSwitchError(varNode); + } + final Block block = blockScoped ? lc.getCurrentBlock() : body; + final Symbol symbol = defineSymbol(block, ident.getName(), ident, varNode.getSymbolFlags()); + if (varNode.isFunctionDeclaration()) { + symbol.setIsFunctionDeclaration(); } - return varNode; + return varNode.setName(ident.setSymbol(symbol)); } }); } @@ -1048,6 +1049,15 @@ final class AssignSymbols extends NodeVisitor implements Loggabl return !(units == null || units.isEmpty()); } + private void throwUnprotectedSwitchError(final VarNode varNode) { + // Block scoped declarations in switch statements without explicit blocks should be declared + // in a common block that contains all the case clauses. We cannot support this without a + // fundamental rewrite of how switch statements are handled (case nodes contain blocks and are + // directly contained by switch node). As a temporary solution we throw a reference error here. + final String msg = ECMAErrors.getMessage("syntax.error.unprotected.switch.declaration", varNode.isLet() ? "let" : "const"); + throwParserException(msg, varNode); + } + private void throwParserException(final String message, final Node origin) { if (origin == null) { throw new ParserException(message); diff --git a/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/src/jdk/nashorn/internal/codegen/CodeGenerator.java index 6e84dd89..1bf3b382 100644 --- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java @@ -3264,6 +3264,13 @@ final class CodeGenerator extends NodeOperatorVisitor implements Lo if (isAlwaysTrue(test)) { //turn it into a for node without a test. - final ForNode forNode = (ForNode)new ForNode(whileNode.getLineNumber(), whileNode.getToken(), whileNode.getFinish(), body, ForNode.IS_FOR).accept(this); + final ForNode forNode = (ForNode)new ForNode(whileNode.getLineNumber(), whileNode.getToken(), whileNode.getFinish(), body, 0).accept(this); lc.replace(whileNode, forNode); return forNode; } diff --git a/src/jdk/nashorn/internal/ir/ForNode.java b/src/jdk/nashorn/internal/ir/ForNode.java index 2847947c..ef6f11db 100644 --- a/src/jdk/nashorn/internal/ir/ForNode.java +++ b/src/jdk/nashorn/internal/ir/ForNode.java @@ -45,14 +45,14 @@ public final class ForNode extends LoopNode { /** Iterator symbol. */ private Symbol iterator; - /** Is this a normal for loop? */ - public static final int IS_FOR = 1 << 0; - /** Is this a normal for in loop? */ - public static final int IS_FOR_IN = 1 << 1; + public static final int IS_FOR_IN = 1 << 0; /** Is this a normal for each in loop? */ - public static final int IS_FOR_EACH = 1 << 2; + public static final int IS_FOR_EACH = 1 << 1; + + /** Does this loop need a per-iteration scope because its init contain a LET declaration? */ + public static final int PER_ITERATION_SCOPE = 1 << 2; private final int flags; @@ -273,4 +273,18 @@ public final class ForNode extends LoopNode { JoinPredecessor setLocalVariableConversionChanged(final LexicalContext lc, final LocalVariableConversion conversion) { return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion)); } + + @Override + public boolean hasPerIterationScope() { + return (flags & PER_ITERATION_SCOPE) != 0; + } + + /** + * Set the per-iteration-scope flag on this node. + * @param lc lexical context + * @return the node with flag set + */ + public ForNode setPerIterationScope(final LexicalContext lc) { + return setFlags(lc, flags | PER_ITERATION_SCOPE); + } } diff --git a/src/jdk/nashorn/internal/ir/LexicalContext.java b/src/jdk/nashorn/internal/ir/LexicalContext.java index 2b59a07c..487d6aeb 100644 --- a/src/jdk/nashorn/internal/ir/LexicalContext.java +++ b/src/jdk/nashorn/internal/ir/LexicalContext.java @@ -597,6 +597,20 @@ public class LexicalContext { throw new AssertionError(target + " was expected in lexical context " + LexicalContext.this + " but wasn't"); } + /** + * Checks whether the current context is inside a switch statement without explicit blocks (curly braces). + * @return true if in unprotected switch statement + */ + public boolean inUnprotectedSwitchContext() { + for (int i = sp; i > 0; i--) { + final LexicalContextNode next = stack[i]; + if (next instanceof Block) { + return stack[i - 1] instanceof SwitchNode; + } + } + return false; + } + @Override public String toString() { final StringBuffer sb = new StringBuffer(); diff --git a/src/jdk/nashorn/internal/ir/LoopNode.java b/src/jdk/nashorn/internal/ir/LoopNode.java index e6436ad9..5991a32a 100644 --- a/src/jdk/nashorn/internal/ir/LoopNode.java +++ b/src/jdk/nashorn/internal/ir/LoopNode.java @@ -176,4 +176,10 @@ public abstract class LoopNode extends BreakableStatement { * @return new loop node if changed otherwise the same */ public abstract LoopNode setControlFlowEscapes(final LexicalContext lc, final boolean controlFlowEscapes); + + /** + * Does this loop have a LET declaration and hence require a per-iteration scope? + * @return true if a per-iteration scope is required. + */ + public abstract boolean hasPerIterationScope(); } diff --git a/src/jdk/nashorn/internal/ir/VarNode.java b/src/jdk/nashorn/internal/ir/VarNode.java index 44d7d4c7..1cee8cb5 100644 --- a/src/jdk/nashorn/internal/ir/VarNode.java +++ b/src/jdk/nashorn/internal/ir/VarNode.java @@ -45,19 +45,16 @@ public final class VarNode extends Statement implements Assignment { /** Is this a var statement (as opposed to a "var" in a for loop statement) */ private final int flags; - /** Flag that determines if this function node is a statement */ - public static final int IS_STATEMENT = 1 << 0; - /** Flag for ES6 LET declaration */ - public static final int IS_LET = 1 << 1; + public static final int IS_LET = 1 << 0; /** Flag for ES6 CONST declaration */ - public static final int IS_CONST = 1 << 2; + public static final int IS_CONST = 1 << 1; /** Flag that determines if this is the last function declaration in a function * This is used to micro optimize the placement of return value assignments for * a program node */ - public static final int IS_LAST_FUNCTION_DECLARATION = 1 << 3; + public static final int IS_LAST_FUNCTION_DECLARATION = 1 << 2; /** * Constructor @@ -69,7 +66,7 @@ public final class VarNode extends Statement implements Assignment { * @param init init node or null if just a declaration */ public VarNode(final int lineNumber, final long token, final int finish, final IdentNode name, final Expression init) { - this(lineNumber, token, finish, name, init, IS_STATEMENT); + this(lineNumber, token, finish, name, init, 0); } private VarNode(final VarNode varNode, final IdentNode name, final Expression init, final int flags) { @@ -259,14 +256,6 @@ public final class VarNode extends Statement implements Assignment { return setFlags(flags | flag); } - /** - * Returns true if this is a var statement (as opposed to a var initializer in a for loop). - * @return true if this is a var statement (as opposed to a var initializer in a for loop). - */ - public boolean isStatement() { - return (flags & IS_STATEMENT) != 0; - } - /** * Returns true if this is a function declaration. * @return true if this is a function declaration. diff --git a/src/jdk/nashorn/internal/ir/WhileNode.java b/src/jdk/nashorn/internal/ir/WhileNode.java index 9a0981fb..7e60fee0 100644 --- a/src/jdk/nashorn/internal/ir/WhileNode.java +++ b/src/jdk/nashorn/internal/ir/WhileNode.java @@ -148,4 +148,9 @@ public final class WhileNode extends LoopNode { } return test == null; } + + @Override + public boolean hasPerIterationScope() { + return false; + } } diff --git a/src/jdk/nashorn/internal/parser/Parser.java b/src/jdk/nashorn/internal/parser/Parser.java index ed11a18b..9c6f974d 100644 --- a/src/jdk/nashorn/internal/parser/Parser.java +++ b/src/jdk/nashorn/internal/parser/Parser.java @@ -559,7 +559,7 @@ loop: // Set up new block. Captures first token. Block newBlock = newBlock(); try { - statement(); + statement(false, false, true); } finally { newBlock = restoreBlock(newBlock); } @@ -772,7 +772,7 @@ loop: try { // Get the next element. - statement(true, allowPropertyFunction); + statement(true, allowPropertyFunction, false); allowPropertyFunction = false; // check for directive prologues @@ -862,13 +862,15 @@ loop: * Parse any of the basic statement types. */ private void statement() { - statement(false, false); + statement(false, false, false); } /** * @param topLevel does this statement occur at the "top level" of a script or a function? + * @param allowPropertyFunction allow property "get" and "set" functions? + * @param singleStatement are we in a single statement context? */ - private void statement(final boolean topLevel, final boolean allowPropertyFunction) { + private void statement(final boolean topLevel, final boolean allowPropertyFunction, final boolean singleStatement) { if (type == FUNCTION) { // As per spec (ECMA section 12), function declarations as arbitrary statement // is not "portable". Implementation can issue a warning or disallow the same. @@ -932,6 +934,9 @@ loop: break; default: if (useBlockScope() && (type == LET || type == CONST)) { + if (singleStatement) { + throw error(AbstractParser.message("expected.stmt", type.getName() + " declaration"), token); + } variableStatement(type, true); break; } @@ -1057,7 +1062,7 @@ loop: next(); final List vars = new ArrayList<>(); - int varFlags = VarNode.IS_STATEMENT; + int varFlags = 0; if (varType == LET) { varFlags |= VarNode.IS_LET; } else if (varType == CONST) { @@ -1210,7 +1215,7 @@ loop: Block outer = useBlockScope() ? newBlock() : null; // Create FOR node, capturing FOR token. - ForNode forNode = new ForNode(line, token, Token.descPosition(token), null, ForNode.IS_FOR); + ForNode forNode = new ForNode(line, token, Token.descPosition(token), null, 0); lc.push(forNode); try { @@ -1230,19 +1235,22 @@ loop: switch (type) { case VAR: - // Var statements captured in for outer block. + // Var declaration captured in for outer block. vars = variableStatement(type, false); break; case SEMICOLON: break; default: if (useBlockScope() && (type == LET || type == CONST)) { - // LET/CONST captured in container block created above. + if (type == LET) { + forNode = forNode.setPerIterationScope(lc); + } + // LET/CONST declaration captured in container block created above. vars = variableStatement(type, false); break; } if (env._const_as_var && type == CONST) { - // Var statements captured in for outer block. + // Var declaration captured in for outer block. vars = variableStatement(TokenType.VAR, false); break; } @@ -1323,11 +1331,12 @@ loop: appendStatement(forNode); } finally { lc.pop(forNode); - if (outer != null) { - outer.setFinish(forNode.getFinish()); - outer = restoreBlock(outer); - appendStatement(new BlockStatement(startLine, outer)); - } + } + + if (outer != null) { + outer.setFinish(forNode.getFinish()); + outer = restoreBlock(outer); + appendStatement(new BlockStatement(startLine, outer)); } } @@ -2699,11 +2708,7 @@ loop: } if (isStatement) { - int varFlags = VarNode.IS_STATEMENT; - if (!topLevel && useBlockScope()) { - // mark ES6 block functions as lexically scoped - varFlags |= VarNode.IS_LET; - } + final int varFlags = (topLevel || !useBlockScope()) ? 0 : VarNode.IS_LET; final VarNode varNode = new VarNode(functionLine, functionToken, finish, name, functionNode, varFlags); if (topLevel) { functionDeclarations.add(varNode); diff --git a/src/jdk/nashorn/internal/runtime/ScriptObject.java b/src/jdk/nashorn/internal/runtime/ScriptObject.java index f87af8ee..3f605910 100644 --- a/src/jdk/nashorn/internal/runtime/ScriptObject.java +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java @@ -46,6 +46,8 @@ import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_ import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid; import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndex; import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex; +import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.isScopeFlag; +import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.isStrictFlag; import static jdk.nashorn.internal.runtime.linker.NashornGuards.explicitInstanceOfCheck; import java.lang.invoke.MethodHandle; @@ -98,7 +100,7 @@ import jdk.nashorn.internal.runtime.linker.NashornGuards; * */ -public abstract class ScriptObject implements PropertyAccess { +public abstract class ScriptObject implements PropertyAccess, Cloneable { /** __proto__ special property name inside object literals. ES6 draft. */ public static final String PROTO_PROPERTY_NAME = "__proto__"; @@ -2202,6 +2204,9 @@ public abstract class ScriptObject implements PropertyAccess { if (find != null) { if (!find.getProperty().isWritable() && !NashornCallSiteDescriptor.isDeclaration(desc)) { + if (NashornCallSiteDescriptor.isScope(desc) && find.getProperty().isLexicalBinding()) { + throw typeError("assign.constant", name); // Overwriting ES6 const should throw also in non-strict mode. + } // Existing, non-writable property return createEmptySetMethod(desc, explicitInstanceOfCheck, "property.not.writable", true); } @@ -3103,7 +3108,7 @@ public abstract class ScriptObject implements PropertyAccess { private boolean doesNotHaveEnsureLength(final long longIndex, final long oldLength, final int callSiteFlags) { if (longIndex >= oldLength) { if (!isExtensible()) { - if (NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)) { + if (isStrictFlag(callSiteFlags)) { throw typeError("object.non.extensible", JSType.toString(longIndex), ScriptRuntime.safeToString(this)); } return true; @@ -3127,7 +3132,7 @@ public abstract class ScriptObject implements PropertyAccess { final long oldLength = getArray().length(); final long longIndex = ArrayIndex.toLongIndex(index); if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) { - final boolean strict = NashornCallSiteDescriptor.isStrictFlag(callSiteFlags); + final boolean strict = isStrictFlag(callSiteFlags); setArray(getArray().set(index, value, strict)); doesNotHaveEnsureDelete(longIndex, oldLength, strict); } @@ -3137,7 +3142,7 @@ public abstract class ScriptObject implements PropertyAccess { final long oldLength = getArray().length(); final long longIndex = ArrayIndex.toLongIndex(index); if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) { - final boolean strict = NashornCallSiteDescriptor.isStrictFlag(callSiteFlags); + final boolean strict = isStrictFlag(callSiteFlags); setArray(getArray().set(index, value, strict)); doesNotHaveEnsureDelete(longIndex, oldLength, strict); } @@ -3147,7 +3152,7 @@ public abstract class ScriptObject implements PropertyAccess { final long oldLength = getArray().length(); final long longIndex = ArrayIndex.toLongIndex(index); if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) { - final boolean strict = NashornCallSiteDescriptor.isStrictFlag(callSiteFlags); + final boolean strict = isStrictFlag(callSiteFlags); setArray(getArray().set(index, value, strict)); doesNotHaveEnsureDelete(longIndex, oldLength, strict); } @@ -3157,7 +3162,7 @@ public abstract class ScriptObject implements PropertyAccess { final long oldLength = getArray().length(); final long longIndex = ArrayIndex.toLongIndex(index); if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) { - final boolean strict = NashornCallSiteDescriptor.isStrictFlag(callSiteFlags); + final boolean strict = isStrictFlag(callSiteFlags); setArray(getArray().set(index, value, strict)); doesNotHaveEnsureDelete(longIndex, oldLength, strict); } @@ -3178,7 +3183,7 @@ public abstract class ScriptObject implements PropertyAccess { invalidateGlobalConstant(key); if (f != null && f.isInherited() && !(f.getProperty() instanceof UserAccessorProperty)) { - final boolean isScope = NashornCallSiteDescriptor.isScopeFlag(callSiteFlags); + final boolean isScope = isScopeFlag(callSiteFlags); // If the start object of the find is not this object it means the property was found inside a // 'with' statement expression (see WithObject.findProperty()). In this case we forward the 'set' // to the 'with' object. @@ -3199,16 +3204,19 @@ public abstract class ScriptObject implements PropertyAccess { if (f != null) { if (!f.getProperty().isWritable()) { - if (NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)) { + if (isScopeFlag(callSiteFlags) && f.getProperty().isLexicalBinding()) { + throw typeError("assign.constant", key); // Overwriting ES6 const should throw also in non-strict mode. + } + if (isStrictFlag(callSiteFlags)) { throw typeError("property.not.writable", key, ScriptRuntime.safeToString(this)); } return; } - f.setValue(value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)); + f.setValue(value, isStrictFlag(callSiteFlags)); } else if (!isExtensible()) { - if (NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)) { + if (isStrictFlag(callSiteFlags)) { throw typeError("object.non.extensible", key, ScriptRuntime.safeToString(this)); } } else { @@ -3235,7 +3243,7 @@ public abstract class ScriptObject implements PropertyAccess { if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { - setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3255,7 +3263,7 @@ public abstract class ScriptObject implements PropertyAccess { if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { - setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3275,7 +3283,7 @@ public abstract class ScriptObject implements PropertyAccess { if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { - setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3295,7 +3303,7 @@ public abstract class ScriptObject implements PropertyAccess { if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { - setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3314,7 +3322,7 @@ public abstract class ScriptObject implements PropertyAccess { if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { - setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3333,7 +3341,7 @@ public abstract class ScriptObject implements PropertyAccess { if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { - setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3352,7 +3360,7 @@ public abstract class ScriptObject implements PropertyAccess { if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { - setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3371,7 +3379,7 @@ public abstract class ScriptObject implements PropertyAccess { if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { - setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3390,7 +3398,7 @@ public abstract class ScriptObject implements PropertyAccess { if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { - setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3409,7 +3417,7 @@ public abstract class ScriptObject implements PropertyAccess { if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { - setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3428,7 +3436,7 @@ public abstract class ScriptObject implements PropertyAccess { if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { - setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3447,7 +3455,7 @@ public abstract class ScriptObject implements PropertyAccess { if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { - setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3465,7 +3473,7 @@ public abstract class ScriptObject implements PropertyAccess { if (isValidArrayIndex(index)) { if (getArray().has(index)) { final ArrayData data = getArray(); - setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3483,7 +3491,7 @@ public abstract class ScriptObject implements PropertyAccess { if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { - setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3502,7 +3510,7 @@ public abstract class ScriptObject implements PropertyAccess { if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { - setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3521,7 +3529,7 @@ public abstract class ScriptObject implements PropertyAccess { if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { - setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3685,6 +3693,29 @@ public abstract class ScriptObject implements PropertyAccess { return true; } + /** + * Return a shallow copy of this ScriptObject. + * @return a shallow copy. + */ + public final ScriptObject copy() { + try { + return clone(); + } catch (final CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + @Override + protected ScriptObject clone() throws CloneNotSupportedException { + final ScriptObject clone = (ScriptObject) super.clone(); + if (objectSpill != null) { + clone.objectSpill = objectSpill.clone(); + clone.primitiveSpill = primitiveSpill.clone(); + } + clone.arrayData = arrayData.copy(); + return clone; + } + /** * Make a new UserAccessorProperty property. getter and setter functions are stored in * this ScriptObject and slot values are used in property object. diff --git a/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java index b018596f..f0a8c7a2 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java +++ b/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java @@ -61,9 +61,9 @@ public abstract class ArrayData { /** * Length of the array data. Not necessarily length of the wrapped array. * This is private to ensure that no one in a subclass is able to touch the length - * without going through {@link setLength}. This is used to implement + * without going through {@link #setLength}. This is used to implement * {@link LengthNotWritableFilter}s, ensuring that there are no ways past - * a {@link setLength} function replaced by a nop + * a {@link #setLength} function replaced by a nop */ private long length; @@ -79,11 +79,7 @@ public abstract class ArrayData { */ private static class UntouchedArrayData extends ContinuousArrayData { private UntouchedArrayData() { - this(0); - } - - private UntouchedArrayData(final int length) { - super(length); + super(0); } private ArrayData toRealArrayData() { @@ -100,7 +96,8 @@ public abstract class ArrayData { @Override public ContinuousArrayData copy() { - return new UntouchedArrayData((int)length()); + assert length() == 0; + return this; } @Override @@ -246,7 +243,7 @@ public abstract class ArrayData { public Class getBoxedElementType() { return Integer.class; } - }; + } /** * Constructor diff --git a/src/jdk/nashorn/internal/runtime/resources/Messages.properties b/src/jdk/nashorn/internal/runtime/resources/Messages.properties index 3a161c8d..71c11743 100644 --- a/src/jdk/nashorn/internal/runtime/resources/Messages.properties +++ b/src/jdk/nashorn/internal/runtime/resources/Messages.properties @@ -116,6 +116,7 @@ type.error.instanceof.on.non.object=instanceof must be called with a javascript type.error.cannot.convert.to.interface=object {0} cannot be converted to {1} due to "{2}" type.error.array.reduce.invalid.init=invalid initialValue for Array.prototype.reduce type.error.array.reduceright.invalid.init=invalid initialValue for Array.prototype.reduceRight +type.error.assign.constant=Assignment to constant "{0}" type.error.cannot.get.default.string=Cannot get default string value type.error.cannot.get.default.number=Cannot get default number value type.error.cant.apply.with.to.null=Cannot apply "with" to null @@ -166,6 +167,7 @@ syntax.error.invalid.json=Invalid JSON: {0} syntax.error.strict.cant.delete=cannot delete "{0}" in strict mode syntax.error.redeclare.variable=Variable "{0}" has already been declared syntax.error.assign.constant=Assignment to constant "{0}" +syntax.error.unprotected.switch.declaration=Unsupported {0} declaration in unprotected switch statement io.error.cant.write=cannot write "{0}" config.error.no.dest=no destination directory supplied diff --git a/test/script/basic/es6/for-let.js b/test/script/basic/es6/for-let.js index 949b348c..848dc3ce 100644 --- a/test/script/basic/es6/for-let.js +++ b/test/script/basic/es6/for-let.js @@ -39,3 +39,40 @@ try { } catch (e) { print(e); } + +let a = []; + +for (let i = 0; i < 10; i++) { + a.push(function() { print(i); }); +} + +a.forEach(function(f) { f(); }); + +a = []; + +for (let i = 0; i < 10; i++) { + if (i == 5) { + i = "foo"; + } + a.push(function() { print(i); }); +} + +a.forEach(function(f) { f(); }); + +try { + print(i); +} catch (e) { + print(e); +} + +a = []; + +for (let i = 0; i < 20; i++) { + if (i % 2 == 1) { + i += 2; + continue; + } + a.push(function() { print(i); }); +} + +a.forEach(function(f) { f(); }); diff --git a/test/script/basic/es6/for-let.js.EXPECTED b/test/script/basic/es6/for-let.js.EXPECTED index 4c1ebad8..21787adb 100644 --- a/test/script/basic/es6/for-let.js.EXPECTED +++ b/test/script/basic/es6/for-let.js.EXPECTED @@ -9,3 +9,25 @@ 8 9 ReferenceError: "i" is not defined +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +0 +1 +2 +3 +4 +foo +ReferenceError: "i" is not defined +0 +4 +8 +12 +16 diff --git a/test/script/basic/es6/let-const-statement-context.js b/test/script/basic/es6/let-const-statement-context.js new file mode 100644 index 00000000..3e662378 --- /dev/null +++ b/test/script/basic/es6/let-const-statement-context.js @@ -0,0 +1,49 @@ +/* + * 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-8057980: let & const: remaining issues with lexical scoping + * + * @test + * @run + * @option --language=es6 + */ + +function tryEval(s) { + try { + eval(s); + } catch (e) { + print(String(e).replace(/\\/g, "/")); + } +} + +tryEval('if (true) let x = 1;'); +tryEval('if (true) const x = 1;'); +tryEval('while (true) let x = 1;'); +tryEval('while (true) const x = 1;'); +tryEval('for (;;) let x = 1;'); +tryEval('for (;;) const x = 1;'); +tryEval('do let x = 1; while (true);'); +tryEval('do const x = 1; while (true);'); +tryEval('with (y) const x = 1;'); +tryEval('with (y) let x = 1;'); diff --git a/test/script/basic/es6/let-const-statement-context.js.EXPECTED b/test/script/basic/es6/let-const-statement-context.js.EXPECTED new file mode 100644 index 00000000..1b73e4c7 --- /dev/null +++ b/test/script/basic/es6/let-const-statement-context.js.EXPECTED @@ -0,0 +1,30 @@ +SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8:1:10 Expected statement but found let declaration +if (true) let x = 1; + ^ +SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8:1:10 Expected statement but found const declaration +if (true) const x = 1; + ^ +SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8:1:13 Expected statement but found let declaration +while (true) let x = 1; + ^ +SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8:1:13 Expected statement but found const declaration +while (true) const x = 1; + ^ +SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8:1:9 Expected statement but found let declaration +for (;;) let x = 1; + ^ +SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8:1:9 Expected statement but found const declaration +for (;;) const x = 1; + ^ +SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8:1:3 Expected statement but found let declaration +do let x = 1; while (true); + ^ +SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8:1:3 Expected statement but found const declaration +do const x = 1; while (true); + ^ +SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8:1:9 Expected statement but found const declaration +with (y) const x = 1; + ^ +SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8:1:9 Expected statement but found let declaration +with (y) let x = 1; + ^ diff --git a/test/script/basic/es6/let-const-switch.js b/test/script/basic/es6/let-const-switch.js new file mode 100644 index 00000000..8a538b80 --- /dev/null +++ b/test/script/basic/es6/let-const-switch.js @@ -0,0 +1,45 @@ +/* + * 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-8057980: let & const: remaining issues with lexical scoping + * + * @test + * @run + * @option --language=es6 + */ + +function tryEval(s) { + try { + eval(s); + } catch (e) { + print(String(e).replace(/\\/g, "/")); + } +} + +tryEval('var x = 0; switch (x) { case 0: { let x = 1; print(x); } case 1: { let x = 2; print(x); }} print(x);'); +tryEval('var x = 0; switch (x) { case 0: { const x = 1; print(x); } case 1: { const x = 2; print(x); }} print(x);'); + +// TODO: the following should not throw +tryEval('switch (x) { case 0: let x = 1; }'); +tryEval('switch (x) { case 0: const x = 1; }'); diff --git a/test/script/basic/es6/let-const-switch.js.EXPECTED b/test/script/basic/es6/let-const-switch.js.EXPECTED new file mode 100644 index 00000000..90309bfe --- /dev/null +++ b/test/script/basic/es6/let-const-switch.js.EXPECTED @@ -0,0 +1,12 @@ +1 +2 +0 +1 +2 +0 +SyntaxError: test/script/basic/es6/let-const-switch.js#34:8:1:25 Unsupported let declaration in unprotected switch statement +switch (x) { case 0: let x = 1; } + ^ +SyntaxError: test/script/basic/es6/let-const-switch.js#34:8:1:27 Unsupported const declaration in unprotected switch statement +switch (x) { case 0: const x = 1; } + ^ diff --git a/test/script/basic/es6/let-load.js b/test/script/basic/es6/let-load.js index 57667543..ff8f4e1c 100644 --- a/test/script/basic/es6/let-load.js +++ b/test/script/basic/es6/let-load.js @@ -40,22 +40,19 @@ load(__DIR__ + "let-load-lib.js"); } print("imported var: " + a); -try { - print("imported let: " + b); -} catch (e) { - print(e); -} +print("imported let: " + b); +print("imported const: " + c); + +top(); try { - print("imported const: " + c); + block(); } catch (e) { print(e); } -top(); - try { - block(); + c = "foo"; } catch (e) { print(e); } diff --git a/test/script/basic/es6/let-load.js.EXPECTED b/test/script/basic/es6/let-load.js.EXPECTED index f92f84c1..a0b2e094 100644 --- a/test/script/basic/es6/let-load.js.EXPECTED +++ b/test/script/basic/es6/let-load.js.EXPECTED @@ -6,3 +6,4 @@ imported let: 2 imported const: 3 top level function ReferenceError: "block" is not defined +TypeError: Assignment to constant "c" diff --git a/test/script/basic/es6/let_const_closure.js.EXPECTED b/test/script/basic/es6/let_const_closure.js.EXPECTED index 5a720d86..f49ca4b9 100644 --- a/test/script/basic/es6/let_const_closure.js.EXPECTED +++ b/test/script/basic/es6/let_const_closure.js.EXPECTED @@ -5,9 +5,9 @@ test test test -3 -3 -3 +0 +1 +2 0 1 2 diff --git a/test/script/basic/es6/lexical-toplevel.js.EXPECTED b/test/script/basic/es6/lexical-toplevel.js.EXPECTED index 804e7506..7580af4f 100644 --- a/test/script/basic/es6/lexical-toplevel.js.EXPECTED +++ b/test/script/basic/es6/lexical-toplevel.js.EXPECTED @@ -13,6 +13,7 @@ false false true true +TypeError: Assignment to constant "CONST" VAR LETLET CONST @@ -28,3 +29,4 @@ false false true true +TypeError: Assignment to constant "CONST" -- cgit v1.2.1 From 9f9274bab0cc84d81a06c4ff8926eafa45c302dd Mon Sep 17 00:00:00 2001 From: attila Date: Thu, 27 Nov 2014 13:04:46 +0100 Subject: 8051778: support bind on all Nashorn callables Reviewed-by: hannesw, lagergren --HG-- rename : src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethod.java => src/jdk/nashorn/internal/runtime/linker/BoundCallable.java rename : src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java => src/jdk/nashorn/internal/runtime/linker/BoundCallableLinker.java --- .../nashorn/internal/objects/NativeFunction.java | 9 +- src/jdk/nashorn/internal/objects/NativeObject.java | 3 +- .../internal/objects/ScriptFunctionImpl.java | 5 +- .../internal/runtime/arrays/IteratorAction.java | 16 +-- .../nashorn/internal/runtime/linker/Bootstrap.java | 59 +++++++-- .../internal/runtime/linker/BoundCallable.java | 96 +++++++++++++++ .../runtime/linker/BoundCallableLinker.java | 132 +++++++++++++++++++++ .../runtime/linker/BoundDynamicMethod.java | 57 --------- .../runtime/linker/BoundDynamicMethodLinker.java | 91 -------------- .../runtime/linker/JavaSuperAdapterLinker.java | 2 +- test/script/basic/JDK-8051778.js | 83 +++++++++++++ test/script/basic/JDK-8051778.js.EXPECTED | 10 ++ 12 files changed, 379 insertions(+), 184 deletions(-) create mode 100644 src/jdk/nashorn/internal/runtime/linker/BoundCallable.java create mode 100644 src/jdk/nashorn/internal/runtime/linker/BoundCallableLinker.java delete mode 100644 src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethod.java delete mode 100644 src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java create mode 100644 test/script/basic/JDK-8051778.js create mode 100644 test/script/basic/JDK-8051778.js.EXPECTED diff --git a/src/jdk/nashorn/internal/objects/NativeFunction.java b/src/jdk/nashorn/internal/objects/NativeFunction.java index c4a79a56..bd2f2dd9 100644 --- a/src/jdk/nashorn/internal/objects/NativeFunction.java +++ b/src/jdk/nashorn/internal/objects/NativeFunction.java @@ -48,6 +48,7 @@ import jdk.nashorn.internal.runtime.ScriptEnvironment; import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.ScriptRuntime; +import jdk.nashorn.internal.runtime.linker.Bootstrap; /** * ECMA 15.3 Function Objects @@ -204,11 +205,7 @@ public final class NativeFunction { * @return function with bound arguments */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) - public static ScriptFunction bind(final Object self, final Object... args) { - if (!(self instanceof ScriptFunction)) { - throw typeError("not.a.function", ScriptRuntime.safeToString(self)); - } - + public static Object bind(final Object self, final Object... args) { final Object thiz = (args.length == 0) ? UNDEFINED : args[0]; Object[] arguments; @@ -219,7 +216,7 @@ public final class NativeFunction { arguments = ScriptRuntime.EMPTY_ARRAY; } - return ((ScriptFunctionImpl)self).makeBoundFunction(thiz, arguments); + return Bootstrap.bindCallable(self, thiz, arguments); } /** diff --git a/src/jdk/nashorn/internal/objects/NativeObject.java b/src/jdk/nashorn/internal/objects/NativeObject.java index 7a1375d3..c086442d 100644 --- a/src/jdk/nashorn/internal/objects/NativeObject.java +++ b/src/jdk/nashorn/internal/objects/NativeObject.java @@ -28,6 +28,7 @@ package jdk.nashorn.internal.objects; 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; @@ -804,7 +805,7 @@ public final class NativeObject { // name and object linked with BeansLinker. (Actually, an even stronger assumption is true: return value is // constant for any given method name and object's class.) return MethodHandles.dropArguments(MethodHandles.constant(Object.class, - Bootstrap.bindDynamicMethod(methodGetter.invoke(source), source)), 0, Object.class); + Bootstrap.bindCallable(methodGetter.invoke(source), source, null)), 0, Object.class); } catch(RuntimeException|Error e) { throw e; } catch(final Throwable t) { diff --git a/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java b/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java index 36e7716b..f147234b 100644 --- a/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java +++ b/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java @@ -30,7 +30,6 @@ import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; import java.lang.invoke.MethodHandle; import java.util.ArrayList; - import jdk.nashorn.internal.runtime.AccessorProperty; import jdk.nashorn.internal.runtime.GlobalFunctions; import jdk.nashorn.internal.runtime.Property; @@ -237,13 +236,13 @@ public class ScriptFunctionImpl extends ScriptFunction { /** * Same as {@link ScriptFunction#makeBoundFunction(Object, Object[])}. The only reason we override it is so that we - * can expose it to methods in this package. + * can expose it. * @param self the self to bind to this function. Can be null (in which case, null is bound as this). * @param args additional arguments to bind to this function. Can be null or empty to not bind additional arguments. * @return a function with the specified self and parameters bound. */ @Override - protected ScriptFunction makeBoundFunction(final Object self, final Object[] args) { + public ScriptFunction makeBoundFunction(final Object self, final Object[] args) { return super.makeBoundFunction(self, args); } diff --git a/src/jdk/nashorn/internal/runtime/arrays/IteratorAction.java b/src/jdk/nashorn/internal/runtime/arrays/IteratorAction.java index 244739b3..ff4c13e2 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/IteratorAction.java +++ b/src/jdk/nashorn/internal/runtime/arrays/IteratorAction.java @@ -25,11 +25,7 @@ package jdk.nashorn.internal.runtime.arrays; -import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; - -import jdk.nashorn.api.scripting.JSObject; import jdk.nashorn.internal.runtime.Context; -import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptRuntime; import jdk.nashorn.internal.runtime.linker.Bootstrap; @@ -98,17 +94,7 @@ public abstract class IteratorAction { * @return result of apply */ public final T apply() { - final boolean strict; - if (callbackfn instanceof ScriptFunction) { - strict = ((ScriptFunction)callbackfn).isStrict(); - } else if (callbackfn instanceof JSObject && - ((JSObject)callbackfn).isFunction()) { - strict = ((JSObject)callbackfn).isStrictFunction(); - } else if (Bootstrap.isDynamicMethod(callbackfn) || Bootstrap.isFunctionalInterfaceObject(callbackfn)) { - strict = false; - } else { - throw typeError("not.a.function", ScriptRuntime.safeToString(callbackfn)); - } + final boolean strict = Bootstrap.isStrictCallable(callbackfn); // for non-strict callback, need to translate undefined thisArg to be global object thisArg = (thisArg == ScriptRuntime.UNDEFINED && !strict)? Context.getGlobal() : thisArg; diff --git a/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java b/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java index 8c270fb8..749c4728 100644 --- a/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java +++ b/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java @@ -26,6 +26,7 @@ package jdk.nashorn.internal.runtime.linker; import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup; +import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; import java.lang.invoke.CallSite; import java.lang.invoke.ConstantCallSite; @@ -50,6 +51,8 @@ import jdk.nashorn.internal.codegen.ObjectClassGenerator; import jdk.nashorn.internal.codegen.RuntimeCallSite; import jdk.nashorn.internal.lookup.MethodHandleFactory; import jdk.nashorn.internal.lookup.MethodHandleFunctionality; +import jdk.nashorn.internal.objects.ScriptFunctionImpl; +import jdk.nashorn.internal.runtime.ECMAException; import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.OptimisticReturnFilters; import jdk.nashorn.internal.runtime.ScriptFunction; @@ -94,7 +97,7 @@ public final class Bootstrap { new NashornLinker(), new NashornPrimitiveLinker(), new NashornStaticClassLinker(), - new BoundDynamicMethodLinker(), + new BoundCallableLinker(), new JavaSuperAdapterLinker(), new JSObjectLinker(nashornBeansLinker), new BrowserJSObjectLinker(nashornBeansLinker), @@ -136,19 +139,47 @@ public final class Bootstrap { } return obj instanceof ScriptFunction || - ((obj instanceof JSObject) && ((JSObject)obj).isFunction()) || - isDynamicMethod(obj) || + isJSObjectFunction(obj) || + BeansLinker.isDynamicMethod(obj) || + obj instanceof BoundCallable || isFunctionalInterfaceObject(obj) || obj instanceof StaticClass; } + /** + * Returns true if the given object is a strict callable + * @param callable the callable object to be checked for strictness + * @return true if the obj is a strict callable, false if it is a non-strict callable. + * @throws ECMAException with {@code TypeError} if the object is not a callable. + */ + public static boolean isStrictCallable(final Object callable) { + if (callable instanceof ScriptFunction) { + return ((ScriptFunction)callable).isStrict(); + } else if (isJSObjectFunction(callable)) { + return ((JSObject)callable).isStrictFunction(); + } else if (callable instanceof BoundCallable) { + return isStrictCallable(((BoundCallable)callable).getCallable()); + } else if (BeansLinker.isDynamicMethod(callable) || callable instanceof StaticClass) { + return false; + } + throw notFunction(callable); + } + + private static ECMAException notFunction(final Object obj) { + return typeError("not.a.function", ScriptRuntime.safeToString(obj)); + } + + private static boolean isJSObjectFunction(final Object obj) { + return obj instanceof JSObject && ((JSObject)obj).isFunction(); + } + /** * Returns if the given object is a dynalink Dynamic method * @param obj object to be checked * @return true if the obj is a dynamic method */ public static boolean isDynamicMethod(final Object obj) { - return obj instanceof BoundDynamicMethod || BeansLinker.isDynamicMethod(obj); + return BeansLinker.isDynamicMethod(obj instanceof BoundCallable ? ((BoundCallable)obj).getCallable() : obj); } /** @@ -370,14 +401,22 @@ public final class Bootstrap { } /** - * Binds a bean dynamic method (returned by invoking {@code dyn:getMethod} on an object linked with - * {@code BeansLinker} to a receiver. - * @param dynamicMethod the dynamic method to bind + * Binds any object Nashorn can use as a [[Callable]] to a receiver and optionally arguments. + * @param callable the callable to bind * @param boundThis the bound "this" value. - * @return a bound dynamic method. + * @param boundArgs the bound arguments. Can be either null or empty array to signify no arguments are bound. + * @return a bound callable. + * @throws ECMAException with {@code TypeError} if the object is not a callable. */ - public static Object bindDynamicMethod(final Object dynamicMethod, final Object boundThis) { - return new BoundDynamicMethod(dynamicMethod, boundThis); + public static Object bindCallable(final Object callable, final Object boundThis, final Object[] boundArgs) { + if (callable instanceof ScriptFunctionImpl) { + return ((ScriptFunctionImpl)callable).makeBoundFunction(boundThis, boundArgs); + } else if (callable instanceof BoundCallable) { + return ((BoundCallable)callable).bind(boundArgs); + } else if (isCallable(callable)) { + return new BoundCallable(callable, boundThis, boundArgs); + } + throw notFunction(callable); } /** diff --git a/src/jdk/nashorn/internal/runtime/linker/BoundCallable.java b/src/jdk/nashorn/internal/runtime/linker/BoundCallable.java new file mode 100644 index 00000000..a0eee0de --- /dev/null +++ b/src/jdk/nashorn/internal/runtime/linker/BoundCallable.java @@ -0,0 +1,96 @@ +/* + * 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.linker; + +import java.util.Arrays; +import jdk.nashorn.internal.runtime.ScriptRuntime; + +/** + * Represents a Nashorn callable bound to a receiver and optionally arguments. Note that objects of this class + * are just the tuples of a callable and a bound this and arguments, without any behavior. All the behavior is + * defined in the {@code BoundCallableLinker}. + */ +public final class BoundCallable { + private final Object callable; + private final Object boundThis; + private final Object[] boundArgs; + + BoundCallable(final Object callable, final Object boundThis, final Object[] boundArgs) { + this.callable = callable; + this.boundThis = boundThis; + this.boundArgs = isEmptyArray(boundArgs) ? ScriptRuntime.EMPTY_ARRAY : boundArgs.clone(); + } + + private BoundCallable(final BoundCallable original, final Object[] extraBoundArgs) { + this.callable = original.callable; + this.boundThis = original.boundThis; + this.boundArgs = original.concatenateBoundArgs(extraBoundArgs); + } + + Object getCallable() { + return callable; + } + + Object getBoundThis() { + return boundThis; + } + + Object[] getBoundArgs() { + return boundArgs; + } + + BoundCallable bind(final Object[] extraBoundArgs) { + if (isEmptyArray(extraBoundArgs)) { + return this; + } + return new BoundCallable(this, extraBoundArgs); + } + + private Object[] concatenateBoundArgs(final Object[] extraBoundArgs) { + if (boundArgs.length == 0) { + return extraBoundArgs.clone(); + } + final int origBoundArgsLen = boundArgs.length; + final int extraBoundArgsLen = extraBoundArgs.length; + final Object[] newBoundArgs = new Object[origBoundArgsLen + extraBoundArgsLen]; + System.arraycopy(boundArgs, 0, newBoundArgs, 0, origBoundArgsLen); + System.arraycopy(extraBoundArgs, 0, newBoundArgs, origBoundArgsLen, extraBoundArgsLen); + return newBoundArgs; + } + + private static boolean isEmptyArray(final Object[] a) { + return a == null || a.length == 0; + } + + @Override + public String toString() { + final StringBuilder b = new StringBuilder(callable.toString()).append(" on ").append(boundThis); + if (boundArgs.length != 0) { + b.append(" with ").append(Arrays.toString(boundArgs)); + } + return b.toString(); + } +} diff --git a/src/jdk/nashorn/internal/runtime/linker/BoundCallableLinker.java b/src/jdk/nashorn/internal/runtime/linker/BoundCallableLinker.java new file mode 100644 index 00000000..d52063bf --- /dev/null +++ b/src/jdk/nashorn/internal/runtime/linker/BoundCallableLinker.java @@ -0,0 +1,132 @@ +/* + * 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.linker; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.Arrays; +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; +import jdk.internal.dynalink.support.Guards; + +/** + * Links {@link BoundCallable} objects. Passes through to linker services for linking a callable (for either + * "dyn:call" or "dyn:new"), and modifies the returned invocation to deal with the receiver and argument binding. + */ +final class BoundCallableLinker implements TypeBasedGuardingDynamicLinker { + @Override + public boolean canLinkType(final Class type) { + return type == BoundCallable.class; + } + + @Override + public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception { + final Object objBoundCallable = linkRequest.getReceiver(); + if(!(objBoundCallable instanceof BoundCallable)) { + return null; + } + + final CallSiteDescriptor descriptor = linkRequest.getCallSiteDescriptor(); + if (descriptor.getNameTokenCount() < 2 || !"dyn".equals(descriptor.getNameToken(CallSiteDescriptor.SCHEME))) { + return null; + } + final String operation = descriptor.getNameToken(CallSiteDescriptor.OPERATOR); + // We need to distinguish "dyn:new" from "dyn:call" because "dyn:call" sites have parameter list of the form + // "callee, this, args", while "dyn:call" sites have "callee, args" -- they lack the "this" parameter. + final boolean isCall; + if ("new".equals(operation)) { + isCall = false; + } else if ("call".equals(operation)) { + isCall = true; + } else { + // Only dyn:call and dyn:new are supported. + return null; + } + final BoundCallable boundCallable = (BoundCallable)objBoundCallable; + final Object callable = boundCallable.getCallable(); + final Object boundThis = boundCallable.getBoundThis(); + + // We need to ask the linker services for a delegate invocation on the target callable. + + // Replace arguments (boundCallable[, this], args) => (callable[, boundThis], boundArgs, args) when delegating + final Object[] args = linkRequest.getArguments(); + final Object[] boundArgs = boundCallable.getBoundArgs(); + final int argsLen = args.length; + final int boundArgsLen = boundArgs.length; + final Object[] newArgs = new Object[argsLen + boundArgsLen]; + newArgs[0] = callable; + final int firstArgIndex; + if (isCall) { + newArgs[1] = boundThis; + firstArgIndex = 2; + } else { + firstArgIndex = 1; + } + System.arraycopy(boundArgs, 0, newArgs, firstArgIndex, boundArgsLen); + System.arraycopy(args, firstArgIndex, newArgs, firstArgIndex + boundArgsLen, argsLen - firstArgIndex); + + // Use R(T0, T1, T2, ...) => R(callable.class, boundThis.class, boundArg0.class, ..., boundArgn.class, T2, ...) + // call site type when delegating to underlying linker (for dyn:new, there's no this). + final MethodType type = descriptor.getMethodType(); + // Use R(T0, ...) => R(callable.class, ...) + MethodType newMethodType = descriptor.getMethodType().changeParameterType(0, callable.getClass()); + if (isCall) { + // R(callable.class, T1, ...) => R(callable.class, boundThis.class, ...) + newMethodType = newMethodType.changeParameterType(1, boundThis.getClass()); + } + // R(callable.class[, boundThis.class], T2, ...) => R(callable.class[, boundThis.class], boundArg0.class, ..., boundArgn.class, T2, ...) + for(int i = boundArgs.length; i-- > 0;) { + newMethodType = newMethodType.insertParameterTypes(firstArgIndex, boundArgs[i] == null ? Object.class : boundArgs[i].getClass()); + } + final CallSiteDescriptor newDescriptor = descriptor.changeMethodType(newMethodType); + + // Delegate to target's linker + final GuardedInvocation inv = linkerServices.getGuardedInvocation(linkRequest.replaceArguments(newDescriptor, newArgs)); + if(inv == null) { + return null; + } + + // Bind (callable[, boundThis], boundArgs) to the delegate handle + final MethodHandle boundHandle = MethodHandles.insertArguments(inv.getInvocation(), 0, + Arrays.copyOf(newArgs, firstArgIndex + boundArgs.length)); + final Class p0Type = type.parameterType(0); + final MethodHandle droppingHandle; + if (isCall) { + // Ignore incoming boundCallable and this + droppingHandle = MethodHandles.dropArguments(boundHandle, 0, p0Type, type.parameterType(1)); + } else { + // Ignore incoming boundCallable + droppingHandle = MethodHandles.dropArguments(boundHandle, 0, p0Type); + } + // Identity guard on boundCallable object + final MethodHandle newGuard = Guards.getIdentityGuard(boundCallable); + return inv.replaceMethods(droppingHandle, newGuard.asType(newGuard.type().changeParameterType(0, p0Type))); + } +} diff --git a/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethod.java b/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethod.java deleted file mode 100644 index 9008547f..00000000 --- a/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethod.java +++ /dev/null @@ -1,57 +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.linker; - -import java.util.Objects; -import jdk.internal.dynalink.beans.BeansLinker; - -/** - * Represents a Dynalink dynamic method bound to a receiver. Note that objects of this class are just the tuples of - * a method and a bound this, without any behavior. All the behavior is defined in the {@code BoundDynamicMethodLinker}. - */ -final class BoundDynamicMethod { - private final Object dynamicMethod; - private final Object boundThis; - - BoundDynamicMethod(final Object dynamicMethod, final Object boundThis) { - assert BeansLinker.isDynamicMethod(dynamicMethod); - this.dynamicMethod = dynamicMethod; - this.boundThis = boundThis; - } - - Object getDynamicMethod() { - return dynamicMethod; - } - - Object getBoundThis() { - return boundThis; - } - - @Override - public String toString() { - return dynamicMethod.toString() + " on " + Objects.toString(boundThis); - } -} diff --git a/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java b/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java deleted file mode 100644 index 67e29835..00000000 --- a/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java +++ /dev/null @@ -1,91 +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.linker; - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import jdk.internal.dynalink.CallSiteDescriptor; -import jdk.internal.dynalink.beans.BeansLinker; -import jdk.internal.dynalink.linker.GuardedInvocation; -import jdk.internal.dynalink.linker.LinkRequest; -import jdk.internal.dynalink.linker.LinkerServices; -import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; -import jdk.internal.dynalink.support.Guards; - -/** - * Links {@code BoundDynamicMethod} objects. Passes through to Dynalink's BeansLinker for linking a dynamic method - * (they only respond to "dyn:call"), and modifies the returned invocation to deal with the receiver binding. - */ -final class BoundDynamicMethodLinker implements TypeBasedGuardingDynamicLinker { - @Override - public boolean canLinkType(final Class type) { - return type == BoundDynamicMethod.class; - } - - @Override - public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception { - final Object objBoundDynamicMethod = linkRequest.getReceiver(); - if(!(objBoundDynamicMethod instanceof BoundDynamicMethod)) { - return null; - } - - final BoundDynamicMethod boundDynamicMethod = (BoundDynamicMethod)objBoundDynamicMethod; - final Object dynamicMethod = boundDynamicMethod.getDynamicMethod(); - final Object boundThis = boundDynamicMethod.getBoundThis(); - - // Replace arguments (boundDynamicMethod, this, ...) => (dynamicMethod, boundThis, ...) when delegating to - // BeansLinker - final Object[] args = linkRequest.getArguments(); - args[0] = dynamicMethod; - args[1] = boundThis; - - // Use R(T0, T1, ...) => R(dynamicMethod.class, boundThis.class, ...) call site type when delegating to - // BeansLinker. - final CallSiteDescriptor descriptor = linkRequest.getCallSiteDescriptor(); - final MethodType type = descriptor.getMethodType(); - final Class dynamicMethodClass = dynamicMethod.getClass(); - final CallSiteDescriptor newDescriptor = descriptor.changeMethodType( - type.changeParameterType(0, dynamicMethodClass).changeParameterType(1, boundThis.getClass())); - - // Delegate to BeansLinker - final GuardedInvocation inv = NashornBeansLinker.getGuardedInvocation(BeansLinker.getLinkerForClass(dynamicMethodClass), - linkRequest.replaceArguments(newDescriptor, args), linkerServices); - if(inv == null) { - return null; - } - - // Bind (dynamicMethod, boundThis) to the handle - final MethodHandle boundHandle = MethodHandles.insertArguments(inv.getInvocation(), 0, dynamicMethod, boundThis); - final Class p0Type = type.parameterType(0); - // Ignore incoming (boundDynamicMethod, this) - final MethodHandle droppingHandle = MethodHandles.dropArguments(boundHandle, 0, p0Type, type.parameterType(1)); - // Identity guard on boundDynamicMethod object - final MethodHandle newGuard = Guards.getIdentityGuard(boundDynamicMethod); - - return inv.replaceMethods(droppingHandle, newGuard.asType(newGuard.type().changeParameterType(0, p0Type))); - } -} diff --git a/src/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java b/src/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java index 5fc93cb4..9aeefd72 100644 --- a/src/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java +++ b/src/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java @@ -165,7 +165,7 @@ final class JavaSuperAdapterLinker implements TypeBasedGuardingDynamicLinker { */ @SuppressWarnings("unused") private static Object bindDynamicMethod(final Object dynamicMethod, final Object boundThis) { - return dynamicMethod == null ? ScriptRuntime.UNDEFINED : Bootstrap.bindDynamicMethod(dynamicMethod, boundThis); + return dynamicMethod == null ? ScriptRuntime.UNDEFINED : Bootstrap.bindCallable(dynamicMethod, boundThis, null); } /** diff --git a/test/script/basic/JDK-8051778.js b/test/script/basic/JDK-8051778.js new file mode 100644 index 00000000..2d8d788a --- /dev/null +++ b/test/script/basic/JDK-8051778.js @@ -0,0 +1,83 @@ +/* + * 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-8051778: support bind on all Nashorn callables + * + * @test + * @run + */ + +var bind = Function.prototype.bind; + +// Bind a POJO method +var l = new java.util.ArrayList(); +var l_add_foo = bind.call(l.add, l, "foo"); +l_add_foo(); +print("l=" + l); + +// Bind a BoundCallable +var l_add = bind.call(l.add, l); +var l_add_foo2 = bind.call(l_add, null, "foo2"); +l_add_foo2(); +print("l=" + l); + +// Bind a POJO method retrieved from one instance to a different but +// compatible instance. +var l2 = new java.util.ArrayList(); +var l2_size = bind.call(l.size, l2); +print("l2_size()=" + l2_size()); + +// Bind a Java type object (used as a constructor). +var construct_two = bind.call(java.lang.Integer, null, 2); +print("Bound Integer(2) constructor: " + new construct_two()) + +// Bind a @FunctionalInterface proxying to an object literal. NOTE: the +// expected value of this.a is always "original" and never "bound". This +// might seem counterintuitive, but we are not binding the apply() +// function of the object literal that defines the BiFunction behaviour, +// we are binding the SAM proxy object instead, and it is always +// forwarding to the apply() function with "this" set to the object +// literal. Basically, binding "this" for SAM proxies is useless; only +// binding arguments makes sense. +var f1 = new java.util.function.BiFunction() { + apply: function(x, y) { + return "BiFunction with literal: " + this.a + ", " + x + ", " + y; + }, + a: "unbound" +}; +print((bind.call(f1, {a: "bound"}))(1, 2)) +print((bind.call(f1, {a: "bound"}, 3))(4)) +print((bind.call(f1, {a: "bound"}, 5, 6))()) + +// Bind a @FunctionalInterface proxying to a function. With the same +// reasoning as above (binding the proxy vs. binding the JS function), +// the value of this.a will always be undefined, and never "bound". +var f2 = new java.util.function.BiFunction( + function(x, y) { + return "BiFunction with function: " + this.a + ", " + x + ", " + y; + } +); +print((bind.call(f2, {a: "bound"}))(7, 8)) +print((bind.call(f2, {a: "bound"}, 9))(10)) +print((bind.call(f2, {a: "bound"}, 11, 12))()) diff --git a/test/script/basic/JDK-8051778.js.EXPECTED b/test/script/basic/JDK-8051778.js.EXPECTED new file mode 100644 index 00000000..4ba3e287 --- /dev/null +++ b/test/script/basic/JDK-8051778.js.EXPECTED @@ -0,0 +1,10 @@ +l=[foo] +l=[foo, foo2] +l2_size()=0 +Bound Integer(2) constructor: 2 +BiFunction with literal: unbound, 1, 2 +BiFunction with literal: unbound, 3, 4 +BiFunction with literal: unbound, 5, 6 +BiFunction with function: undefined, 7, 8 +BiFunction with function: undefined, 9, 10 +BiFunction with function: undefined, 11, 12 -- cgit v1.2.1 From db7258d41f6866d2b6746d54aa758aa17ddbbde7 Mon Sep 17 00:00:00 2001 From: lagergren Date: Fri, 28 Nov 2014 11:02:54 +0100 Subject: 8066119: Invalid resource tag used for looking up error message in NativeDataView Reviewed-by: hannesw, sundar --- src/jdk/nashorn/internal/objects/NativeDataView.java | 20 ++++++++++---------- .../internal/runtime/resources/Messages.properties | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/jdk/nashorn/internal/objects/NativeDataView.java b/src/jdk/nashorn/internal/objects/NativeDataView.java index fb502771..14c11f69 100644 --- a/src/jdk/nashorn/internal/objects/NativeDataView.java +++ b/src/jdk/nashorn/internal/objects/NativeDataView.java @@ -105,10 +105,10 @@ public class NativeDataView extends ScriptObject { private NativeDataView(final NativeArrayBuffer arrBuf, final ByteBuffer buf, final int offset, final int length) { super(Global.instance().getDataViewPrototype(), $nasgenmap$); - this.buffer = arrBuf; + this.buffer = arrBuf; this.byteOffset = offset; this.byteLength = length; - this.buf = buf; + this.buf = buf; } /** @@ -135,14 +135,14 @@ public class NativeDataView extends ScriptObject { throw typeError("not.an.arraybuffer.in.dataview"); } - final NativeArrayBuffer arrBuf = (NativeArrayBuffer) args[0]; + final NativeArrayBuffer arrBuf = (NativeArrayBuffer)args[0]; switch (args.length) { - case 1: - return new NativeDataView(arrBuf); - case 2: - return new NativeDataView(arrBuf, JSType.toInt32(args[1])); - default: - return new NativeDataView(arrBuf, JSType.toInt32(args[1]), JSType.toInt32(args[2])); + case 1: + return new NativeDataView(arrBuf); + case 2: + return new NativeDataView(arrBuf, JSType.toInt32(args[1])); + default: + return new NativeDataView(arrBuf, JSType.toInt32(args[1]), JSType.toInt32(args[2])); } } @@ -995,7 +995,7 @@ public class NativeDataView extends ScriptObject { private static NativeDataView checkSelf(final Object self) { if (!(self instanceof NativeDataView)) { - throw typeError("not.an.arraybuffer", ScriptRuntime.safeToString(self)); + throw typeError("not.an.arraybuffer.in.dataview", ScriptRuntime.safeToString(self)); } return (NativeDataView)self; } diff --git a/src/jdk/nashorn/internal/runtime/resources/Messages.properties b/src/jdk/nashorn/internal/runtime/resources/Messages.properties index 71c11743..119277df 100644 --- a/src/jdk/nashorn/internal/runtime/resources/Messages.properties +++ b/src/jdk/nashorn/internal/runtime/resources/Messages.properties @@ -82,7 +82,7 @@ type.error.not.a.constructor={0} is not a constructor function type.error.not.a.file={0} is not a File type.error.not.a.numeric.array={0} is not a numeric array type.error.not.a.bytebuffer={0} is not a java.nio.ByteBuffer -type.error.not.an.arraybuffer.in.dataview=First arg to DataView constructor must be an ArrayBuffer +type.error.not.an.arraybuffer.in.dataview=First argument to DataView constructor must be an ArrayBuffer type.error.no.reflection.with.classfilter=Java reflection not supported when class filter is present # operations not permitted on undefined -- cgit v1.2.1 From 09b6bf8d7aa88ba3f09434e6576eba1b45cee5e5 Mon Sep 17 00:00:00 2001 From: slugovoy Date: Fri, 28 Nov 2014 18:23:04 +0300 Subject: 8057779: Tests failed on Windows when in output contains path to script Reviewed-by: coffeys --- test/script/basic/es6/const-empty.js | 2 +- test/script/basic/es6/const-redeclare-extra.js | 2 +- test/script/basic/es6/const-redeclare.js | 2 +- test/script/basic/es6/let-redeclare-extra.js | 2 +- test/script/basic/es6/let-redeclare.js | 2 +- test/script/basic/es6/let_const_reuse.js | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/script/basic/es6/const-empty.js b/test/script/basic/es6/const-empty.js index 0687aa2e..c34d1d51 100644 --- a/test/script/basic/es6/const-empty.js +++ b/test/script/basic/es6/const-empty.js @@ -33,5 +33,5 @@ try { eval('"use strict";\n' + 'const x;\n'); } catch (e) { - print(e); + print(String(e).replace(/\\/g, "/")); } diff --git a/test/script/basic/es6/const-redeclare-extra.js b/test/script/basic/es6/const-redeclare-extra.js index 6d77e18e..94fc53b2 100644 --- a/test/script/basic/es6/const-redeclare-extra.js +++ b/test/script/basic/es6/const-redeclare-extra.js @@ -35,7 +35,7 @@ function tryIt (code) { try { eval(code) } catch (e) { - print(e) + print(String(e).replace(/\\/g, "/")) } } diff --git a/test/script/basic/es6/const-redeclare.js b/test/script/basic/es6/const-redeclare.js index 8e4aa7e4..efe34ac2 100644 --- a/test/script/basic/es6/const-redeclare.js +++ b/test/script/basic/es6/const-redeclare.js @@ -34,5 +34,5 @@ try { 'const x = 2;\n' + 'const x = 2;\n'); } catch (e) { - print(e); + print(String(e).replace(/\\/g, "/")); } diff --git a/test/script/basic/es6/let-redeclare-extra.js b/test/script/basic/es6/let-redeclare-extra.js index 630513f4..ddb205e4 100644 --- a/test/script/basic/es6/let-redeclare-extra.js +++ b/test/script/basic/es6/let-redeclare-extra.js @@ -34,7 +34,7 @@ function tryIt (code) { try { eval(code) } catch (e) { - print(e) + print(String(e).replace(/\\/g, "/")) } } diff --git a/test/script/basic/es6/let-redeclare.js b/test/script/basic/es6/let-redeclare.js index b6ad0f0a..adc05196 100644 --- a/test/script/basic/es6/let-redeclare.js +++ b/test/script/basic/es6/let-redeclare.js @@ -34,5 +34,5 @@ try { 'let x = 2;\n' + 'let x = 2;\n'); } catch (e) { - print(e); + print(String(e).replace(/\\/g, "/")); } diff --git a/test/script/basic/es6/let_const_reuse.js b/test/script/basic/es6/let_const_reuse.js index 556c23dc..bc9e8f84 100644 --- a/test/script/basic/es6/let_const_reuse.js +++ b/test/script/basic/es6/let_const_reuse.js @@ -34,7 +34,7 @@ function tryIt (code) { try { eval(code) } catch (e) { - print(e) + print(String(e).replace(/\\/g, "/")) } } -- cgit v1.2.1 From 9ad712ca825640ee64a8f1f9bee1d367dc1b8f26 Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 1 Dec 2014 18:08:40 +0000 Subject: 8057629: Third Party License Readme update for 8u40 Reviewed-by: tbell --- THIRD_PARTY_README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/THIRD_PARTY_README b/THIRD_PARTY_README index 6d1c60f2..c34ce6b3 100644 --- a/THIRD_PARTY_README +++ b/THIRD_PARTY_README @@ -3385,7 +3385,7 @@ with JRE 8, JDK 8, and OpenJDK 8. included with JRE 8, JDK 8, and OpenJDK 8. Apache Commons Math 3.2 - Apache Derby 10.10.1.3 + Apache Derby 10.11.1.2 Apache Jakarta BCEL 5.1 Apache Jakarta Regexp 1.4 Apache Santuario XML Security for Java 1.5.4 -- cgit v1.2.1 From 33c4e3e8db57edd5ec332f2a19511cb46c3c4609 Mon Sep 17 00:00:00 2001 From: asaha Date: Tue, 2 Dec 2014 11:13:14 -0800 Subject: Added tag jdk8u31-b11 for changeset 599bd596fa54 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 8a271cfe..d35cfdbe 100644 --- a/.hgtags +++ b/.hgtags @@ -333,3 +333,4 @@ cdbf34dbef404b47805c8c85b11c65c2afaa6674 jdk8u25-b18 b17ecf341ee544cc5507b9b586c14a13c3adc058 jdk8u31-b08 762eaacc45cec3f7d593bedd08fb8de478d4415b jdk8u31-b09 c68ba913a0eeea6eb94d9568e9985505ec3408a3 jdk8u31-b10 +599bd596fa549d882aa8fc5104c322a75a3af728 jdk8u31-b11 -- cgit v1.2.1 From 43eada765f54df8725d79f2ccde71d3c4cd7cdf3 Mon Sep 17 00:00:00 2001 From: hannesw Date: Wed, 3 Dec 2014 14:49:36 +0100 Subject: 8065769: OOM on Window/Solaris in test compile-octane-splitter.js Reviewed-by: sundar, jlaskey --- src/jdk/nashorn/internal/codegen/AstSerializer.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/jdk/nashorn/internal/codegen/AstSerializer.java b/src/jdk/nashorn/internal/codegen/AstSerializer.java index 19197a26..dc35f964 100644 --- a/src/jdk/nashorn/internal/codegen/AstSerializer.java +++ b/src/jdk/nashorn/internal/codegen/AstSerializer.java @@ -48,11 +48,13 @@ final class AstSerializer { private static final int COMPRESSION_LEVEL = Options.getIntProperty("nashorn.serialize.compression", 4); static byte[] serialize(final FunctionNode fn) { final ByteArrayOutputStream out = new ByteArrayOutputStream(); - try (final ObjectOutputStream oout = new ObjectOutputStream(new DeflaterOutputStream(out, - new Deflater(COMPRESSION_LEVEL)))) { + final Deflater deflater = new Deflater(COMPRESSION_LEVEL); + try (final ObjectOutputStream oout = new ObjectOutputStream(new DeflaterOutputStream(out, deflater))) { oout.writeObject(removeInnerFunctionBodies(fn)); } catch (final IOException e) { throw new AssertionError("Unexpected exception serializing function", e); + } finally { + deflater.end(); } return out.toByteArray(); } -- cgit v1.2.1 From 719866d0cb4929f4c80e7c0b9fc1f6ec1b3c10b2 Mon Sep 17 00:00:00 2001 From: katleman Date: Wed, 3 Dec 2014 11:12:46 -0800 Subject: Added tag jdk8u40-b17 for changeset 88e22262fdb2 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 2941d00d..93cd9b56 100644 --- a/.hgtags +++ b/.hgtags @@ -336,3 +336,4 @@ d60fbb5343c186abbf92b0259e67efb3b71377b4 jdk8u40-b13 7e34104c55cafa0b579be3a480dda383c616a378 jdk8u40-b14 fc37699ddc0ed41d4ab5da821211a6d2648c8883 jdk8u40-b15 e079f3f6d536510b1ab3589b1038d893d78302ac jdk8u40-b16 +88e22262fdb26e3154a1034c2413415e97b9a86a jdk8u40-b17 -- cgit v1.2.1 From c953a34fa1cc15c71119a4b1268ccaf994abee86 Mon Sep 17 00:00:00 2001 From: attila Date: Mon, 8 Dec 2014 15:13:16 +0100 Subject: 8066230: Undefined object type assertion when computing TypeBounds Reviewed-by: hannesw, lagergren --- .../nashorn/internal/codegen/CodeGenerator.java | 25 +++++++++------- test/script/basic/JDK-8066230.js | 34 ++++++++++++++++++++++ test/script/basic/JDK-8066230.js.EXPECTED | 1 + 3 files changed, 50 insertions(+), 10 deletions(-) create mode 100644 test/script/basic/JDK-8066230.js create mode 100644 test/script/basic/JDK-8066230.js.EXPECTED diff --git a/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/src/jdk/nashorn/internal/codegen/CodeGenerator.java index 1bf3b382..360410ae 100644 --- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java @@ -571,9 +571,11 @@ final class CodeGenerator extends NodeOperatorVisitor Date: Mon, 8 Dec 2014 15:14:11 +0100 Subject: 8066227: CodeGenerator load unitialized slot Reviewed-by: hannesw, lagergren --- .../nashorn/internal/codegen/CodeGenerator.java | 3 +- .../codegen/LocalVariableTypesCalculator.java | 159 ++++++++++++++++----- src/jdk/nashorn/internal/ir/BinaryNode.java | 5 +- test/script/basic/JDK-8066227.js | 40 ++++++ test/script/basic/JDK-8066227.js.EXPECTED | 10 ++ 5 files changed, 173 insertions(+), 44 deletions(-) create mode 100644 test/script/basic/JDK-8066227.js create mode 100644 test/script/basic/JDK-8066227.js.EXPECTED diff --git a/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/src/jdk/nashorn/internal/codegen/CodeGenerator.java index 360410ae..7bb0da3f 100644 --- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java @@ -3697,8 +3697,7 @@ final class CodeGenerator extends NodeOperatorVisitor{ @Override public boolean enterBinaryNode(final BinaryNode binaryNode) { + // NOTE: regardless of operator's lexical associativity, lhs is always evaluated first. final Expression lhs = binaryNode.lhs(); - final Expression rhs = binaryNode.rhs(); final boolean isAssignment = binaryNode.isAssignment(); - - final TokenType tokenType = Token.descType(binaryNode.getToken()); - if(tokenType.isLeftAssociative()) { - assert !isAssignment; - final boolean isLogical = binaryNode.isLogical(); - final Label joinLabel = isLogical ? new Label("") : null; - lhs.accept(this); - if(isLogical) { - jumpToLabel((JoinPredecessor)lhs, joinLabel); - } - rhs.accept(this); - if(isLogical) { - jumpToLabel((JoinPredecessor)rhs, joinLabel); - } - joinOnLabel(joinLabel); - } else { - rhs.accept(this); - if(isAssignment) { - if(lhs instanceof BaseNode) { - ((BaseNode)lhs).getBase().accept(this); - if(lhs instanceof IndexNode) { - ((IndexNode)lhs).getIndex().accept(this); - } else { - assert lhs instanceof AccessNode; - } + LvarType lhsTypeOnLoad = null; + if(isAssignment) { + if(lhs instanceof BaseNode) { + ((BaseNode)lhs).getBase().accept(this); + if(lhs instanceof IndexNode) { + ((IndexNode)lhs).getIndex().accept(this); } else { - assert lhs instanceof IdentNode; - if(binaryNode.isSelfModifying()) { - ((IdentNode)lhs).accept(this); - } + assert lhs instanceof AccessNode; } } else { - lhs.accept(this); + assert lhs instanceof IdentNode; + if(binaryNode.isSelfModifying()) { + final IdentNode ident = ((IdentNode)lhs); + ident.accept(this); + // Self-assignment can cause a change in the type of the variable. For purposes of evaluating + // the type of the operation, we must use its type as it was when it was loaded. If we didn't + // do this, some awkward expressions would end up being calculated incorrectly, e.g. + // "var x; x += x = 0;". In this case we have undefined+int so the result type is double (NaN). + // However, if we used the type of "x" on LHS after we evaluated RHS, we'd see int+int, so the + // result type would be either optimistic int or pessimistic long, which would be wrong. + lhsTypeOnLoad = getLocalVariableTypeIfBytecode(ident.getSymbol()); + } } + } else { + lhs.accept(this); + } + + final boolean isLogical = binaryNode.isLogical(); + assert !(isAssignment && isLogical); // there are no logical assignment operators in JS + final Label joinLabel = isLogical ? new Label("") : null; + if(isLogical) { + jumpToLabel((JoinPredecessor)lhs, joinLabel); + } + + final Expression rhs = binaryNode.rhs(); + rhs.accept(this); + if(isLogical) { + jumpToLabel((JoinPredecessor)rhs, joinLabel); } + joinOnLabel(joinLabel); if(isAssignment && lhs instanceof IdentNode) { if(binaryNode.isSelfModifying()) { - onSelfAssignment((IdentNode)lhs, binaryNode); + onSelfAssignment((IdentNode)lhs, binaryNode, lhsTypeOnLoad); } else { onAssignment((IdentNode)lhs, rhs); } @@ -919,7 +924,8 @@ final class LocalVariableTypesCalculator extends NodeVisitor{ if(unaryNode.isSelfModifying()) { if(expr instanceof IdentNode) { - onSelfAssignment((IdentNode)expr, unaryNode); + final IdentNode ident = (IdentNode)expr; + onSelfAssignment(ident, unaryNode, getLocalVariableTypeIfBytecode(ident.getSymbol())); } } return false; @@ -973,12 +979,41 @@ final class LocalVariableTypesCalculator extends NodeVisitor{ return types; } + /** + * Returns the current type of the local variable represented by the symbol. This is the most strict of all + * {@code getLocalVariableType*} methods, as it will throw an assertion if the type is null. Therefore, it is only + * safe to be invoked on symbols known to be bytecode locals, and only after they have been initialized. + * Regardless, it is recommended to use this method in majority of cases, as because of its strictness it is the + * best suited for catching missing type calculation bugs early. + * @param symbol a symbol representing a bytecode local variable. + * @return the current type of the local variable represented by the symbol + */ private LvarType getLocalVariableType(final Symbol symbol) { final LvarType type = getLocalVariableTypeOrNull(symbol); assert type != null; return type; } + /** + * Gets the type for a local variable if it is a bytecode local, otherwise null. Can be used in circumstances where + * the type is irrelevant if the symbol is not a bytecode local. Note that for bytecode locals, it delegates to + * {@link #getLocalVariableType(Symbol)}, so it will still assert that the type for such variable is already + * defined (that is, not null). + * @param symbol the symbol representing the variable. + * @return the current variable type, if it is a bytecode local, otherwise null. + */ + private LvarType getLocalVariableTypeIfBytecode(final Symbol symbol) { + return symbol.isBytecodeLocal() ? getLocalVariableType(symbol) : null; + } + + /** + * Gets the type for a variable represented by a symbol, or null if the type is not know. This is the least strict + * of all local variable type getters, and as such its use is discouraged except in initialization scenarios (where + * a just-defined symbol might still be null). + * @param symbol the symbol + * @return the current type for the symbol, or null if the type is not known either because the symbol has not been + * initialized, or because the symbol does not represent a bytecode local variable. + */ private LvarType getLocalVariableTypeOrNull(final Symbol symbol) { return localVariableTypes.get(symbol); } @@ -1358,13 +1393,13 @@ final class LocalVariableTypesCalculator extends NodeVisitor{ jumpToCatchBlock(identNode); } - private void onSelfAssignment(final IdentNode identNode, final Expression assignment) { + private void onSelfAssignment(final IdentNode identNode, final Expression assignment, final LvarType typeOnLoad) { final Symbol symbol = identNode.getSymbol(); assert symbol != null : identNode.getName(); if(!symbol.isBytecodeLocal()) { return; } - final LvarType type = toLvarType(getType(assignment)); + final LvarType type = toLvarType(getType(assignment, symbol, typeOnLoad.type)); // Self-assignment never produce either a boolean or undefined assert type != null && type != LvarType.UNDEFINED && type != LvarType.BOOLEAN; setType(symbol, type); @@ -1445,13 +1480,24 @@ final class LocalVariableTypesCalculator extends NodeVisitor{ symbolIsUsed(symbol, getLocalVariableType(symbol)); } + /** + * Gets the type of the expression, dependent on the current types of the local variables. + * + * @param expr the expression + * @return the current type of the expression dependent on the current types of the local variables. + */ private Type getType(final Expression expr) { return expr.getType(getSymbolToType()); } + /** + * Returns a function object from symbols to their types, used by the expressions to evaluate their type. + * {@link BinaryNode} specifically uses identity of the function to cache type calculations. This method makes + * sure to return the same function object while the local variable types don't change, and create a new function + * object if the local variable types have been changed. + * @return a function object representing a mapping from symbols to their types. + */ private Function getSymbolToType() { - // BinaryNode uses identity of the function to cache type calculations. Therefore, we must use different - // function instances for different localVariableTypes instances. if(symbolToType.isStale()) { symbolToType = new SymbolToType(); } @@ -1469,4 +1515,41 @@ final class LocalVariableTypesCalculator extends NodeVisitor{ return boundTypes != localVariableTypes; } } + + /** + * Gets the type of the expression, dependent on the current types of the local variables and a single overridden + * symbol type. Used by type calculation on compound operators to ensure the type of the LHS at the time it was + * loaded (which can potentially be different after RHS evaluation, e.g. "var x; x += x = 0;") is preserved for + * the calculation. + * + * @param expr the expression + * @param overriddenSymbol the overridden symbol + * @param overriddenType the overridden type + * @return the current type of the expression dependent on the current types of the local variables and the single + * potentially overridden type. + */ + private Type getType(final Expression expr, final Symbol overriddenSymbol, final Type overriddenType) { + return expr.getType(getSymbolToType(overriddenSymbol, overriddenType)); + } + + private Function getSymbolToType(final Symbol overriddenSymbol, final Type overriddenType) { + return getLocalVariableType(overriddenSymbol).type == overriddenType ? getSymbolToType() : + new SymbolToTypeOverride(overriddenSymbol, overriddenType); + } + + private class SymbolToTypeOverride implements Function { + private final Function originalSymbolToType = getSymbolToType(); + private final Symbol overriddenSymbol; + private final Type overriddenType; + + SymbolToTypeOverride(final Symbol overriddenSymbol, final Type overriddenType) { + this.overriddenSymbol = overriddenSymbol; + this.overriddenType = overriddenType; + } + + @Override + public Type apply(final Symbol symbol) { + return symbol == overriddenSymbol ? overriddenType : originalSymbolToType.apply(symbol); + } + } } diff --git a/src/jdk/nashorn/internal/ir/BinaryNode.java b/src/jdk/nashorn/internal/ir/BinaryNode.java index cb8cc918..f625fe1a 100644 --- a/src/jdk/nashorn/internal/ir/BinaryNode.java +++ b/src/jdk/nashorn/internal/ir/BinaryNode.java @@ -341,10 +341,7 @@ public final class BinaryNode extends Expression implements Assignment visitor) { if (visitor.enterBinaryNode(this)) { - if(tokenType().isLeftAssociative()) { - return visitor.leaveBinaryNode(setLHS((Expression)lhs.accept(visitor)).setRHS((Expression)rhs.accept(visitor))); - } - return visitor.leaveBinaryNode(setRHS((Expression)rhs.accept(visitor)).setLHS((Expression)lhs.accept(visitor))); + return visitor.leaveBinaryNode(setLHS((Expression)lhs.accept(visitor)).setRHS((Expression)rhs.accept(visitor))); } return this; diff --git a/test/script/basic/JDK-8066227.js b/test/script/basic/JDK-8066227.js new file mode 100644 index 00000000..aded343f --- /dev/null +++ b/test/script/basic/JDK-8066227.js @@ -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-8066227: CodeGenerator load unitialized slot + * + * @test + * @run + */ + +print((function () { var x; (x += x = 0); return x; })()); +print((function () { var x; (x -= x = 0); return x; })()); +print((function () { var x; (x *= x = 0); return x; })()); +print((function () { var x; (x /= x = 0); return x; })()); +print((function () { var x; (x %= x = 0); return x; })()); +print((function () { var x; (x <<= x = 0); return x; })()); +print((function () { var x; (x >>= x = 0); return x; })()); +print((function () { var x; (x >>>= x = 0); return x; })()); +print((function () { var x; (x |= x = 0); return x; })()); +print((function () { var x; (x &= x = 0); return x; })()); diff --git a/test/script/basic/JDK-8066227.js.EXPECTED b/test/script/basic/JDK-8066227.js.EXPECTED new file mode 100644 index 00000000..18418221 --- /dev/null +++ b/test/script/basic/JDK-8066227.js.EXPECTED @@ -0,0 +1,10 @@ +NaN +NaN +NaN +NaN +NaN +0 +0 +0 +0 +0 -- cgit v1.2.1 From 952b123e393cf96c07ac8448b30d5c74897f196c Mon Sep 17 00:00:00 2001 From: asaha Date: Mon, 8 Dec 2014 12:30:54 -0800 Subject: Added tag jdk8u31-b12 for changeset f36c71a03e4e --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index d35cfdbe..6c80bc88 100644 --- a/.hgtags +++ b/.hgtags @@ -334,3 +334,4 @@ b17ecf341ee544cc5507b9b586c14a13c3adc058 jdk8u31-b08 762eaacc45cec3f7d593bedd08fb8de478d4415b jdk8u31-b09 c68ba913a0eeea6eb94d9568e9985505ec3408a3 jdk8u31-b10 599bd596fa549d882aa8fc5104c322a75a3af728 jdk8u31-b11 +f36c71a03e4ed467f630cc46d076a5bb4c58b6d5 jdk8u31-b12 -- cgit v1.2.1 From e9ee5116da0c0f5ee9b76a3a7344c8683994091f Mon Sep 17 00:00:00 2001 From: sundar Date: Wed, 10 Dec 2014 19:42:01 +0530 Subject: 8067136: BrowserJSObjectLinker does not handle call on JSObjects Reviewed-by: attila, hannesw, lagergren --- samples/browser_dom.js | 91 ++++++++++++++++++++++ .../runtime/linker/BrowserJSObjectLinker.java | 9 +++ test/script/basic/JDK-8067136.js | 69 ++++++++++++++++ test/script/basic/JDK-8067136.js.EXPECTED | 1 + 4 files changed, 170 insertions(+) create mode 100644 samples/browser_dom.js create mode 100644 test/script/basic/JDK-8067136.js create mode 100644 test/script/basic/JDK-8067136.js.EXPECTED diff --git a/samples/browser_dom.js b/samples/browser_dom.js new file mode 100644 index 00000000..94324c7a --- /dev/null +++ b/samples/browser_dom.js @@ -0,0 +1,91 @@ +#// Usage: jjs -fx browser.js + +/* + * 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. + */ + +if (!$OPTIONS._fx) { + print("Usage: jjs -fx browser.js"); + exit(1); +} + +// JavaFX classes used +var ChangeListener = Java.type("javafx.beans.value.ChangeListener"); +var Scene = Java.type("javafx.scene.Scene"); +var WebView = Java.type("javafx.scene.web.WebView"); +var EventListener = Java.type("org.w3c.dom.events.EventListener"); + +// JavaFX start method +function start(stage) { + start.title = "Web View"; + var wv = new WebView(); + wv.engine.loadContent(< + + +This is the title + + + + +Button from the input html
+
+ + +EOF, "text/html"); + + // attach onload handler + wv.engine.loadWorker.stateProperty().addListener( + new ChangeListener() { + changed: function() { + // DOM document element + var document = wv.engine.document; + // DOM manipulation + var btn = document.createElement("button"); + var n = 0; + // attach a button handler - nashorn function! + btn.onclick = new EventListener(function() { + n++; print("You clicked " + n + " time(s)"); + print("you clicked OK " + wv.engine.executeScript("okCount")); + }); + // attach text to button + var t = document.createTextNode("Click Me!"); + btn.appendChild(t); + // attach button to the document + document.body.appendChild(btn); + } + } + ); + stage.scene = new Scene(wv, 750, 500); + stage.show(); +} diff --git a/src/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java b/src/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java index fa43e4c8..d2f23e82 100644 --- a/src/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java +++ b/src/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java @@ -29,6 +29,7 @@ import static jdk.nashorn.internal.runtime.linker.BrowserJSObjectLinker.JSObject import static jdk.nashorn.internal.runtime.linker.BrowserJSObjectLinker.JSObjectHandles.JSOBJECT_GETSLOT; import static jdk.nashorn.internal.runtime.linker.BrowserJSObjectLinker.JSObjectHandles.JSOBJECT_SETMEMBER; import static jdk.nashorn.internal.runtime.linker.BrowserJSObjectLinker.JSObjectHandles.JSOBJECT_SETSLOT; +import static jdk.nashorn.internal.runtime.linker.BrowserJSObjectLinker.JSObjectHandles.JSOBJECT_CALL; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import jdk.internal.dynalink.CallSiteDescriptor; @@ -123,6 +124,8 @@ final class BrowserJSObjectLinker implements TypeBasedGuardingDynamicLinker { case "setProp": case "setElem": return c > 2 ? findSetMethod(desc) : findSetIndexMethod(); + case "call": + return findCallMethod(desc); default: return null; } @@ -148,6 +151,11 @@ final class BrowserJSObjectLinker implements TypeBasedGuardingDynamicLinker { return new GuardedInvocation(JSOBJECTLINKER_PUT, IS_JSOBJECT_GUARD); } + private static GuardedInvocation findCallMethod(final CallSiteDescriptor desc) { + final MethodHandle call = MH.insertArguments(JSOBJECT_CALL, 1, "call"); + return new GuardedInvocation(MH.asCollector(call, Object[].class, desc.getMethodType().parameterCount() - 1), IS_JSOBJECT_GUARD); + } + @SuppressWarnings("unused") private static boolean isJSObject(final Object self) { return jsObjectClass.isInstance(self); @@ -207,6 +215,7 @@ final class BrowserJSObjectLinker implements TypeBasedGuardingDynamicLinker { static final MethodHandle JSOBJECT_GETSLOT = findJSObjectMH_V("getSlot", Object.class, int.class).asType(MH.type(Object.class, Object.class, int.class)); static final MethodHandle JSOBJECT_SETMEMBER = findJSObjectMH_V("setMember", Void.TYPE, String.class, Object.class).asType(MH.type(Void.TYPE, Object.class, String.class, Object.class)); static final MethodHandle JSOBJECT_SETSLOT = findJSObjectMH_V("setSlot", Void.TYPE, int.class, Object.class).asType(MH.type(Void.TYPE, Object.class, int.class, Object.class)); + static final MethodHandle JSOBJECT_CALL = findJSObjectMH_V("call", Object.class, String.class, Object[].class).asType(MH.type(Object.class, Object.class, String.class, Object[].class)); private static MethodHandle findJSObjectMH_V(final String name, final Class rtype, final Class... types) { checkJSObjectClass(); diff --git a/test/script/basic/JDK-8067136.js b/test/script/basic/JDK-8067136.js new file mode 100644 index 00000000..1c7c13a2 --- /dev/null +++ b/test/script/basic/JDK-8067136.js @@ -0,0 +1,69 @@ +/* + * 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-8067136: BrowserJSObjectLinker does not handle call on JSObjects + * + * @test + * @option -scripting + * @run + */ + +// call on netscape.javascript.JSObject + +function main() { + var JSObject; + try { + JSObject = Java.type("netscape.javascript.JSObject"); + } catch (e) { + if (e instanceof java.lang.ClassNotFoundException) { + // pass vacuously by emitting the .EXPECTED file content + var str = readFully(__DIR__ + "JDK-8067136.js.EXPECTED"); + print(str.substring(0, str.length - 1)); + return; + } else{ + fail("unexpected exception for JSObject", e); + } + } + test(JSObject); +} + +function test(JSObject) { + var obj = new (Java.extend(JSObject))() { + getMember: function(name) { + if (name == "func") { + return new (Java.extend(JSObject)) { + call: function(n) { + print("func called"); + } + } + } + return name.toUpperCase(); + }, + + }; + + obj.func(); +} + +main(); diff --git a/test/script/basic/JDK-8067136.js.EXPECTED b/test/script/basic/JDK-8067136.js.EXPECTED new file mode 100644 index 00000000..5897ee65 --- /dev/null +++ b/test/script/basic/JDK-8067136.js.EXPECTED @@ -0,0 +1 @@ +func called -- cgit v1.2.1 From 118da86f6ed4d0bc0ac63ebc157ddfb63d41198f Mon Sep 17 00:00:00 2001 From: attila Date: Wed, 10 Dec 2014 11:55:04 +0100 Subject: 8066225: NPE in MethodEmitter with duplicate integer switch cases Reviewed-by: hannesw, lagergren --- .../nashorn/internal/codegen/AssignSymbols.java | 2 +- .../nashorn/internal/codegen/CodeGenerator.java | 2 +- .../nashorn/internal/codegen/FoldConstants.java | 31 ++++++++++++++ .../codegen/LocalVariableTypesCalculator.java | 2 +- src/jdk/nashorn/internal/codegen/Lower.java | 2 +- src/jdk/nashorn/internal/ir/SwitchNode.java | 47 +++++++++++++--------- test/script/basic/JDK-8066225.js | 36 +++++++++++++++++ test/script/basic/JDK-8066225.js.EXPECTED | 2 + 8 files changed, 102 insertions(+), 22 deletions(-) create mode 100644 test/script/basic/JDK-8066225.js create mode 100644 test/script/basic/JDK-8066225.js.EXPECTED diff --git a/src/jdk/nashorn/internal/codegen/AssignSymbols.java b/src/jdk/nashorn/internal/codegen/AssignSymbols.java index 6eb89a16..a4fb7bd1 100644 --- a/src/jdk/nashorn/internal/codegen/AssignSymbols.java +++ b/src/jdk/nashorn/internal/codegen/AssignSymbols.java @@ -910,7 +910,7 @@ final class AssignSymbols extends NodeVisitor implements Loggabl @Override public Node leaveSwitchNode(final SwitchNode switchNode) { // We only need a symbol for the tag if it's not an integer switch node - if(!switchNode.isInteger()) { + if(!switchNode.isUniqueInteger()) { switchNode.setTag(newObjectInternal(SWITCH_TAG_PREFIX)); } return switchNode; diff --git a/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/src/jdk/nashorn/internal/codegen/CodeGenerator.java index 7bb0da3f..3ef1b08a 100644 --- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java @@ -2817,7 +2817,7 @@ final class CodeGenerator extends NodeOperatorVisitor tree = new TreeMap<>(); diff --git a/src/jdk/nashorn/internal/codegen/FoldConstants.java b/src/jdk/nashorn/internal/codegen/FoldConstants.java index 79d20ea1..72f9fd12 100644 --- a/src/jdk/nashorn/internal/codegen/FoldConstants.java +++ b/src/jdk/nashorn/internal/codegen/FoldConstants.java @@ -26,12 +26,16 @@ package jdk.nashorn.internal.codegen; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.BinaryNode; import jdk.nashorn.internal.ir.Block; import jdk.nashorn.internal.ir.BlockStatement; +import jdk.nashorn.internal.ir.CaseNode; import jdk.nashorn.internal.ir.EmptyNode; +import jdk.nashorn.internal.ir.Expression; import jdk.nashorn.internal.ir.FunctionNode; import jdk.nashorn.internal.ir.FunctionNode.CompilationState; import jdk.nashorn.internal.ir.IfNode; @@ -40,6 +44,7 @@ import jdk.nashorn.internal.ir.LiteralNode; import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode; import jdk.nashorn.internal.ir.Node; import jdk.nashorn.internal.ir.Statement; +import jdk.nashorn.internal.ir.SwitchNode; import jdk.nashorn.internal.ir.TernaryNode; import jdk.nashorn.internal.ir.UnaryNode; import jdk.nashorn.internal.ir.VarNode; @@ -131,6 +136,32 @@ final class FoldConstants extends NodeVisitor implements Loggabl return ternaryNode; } + @Override + public Node leaveSwitchNode(final SwitchNode switchNode) { + return switchNode.setUniqueInteger(lc, isUniqueIntegerSwitchNode(switchNode)); + } + + private static boolean isUniqueIntegerSwitchNode(final SwitchNode switchNode) { + final Set alreadySeen = new HashSet<>(); + for (final CaseNode caseNode : switchNode.getCases()) { + final Expression test = caseNode.getTest(); + if (test != null && !isUniqueIntegerLiteral(test, alreadySeen)) { + return false; + } + } + return true; + } + + private static boolean isUniqueIntegerLiteral(final Expression expr, final Set alreadySeen) { + if (expr instanceof LiteralNode) { + final Object value = ((LiteralNode)expr).getValue(); + if (value instanceof Integer) { + return alreadySeen.add((Integer)value); + } + } + return false; + } + /** * Helper class to evaluate constant expressions at compile time This is * also a simplifier used by BinaryNode visits, UnaryNode visits and diff --git a/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java b/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java index 91e0c254..af1a8786 100644 --- a/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java +++ b/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java @@ -709,7 +709,7 @@ final class LocalVariableTypesCalculator extends NodeVisitor{ // Control flow is different for all-integer cases where we dispatch by switch table, and for all other cases // where we do sequential comparison. Note that CaseNode objects act as join points. - final boolean isInteger = switchNode.isInteger(); + final boolean isInteger = switchNode.isUniqueInteger(); final Label breakLabel = switchNode.getBreakLabel(); final boolean hasDefault = switchNode.getDefaultCase() != null; diff --git a/src/jdk/nashorn/internal/codegen/Lower.java b/src/jdk/nashorn/internal/codegen/Lower.java index b52d3984..6f8f3e98 100644 --- a/src/jdk/nashorn/internal/codegen/Lower.java +++ b/src/jdk/nashorn/internal/codegen/Lower.java @@ -275,7 +275,7 @@ final class Lower extends NodeOperatorVisitor implements Lo @Override public Node leaveSwitchNode(final SwitchNode switchNode) { - if(!switchNode.isInteger()) { + if(!switchNode.isUniqueInteger()) { // Wrap it in a block so its internally created tag is restricted in scope addStatementEnclosedInBlock(switchNode); } else { diff --git a/src/jdk/nashorn/internal/ir/SwitchNode.java b/src/jdk/nashorn/internal/ir/SwitchNode.java index 8936764c..ca447587 100644 --- a/src/jdk/nashorn/internal/ir/SwitchNode.java +++ b/src/jdk/nashorn/internal/ir/SwitchNode.java @@ -48,6 +48,10 @@ public final class SwitchNode extends BreakableStatement { /** Switch default index. */ private final int defaultCaseIndex; + /** True if all cases are 32-bit signed integer constants, without repetitions. It's a prerequisite for + * using a tableswitch/lookupswitch when generating code. */ + private final boolean uniqueInteger; + /** Tag symbol. */ private Symbol tag; @@ -66,15 +70,17 @@ public final class SwitchNode extends BreakableStatement { this.expression = expression; this.cases = cases; this.defaultCaseIndex = defaultCase == null ? -1 : cases.indexOf(defaultCase); + this.uniqueInteger = false; } private SwitchNode(final SwitchNode switchNode, final Expression expression, final List cases, - final int defaultCaseIndex, final LocalVariableConversion conversion) { + final int defaultCaseIndex, final LocalVariableConversion conversion, final boolean uniqueInteger) { super(switchNode, conversion); this.expression = expression; this.cases = cases; this.defaultCaseIndex = defaultCaseIndex; - this.tag = switchNode.getTag(); //TODO are symbols inhereted as references? + this.tag = switchNode.getTag(); //TODO are symbols inherited as references? + this.uniqueInteger = uniqueInteger; } @Override @@ -83,7 +89,7 @@ public final class SwitchNode extends BreakableStatement { for (final CaseNode caseNode : cases) { newCases.add(new CaseNode(caseNode, caseNode.getTest(), caseNode.getBody(), caseNode.getLocalVariableConversion())); } - return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, newCases, defaultCaseIndex, conversion)); + return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, newCases, defaultCaseIndex, conversion, uniqueInteger)); } @Override @@ -151,7 +157,7 @@ public final class SwitchNode extends BreakableStatement { if (this.cases == cases) { return this; } - return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion)); + return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger)); } /** @@ -183,7 +189,7 @@ public final class SwitchNode extends BreakableStatement { if (this.expression == expression) { return this; } - return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion)); + return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger)); } /** @@ -205,25 +211,30 @@ public final class SwitchNode extends BreakableStatement { } /** - * Returns true if all cases of this switch statement are 32-bit signed integer constants. - * @return true if all cases of this switch statement are 32-bit signed integer constants. + * Returns true if all cases of this switch statement are 32-bit signed integer constants, without repetitions. + * @return true if all cases of this switch statement are 32-bit signed integer constants, without repetitions. */ - public boolean isInteger() { - for (final CaseNode caseNode : cases) { - final Expression test = caseNode.getTest(); - if (test != null && !isIntegerLiteral(test)) { - return false; - } + public boolean isUniqueInteger() { + return uniqueInteger; + } + + /** + * Sets whether all cases of this switch statement are 32-bit signed integer constants, without repetitions. + * @param lc lexical context + * @param uniqueInteger if true, all cases of this switch statement have been determined to be 32-bit signed + * integer constants, without repetitions. + * @return this switch node, if the value didn't change, or a new switch node with the changed value + */ + public SwitchNode setUniqueInteger(final LexicalContext lc, final boolean uniqueInteger) { + if(this.uniqueInteger == uniqueInteger) { + return this; } - return true; + return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger)); } @Override JoinPredecessor setLocalVariableConversionChanged(final LexicalContext lc, final LocalVariableConversion conversion) { - return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion)); + return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger)); } - private static boolean isIntegerLiteral(final Expression expr) { - return expr instanceof LiteralNode && ((LiteralNode)expr).getValue() instanceof Integer; - } } diff --git a/test/script/basic/JDK-8066225.js b/test/script/basic/JDK-8066225.js new file mode 100644 index 00000000..84d56b81 --- /dev/null +++ b/test/script/basic/JDK-8066225.js @@ -0,0 +1,36 @@ +/* + * 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-8066225: NPE in MethodEmitter with duplicate integer switch cases + * + * @test + * @run + */ + +(function (x){ + switch(x) { + case 44: for (var x in {}) {x}; print("1"); + case 44: print("2"); + } +})(44); diff --git a/test/script/basic/JDK-8066225.js.EXPECTED b/test/script/basic/JDK-8066225.js.EXPECTED new file mode 100644 index 00000000..1191247b --- /dev/null +++ b/test/script/basic/JDK-8066225.js.EXPECTED @@ -0,0 +1,2 @@ +1 +2 -- cgit v1.2.1 From 9771c5c5826ed3c888ff61e5c0a6c44c8de6cc35 Mon Sep 17 00:00:00 2001 From: attila Date: Wed, 10 Dec 2014 11:55:25 +0100 Subject: 8066224: fixes for folding a constant-test ternary operator Reviewed-by: hannesw, lagergren --- .../nashorn/internal/codegen/CodeGenerator.java | 15 ++++++++- .../nashorn/internal/codegen/FoldConstants.java | 2 +- test/script/basic/JDK-8066224.js | 38 ++++++++++++++++++++++ test/script/basic/JDK-8066224.js.EXPECTED | 1 + 4 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 test/script/basic/JDK-8066224.js create mode 100644 test/script/basic/JDK-8066224.js.EXPECTED diff --git a/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/src/jdk/nashorn/internal/codegen/CodeGenerator.java index 3ef1b08a..8d6f980b 100644 --- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java @@ -2021,6 +2021,19 @@ final class CodeGenerator extends NodeOperatorVisitor implements Loggabl public Node leaveTernaryNode(final TernaryNode ternaryNode) { final Node test = ternaryNode.getTest(); if (test instanceof LiteralNode.PrimitiveLiteralNode) { - return ((LiteralNode.PrimitiveLiteralNode)test).isTrue() ? ternaryNode.getTrueExpression() : ternaryNode.getFalseExpression(); + return (((LiteralNode.PrimitiveLiteralNode)test).isTrue() ? ternaryNode.getTrueExpression() : ternaryNode.getFalseExpression()).getExpression(); } return ternaryNode; } diff --git a/test/script/basic/JDK-8066224.js b/test/script/basic/JDK-8066224.js new file mode 100644 index 00000000..b29ba353 --- /dev/null +++ b/test/script/basic/JDK-8066224.js @@ -0,0 +1,38 @@ +/* + * 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-8066224: fixes for folding a constant-test ternary operator + * + * @test + * @run + */ + +print((function(){ + if(false ? 0 : '') { + throw false; + } else if (x = this) { + var x = x; + } + return x === this; +})()) diff --git a/test/script/basic/JDK-8066224.js.EXPECTED b/test/script/basic/JDK-8066224.js.EXPECTED new file mode 100644 index 00000000..27ba77dd --- /dev/null +++ b/test/script/basic/JDK-8066224.js.EXPECTED @@ -0,0 +1 @@ +true -- cgit v1.2.1 From 4dbb99b9367c0faeab8e13923060c14dd58e39b1 Mon Sep 17 00:00:00 2001 From: attila Date: Wed, 10 Dec 2014 12:30:48 +0100 Subject: 8066236: RuntimeNode forces copy creation on visitation Reviewed-by: hannesw, lagergren --- .../codegen/LocalVariableTypesCalculator.java | 7 ++++ src/jdk/nashorn/internal/ir/RuntimeNode.java | 7 +--- test/script/basic/JDK-8066236.js | 46 ++++++++++++++++++++++ test/script/basic/JDK-8066236.js.EXPECTED | 3 ++ 4 files changed, 57 insertions(+), 6 deletions(-) create mode 100644 test/script/basic/JDK-8066236.js create mode 100644 test/script/basic/JDK-8066236.js.EXPECTED diff --git a/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java b/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java index af1a8786..ac3c2934 100644 --- a/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java +++ b/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java @@ -93,6 +93,13 @@ import jdk.nashorn.internal.parser.TokenType; * variable to its widest used type after the join point. That would eliminate some widenings of undefined variables to * object, most notably those used only in loops. We need a full liveness analysis for that. Currently, we can establish * per-type liveness, which eliminates most of unwanted dead widenings. + * NOTE: the way this class is implemented, it actually processes the AST in two passes. The first pass is top-down and + * implemented in {@code enterXxx} methods. This pass does not mutate the AST (except for one occurrence, noted below), + * as being able to find relevant labels for control flow joins is sensitive to their reference identity, and mutated + * label-carrying nodes will create copies of their labels. A second bottom-up pass applying the changes is implemented + * in the separate visitor sitting in {@link #leaveFunctionNode(FunctionNode)}. This visitor will also instantiate new + * instances of the calculator to be run on nested functions (when not lazy compiling). + * */ final class LocalVariableTypesCalculator extends NodeVisitor{ diff --git a/src/jdk/nashorn/internal/ir/RuntimeNode.java b/src/jdk/nashorn/internal/ir/RuntimeNode.java index fd34c3ec..4eca8ff0 100644 --- a/src/jdk/nashorn/internal/ir/RuntimeNode.java +++ b/src/jdk/nashorn/internal/ir/RuntimeNode.java @@ -27,7 +27,6 @@ package jdk.nashorn.internal.ir; import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -468,11 +467,7 @@ public class RuntimeNode extends Expression implements Optimistic { @Override public Node accept(final NodeVisitor visitor) { if (visitor.enterRuntimeNode(this)) { - final List newArgs = new ArrayList<>(); - for (final Node arg : args) { - newArgs.add((Expression)arg.accept(visitor)); - } - return visitor.leaveRuntimeNode(setArgs(newArgs)); + return visitor.leaveRuntimeNode(setArgs(Node.accept(visitor, args))); } return this; diff --git a/test/script/basic/JDK-8066236.js b/test/script/basic/JDK-8066236.js new file mode 100644 index 00000000..760e0f46 --- /dev/null +++ b/test/script/basic/JDK-8066236.js @@ -0,0 +1,46 @@ +/* + * 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-8066236: RuntimeNode forces copy creation on visitation + * + * @test + * @run + */ + +// Note: we're using Function("code") instead of (function(){ code }) so that +// we don't trigger parser API validation in JDK-8008448 tests. The test code +// encapsulated in functions below can't be correctly handled by the parser API +// currently, as it contains parser-generated REFERENCE_ERROR runtime nodes. +try { + Function("L: {this = x;break L}")(); +} catch (e) { + print("threw ReferenceError: " + (e instanceof ReferenceError)); +} +try { + Function("L:with(this--)break L;")(); +} catch (e) { + print("threw ReferenceError: " + (e instanceof ReferenceError)); +} +Function("L:with(Object in Object)break L;")(); +print("SUCCESS"); diff --git a/test/script/basic/JDK-8066236.js.EXPECTED b/test/script/basic/JDK-8066236.js.EXPECTED new file mode 100644 index 00000000..b64a3056 --- /dev/null +++ b/test/script/basic/JDK-8066236.js.EXPECTED @@ -0,0 +1,3 @@ +threw ReferenceError: true +threw ReferenceError: true +SUCCESS -- cgit v1.2.1 From 84a429270270aa1a98e6d5de2a7fab4aeca882d2 Mon Sep 17 00:00:00 2001 From: attila Date: Wed, 10 Dec 2014 18:28:41 +0100 Subject: 8066221: anonymous function statement name clashes with another symbol Reviewed-by: lagergren, sundar --- src/jdk/nashorn/internal/parser/Parser.java | 28 ++++++++++++++++++++++---- test/script/basic/JDK-8066221.js | 31 +++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 4 deletions(-) create mode 100644 test/script/basic/JDK-8066221.js diff --git a/src/jdk/nashorn/internal/parser/Parser.java b/src/jdk/nashorn/internal/parser/Parser.java index 9c6f974d..12ad59e3 100644 --- a/src/jdk/nashorn/internal/parser/Parser.java +++ b/src/jdk/nashorn/internal/parser/Parser.java @@ -2644,7 +2644,7 @@ loop: // name is null, generate anonymous name boolean isAnonymous = false; if (name == null) { - final String tmpName = getDefaultValidFunctionName(functionLine); + final String tmpName = getDefaultValidFunctionName(functionLine, isStatement); name = new IdentNode(functionToken, Token.descPosition(functionToken), tmpName); isAnonymous = true; } @@ -2653,7 +2653,15 @@ loop: final List parameters = formalParameterList(); expect(RPAREN); - FunctionNode functionNode = functionBody(functionToken, name, parameters, FunctionNode.Kind.NORMAL, functionLine); + FunctionNode functionNode; + // Hide the current default name across function boundaries. E.g. "x3 = function x1() { function() {}}" + // If we didn't hide the current default name, then the innermost anonymous function would receive "x3". + hideDefaultName(); + try { + functionNode = functionBody(functionToken, name, parameters, FunctionNode.Kind.NORMAL, functionLine); + } finally { + defaultNames.pop(); + } if (isStatement) { if (topLevel || useBlockScope()) { @@ -2722,9 +2730,17 @@ loop: return functionNode; } - private String getDefaultValidFunctionName(final int functionLine) { + private String getDefaultValidFunctionName(final int functionLine, final boolean isStatement) { final String defaultFunctionName = getDefaultFunctionName(); - return isValidIdentifier(defaultFunctionName) ? defaultFunctionName : ANON_FUNCTION_PREFIX.symbolName() + functionLine; + if (isValidIdentifier(defaultFunctionName)) { + if (isStatement) { + // The name will be used as the LHS of a symbol assignment. We add the anonymous function + // prefix to ensure that it can't clash with another variable. + return ANON_FUNCTION_PREFIX.symbolName() + defaultFunctionName; + } + return defaultFunctionName; + } + return ANON_FUNCTION_PREFIX.symbolName() + functionLine; } private static boolean isValidIdentifier(final String name) { @@ -2758,6 +2774,10 @@ loop: private void markDefaultNameUsed() { defaultNames.pop(); + hideDefaultName(); + } + + private void hideDefaultName() { // Can be any value as long as getDefaultFunctionName doesn't recognize it as something it can extract a value // from. Can't be null defaultNames.push(""); diff --git a/test/script/basic/JDK-8066221.js b/test/script/basic/JDK-8066221.js new file mode 100644 index 00000000..7af4dfa1 --- /dev/null +++ b/test/script/basic/JDK-8066221.js @@ -0,0 +1,31 @@ +/* + * 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-8066221: anonymous function statement name clashes with another symbol + * (compile-only test) + * + * @test + */ + +x3 = function x1(x3) { function (){} }; -- cgit v1.2.1 From 14acd70e6f6b96c5b4ab23d382aa2f9e378354ce Mon Sep 17 00:00:00 2001 From: katleman Date: Wed, 10 Dec 2014 14:36:00 -0800 Subject: Added tag jdk8u40-b18 for changeset 653739706172 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 93cd9b56..357e2b9a 100644 --- a/.hgtags +++ b/.hgtags @@ -337,3 +337,4 @@ d60fbb5343c186abbf92b0259e67efb3b71377b4 jdk8u40-b13 fc37699ddc0ed41d4ab5da821211a6d2648c8883 jdk8u40-b15 e079f3f6d536510b1ab3589b1038d893d78302ac jdk8u40-b16 88e22262fdb26e3154a1034c2413415e97b9a86a jdk8u40-b17 +653739706172ae94e999731a3a9f10f8ce11ffca jdk8u40-b18 -- cgit v1.2.1 From eef5dee65c1939b8f2a8f54835500776a9649d78 Mon Sep 17 00:00:00 2001 From: hannesw Date: Thu, 11 Dec 2014 14:32:26 +0100 Subject: 8066932: __noSuchMethod__ binds to this-object without proper guard Reviewed-by: attila, lagergren --- src/jdk/nashorn/internal/runtime/ScriptObject.java | 9 ++-- test/script/basic/JDK-8066932.js | 48 ++++++++++++++++++++++ 2 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 test/script/basic/JDK-8066932.js diff --git a/src/jdk/nashorn/internal/runtime/ScriptObject.java b/src/jdk/nashorn/internal/runtime/ScriptObject.java index 3f605910..c47497de 100644 --- a/src/jdk/nashorn/internal/runtime/ScriptObject.java +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java @@ -2333,8 +2333,9 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable { } final ScriptFunction func = (ScriptFunction)value; - final Object thiz = scopeCall && func.isStrict() ? ScriptRuntime.UNDEFINED : this; + final Object thiz = scopeCall && func.isStrict() ? UNDEFINED : this; // TODO: It'd be awesome if we could bind "name" without binding "this". + // Since we're binding this we must use an identity guard here. return new GuardedInvocation( MH.dropArguments( MH.constant( @@ -2342,9 +2343,9 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable { func.makeBoundFunction(thiz, new Object[] { name })), 0, Object.class), - NashornGuards.getMapGuard(getMap(), explicitInstanceOfCheck), - (SwitchPoint)null, - explicitInstanceOfCheck ? null : ClassCastException.class); + NashornGuards.combineGuards( + NashornGuards.getIdentityGuard(this), + NashornGuards.getMapGuard(getMap(), true))); } /** diff --git a/test/script/basic/JDK-8066932.js b/test/script/basic/JDK-8066932.js new file mode 100644 index 00000000..6dda1e09 --- /dev/null +++ b/test/script/basic/JDK-8066932.js @@ -0,0 +1,48 @@ +/* + * 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. + */ + +/** + * JDK-8066932: __noSuchMethod__ binds to this-object without proper guard + * + * @test + * @run + */ + +function C(id) { + this.id = id; +} + +C.prototype.__noSuchMethod__ = function(name, args) { + return this.id; +}; + +function test(id) { + var c = new C(id); + return c.nonExistingMethod(); +} + +for (var i = 0; i < 30; i++) { + if (test(i) !== i) { + throw new Error("Wrong result from noSuchMethod in iteration " + i); + } +} -- cgit v1.2.1 From dfc130c9207f0b7617691b75c359c2722d6c56df Mon Sep 17 00:00:00 2001 From: hannesw Date: Thu, 11 Dec 2014 17:46:50 +0100 Subject: 8066669: dust.js performance regression caused by primitive field conversion Reviewed-by: attila, sundar --- .../nashorn/internal/codegen/CodeGenerator.java | 22 ++++---- src/jdk/nashorn/internal/codegen/Lower.java | 31 +++++++++++- .../nashorn/internal/codegen/MethodEmitter.java | 28 ++++++++--- .../nashorn/internal/codegen/SharedScopeCall.java | 2 +- src/jdk/nashorn/internal/ir/AccessNode.java | 10 ++++ src/jdk/nashorn/internal/runtime/ScriptObject.java | 3 +- test/script/basic/JDK-8066669.js | 58 ++++++++++++++++++++++ test/script/basic/JDK-8066669.js.EXPECTED | 13 +++++ test/script/basic/list.js.EXPECTED | 2 +- 9 files changed, 146 insertions(+), 23 deletions(-) create mode 100644 test/script/basic/JDK-8066669.js create mode 100644 test/script/basic/JDK-8066669.js.EXPECTED diff --git a/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/src/jdk/nashorn/internal/codegen/CodeGenerator.java index 8d6f980b..4c132454 100644 --- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java @@ -465,10 +465,10 @@ final class CodeGenerator extends NodeOperatorVisitor implements Lo private final DebugLogger log; + // Conservative pattern to test if element names consist of characters valid for identifiers. + // This matches any non-zero length alphanumeric string including _ and $ and not starting with a digit. + private static Pattern SAFE_PROPERTY_NAME = Pattern.compile("[a-zA-Z_$][\\w$]*"); + /** * Constructor. */ @@ -140,7 +147,7 @@ final class Lower extends NodeOperatorVisitor implements Lo