From 13df33a2ab6fc2369cb8fd535bf644939d30319f Mon Sep 17 00:00:00 2001 From: attila Date: Thu, 17 Oct 2013 12:38:50 +0200 Subject: 8026161: Don't narrow floating-point literals in the lexer Reviewed-by: hannesw, jlaskey --- src/jdk/nashorn/internal/parser/Lexer.java | 13 +-------- src/jdk/nashorn/internal/runtime/JSType.java | 20 -------------- test/script/basic/JDK-8026161.js | 32 ++++++++++++++++++++++ test/script/basic/JDK-8026161.js.EXPECTED | 2 ++ .../nashorn/api/javaaccess/MethodAccessTest.java | 6 ++-- 5 files changed, 38 insertions(+), 35 deletions(-) create mode 100644 test/script/basic/JDK-8026161.js create mode 100644 test/script/basic/JDK-8026161.js.EXPECTED diff --git a/src/jdk/nashorn/internal/parser/Lexer.java b/src/jdk/nashorn/internal/parser/Lexer.java index 09269c6c..a01705dd 100644 --- a/src/jdk/nashorn/internal/parser/Lexer.java +++ b/src/jdk/nashorn/internal/parser/Lexer.java @@ -47,7 +47,6 @@ import static jdk.nashorn.internal.parser.TokenType.XML; import jdk.nashorn.internal.runtime.ECMAErrors; import jdk.nashorn.internal.runtime.ErrorManager; import jdk.nashorn.internal.runtime.JSErrorType; -import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.ParserException; import jdk.nashorn.internal.runtime.Source; import jdk.nashorn.internal.runtime.options.Options; @@ -1053,16 +1052,6 @@ public class Lexer extends Scanner { } } - /** - * Convert string to number. - * - * @param valueString String to convert. - * @return Converted number. - */ - private static Number valueOf(final String valueString) throws NumberFormatException { - return JSType.narrowestIntegerRepresentation(Double.valueOf(valueString)); - } - /** * Scan a number. */ @@ -1623,7 +1612,7 @@ public class Lexer extends Scanner { case HEXADECIMAL: return Lexer.valueOf(source.getString(start + 2, len - 2), 16); // number case FLOATING: - return Lexer.valueOf(source.getString(start, len)); // number + return Double.valueOf(source.getString(start, len)); // number case STRING: return source.getString(start, len); // String case ESCSTRING: diff --git a/src/jdk/nashorn/internal/runtime/JSType.java b/src/jdk/nashorn/internal/runtime/JSType.java index 774295a1..9fbb7297 100644 --- a/src/jdk/nashorn/internal/runtime/JSType.java +++ b/src/jdk/nashorn/internal/runtime/JSType.java @@ -209,26 +209,6 @@ public enum JSType { return (long)number == number; } - /** - * Get the smallest integer representation of a number. Returns an Integer - * for something that is int representable, and Long for something that - * is long representable. If the number needs to be a double, this is an - * identity function - * - * @param number number to check - * - * @return Number instanceof the narrowest possible integer representation for number - */ - public static Number narrowestIntegerRepresentation(final double number) { - if (isRepresentableAsInt(number)) { - return (int)number; - } else if (isRepresentableAsLong(number)) { - return (long)number; - } else { - return number; - } - } - /** * Check whether an object is primitive * diff --git a/test/script/basic/JDK-8026161.js b/test/script/basic/JDK-8026161.js new file mode 100644 index 00000000..49f888b7 --- /dev/null +++ b/test/script/basic/JDK-8026161.js @@ -0,0 +1,32 @@ +/* + * 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-8026161: Don't narrow floating-point literals in the lexer + * + * @test + * @run + */ + +print(new java.awt.Color(1, 1, 1)) // creates Color[r=1,g=1,b=1] +print(new java.awt.Color(1.0, 1.0, 1.0)) // Color[r=255,g=255,b=255] diff --git a/test/script/basic/JDK-8026161.js.EXPECTED b/test/script/basic/JDK-8026161.js.EXPECTED new file mode 100644 index 00000000..c7b00b08 --- /dev/null +++ b/test/script/basic/JDK-8026161.js.EXPECTED @@ -0,0 +1,2 @@ +java.awt.Color[r=1,g=1,b=1] +java.awt.Color[r=255,g=255,b=255] diff --git a/test/src/jdk/nashorn/api/javaaccess/MethodAccessTest.java b/test/src/jdk/nashorn/api/javaaccess/MethodAccessTest.java index 14207b7d..4be66b81 100644 --- a/test/src/jdk/nashorn/api/javaaccess/MethodAccessTest.java +++ b/test/src/jdk/nashorn/api/javaaccess/MethodAccessTest.java @@ -412,7 +412,7 @@ public class MethodAccessTest { @Test public void accessMethodMixedWithEllipsis() throws ScriptException { - assertArrayEquals(new Object[] { "Hello", 10, true, -100500, 80 }, (Object[])e.eval("o.methodMixedWithEllipsis('Hello', 10, true, -100500,80.0);")); + assertArrayEquals(new Object[] { "Hello", 10, true, -100500, 80d }, (Object[])e.eval("o.methodMixedWithEllipsis('Hello', 10, true, -100500,80.0);")); assertArrayEquals(new Object[] { "Nashorn", 15 }, (Object[])e.eval("o.methodMixedWithEllipsis('Nashorn',15);")); } @@ -431,8 +431,8 @@ public class MethodAccessTest { @Test public void accessMethodDoubleVSintOverloaded() throws ScriptException { - assertEquals("int", e.eval("o.overloadedMethodDoubleVSint(0.0);")); - assertEquals("int", e.eval("o.overloadedMethodDoubleVSint(1000.0);")); + assertEquals("double", e.eval("o.overloadedMethodDoubleVSint(0.0);")); + assertEquals("double", e.eval("o.overloadedMethodDoubleVSint(1000.0);")); assertEquals("double", e.eval("o.overloadedMethodDoubleVSint(0.01);")); assertEquals("double", e.eval("o.overloadedMethodDoubleVSint(100.02);")); assertEquals("int", e.eval("o.overloadedMethodDoubleVSint(0);")); -- cgit v1.2.3 From cb755b54b3a57c1aacecd7e112510611a4053aa2 Mon Sep 17 00:00:00 2001 From: hannesw Date: Thu, 17 Oct 2013 17:33:16 +0200 Subject: 8026701: Array.prototype.splice is slow on dense arrays Reviewed-by: lagergren, sundar, jlaskey --- src/jdk/nashorn/internal/objects/NativeArray.java | 47 +++++-- src/jdk/nashorn/internal/runtime/ScriptObject.java | 2 +- .../nashorn/internal/runtime/arrays/ArrayData.java | 18 ++- .../internal/runtime/arrays/IntArrayData.java | 28 ++++ .../internal/runtime/arrays/LongArrayData.java | 30 ++++- .../internal/runtime/arrays/NumberArrayData.java | 28 ++++ .../internal/runtime/arrays/ObjectArrayData.java | 28 ++++ test/examples/array-micro.js | 18 +++ test/script/basic/JDK-8026701.js | 72 ++++++++++ test/script/basic/JDK-8026701.js.EXPECTED | 147 +++++++++++++++++++++ 10 files changed, 403 insertions(+), 15 deletions(-) create mode 100644 test/script/basic/JDK-8026701.js create mode 100644 test/script/basic/JDK-8026701.js.EXPECTED diff --git a/src/jdk/nashorn/internal/objects/NativeArray.java b/src/jdk/nashorn/internal/objects/NativeArray.java index 37b6355b..a6c207a9 100644 --- a/src/jdk/nashorn/internal/objects/NativeArray.java +++ b/src/jdk/nashorn/internal/objects/NativeArray.java @@ -1007,19 +1007,42 @@ public final class NativeArray extends ScriptObject { final long actualStart = relativeStart < 0 ? Math.max(len + relativeStart, 0) : Math.min(relativeStart, len); final long actualDeleteCount = Math.min(Math.max(JSType.toLong(deleteCount), 0), len - actualStart); - final NativeArray array = new NativeArray(actualDeleteCount); + NativeArray returnValue; - for (long k = 0; k < actualDeleteCount; k++) { - final long from = actualStart + k; + if (actualStart <= Integer.MAX_VALUE && actualDeleteCount <= Integer.MAX_VALUE && bulkable(sobj)) { + try { + returnValue = new NativeArray(sobj.getArray().fastSplice((int)actualStart, (int)actualDeleteCount, items.length)); + + // Since this is a dense bulkable array we can use faster defineOwnProperty to copy new elements + int k = (int) actualStart; + for (int i = 0; i < items.length; i++, k++) { + sobj.defineOwnProperty(k, items[i]); + } + } catch (UnsupportedOperationException uoe) { + returnValue = slowSplice(sobj, actualStart, actualDeleteCount, items, len); + } + } else { + returnValue = slowSplice(sobj, actualStart, actualDeleteCount, items, len); + } + + return returnValue; + } + + private static NativeArray slowSplice(final ScriptObject sobj, final long start, final long deleteCount, final Object[] items, final long len) { + + final NativeArray array = new NativeArray(deleteCount); + + for (long k = 0; k < deleteCount; k++) { + final long from = start + k; if (sobj.has(from)) { array.defineOwnProperty(ArrayIndex.getArrayIndex(k), sobj.get(from)); } } - if (items.length < actualDeleteCount) { - for (long k = actualStart; k < (len - actualDeleteCount); k++) { - final long from = k + actualDeleteCount; + if (items.length < deleteCount) { + for (long k = start; k < (len - deleteCount); k++) { + final long from = k + deleteCount; final long to = k + items.length; if (sobj.has(from)) { @@ -1029,12 +1052,12 @@ public final class NativeArray extends ScriptObject { } } - for (long k = len; k > (len - actualDeleteCount + items.length); k--) { + for (long k = len; k > (len - deleteCount + items.length); k--) { sobj.delete(k - 1, true); } - } else if (items.length > actualDeleteCount) { - for (long k = len - actualDeleteCount; k > actualStart; k--) { - final long from = k + actualDeleteCount - 1; + } else if (items.length > deleteCount) { + for (long k = len - deleteCount; k > start; k--) { + final long from = k + deleteCount - 1; final long to = k + items.length - 1; if (sobj.has(from)) { @@ -1046,12 +1069,12 @@ public final class NativeArray extends ScriptObject { } } - long k = actualStart; + long k = start; for (int i = 0; i < items.length; i++, k++) { sobj.set(k, items[i], true); } - final long newLength = len - actualDeleteCount + items.length; + final long newLength = len - deleteCount + items.length; sobj.set("length", newLength, true); return array; diff --git a/src/jdk/nashorn/internal/runtime/ScriptObject.java b/src/jdk/nashorn/internal/runtime/ScriptObject.java index 59b50eb0..66920c14 100644 --- a/src/jdk/nashorn/internal/runtime/ScriptObject.java +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java @@ -594,7 +594,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr * @param index key for property * @param value value to define */ - protected final void defineOwnProperty(final int index, final Object value) { + public final void defineOwnProperty(final int index, final Object value) { assert isValidArrayIndex(index) : "invalid array index"; final long longIndex = ArrayIndex.toLongIndex(index); if (longIndex >= getArray().length()) { diff --git a/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java index ca4adb62..5c0c0476 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java +++ b/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java @@ -461,7 +461,23 @@ public abstract class ArrayData { */ public abstract ArrayData slice(long from, long to); - private static Class widestType(final Object... items) { + /** + * Fast splice operation. This just modifies the array according to the number of + * elements added and deleted but does not insert the added elements. Throws + * {@code UnsupportedOperationException} if fast splice operation is not supported + * for this class or arguments. + * + * @param start start index of splice operation + * @param removed number of removed elements + * @param added number of added elements + * @throws UnsupportedOperationException if fast splice is not supported for the class or arguments. + */ + public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + + static Class widestType(final Object... items) { assert items.length > 0; Class widest = Integer.class; diff --git a/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java index add39912..07ddda2d 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java +++ b/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java @@ -269,4 +269,32 @@ final class IntArrayData extends ArrayData { return new IntArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength); } + + @Override + public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException { + final long oldLength = length(); + final long newLength = oldLength - removed + added; + if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) { + throw new UnsupportedOperationException(); + } + final ArrayData returnValue = (removed == 0) ? + EMPTY_ARRAY : new IntArrayData(Arrays.copyOfRange(array, start, start + removed), removed); + + if (newLength != oldLength) { + final int[] newArray; + + if (newLength > array.length) { + newArray = new int[ArrayData.nextSize((int)newLength)]; + System.arraycopy(array, 0, newArray, 0, start); + } else { + newArray = array; + } + + System.arraycopy(array, start + removed, newArray, start + added, (int)(oldLength - start - removed)); + array = newArray; + setLength(newLength); + } + + return returnValue; + } } diff --git a/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java index 59a63155..4bb96aae 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java +++ b/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java @@ -92,7 +92,7 @@ final class LongArrayData extends ArrayData { @Override public ArrayData convert(final Class type) { - if (type == Long.class) { + if (type == Integer.class || type == Long.class) { return this; } final int length = (int) length(); @@ -238,4 +238,32 @@ final class LongArrayData extends ArrayData { final long newLength = to - start; return new LongArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength); } + + @Override + public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException { + final long oldLength = length(); + final long newLength = oldLength - removed + added; + if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) { + throw new UnsupportedOperationException(); + } + final ArrayData returnValue = (removed == 0) ? + EMPTY_ARRAY : new LongArrayData(Arrays.copyOfRange(array, start, start + removed), removed); + + if (newLength != oldLength) { + final long[] newArray; + + if (newLength > array.length) { + newArray = new long[ArrayData.nextSize((int)newLength)]; + System.arraycopy(array, 0, newArray, 0, start); + } else { + newArray = array; + } + + System.arraycopy(array, start + removed, newArray, start + added, (int)(oldLength - start - removed)); + array = newArray; + setLength(newLength); + } + + return returnValue; + } } diff --git a/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java index 2ecf9d74..8254db63 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java +++ b/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java @@ -218,4 +218,32 @@ final class NumberArrayData extends ArrayData { final long newLength = to - start; return new NumberArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength); } + + @Override + public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException { + final long oldLength = length(); + final long newLength = oldLength - removed + added; + if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) { + throw new UnsupportedOperationException(); + } + final ArrayData returnValue = (removed == 0) ? + EMPTY_ARRAY : new NumberArrayData(Arrays.copyOfRange(array, start, start + removed), removed); + + if (newLength != oldLength) { + final double[] newArray; + + if (newLength > array.length) { + newArray = new double[ArrayData.nextSize((int)newLength)]; + System.arraycopy(array, 0, newArray, 0, start); + } else { + newArray = array; + } + + System.arraycopy(array, start + removed, newArray, start + added, (int)(oldLength - start - removed)); + array = newArray; + setLength(newLength); + } + + return returnValue; + } } diff --git a/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java index 136e6437..a9a1b5b2 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java +++ b/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java @@ -206,4 +206,32 @@ final class ObjectArrayData extends ArrayData { final long newLength = to - start; return new ObjectArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength); } + + @Override + public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException { + final long oldLength = length(); + final long newLength = oldLength - removed + added; + if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) { + throw new UnsupportedOperationException(); + } + final ArrayData returnValue = (removed == 0) ? + EMPTY_ARRAY : new ObjectArrayData(Arrays.copyOfRange(array, start, start + removed), removed); + + if (newLength != oldLength) { + final Object[] newArray; + + if (newLength > array.length) { + newArray = new Object[ArrayData.nextSize((int)newLength)]; + System.arraycopy(array, 0, newArray, 0, start); + } else { + newArray = array; + } + + System.arraycopy(array, start + removed, newArray, start + added, (int)(oldLength - start - removed)); + array = newArray; + setLength(newLength); + } + + return returnValue; + } } diff --git a/test/examples/array-micro.js b/test/examples/array-micro.js index 075e78d8..9bb898f6 100644 --- a/test/examples/array-micro.js +++ b/test/examples/array-micro.js @@ -90,6 +90,24 @@ bench("set", function() { array[6] = 6; }); +bench("push", function() { + var arr = [1, 2, 3]; + arr.push(4); + arr.push(5); + arr.push(6); +}); + +bench("pop", function() { + var arr = [1, 2, 3]; + arr.pop(); + arr.pop(); + arr.pop(); +}); + +bench("splice", function() { + [1, 2, 3].splice(0, 2, 5, 6, 7); +}); + var all = function(e) { return true; }; var none = function(e) { return false; }; diff --git a/test/script/basic/JDK-8026701.js b/test/script/basic/JDK-8026701.js new file mode 100644 index 00000000..90a1739c --- /dev/null +++ b/test/script/basic/JDK-8026701.js @@ -0,0 +1,72 @@ +/* + * 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-8026701: Array.prototype.splice is slow on dense arrays + * + * @test + * @run + */ + +function testSplice(arr, e1, e2, e3) { + try { + print(arr); + print(arr.splice(3, 0, e1, e2, e3)); + print(arr); + print(arr.splice(2, 3)); + print(arr); + print(arr.splice(2, 3, arr[2], arr[3], arr[4])); + print(arr); + print(arr.splice(20, 10)); + print(arr); + print(arr.splice(arr.length, 0, e1, e2, e3)); + print(arr); + print(arr.splice(0, 2, arr[0], arr[1], arr[2], arr[3])); + print(arr); + } catch (error) { + print(error); + } +} + +function convert(array, type) { + return (typeof Java === "undefined") ? array : Java.from(Java.to(array, type)); +} + +// run some splice tests on all dense array implementations +testSplice([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], -1, -2, -3); +testSplice(convert([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], "long[]"), -1, -2, -3); +testSplice(convert([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], "double[]"), -1, -2, -3); +testSplice(["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"], -1, -2, -3); + +// test array conversion during splice +testSplice([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], -1, "-2", "-3"); +testSplice([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], -1, -2.5, -3.5); +testSplice(convert([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], "long[]"), -1, "-2", "-3"); +testSplice(convert([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], "long[]"), -1, -2.5, -3.5); +testSplice(convert([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], "double[]"), -1, "-2", "-3"); + +// test combination with defined elements +testSplice(Object.defineProperty([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 5, {value: 13}), -1, -2, -3); +testSplice(Object.defineProperty([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 5, {value: 13, writable: false}), -1, -2, -3); +testSplice(Object.defineProperty([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 5, {value: 13, configurable: false}), -1, -2, -3); +testSplice(Object.defineProperty([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 5, {value: 13, writable: false, configurable: false}), -1, -2, -3); diff --git a/test/script/basic/JDK-8026701.js.EXPECTED b/test/script/basic/JDK-8026701.js.EXPECTED new file mode 100644 index 00000000..b70bbe25 --- /dev/null +++ b/test/script/basic/JDK-8026701.js.EXPECTED @@ -0,0 +1,147 @@ +1,2,3,4,5,6,7,8,9,10 + +1,2,3,-1,-2,-3,4,5,6,7,8,9,10 +3,-1,-2 +1,2,-3,4,5,6,7,8,9,10 +-3,4,5 +1,2,-3,4,5,6,7,8,9,10 + +1,2,-3,4,5,6,7,8,9,10 + +1,2,-3,4,5,6,7,8,9,10,-1,-2,-3 +1,2 +1,2,-3,4,-3,4,5,6,7,8,9,10,-1,-2,-3 +1,2,3,4,5,6,7,8,9,10 + +1,2,3,-1,-2,-3,4,5,6,7,8,9,10 +3,-1,-2 +1,2,-3,4,5,6,7,8,9,10 +-3,4,5 +1,2,-3,4,5,6,7,8,9,10 + +1,2,-3,4,5,6,7,8,9,10 + +1,2,-3,4,5,6,7,8,9,10,-1,-2,-3 +1,2 +1,2,-3,4,-3,4,5,6,7,8,9,10,-1,-2,-3 +1,2,3,4,5,6,7,8,9,10 + +1,2,3,-1,-2,-3,4,5,6,7,8,9,10 +3,-1,-2 +1,2,-3,4,5,6,7,8,9,10 +-3,4,5 +1,2,-3,4,5,6,7,8,9,10 + +1,2,-3,4,5,6,7,8,9,10 + +1,2,-3,4,5,6,7,8,9,10,-1,-2,-3 +1,2 +1,2,-3,4,-3,4,5,6,7,8,9,10,-1,-2,-3 +1,2,3,4,5,6,7,8,9,10 + +1,2,3,-1,-2,-3,4,5,6,7,8,9,10 +3,-1,-2 +1,2,-3,4,5,6,7,8,9,10 +-3,4,5 +1,2,-3,4,5,6,7,8,9,10 + +1,2,-3,4,5,6,7,8,9,10 + +1,2,-3,4,5,6,7,8,9,10,-1,-2,-3 +1,2 +1,2,-3,4,-3,4,5,6,7,8,9,10,-1,-2,-3 +1,2,3,4,5,6,7,8,9,10 + +1,2,3,-1,-2,-3,4,5,6,7,8,9,10 +3,-1,-2 +1,2,-3,4,5,6,7,8,9,10 +-3,4,5 +1,2,-3,4,5,6,7,8,9,10 + +1,2,-3,4,5,6,7,8,9,10 + +1,2,-3,4,5,6,7,8,9,10,-1,-2,-3 +1,2 +1,2,-3,4,-3,4,5,6,7,8,9,10,-1,-2,-3 +1,2,3,4,5,6,7,8,9,10 + +1,2,3,-1,-2.5,-3.5,4,5,6,7,8,9,10 +3,-1,-2.5 +1,2,-3.5,4,5,6,7,8,9,10 +-3.5,4,5 +1,2,-3.5,4,5,6,7,8,9,10 + +1,2,-3.5,4,5,6,7,8,9,10 + +1,2,-3.5,4,5,6,7,8,9,10,-1,-2.5,-3.5 +1,2 +1,2,-3.5,4,-3.5,4,5,6,7,8,9,10,-1,-2.5,-3.5 +1,2,3,4,5,6,7,8,9,10 + +1,2,3,-1,-2,-3,4,5,6,7,8,9,10 +3,-1,-2 +1,2,-3,4,5,6,7,8,9,10 +-3,4,5 +1,2,-3,4,5,6,7,8,9,10 + +1,2,-3,4,5,6,7,8,9,10 + +1,2,-3,4,5,6,7,8,9,10,-1,-2,-3 +1,2 +1,2,-3,4,-3,4,5,6,7,8,9,10,-1,-2,-3 +1,2,3,4,5,6,7,8,9,10 + +1,2,3,-1,-2.5,-3.5,4,5,6,7,8,9,10 +3,-1,-2.5 +1,2,-3.5,4,5,6,7,8,9,10 +-3.5,4,5 +1,2,-3.5,4,5,6,7,8,9,10 + +1,2,-3.5,4,5,6,7,8,9,10 + +1,2,-3.5,4,5,6,7,8,9,10,-1,-2.5,-3.5 +1,2 +1,2,-3.5,4,-3.5,4,5,6,7,8,9,10,-1,-2.5,-3.5 +1,2,3,4,5,6,7,8,9,10 + +1,2,3,-1,-2,-3,4,5,6,7,8,9,10 +3,-1,-2 +1,2,-3,4,5,6,7,8,9,10 +-3,4,5 +1,2,-3,4,5,6,7,8,9,10 + +1,2,-3,4,5,6,7,8,9,10 + +1,2,-3,4,5,6,7,8,9,10,-1,-2,-3 +1,2 +1,2,-3,4,-3,4,5,6,7,8,9,10,-1,-2,-3 +1,2,3,4,5,13,7,8,9,10 + +1,2,3,-1,-2,-3,4,5,13,7,8,9,10 +3,-1,-2 +1,2,-3,4,5,13,7,8,9,10 +-3,4,5 +1,2,-3,4,5,13,7,8,9,10 + +1,2,-3,4,5,13,7,8,9,10 + +1,2,-3,4,5,13,7,8,9,10,-1,-2,-3 +1,2 +1,2,-3,4,-3,4,5,13,7,8,9,10,-1,-2,-3 +1,2,3,4,5,13,7,8,9,10 +TypeError: "5" is not a writable property of [object Array] +1,2,3,4,5,13,7,8,9,10 + +1,2,3,-1,-2,-3,4,5,13,7,8,9,10 +3,-1,-2 +1,2,-3,4,5,13,7,8,9,10 +-3,4,5 +1,2,-3,4,5,13,7,8,9,10 + +1,2,-3,4,5,13,7,8,9,10 + +1,2,-3,4,5,13,7,8,9,10,-1,-2,-3 +1,2 +1,2,-3,4,-3,4,5,13,7,8,9,10,-1,-2,-3 +1,2,3,4,5,13,7,8,9,10 +TypeError: "5" is not a writable property of [object Array] -- cgit v1.2.3 From 02534a7e814280cec3d0d18c58fcb5b5c5d54297 Mon Sep 17 00:00:00 2001 From: hannesw Date: Fri, 18 Oct 2013 12:50:21 +0200 Subject: 8026805: Array.prototype.length doesn't work as expected Reviewed-by: sundar, lagergren --- src/jdk/nashorn/internal/objects/Global.java | 4 +- src/jdk/nashorn/internal/objects/NativeArray.java | 24 +++++++++-- .../nashorn/internal/objects/NativeJSAdapter.java | 3 +- test/script/basic/JDK-8026805.js | 49 ++++++++++++++++++++++ 4 files changed, 74 insertions(+), 6 deletions(-) create mode 100644 test/script/basic/JDK-8026805.js diff --git a/src/jdk/nashorn/internal/objects/Global.java b/src/jdk/nashorn/internal/objects/Global.java index f2fd08a5..a0df10b0 100644 --- a/src/jdk/nashorn/internal/objects/Global.java +++ b/src/jdk/nashorn/internal/objects/Global.java @@ -1665,9 +1665,9 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { final ScriptObject stringPrototype = getStringPrototype(); stringPrototype.addOwnProperty("length", Attribute.NON_ENUMERABLE_CONSTANT, 0.0); - // add Array.prototype.length + // set isArray flag on Array.prototype final ScriptObject arrayPrototype = getArrayPrototype(); - arrayPrototype.addOwnProperty("length", Attribute.NOT_ENUMERABLE|Attribute.NOT_CONFIGURABLE, 0.0); + arrayPrototype.setIsArray(); this.DEFAULT_DATE = new NativeDate(Double.NaN, this); diff --git a/src/jdk/nashorn/internal/objects/NativeArray.java b/src/jdk/nashorn/internal/objects/NativeArray.java index a6c207a9..a00178f4 100644 --- a/src/jdk/nashorn/internal/objects/NativeArray.java +++ b/src/jdk/nashorn/internal/objects/NativeArray.java @@ -372,9 +372,7 @@ public final class NativeArray extends ScriptObject { */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static Object isArray(final Object self, final Object arg) { - return isArray(arg) || (arg == Global.instance().getArrayPrototype()) - || (arg instanceof NativeRegExpExecResult) - || (arg instanceof JSObject && ((JSObject)arg).isArray()); + return isArray(arg) || (arg instanceof JSObject && ((JSObject)arg).isArray()); } /** @@ -403,6 +401,26 @@ public final class NativeArray extends ScriptObject { } } + /** + * Prototype length getter + * @param self self reference + * @return the length of the object + */ + @Getter(name = "length", where = Where.PROTOTYPE, attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE) + public static Object getProtoLength(final Object self) { + return length(self); // Same as instance getter but we can't make nasgen use the same method for prototype + } + + /** + * Prototype length setter + * @param self self reference + * @param length new length property + */ + @Setter(name = "length", where = Where.PROTOTYPE, attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE) + public static void setProtoLength(final Object self, final Object length) { + length(self, length); // Same as instance setter but we can't make nasgen use the same method for prototype + } + static long validLength(final Object length, final boolean reject) { final double doubleLength = JSType.toNumber(length); if (!Double.isNaN(doubleLength) && JSType.isRepresentableAsLong(doubleLength)) { diff --git a/src/jdk/nashorn/internal/objects/NativeJSAdapter.java b/src/jdk/nashorn/internal/objects/NativeJSAdapter.java index 5b89e2ca..668ca8cd 100644 --- a/src/jdk/nashorn/internal/objects/NativeJSAdapter.java +++ b/src/jdk/nashorn/internal/objects/NativeJSAdapter.java @@ -629,7 +629,8 @@ public final class NativeJSAdapter extends ScriptObject { // to name. Probably not a big deal, but if we can ever make it leaner, it'd be nice. return new GuardedInvocation(MH.dropArguments(MH.constant(Object.class, func.makeBoundFunction(this, new Object[] { name })), 0, Object.class), - adaptee.getMap().getProtoGetSwitchPoint(adaptee.getProto(), __call__), testJSAdaptor(adaptee, null, null, null)); + adaptee.getMap().getProtoGetSwitchPoint(adaptee.getProto(), __call__), + testJSAdaptor(adaptee, null, null, null)); } } throw typeError("no.such.function", desc.getNameToken(2), ScriptRuntime.safeToString(this)); diff --git a/test/script/basic/JDK-8026805.js b/test/script/basic/JDK-8026805.js new file mode 100644 index 00000000..0133a0b6 --- /dev/null +++ b/test/script/basic/JDK-8026805.js @@ -0,0 +1,49 @@ +/* + * 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-8026805: Array.prototype.length doesn't work as expected + * + * @test + * @run + */ + +if (Array.prototype.length !== 0) { + throw new Error("Initial length not 0"); +} + +Array.prototype[3] = 1; + +if (Array.prototype.length !== 4) { + throw new Error("length not updated to 4"); +} + +Array.prototype.length = 0; + +if (Array.prototype.length !== 0) { + throw new Error("length not reset to 0"); +} + +if (3 in Array.prototype) { + throw new Error("array element not deleted"); +} -- cgit v1.2.3 From f5cb6aec799345739793a6ecd59ef17029b583af Mon Sep 17 00:00:00 2001 From: hannesw Date: Fri, 18 Oct 2013 22:42:41 +0200 Subject: 8026858: Array length does not handle defined properties correctly Reviewed-by: jlaskey --- src/jdk/nashorn/internal/codegen/Lower.java | 4 +- src/jdk/nashorn/internal/runtime/PropertyMap.java | 54 +++++++++++++----- src/jdk/nashorn/internal/runtime/ScriptObject.java | 51 +++++++++-------- test/script/basic/JDK-8026858.js | 66 ++++++++++++++++++++++ 4 files changed, 135 insertions(+), 40 deletions(-) create mode 100644 test/script/basic/JDK-8026858.js diff --git a/src/jdk/nashorn/internal/codegen/Lower.java b/src/jdk/nashorn/internal/codegen/Lower.java index 82e9890c..bf6872fe 100644 --- a/src/jdk/nashorn/internal/codegen/Lower.java +++ b/src/jdk/nashorn/internal/codegen/Lower.java @@ -88,12 +88,12 @@ final class Lower extends NodeOperatorVisitor { private static final DebugLogger LOG = new DebugLogger("lower"); // needed only to get unique eval id - private final CodeInstaller installer; + private final CodeInstaller installer; /** * Constructor. */ - Lower(final CodeInstaller installer) { + Lower(final CodeInstaller installer) { super(new BlockLexicalContext() { @Override diff --git a/src/jdk/nashorn/internal/runtime/PropertyMap.java b/src/jdk/nashorn/internal/runtime/PropertyMap.java index e24364d6..03c4978a 100644 --- a/src/jdk/nashorn/internal/runtime/PropertyMap.java +++ b/src/jdk/nashorn/internal/runtime/PropertyMap.java @@ -26,6 +26,8 @@ package jdk.nashorn.internal.runtime; import static jdk.nashorn.internal.runtime.PropertyHashMap.EMPTY_HASHMAP; +import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndex; +import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex; import java.lang.invoke.SwitchPoint; import java.lang.ref.WeakReference; @@ -50,6 +52,8 @@ import java.util.WeakHashMap; public final class PropertyMap implements Iterable, PropertyListener { /** Used for non extensible PropertyMaps, negative logic as the normal case is extensible. See {@link ScriptObject#preventExtensions()} */ public static final int NOT_EXTENSIBLE = 0b0000_0001; + /** Does this map contain valid array keys? */ + public static final int CONTAINS_ARRAY_KEYS = 0b0000_0010; /** This mask is used to preserve certain flags when cloning the PropertyMap. Others should not be copied */ private static final int CLONEABLE_FLAGS_MASK = 0b0000_1111; /** Has a listener been added to this property map. This flag is not copied when cloning a map. See {@link PropertyListener} */ @@ -91,27 +95,22 @@ public final class PropertyMap implements Iterable, PropertyListener { * @param fieldCount Number of fields in use. * @param fieldMaximum Number of fields available. * @param spillLength Number of spill slots used. + * @param containsArrayKeys True if properties contain numeric keys */ - private PropertyMap(final PropertyHashMap properties, final int fieldCount, final int fieldMaximum, final int spillLength) { + private PropertyMap(final PropertyHashMap properties, final int fieldCount, final int fieldMaximum, final int spillLength, final boolean containsArrayKeys) { this.properties = properties; this.fieldCount = fieldCount; this.fieldMaximum = fieldMaximum; this.spillLength = spillLength; + if (containsArrayKeys) { + setContainsArrayKeys(); + } if (Context.DEBUG) { count++; } } - /** - * Constructor. - * - * @param properties A {@link PropertyHashMap} with initial contents. - */ - private PropertyMap(final PropertyHashMap properties) { - this(properties, 0, 0, 0); - } - /** * Cloning constructor. * @@ -152,12 +151,15 @@ public final class PropertyMap implements Iterable, PropertyListener { if (Context.DEBUG) { duplicatedCount++; } - return new PropertyMap(this.properties); + return new PropertyMap(this.properties, 0, 0, 0, containsArrayKeys()); } /** * Public property map allocator. * + *

It is the caller's responsibility to make sure that {@code properties} does not contain + * properties with keys that are valid array indices.

+ * * @param properties Collection of initial properties. * @param fieldCount Number of fields in use. * @param fieldMaximum Number of fields available. @@ -166,11 +168,15 @@ public final class PropertyMap implements Iterable, PropertyListener { */ public static PropertyMap newMap(final Collection properties, final int fieldCount, final int fieldMaximum, final int spillLength) { PropertyHashMap newProperties = EMPTY_HASHMAP.immutableAdd(properties); - return new PropertyMap(newProperties, fieldCount, fieldMaximum, spillLength); + return new PropertyMap(newProperties, fieldCount, fieldMaximum, spillLength, false); } /** * Public property map allocator. Used by nasgen generated code. + * + *

It is the caller's responsibility to make sure that {@code properties} does not contain + * properties with keys that are valid array indices.

+ * * @param properties Collection of initial properties. * @return New {@link PropertyMap}. */ @@ -184,7 +190,7 @@ public final class PropertyMap implements Iterable, PropertyListener { * @return New empty {@link PropertyMap}. */ public static PropertyMap newMap() { - return new PropertyMap(EMPTY_HASHMAP); + return new PropertyMap(EMPTY_HASHMAP, 0, 0, 0, false); } /** @@ -294,6 +300,9 @@ public final class PropertyMap implements Iterable, PropertyListener { if(!property.isSpill()) { newMap.fieldCount = Math.max(newMap.fieldCount, property.getSlot() + 1); } + if (isValidArrayIndex(getArrayIndex(property.getKey()))) { + newMap.setContainsArrayKeys(); + } newMap.spillLength += property.getSpillCount(); } @@ -408,6 +417,9 @@ public final class PropertyMap implements Iterable, PropertyListener { final PropertyMap newMap = new PropertyMap(this, newProperties); for (final Property property : otherProperties) { + if (isValidArrayIndex(getArrayIndex(property.getKey()))) { + newMap.setContainsArrayKeys(); + } newMap.spillLength += property.getSpillCount(); } @@ -699,6 +711,22 @@ public final class PropertyMap implements Iterable, PropertyListener { return new PropertyMapIterator(this); } + /** + * Check if this map contains properties with valid array keys + * + * @return {@code true} if this map contains properties with valid array keys + */ + public final boolean containsArrayKeys() { + return (flags & CONTAINS_ARRAY_KEYS) != 0; + } + + /** + * Flag this object as having array keys in defined properties + */ + private void setContainsArrayKeys() { + flags |= CONTAINS_ARRAY_KEYS; + } + /** * Check whether a {@link PropertyListener} has been added to this map. * diff --git a/src/jdk/nashorn/internal/runtime/ScriptObject.java b/src/jdk/nashorn/internal/runtime/ScriptObject.java index 66920c14..5d1fbcd6 100644 --- a/src/jdk/nashorn/internal/runtime/ScriptObject.java +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java @@ -508,7 +508,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr if (property == null) { // promoting an arrayData value to actual property addOwnProperty(key, propFlags, value); - removeArraySlot(key); + checkIntegerKey(key); } else { // Now set the new flags modifyOwnProperty(property, propFlags); @@ -616,15 +616,6 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr } } - private void removeArraySlot(final String key) { - final int index = getArrayIndex(key); - final ArrayData array = getArray(); - - if (array.has(index)) { - setArray(array.delete(index)); - } - } - /** * Add a new property to the object. * @@ -1203,21 +1194,10 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr * Check if this ScriptObject has array entries. This means that someone has * set values with numeric keys in the object. * - * Note: this can be O(n) up to the array length - * * @return true if array entries exists. */ public boolean hasArrayEntries() { - final ArrayData array = getArray(); - final long length = array.length(); - - for (long i = 0; i < length; i++) { - if (array.has((int)i)) { - return true; - } - } - - return false; + return getArray().length() > 0 || getMap().containsArrayKeys(); } /** @@ -2356,8 +2336,29 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr } if (newLength < arrayLength) { - setArray(getArray().shrink(newLength)); - getArray().setLength(newLength); + long actualLength = newLength; + + // Check for numeric keys in property map and delete them or adjust length, depending on whether + // they're defined as configurable. See ES5 #15.4.5.2 + if (getMap().containsArrayKeys()) { + + for (long l = arrayLength - 1; l >= newLength; l--) { + final FindProperty find = findProperty(JSType.toString(l), false); + + if (find != null) { + + if (find.getProperty().isConfigurable()) { + deleteOwnProperty(find.getProperty()); + } else { + actualLength = l + 1; + break; + } + } + } + } + + setArray(getArray().shrink(actualLength)); + getArray().setLength(actualLength); } } @@ -2680,7 +2681,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr final long oldLength = getArray().length(); final long longIndex = index & JSType.MAX_UINT; - if (!getArray().has(index)) { + if (getMap().containsArrayKeys()) { final String key = JSType.toString(longIndex); final FindProperty find = findProperty(key, true); diff --git a/test/script/basic/JDK-8026858.js b/test/script/basic/JDK-8026858.js new file mode 100644 index 00000000..92562ac1 --- /dev/null +++ b/test/script/basic/JDK-8026858.js @@ -0,0 +1,66 @@ +/* + * 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-8026858: Array length does not handle defined properties correctly + * + * @test + * @run + */ + +var arr = []; + +Object.defineProperty(arr, "3", {value: 1 /* configurable: false */}); + +if (arr[3] != 1) { + throw new Error("arr[3] not defined"); +} + +if (arr.length !== 4) { + throw new Error("Array length not updated to 4"); +} + +Object.defineProperty(arr, "5", {value: 1, configurable: true}); + +if (arr[5] != 1) { + throw new Error("arr[5] not defined"); +} + +if (arr.length !== 6) { + throw new Error("Array length not updated to 4"); +} + +arr.length = 0; + +if (5 in arr) { + throw new Error("configurable element was not deleted"); +} + +if (arr[3] != 1) { + throw new Error("non-configurable element was deleted"); +} + +if (arr.length !== 4) { + throw new Error("Array length not set"); +} + -- cgit v1.2.3 From 9fd64f71e21ec6ea4f381c5cbe1d15454a4553e4 Mon Sep 17 00:00:00 2001 From: kshefov Date: Mon, 21 Oct 2013 13:31:03 +0400 Subject: 8026871: NASHORN TEST: Enable possibility to test Nashorn use of JavaFX canvas. Reviewed-by: jlaskey, sundar --- make/build.xml | 35 +++++ make/project.properties | 27 ++++ test/script/jfx.js | 92 ++++++++++++++ test/script/jfx/flyingimage.js | 83 ++++++++++++ test/script/jfx/flyingimage/flyingimage.png | Bin 0 -> 439 bytes test/script/jfx/flyingimage/golden/linux.png | Bin 0 -> 14754 bytes test/script/jfx/flyingimage/golden/macosx.png | Bin 0 -> 12298 bytes test/script/jfx/flyingimage/golden/windows.png | Bin 0 -> 9849 bytes test/script/jfx/kaleidoscope.js | 162 ++++++++++++++++++++++++ test/script/jfx/kaleidoscope/golden/linux.png | Bin 0 -> 185802 bytes test/script/jfx/kaleidoscope/golden/macosx.png | Bin 0 -> 202995 bytes test/script/jfx/kaleidoscope/golden/windows.png | Bin 0 -> 202946 bytes 12 files changed, 399 insertions(+) create mode 100644 test/script/jfx.js create mode 100644 test/script/jfx/flyingimage.js create mode 100644 test/script/jfx/flyingimage/flyingimage.png create mode 100644 test/script/jfx/flyingimage/golden/linux.png create mode 100644 test/script/jfx/flyingimage/golden/macosx.png create mode 100644 test/script/jfx/flyingimage/golden/windows.png create mode 100644 test/script/jfx/kaleidoscope.js create mode 100644 test/script/jfx/kaleidoscope/golden/linux.png create mode 100644 test/script/jfx/kaleidoscope/golden/macosx.png create mode 100644 test/script/jfx/kaleidoscope/golden/windows.png diff --git a/make/build.xml b/make/build.xml index 01410947..c90cdd6f 100644 --- a/make/build.xml +++ b/make/build.xml @@ -46,6 +46,16 @@ + + + + + + + + + + @@ -351,6 +361,31 @@ grant codeBase "file:/${basedir}/test/script/basic/classloader.js" { + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/make/project.properties b/make/project.properties index 2ad619be..33c94780 100644 --- a/make/project.properties +++ b/make/project.properties @@ -118,6 +118,7 @@ test.trusted.dir=test/script/trusted test.external.dir=test/script/external test262.dir=${test.external.dir}/test262 test262.suite.dir=${test262.dir}/test/suite +testjfx.dir=${test.script.dir}/jfx test-sys-prop.test.dir=${test.dir} test-sys-prop.test.js.roots=${test.basic.dir} ${test.error.dir} ${test.sandbox.dir} ${test.trusted.dir} @@ -208,6 +209,32 @@ test262-test-sys-prop.test.js.framework=\ ${test262.dir}/test/harness/framework.js \ ${test262.dir}/test/harness/sta.js +# testjfx test root +testjfx-test-sys-prop.test.js.roots=${testjfx.dir} + +# execute testjfx tests in shared nashorn context or not? +testjfx-test-sys-prop.test.js.shared.context=false + +# framework root for our script tests +testjfx-test-sys-prop.test.js.framework=\ + -fx \ + ${test.script.dir}${file.separator}jfx.js + +file.reference.jemmyfx.jar=test${file.separator}lib${file.separator}JemmyFX.jar +file.reference.jemmycore.jar=test${file.separator}lib${file.separator}JemmyCore.jar +file.reference.jemmyawtinput.jar=test${file.separator}lib${file.separator}JemmyAWTInput.jar +file.reference.jfxrt.jar=${java.home}${file.separator}lib${file.separator}ext${file.separator}jfxrt.jar +testjfx.run.test.classpath=\ + ${file.reference.jemmyfx.jar}${path.separator}\ + ${file.reference.jemmycore.jar}${path.separator}\ + ${file.reference.jemmyawtinput.jar}${path.separator}\ + ${file.reference.testng.jar}${path.separator}\ + ${nashorn.internal.tests.jar}${path.separator}\ + ${nashorn.api.tests.jar} + +# testjfx VM options for script tests with @fork option +testjfx-test-sys-prop.test.fork.jvm.options=${run.test.jvmargs.main} -Xmx${run.test.xmx} -cp ${testjfx.run.test.classpath} + run.test.classpath=\ ${file.reference.testng.jar}:\ ${nashorn.internal.tests.jar}:\ diff --git a/test/script/jfx.js b/test/script/jfx.js new file mode 100644 index 00000000..26f97873 --- /dev/null +++ b/test/script/jfx.js @@ -0,0 +1,92 @@ +/* + * Copyright (c) 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. + */ + +/** + * Base library for JavaFX canvas run by Nashorn testing. + * @subtest + * + * + */ + +var System = Java.type("java.lang.System"); +var AWTImage = Java.type("org.jemmy.image.AWTImage"); +var PNGDecoder = Java.type("org.jemmy.image.PNGDecoder"); +var JemmyFxRoot = Java.type("org.jemmy.fx.Root"); +var AWTRobotCapturer = Java.type("org.jemmy.image.AWTRobotCapturer"); +var ByWindowType = Java.type("org.jemmy.fx.ByWindowType"); +var Scene = Java.type("javafx.scene.Scene"); +var Stage = Java.type("javafx.stage.Stage"); +var File = Java.type("java.io.File"); +var Timer = Java.type("java.util.Timer"); +var TimerTask = Java.type("java.util.TimerTask"); +var OSInfo = Java.type("sun.awt.OSInfo"); +var OSType = Java.type("sun.awt.OSInfo.OSType"); +var StringBuffer = Java.type("java.lang.StringBuffer"); + +var WAIT = 2000; +var TESTNAME = "test"; +var fsep = System.getProperty("file.separator"); + +function checkImageAndExit() { + var raceTimer = new Timer(true); + var timerTask = new TimerTask() { + run: function run() { + var tmpdir = System.getProperty("java.io.tmpdir"); + var timenow = (new Date()).getTime(); + makeScreenShot(tmpdir + fsep + "screenshot" + timenow +".png"); + var dupImg = isDuplicateImages(tmpdir + fsep + "screenshot" + timenow +".png", __DIR__ + "jfx" + fsep + TESTNAME + fsep + "golden"); + (new File(mpdir + fsep + "screenshot" + timenow +".png")).delete(); + if (!dupImg) System.err.println("ERROR: screenshot does not match golden image"); + exit(0); + } + }; + raceTimer.schedule(timerTask, WAIT); +} + +function makeScreenShot(shootToImg) { + JemmyFxRoot.ROOT.getEnvironment().setImageCapturer(new AWTRobotCapturer()); + var wrap = JemmyFxRoot.ROOT.lookup(new ByWindowType($STAGE.class)).lookup(Scene.class).wrap(0); + var imageJemmy = wrap.getScreenImage(); + imageJemmy.save(shootToImg); +} + +function isDuplicateImages(file1, file2) { + var f1 = new File(file1); + var f2; + var sb = new StringBuffer(file2); + if (OSInfo.getOSType() == OSType.WINDOWS) { + f2 = new File(sb.append(fsep + "windows.png").toString()); + } else if (OSInfo.getOSType() == OSType.LINUX) { + f2 = new File(sb.append(fsep + "linux.png").toString()); + } else if (OSInfo.getOSType() == OSType.MACOSX) { + f2 = new File(sb.append(fsep + "macosx.png").toString()); + } + print(f1.getAbsolutePath()); + print(f2.getAbsolutePath()); + if (f1.exists() && f2.exists()) { + var image1 = new AWTImage(PNGDecoder.decode(f1.getAbsolutePath())); + var image2 = new AWTImage(PNGDecoder.decode(f2.getAbsolutePath())); + return image1.compareTo(image2) == null ? true : false; + } + return false; +} diff --git a/test/script/jfx/flyingimage.js b/test/script/jfx/flyingimage.js new file mode 100644 index 00000000..4cf3f7fc --- /dev/null +++ b/test/script/jfx/flyingimage.js @@ -0,0 +1,83 @@ +/* + * Copyright (c) 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. + */ + +/** + * Testing JavaFX canvas run by Nashorn. + * + * @test/nocompare + * @run + * @fork + */ + +TESTNAME = "flyingimage"; + +var Image = Java.type("javafx.scene.image.Image"); +var Color = Java.type("javafx.scene.paint.Color"); +var Canvas = Java.type("javafx.scene.canvas.Canvas"); +var BorderPane = Java.type("javafx.scene.layout.BorderPane"); +var StackPane = Java.type("javafx.scene.layout.StackPane"); +var Font = Java.type("javafx.scene.text.Font"); +var FontSmoothingType = Java.type("javafx.scene.text.FontSmoothingType"); +var Text = Java.type("javafx.scene.text.Text"); + +var WIDTH = 800; +var HEIGHT = 600; +var canvas = new Canvas(WIDTH, HEIGHT); +function fileToURL(file) { + return new File(file).toURI().toURL().toExternalForm(); +} +var imageUrl = fileToURL(__DIR__ + "flyingimage/flyingimage.png"); +var img = new Image(imageUrl); +var font = new Font("Arial", 16); +var t = 0; +var isFrameRendered = false; +function renderFrame() { + var gc = canvas.graphicsContext2D; + gc.setFill(Color.web("#cccccc")); + gc.fillRect(0, 0, WIDTH, HEIGHT); + gc.setStroke(Color.web("#000000")); + gc.setLineWidth(1); + gc.strokeRect(5, 5, WIDTH - 10, HEIGHT - 10); + var c = 200; + var msc= 0.5 * HEIGHT / img.height; + var sp0 = 0.003; + for (var h = 0; h < c; h++, t++) { + gc.setTransform(1, 0, 0, 1, 0, 0); + var yh = h / (c - 1); + gc.translate((0.5 + Math.sin(t * sp0 + h * 0.1) / 3) * WIDTH, 25 + (HEIGHT * 3 / 4 - 40) * (yh * yh)); + var sc = 30 / img.height + msc * yh * yh; + gc.rotate(90 * Math.sin(t * sp0 + h * 0.1 + Math.PI)); + gc.scale(sc, sc); + gc.drawImage(img, -img.width / 2, -img.height / 2); + } + gc.setTransform(1, 0, 0, 1, 0, 0); + isFrameRendered = true; +} +var stack = new StackPane(); +var pane = new BorderPane(); + +pane.setCenter(canvas); +stack.getChildren().add(pane); +$STAGE.scene = new Scene(stack); +renderFrame(); +checkImageAndExit(); diff --git a/test/script/jfx/flyingimage/flyingimage.png b/test/script/jfx/flyingimage/flyingimage.png new file mode 100644 index 00000000..ecd98a14 Binary files /dev/null and b/test/script/jfx/flyingimage/flyingimage.png differ diff --git a/test/script/jfx/flyingimage/golden/linux.png b/test/script/jfx/flyingimage/golden/linux.png new file mode 100644 index 00000000..4f678853 Binary files /dev/null and b/test/script/jfx/flyingimage/golden/linux.png differ diff --git a/test/script/jfx/flyingimage/golden/macosx.png b/test/script/jfx/flyingimage/golden/macosx.png new file mode 100644 index 00000000..cb153219 Binary files /dev/null and b/test/script/jfx/flyingimage/golden/macosx.png differ diff --git a/test/script/jfx/flyingimage/golden/windows.png b/test/script/jfx/flyingimage/golden/windows.png new file mode 100644 index 00000000..e3897148 Binary files /dev/null and b/test/script/jfx/flyingimage/golden/windows.png differ diff --git a/test/script/jfx/kaleidoscope.js b/test/script/jfx/kaleidoscope.js new file mode 100644 index 00000000..a932c517 --- /dev/null +++ b/test/script/jfx/kaleidoscope.js @@ -0,0 +1,162 @@ +/* + * Copyright (c) 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. + */ + +/** + * Testing JavaFX canvas run by Nashorn. + * + * @test/nocompare + * @run + * @fork + */ + +TESTNAME = "kaleidoscope"; +WAIT = 4000; + +var Paint = Java.type("javafx.scene.paint.Paint"); +var Canvas = Java.type("javafx.scene.canvas.Canvas"); +var BorderPane = Java.type("javafx.scene.layout.BorderPane"); +var StackPane = Java.type("javafx.scene.layout.StackPane"); +var StrokeLineCap = Java.type("javafx.scene.shape.StrokeLineCap"); + +var WIDTH = 800; +var HEIGHT = 600; +var canvas = new Canvas(WIDTH, HEIGHT); +var context = canvas.graphicsContext2D; + +var x,y; +var p_x,p_y; +var a=0; +var b=0; +var angle=Math.PI/180*8; +var color=0; +var limit1=Math.PI*1.5; +var limit2=Math.PI*1.79; +var c=new Array(6); +var d=new Array(6); +var r,e; +var fade; +var prv_x,prv_y,prv_x2,prv_y2; + +function renderFrame() { + a=0.2*angle; + b=0.7*angle; + r=0; + fade=32; + for(var i=0;i<6;i++) + { + c[i]=1.0/(i+1)/2; + d[i]=1.0/(i+1)/2; + } + radius=Math.round((WIDTH+HEIGHT)/8); + e=radius*0.2; + p_x=Math.round(WIDTH/2); + p_y=Math.round(HEIGHT/2); + x=(radius*c[0])*Math.cos(a*d[1])+(radius*c[2])*Math.sin(a*d[3])+(radius*c[4])*Math.sin(a*d[5]); + y=(radius*c[5])*Math.sin(a*d[4])+(radius*c[3])*Math.cos(a*d[2])+(radius*c[1])*Math.cos(a*d[0]); + for (i = 0; i < 800; i++) { + anim(); + } +} + +function anim() { + var a1=Math.cos(a*2); + var a2=Math.cos(a*4); + var a3=Math.cos(a); + var a4=Math.sin(a); + if(b>limit1&&b Date: Tue, 22 Oct 2013 14:27:52 +0530 Subject: 8027016: Array.prototype.indexOf should return -1 when array is of length zero Reviewed-by: lagergren, attila --- src/jdk/nashorn/internal/objects/NativeArray.java | 8 +++-- test/script/basic/JDK-8027016.js | 42 +++++++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 test/script/basic/JDK-8027016.js diff --git a/src/jdk/nashorn/internal/objects/NativeArray.java b/src/jdk/nashorn/internal/objects/NativeArray.java index a00178f4..67b9f1f1 100644 --- a/src/jdk/nashorn/internal/objects/NativeArray.java +++ b/src/jdk/nashorn/internal/objects/NativeArray.java @@ -1163,12 +1163,16 @@ public final class NativeArray extends ScriptObject { try { final ScriptObject sobj = (ScriptObject)Global.toObject(self); final long len = JSType.toUint32(sobj.getLength()); - final long n = JSType.toLong(fromIndex); + if (len == 0) { + return -1; + } - if (len == 0 || n >= len) { + final long n = JSType.toLong(fromIndex); + if (n >= len) { return -1; } + for (long k = Math.max(0, (n < 0) ? (len - Math.abs(n)) : n); k < len; k++) { if (sobj.has(k)) { if (ScriptRuntime.EQ_STRICT(sobj.get(k), searchElement)) { diff --git a/test/script/basic/JDK-8027016.js b/test/script/basic/JDK-8027016.js new file mode 100644 index 00000000..f84050fb --- /dev/null +++ b/test/script/basic/JDK-8027016.js @@ -0,0 +1,42 @@ +/* + * 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-8027016: Array.prototype.indexOf should return -1 when array is of length zero + * + * @test + * @run + */ + +var res = [].indexOf(null, {valueOf:function(){throw "not reached"}}); +if (res != -1) { + fail("expected -1 on indexOf on empty array"); +} + +// add index beyond length check as well + +res = [].indexOf(null, 1); +if (res != -1) { + fail("expected -1 on indexOf on empty array"); +} + -- cgit v1.2.3 From e309e80f0b70000bc961bab8523ece234a7db290 Mon Sep 17 00:00:00 2001 From: hannesw Date: Tue, 22 Oct 2013 11:12:36 +0200 Subject: 8027015: AutoCloseable no longer implements @FunctionalInterface Reviewed-by: lagergren, sundar --- test/script/basic/NASHORN-397.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/test/script/basic/NASHORN-397.js b/test/script/basic/NASHORN-397.js index e9484bc0..63e7b3ac 100644 --- a/test/script/basic/NASHORN-397.js +++ b/test/script/basic/NASHORN-397.js @@ -35,11 +35,8 @@ if (typeof (5).x !== 'number') { fail("typeof(5).x is not 'number'"); } -// It is function because PrintStream implements Closeable, which is -// marked with @FunctionalInterface. Yes, this means calling a stream -// like "stream()" closes it. -if (typeof (java.lang.System.out) != 'function') { - fail("typeof java.lang.System.out is not 'object'"); +if (typeof (java.net.Proxy.NO_PROXY) != 'object') { + fail("typeof java.net.Proxy.NO_PROXY is not 'object'"); } if (typeof (java.lang.Math.PI) != 'number') { -- cgit v1.2.3 From ff38b1cb449eb2e8c2c3c6fadea4b07c2ee039f6 Mon Sep 17 00:00:00 2001 From: hannesw Date: Tue, 22 Oct 2013 11:31:03 +0200 Subject: 8026955: for-in should convert primitive values to object Reviewed-by: jlaskey, lagergren --- .../nashorn/internal/runtime/ScriptRuntime.java | 11 +++++ test/script/basic/JDK-8026955.js | 51 ++++++++++++++++++++++ test/script/basic/JDK-8026955.js.EXPECTED | 22 ++++++++++ 3 files changed, 84 insertions(+) create mode 100644 test/script/basic/JDK-8026955.js create mode 100644 test/script/basic/JDK-8026955.js.EXPECTED diff --git a/src/jdk/nashorn/internal/runtime/ScriptRuntime.java b/src/jdk/nashorn/internal/runtime/ScriptRuntime.java index c9b40512..d9705676 100644 --- a/src/jdk/nashorn/internal/runtime/ScriptRuntime.java +++ b/src/jdk/nashorn/internal/runtime/ScriptRuntime.java @@ -47,6 +47,7 @@ import jdk.nashorn.api.scripting.JSObject; import jdk.nashorn.api.scripting.ScriptObjectMirror; import jdk.nashorn.internal.codegen.CompilerConstants.Call; import jdk.nashorn.internal.ir.debug.JSONWriter; +import jdk.nashorn.internal.objects.Global; import jdk.nashorn.internal.parser.Lexer; import jdk.nashorn.internal.runtime.linker.Bootstrap; @@ -258,6 +259,11 @@ public final class ScriptRuntime { return ((Map)obj).keySet().iterator(); } + final Object wrapped = Global.instance().wrapAsObject(obj); + if (wrapped instanceof ScriptObject) { + return ((ScriptObject)wrapped).propertyIterator(); + } + return Collections.emptyIterator(); } @@ -336,6 +342,11 @@ public final class ScriptRuntime { return ((Iterable)obj).iterator(); } + final Object wrapped = Global.instance().wrapAsObject(obj); + if (wrapped instanceof ScriptObject) { + return ((ScriptObject)wrapped).valueIterator(); + } + return Collections.emptyIterator(); } diff --git a/test/script/basic/JDK-8026955.js b/test/script/basic/JDK-8026955.js new file mode 100644 index 00000000..a54e3d96 --- /dev/null +++ b/test/script/basic/JDK-8026955.js @@ -0,0 +1,51 @@ +/* + * 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-8026955: for-in should convert primitive values to object + * + * @test + * @run + */ + +Object.prototype[4] = "world"; +String.prototype[3] = "hello"; +Number.prototype[3] = "hello"; +Boolean.prototype[3] = "hello"; + +function testForIn(x) { + for (var i in x) { + print(i, x[i]); + } + for each (var i in x) { + print(i); + } +} + +testForIn("abc"); +testForIn(false); +testForIn(3); +testForIn(null); +testForIn(); +testForIn(String.prototype); + diff --git a/test/script/basic/JDK-8026955.js.EXPECTED b/test/script/basic/JDK-8026955.js.EXPECTED new file mode 100644 index 00000000..3852d5ab --- /dev/null +++ b/test/script/basic/JDK-8026955.js.EXPECTED @@ -0,0 +1,22 @@ +0 a +1 b +2 c +3 hello +4 world +a +b +c +hello +world +3 hello +4 world +hello +world +3 hello +4 world +hello +world +3 hello +4 world +hello +world -- cgit v1.2.3 From f9dd2955a99e704efdd3de787946f3bdf03ad0ed Mon Sep 17 00:00:00 2001 From: sundar Date: Tue, 22 Oct 2013 17:38:12 +0530 Subject: 8027024: String.prototype.charAt and charCodeAt do not evaluate 'self' and 'pos' arguments in right order Reviewed-by: jlaskey, attila, lagergren --- src/jdk/nashorn/internal/objects/NativeString.java | 14 ++++-- src/overview.html | 2 +- test/script/basic/JDK-8027024.js | 58 ++++++++++++++++++++++ test/script/basic/JDK-8027024.js.EXPECTED | 4 ++ 4 files changed, 73 insertions(+), 5 deletions(-) create mode 100644 test/script/basic/JDK-8027024.js create mode 100644 test/script/basic/JDK-8027024.js.EXPECTED diff --git a/src/jdk/nashorn/internal/objects/NativeString.java b/src/jdk/nashorn/internal/objects/NativeString.java index 1694b3da..9fd59191 100644 --- a/src/jdk/nashorn/internal/objects/NativeString.java +++ b/src/jdk/nashorn/internal/objects/NativeString.java @@ -505,7 +505,7 @@ public final class NativeString extends ScriptObject { */ @Function(attributes = Attribute.NOT_ENUMERABLE) public static Object charAt(final Object self, final Object pos) { - return charAt(self, JSType.toInteger(pos)); + return charAtImpl(checkObjectToString(self), JSType.toInteger(pos)); } /** @@ -527,7 +527,10 @@ public final class NativeString extends ScriptObject { */ @SpecializedFunction public static String charAt(final Object self, final int pos) { - final String str = checkObjectToString(self); + return charAtImpl(checkObjectToString(self), pos); + } + + private static String charAtImpl(final String str, final int pos) { return (pos < 0 || pos >= str.length()) ? "" : String.valueOf(str.charAt(pos)); } @@ -539,7 +542,7 @@ public final class NativeString extends ScriptObject { */ @Function(attributes = Attribute.NOT_ENUMERABLE) public static Object charCodeAt(final Object self, final Object pos) { - return charCodeAt(self, JSType.toInteger(pos)); + return charCodeAtImpl(checkObjectToString(self), JSType.toInteger(pos)); } /** @@ -561,7 +564,10 @@ public final class NativeString extends ScriptObject { */ @SpecializedFunction public static double charCodeAt(final Object self, final int pos) { - final String str = checkObjectToString(self); + return charCodeAtImpl(checkObjectToString(self), pos); + } + + private static double charCodeAtImpl(final String str, final int pos) { return (pos < 0 || pos >= str.length()) ? Double.NaN : str.charAt(pos); } diff --git a/src/overview.html b/src/overview.html index 5418854f..e242a5b9 100644 --- a/src/overview.html +++ b/src/overview.html @@ -108,6 +108,6 @@ identity and doesn't carry i.e. static members. Again, see the link for {@code N

Other non-standard built-in objects

In addition to {@code Java}, Nashorn also exposes some other non-standard built-in objects: {@code JSAdapter}, -{@code JavaImporter}, +{@code JavaImporter}, {@code Packages}. diff --git a/test/script/basic/JDK-8027024.js b/test/script/basic/JDK-8027024.js new file mode 100644 index 00000000..890c6917 --- /dev/null +++ b/test/script/basic/JDK-8027024.js @@ -0,0 +1,58 @@ +/* + * 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-8027024: String.prototype.charAt and charCodeAt do not evaluate 'self' and 'pos' arguments in right order + * + * @test + * @run + */ + + +String.prototype.charAt.call( + { + toString: function() { + print("charAt.self.toString"); + } + }, + + { + valueOf: function() { + print("charAt.pos.valueOf"); + } + } +); + +String.prototype.charCodeAt.call( + { + toString: function() { + print("charCodeAt.self.toString"); + } + }, + + { + valueOf: function() { + print("charCodeAt.pos.valueOf"); + } + } +); diff --git a/test/script/basic/JDK-8027024.js.EXPECTED b/test/script/basic/JDK-8027024.js.EXPECTED new file mode 100644 index 00000000..9793e73a --- /dev/null +++ b/test/script/basic/JDK-8027024.js.EXPECTED @@ -0,0 +1,4 @@ +charAt.self.toString +charAt.pos.valueOf +charCodeAt.self.toString +charCodeAt.pos.valueOf -- cgit v1.2.3 From 70b5fdcdfa7f6baed60964817e41b83144b04765 Mon Sep 17 00:00:00 2001 From: attila Date: Tue, 22 Oct 2013 16:43:27 +0200 Subject: 8027031: complete merging of loads and converts Reviewed-by: jlaskey, lagergren --- .../nashorn/api/scripting/ScriptObjectMirror.java | 42 +++++++++++++ .../nashorn/internal/codegen/BranchOptimizer.java | 9 +-- .../nashorn/internal/codegen/CodeGenerator.java | 26 ++++---- .../internal/codegen/SpillObjectCreator.java | 3 +- src/jdk/nashorn/internal/runtime/JSType.java | 45 ++++++++++++-- .../internal/runtime/linker/JSObjectLinker.java | 70 ++++++++++++++++------ 6 files changed, 151 insertions(+), 44 deletions(-) diff --git a/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java b/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java index 3a27d23e..f23a4e9d 100644 --- a/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java +++ b/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java @@ -43,6 +43,7 @@ import java.util.concurrent.Callable; import javax.script.Bindings; import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.GlobalObject; +import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.ScriptRuntime; @@ -705,4 +706,45 @@ public final class ScriptObjectMirror extends JSObject implements Bindings { } } } + + /** + * JavaScript compliant Object to int32 conversion + * See ECMA 9.5 ToInt32 + * + * @return this object's int32 representation + */ + public int toInt32() { + return inGlobal(new Callable() { + @Override public Integer call() { + return JSType.toInt32(sobj); + } + }); + } + + /** + * JavaScript compliant Object to int64 conversion + * + * @return this object's int64 representation + */ + public long toInt64() { + return inGlobal(new Callable() { + @Override public Long call() { + return JSType.toInt64(sobj); + } + }); + } + + /** + * JavaScript compliant conversion of Object to number + * See ECMA 9.3 ToNumber + * + * @return this object's number representation + */ + public double toNumber() { + return inGlobal(new Callable() { + @Override public Double call() { + return JSType.toNumber(sobj); + } + }); + } } diff --git a/src/jdk/nashorn/internal/codegen/BranchOptimizer.java b/src/jdk/nashorn/internal/codegen/BranchOptimizer.java index bf01de0f..ad9bdb07 100644 --- a/src/jdk/nashorn/internal/codegen/BranchOptimizer.java +++ b/src/jdk/nashorn/internal/codegen/BranchOptimizer.java @@ -72,8 +72,7 @@ final class BranchOptimizer { } // convert to boolean - codegen.load(unaryNode); - method.convert(Type.BOOLEAN); + codegen.load(unaryNode, Type.BOOLEAN); if (state) { method.ifne(label); } else { @@ -146,8 +145,7 @@ final class BranchOptimizer { break; } - codegen.load(binaryNode); - method.convert(Type.BOOLEAN); + codegen.load(binaryNode, Type.BOOLEAN); if (state) { method.ifne(label); } else { @@ -169,8 +167,7 @@ final class BranchOptimizer { } } - codegen.load(node); - method.convert(Type.BOOLEAN); + codegen.load(node, Type.BOOLEAN); if (state) { method.ifne(label); } else { diff --git a/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/src/jdk/nashorn/internal/codegen/CodeGenerator.java index e7093572..7dd12de1 100644 --- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java @@ -402,7 +402,7 @@ final class CodeGenerator extends NodeOperatorVisitor= argCount) { + load(arg); method.pop(); // we had to load the arg for its side effects } else if (params != null) { - method.convert(params[n]); + load(arg, params[n]); + } else { + load(arg); } n++; } @@ -1277,7 +1279,7 @@ final class CodeGenerator extends NodeOperatorVisitor args = callNode.getArgs(); // Load function reference. - load(callNode.getFunction()).convert(Type.OBJECT); // must detect type error + load(callNode.getFunction(), Type.OBJECT); // must detect type error method.dynamicNew(1 + loadArgs(args), getCallSiteFlags()); method.store(unaryNode.getSymbol()); @@ -2383,7 +2385,7 @@ final class CodeGenerator extends NodeOperatorVisitor hint) { - if (!(obj instanceof ScriptObject)) { - return obj; - } + return obj instanceof ScriptObject ? toPrimitive((ScriptObject)obj, hint) : obj; + } - final ScriptObject sobj = (ScriptObject)obj; - final Object result = sobj.getDefaultValue(hint); + private static Object toPrimitive(final ScriptObject sobj, final Class hint) { + final Object result = sobj.getDefaultValue(hint); if (!isPrimitive(result)) { throw typeError("bad.default.value", result.toString()); @@ -475,6 +474,19 @@ public enum JSType { return toNumberGeneric(obj); } + + /** + * JavaScript compliant conversion of Object to number + * See ECMA 9.3 ToNumber + * + * @param obj an object + * + * @return a number + */ + public static double toNumber(final ScriptObject obj) { + return toNumber(toPrimitive(obj, Number.class)); + } + /** * Digit representation for a character * @@ -618,6 +630,17 @@ public enum JSType { return toInt32(toNumber(obj)); } + /** + * JavaScript compliant Object to int32 conversion + * See ECMA 9.5 ToInt32 + * + * @param obj an object + * @return an int32 + */ + public static int toInt32(final ScriptObject obj) { + return toInt32(toNumber(obj)); + } + /** * JavaScript compliant long to int32 conversion * @@ -648,6 +671,16 @@ public enum JSType { return toInt64(toNumber(obj)); } + /** + * JavaScript compliant Object to int64 conversion + * + * @param obj an object + * @return an int64 + */ + public static long toInt64(final ScriptObject obj) { + return toInt64(toNumber(obj)); + } + /** * JavaScript compliant number to int64 conversion * @@ -1028,7 +1061,7 @@ public enum JSType { } if (obj instanceof ScriptObject) { - return toNumber(toPrimitive(obj, Number.class)); + return toNumber((ScriptObject)obj); } return Double.NaN; diff --git a/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java b/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java index f9491dec..cd59399f 100644 --- a/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java +++ b/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java @@ -25,25 +25,29 @@ package jdk.nashorn.internal.runtime.linker; -import jdk.nashorn.internal.lookup.MethodHandleFunctionality; -import jdk.nashorn.internal.lookup.MethodHandleFactory; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; +import java.util.HashMap; +import java.util.Map; import jdk.internal.dynalink.CallSiteDescriptor; import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.GuardingTypeConverterFactory; import jdk.internal.dynalink.linker.LinkRequest; import jdk.internal.dynalink.linker.LinkerServices; import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; import jdk.internal.dynalink.support.CallSiteDescriptorFactory; -import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.api.scripting.JSObject; +import jdk.nashorn.api.scripting.ScriptObjectMirror; +import jdk.nashorn.internal.lookup.MethodHandleFactory; +import jdk.nashorn.internal.lookup.MethodHandleFunctionality; +import jdk.nashorn.internal.runtime.JSType; /** * A Dynalink linker to handle web browser built-in JS (DOM etc.) objects as well * as ScriptObjects from other Nashorn contexts. */ -final class JSObjectLinker implements TypeBasedGuardingDynamicLinker { +final class JSObjectLinker implements TypeBasedGuardingDynamicLinker, GuardingTypeConverterFactory { @Override public boolean canLinkType(final Class type) { return canLinkTypeStatic(type); @@ -75,6 +79,21 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker { return Bootstrap.asType(inv, linkerServices, desc); } + @Override + public GuardedInvocation convertToType(final Class sourceType, final Class targetType) throws Exception { + if(!sourceType.isAssignableFrom(ScriptObjectMirror.class)) { + return null; + } + + final MethodHandle converter = MIRROR_CONVERTERS.get(targetType); + if(converter == null) { + return null; + } + + return new GuardedInvocation(converter, sourceType == ScriptObjectMirror.class ? null : IS_MIRROR_GUARD).asType(MethodType.methodType(targetType, sourceType)); + } + + private static GuardedInvocation lookup(final CallSiteDescriptor desc) { final String operator = CallSiteDescriptorFactory.tokenizeOperators(desc).get(0); final int c = desc.getNameTokenCount(); @@ -87,9 +106,9 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker { case "setElem": return c > 2 ? findSetMethod(desc) : findSetIndexMethod(); case "call": - return findCallMethod(desc, operator); + return findCallMethod(desc); case "callMethod": - return findCallMethodMethod(desc, operator); + return findCallMethodMethod(desc); case "new": return findNewMethod(desc); default: @@ -115,14 +134,14 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker { return new GuardedInvocation(JSOBJECTLINKER_PUT, null, IS_JSOBJECT_GUARD); } - private static GuardedInvocation findCallMethodMethod(final CallSiteDescriptor desc, final String operator) { + private static GuardedInvocation findCallMethodMethod(final CallSiteDescriptor desc) { final String methodName = desc.getNameToken(2); MethodHandle func = MH.insertArguments(JSOBJECT_CALLMEMBER, 1, methodName); func = MH.asCollector(func, Object[].class, desc.getMethodType().parameterCount() - 1); return new GuardedInvocation(func, null, IS_JSOBJECT_GUARD); } - private static GuardedInvocation findCallMethod(final CallSiteDescriptor desc, final String operator) { + private static GuardedInvocation findCallMethod(final CallSiteDescriptor desc) { final MethodHandle func = MH.asCollector(JSOBJECT_CALL, Object[].class, desc.getMethodType().parameterCount() - 2); return new GuardedInvocation(func, null, IS_JSOBJECT_GUARD); } @@ -137,6 +156,11 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker { return self instanceof JSObject; } + @SuppressWarnings("unused") + private static boolean isScriptObjectMirror(final Object self) { + return self instanceof ScriptObjectMirror; + } + @SuppressWarnings("unused") private static Object get(final Object jsobj, final Object key) { if (key instanceof Integer) { @@ -172,6 +196,7 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker { // method handles of the current class private static final MethodHandle IS_JSOBJECT_GUARD = findOwnMH("isJSObject", boolean.class, Object.class); + private static final MethodHandle IS_MIRROR_GUARD = findOwnMH("isScriptObjectMirror", boolean.class, Object.class); private static final MethodHandle JSOBJECTLINKER_GET = findOwnMH("get", Object.class, Object.class, Object.class); private static final MethodHandle JSOBJECTLINKER_PUT = findOwnMH("put", Void.TYPE, Object.class, Object.class, Object.class); @@ -182,23 +207,32 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker { private static final MethodHandle JSOBJECT_CALL = findJSObjectMH("call", Object.class, Object.class, Object[].class); private static final MethodHandle JSOBJECT_NEW = findJSObjectMH("newObject", Object.class, Object[].class); + private static final Map, MethodHandle> MIRROR_CONVERTERS = new HashMap<>(); + static { + MIRROR_CONVERTERS.put(boolean.class, MH.dropArguments(MH.constant(boolean.class, Boolean.TRUE), 0, Object.class)); + MIRROR_CONVERTERS.put(int.class, findMirrorMH("toInt32", int.class)); + MIRROR_CONVERTERS.put(long.class, findMirrorMH("toInt64", long.class)); + MIRROR_CONVERTERS.put(double.class, findMirrorMH("toNumber", double.class)); + } + private static MethodHandle findOwnMH(final String name, final Class rtype, final Class... types) { - final Class own = JSObjectLinker.class; - final MethodType mt = MH.type(rtype, types); - try { - return MH.findStatic(MethodHandles.lookup(), own, name, mt); - } catch (final MethodHandleFactory.LookupException e) { - return MH.findVirtual(MethodHandles.lookup(), own, name, mt); - } + return findMH(name, JSObjectLinker.class, rtype, types); } private static MethodHandle findJSObjectMH(final String name, final Class rtype, final Class... types) { - final Class own = JSObject.class; + return findMH(name, JSObject.class, rtype, types); + } + + private static MethodHandle findMirrorMH(final String name, final Class rtype, final Class... types) { + return findMH(name, ScriptObjectMirror.class, rtype, types); + } + + private static MethodHandle findMH(final String name, final Class target, final Class rtype, final Class... types) { final MethodType mt = MH.type(rtype, types); try { - return MH.findVirtual(MethodHandles.publicLookup(), own, name, mt); + return MH.findStatic(MethodHandles.lookup(), target, name, mt); } catch (final MethodHandleFactory.LookupException e) { - return MH.findVirtual(MethodHandles.lookup(), own, name, mt); + return MH.findVirtual(MethodHandles.lookup(), target, name, mt); } } } -- cgit v1.2.3 From b54abdb27011dfb792057bf448a34f687c5e31aa Mon Sep 17 00:00:00 2001 From: attila Date: Tue, 22 Oct 2013 17:52:37 +0200 Subject: 8027037: Make ScriptObjectMirror conversions work for any JSObject Reviewed-by: jlaskey, lagergren, sundar --- src/jdk/nashorn/api/scripting/JSObject.java | 9 +++++ .../nashorn/api/scripting/ScriptObjectMirror.java | 34 +--------------- src/jdk/nashorn/internal/runtime/JSType.java | 21 ---------- .../internal/runtime/linker/JSObjectLinker.java | 47 +++++++++++++--------- 4 files changed, 38 insertions(+), 73 deletions(-) diff --git a/src/jdk/nashorn/api/scripting/JSObject.java b/src/jdk/nashorn/api/scripting/JSObject.java index a2d761b4..7118562b 100644 --- a/src/jdk/nashorn/api/scripting/JSObject.java +++ b/src/jdk/nashorn/api/scripting/JSObject.java @@ -234,4 +234,13 @@ public abstract class JSObject { public boolean isArray() { return false; } + + /** + * Returns this object's numeric value. + * + * @return this object's numeric value. + */ + public double toNumber() { + return Double.NaN; + } } diff --git a/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java b/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java index f23a4e9d..0da76311 100644 --- a/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java +++ b/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java @@ -707,39 +707,7 @@ public final class ScriptObjectMirror extends JSObject implements Bindings { } } - /** - * JavaScript compliant Object to int32 conversion - * See ECMA 9.5 ToInt32 - * - * @return this object's int32 representation - */ - public int toInt32() { - return inGlobal(new Callable() { - @Override public Integer call() { - return JSType.toInt32(sobj); - } - }); - } - - /** - * JavaScript compliant Object to int64 conversion - * - * @return this object's int64 representation - */ - public long toInt64() { - return inGlobal(new Callable() { - @Override public Long call() { - return JSType.toInt64(sobj); - } - }); - } - - /** - * JavaScript compliant conversion of Object to number - * See ECMA 9.3 ToNumber - * - * @return this object's number representation - */ + @Override public double toNumber() { return inGlobal(new Callable() { @Override public Double call() { diff --git a/src/jdk/nashorn/internal/runtime/JSType.java b/src/jdk/nashorn/internal/runtime/JSType.java index c0769756..7d8e4d53 100644 --- a/src/jdk/nashorn/internal/runtime/JSType.java +++ b/src/jdk/nashorn/internal/runtime/JSType.java @@ -630,17 +630,6 @@ public enum JSType { return toInt32(toNumber(obj)); } - /** - * JavaScript compliant Object to int32 conversion - * See ECMA 9.5 ToInt32 - * - * @param obj an object - * @return an int32 - */ - public static int toInt32(final ScriptObject obj) { - return toInt32(toNumber(obj)); - } - /** * JavaScript compliant long to int32 conversion * @@ -671,16 +660,6 @@ public enum JSType { return toInt64(toNumber(obj)); } - /** - * JavaScript compliant Object to int64 conversion - * - * @param obj an object - * @return an int64 - */ - public static long toInt64(final ScriptObject obj) { - return toInt64(toNumber(obj)); - } - /** * JavaScript compliant number to int64 conversion * diff --git a/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java b/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java index cd59399f..bee2f025 100644 --- a/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java +++ b/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java @@ -38,7 +38,6 @@ import jdk.internal.dynalink.linker.LinkerServices; import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; import jdk.internal.dynalink.support.CallSiteDescriptorFactory; import jdk.nashorn.api.scripting.JSObject; -import jdk.nashorn.api.scripting.ScriptObjectMirror; import jdk.nashorn.internal.lookup.MethodHandleFactory; import jdk.nashorn.internal.lookup.MethodHandleFunctionality; import jdk.nashorn.internal.runtime.JSType; @@ -81,16 +80,17 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker, GuardingTy @Override public GuardedInvocation convertToType(final Class sourceType, final Class targetType) throws Exception { - if(!sourceType.isAssignableFrom(ScriptObjectMirror.class)) { + final boolean sourceIsAlwaysJSObject = JSObject.class.isAssignableFrom(sourceType); + if(!sourceIsAlwaysJSObject && !sourceType.isAssignableFrom(JSObject.class)) { return null; } - final MethodHandle converter = MIRROR_CONVERTERS.get(targetType); + final MethodHandle converter = CONVERTERS.get(targetType); if(converter == null) { return null; } - return new GuardedInvocation(converter, sourceType == ScriptObjectMirror.class ? null : IS_MIRROR_GUARD).asType(MethodType.methodType(targetType, sourceType)); + return new GuardedInvocation(converter, sourceIsAlwaysJSObject ? null : IS_JSOBJECT_GUARD).asType(MethodType.methodType(targetType, sourceType)); } @@ -156,11 +156,6 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker, GuardingTy return self instanceof JSObject; } - @SuppressWarnings("unused") - private static boolean isScriptObjectMirror(final Object self) { - return self instanceof ScriptObjectMirror; - } - @SuppressWarnings("unused") private static Object get(final Object jsobj, final Object key) { if (key instanceof Integer) { @@ -187,6 +182,25 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker, GuardingTy } } + @SuppressWarnings("unused") + private static int toInt32(final JSObject obj) { + return JSType.toInt32(toNumber(obj)); + } + + @SuppressWarnings("unused") + private static long toInt64(final JSObject obj) { + return JSType.toInt64(toNumber(obj)); + } + + private static double toNumber(final JSObject obj) { + return obj == null ? 0 : obj.toNumber(); + } + + @SuppressWarnings("unused") + private static boolean toBoolean(final JSObject obj) { + return obj != null; + } + private static int getIndex(final Number n) { final double value = n.doubleValue(); return JSType.isRepresentableAsInt(value) ? (int)value : -1; @@ -196,7 +210,6 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker, GuardingTy // method handles of the current class private static final MethodHandle IS_JSOBJECT_GUARD = findOwnMH("isJSObject", boolean.class, Object.class); - private static final MethodHandle IS_MIRROR_GUARD = findOwnMH("isScriptObjectMirror", boolean.class, Object.class); private static final MethodHandle JSOBJECTLINKER_GET = findOwnMH("get", Object.class, Object.class, Object.class); private static final MethodHandle JSOBJECTLINKER_PUT = findOwnMH("put", Void.TYPE, Object.class, Object.class, Object.class); @@ -207,12 +220,12 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker, GuardingTy private static final MethodHandle JSOBJECT_CALL = findJSObjectMH("call", Object.class, Object.class, Object[].class); private static final MethodHandle JSOBJECT_NEW = findJSObjectMH("newObject", Object.class, Object[].class); - private static final Map, MethodHandle> MIRROR_CONVERTERS = new HashMap<>(); + private static final Map, MethodHandle> CONVERTERS = new HashMap<>(); static { - MIRROR_CONVERTERS.put(boolean.class, MH.dropArguments(MH.constant(boolean.class, Boolean.TRUE), 0, Object.class)); - MIRROR_CONVERTERS.put(int.class, findMirrorMH("toInt32", int.class)); - MIRROR_CONVERTERS.put(long.class, findMirrorMH("toInt64", long.class)); - MIRROR_CONVERTERS.put(double.class, findMirrorMH("toNumber", double.class)); + CONVERTERS.put(boolean.class, findOwnMH("toBoolean", boolean.class, JSObject.class)); + CONVERTERS.put(int.class, findOwnMH("toInt32", int.class, JSObject.class)); + CONVERTERS.put(long.class, findOwnMH("toInt64", long.class, JSObject.class)); + CONVERTERS.put(double.class, findOwnMH("toNumber", double.class, JSObject.class)); } private static MethodHandle findOwnMH(final String name, final Class rtype, final Class... types) { @@ -223,10 +236,6 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker, GuardingTy return findMH(name, JSObject.class, rtype, types); } - private static MethodHandle findMirrorMH(final String name, final Class rtype, final Class... types) { - return findMH(name, ScriptObjectMirror.class, rtype, types); - } - private static MethodHandle findMH(final String name, final Class target, final Class rtype, final Class... types) { final MethodType mt = MH.type(rtype, types); try { -- cgit v1.2.3 From 260c6fddd9606f944e7ba3c424ed24328692665f Mon Sep 17 00:00:00 2001 From: sundar Date: Tue, 22 Oct 2013 22:04:46 +0530 Subject: 8027020: [regression] java.lang.VerifyError: Bad type on operand stack Reviewed-by: jlaskey, attila --- src/jdk/nashorn/internal/runtime/ScriptLoader.java | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/src/jdk/nashorn/internal/runtime/ScriptLoader.java b/src/jdk/nashorn/internal/runtime/ScriptLoader.java index 42c8fb4a..78185b1c 100644 --- a/src/jdk/nashorn/internal/runtime/ScriptLoader.java +++ b/src/jdk/nashorn/internal/runtime/ScriptLoader.java @@ -52,24 +52,10 @@ final class ScriptLoader extends NashornLoader { @Override protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { checkPackageAccess(name); - try { - return super.loadClass(name, resolve); - } catch (final ClassNotFoundException | SecurityException e) { - // We'll get ClassNotFoundException for Nashorn 'struct' classes. - // Also, we'll get SecurityException for jdk.nashorn.internal.* - // classes. So, load these using to context's 'shared' loader. - // All these classes start with "jdk.nashorn.internal." prefix. - try { - if (name.startsWith(NASHORN_PKG_PREFIX)) { - return context.getSharedLoader().loadClass(name); - } - } catch (final ClassNotFoundException ignored) { - //ignored - } - - // throw the original exception from here - throw e; + if (name.startsWith(NASHORN_PKG_PREFIX)) { + return context.getSharedLoader().loadClass(name); } + return super.loadClass(name, resolve); } // package-private and private stuff below this point -- cgit v1.2.3 From f956cc664089ece348b1e31c88fc2b28e48a310b Mon Sep 17 00:00:00 2001 From: sundar Date: Wed, 23 Oct 2013 17:30:13 +0530 Subject: 8027128: jdk.nashorn.api.scripting.JSObject should be an interface Reviewed-by: hannesw, attila, jlaskey --- .../nashorn/api/scripting/AbstractJSObject.java | 254 +++++++++++++++++++++ src/jdk/nashorn/api/scripting/JSObject.java | 101 ++------ .../nashorn/api/scripting/ScriptObjectMirror.java | 3 +- src/jdk/nashorn/internal/runtime/JSType.java | 4 + .../internal/runtime/linker/JSObjectLinker.java | 10 - test/script/basic/JDK-8024847.js | 6 + test/script/basic/JDK-8024847.js.EXPECTED | 1 + .../api/scripting/PluggableJSObjectTest.java | 8 +- .../api/scripting/ScriptObjectMirrorTest.java | 2 +- 9 files changed, 293 insertions(+), 96 deletions(-) create mode 100644 src/jdk/nashorn/api/scripting/AbstractJSObject.java diff --git a/src/jdk/nashorn/api/scripting/AbstractJSObject.java b/src/jdk/nashorn/api/scripting/AbstractJSObject.java new file mode 100644 index 00000000..a7761645 --- /dev/null +++ b/src/jdk/nashorn/api/scripting/AbstractJSObject.java @@ -0,0 +1,254 @@ +/* + * 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.api.scripting; + +import java.util.Collection; +import java.util.Collections; +import java.util.Set; + +/** + * This is the base class for nashorn ScriptObjectMirror class. + * + * This class can also be subclassed by an arbitrary Java class. Nashorn will + * treat objects of such classes just like nashorn script objects. Usual nashorn + * operations like obj[i], obj.foo, obj.func(), delete obj.foo will be glued + * to appropriate method call of this class. + */ +public abstract class AbstractJSObject implements JSObject { + /** + * Call this object as a JavaScript function. This is equivalent to + * 'func.apply(thiz, args)' in JavaScript. + * + * @param thiz 'this' object to be passed to the function + * @param args arguments to method + * @return result of call + */ + @Override + public Object call(final Object thiz, final Object... args) { + throw new UnsupportedOperationException("call"); + } + + /** + * Call this 'constructor' JavaScript function to create a new object. + * This is equivalent to 'new func(arg1, arg2...)' in JavaScript. + * + * @param args arguments to method + * @return result of constructor call + */ + @Override + public Object newObject(final Object... args) { + throw new UnsupportedOperationException("newObject"); + } + + /** + * Evaluate a JavaScript expression. + * + * @param s JavaScript expression to evaluate + * @return evaluation result + */ + @Override + public Object eval(final String s) { + throw new UnsupportedOperationException("eval"); + } + + /** + * Retrieves a named member of this JavaScript object. + * + * @param name of member + * @return member + */ + @Override + public Object getMember(final String name) { + return null; + } + + /** + * Retrieves an indexed member of this JavaScript object. + * + * @param index index slot to retrieve + * @return member + */ + @Override + public Object getSlot(final int index) { + return null; + } + + /** + * Does this object have a named member? + * + * @param name name of member + * @return true if this object has a member of the given name + */ + @Override + public boolean hasMember(final String name) { + return false; + } + + /** + * Does this object have a indexed property? + * + * @param slot index to check + * @return true if this object has a slot + */ + @Override + public boolean hasSlot(final int slot) { + return false; + } + + /** + * Remove a named member from this JavaScript object + * + * @param name name of the member + */ + @Override + public void removeMember(final String name) { + //empty + } + + /** + * Set a named member in this JavaScript object + * + * @param name name of the member + * @param value value of the member + */ + @Override + public void setMember(final String name, final Object value) { + //empty + } + + /** + * Set an indexed member in this JavaScript object + * + * @param index index of the member slot + * @param value value of the member + */ + @Override + public void setSlot(final int index, final Object value) { + //empty + } + + // property and value iteration + + /** + * Returns the set of all property names of this object. + * + * @return set of property names + */ + @Override + @SuppressWarnings("unchecked") + public Set keySet() { + return Collections.EMPTY_SET; + } + + /** + * Returns the set of all property values of this object. + * + * @return set of property values. + */ + @Override + @SuppressWarnings("unchecked") + public Collection values() { + return Collections.EMPTY_SET; + } + + // JavaScript instanceof check + + /** + * Checking whether the given object is an instance of 'this' object. + * + * @param instance instace to check + * @return true if the given 'instance' is an instance of this 'function' object + */ + @Override + public boolean isInstance(final Object instance) { + return false; + } + + /** + * Checking whether this object is an instance of the given 'clazz' object. + * + * @param clazz clazz to check + * @return true if this object is an instance of the given 'clazz' + */ + @Override + public boolean isInstanceOf(final Object clazz) { + if (clazz instanceof JSObject) { + return ((JSObject)clazz).isInstance(this); + } + + return false; + } + + /** + * ECMA [[Class]] property + * + * @return ECMA [[Class]] property value of this object + */ + @Override + public String getClassName() { + return getClass().getName(); + } + + /** + * Is this a function object? + * + * @return if this mirror wraps a ECMAScript function instance + */ + @Override + public boolean isFunction() { + return false; + } + + /** + * Is this a 'use strict' function object? + * + * @return true if this mirror represents a ECMAScript 'use strict' function + */ + @Override + public boolean isStrictFunction() { + return false; + } + + /** + * Is this an array object? + * + * @return if this mirror wraps a ECMAScript array object + */ + @Override + public boolean isArray() { + return false; + } + + /** + * Returns this object's numeric value. + * + * @return this object's numeric value. + */ + @Override + public double toNumber() { + return Double.NaN; + } +} diff --git a/src/jdk/nashorn/api/scripting/JSObject.java b/src/jdk/nashorn/api/scripting/JSObject.java index 7118562b..bd6e820b 100644 --- a/src/jdk/nashorn/api/scripting/JSObject.java +++ b/src/jdk/nashorn/api/scripting/JSObject.java @@ -30,14 +30,12 @@ import java.util.Collections; import java.util.Set; /** - * This is the base class for nashorn ScriptObjectMirror class. - * - * This class can also be subclassed by an arbitrary Java class. Nashorn will + * This interface can be implemented by an arbitrary Java class. Nashorn will * treat objects of such classes just like nashorn script objects. Usual nashorn * operations like obj[i], obj.foo, obj.func(), delete obj.foo will be glued - * to appropriate method call of this class. + * to appropriate method call of this interface. */ -public abstract class JSObject { +public interface JSObject { /** * Call this object as a JavaScript function. This is equivalent to * 'func.apply(thiz, args)' in JavaScript. @@ -46,9 +44,7 @@ public abstract class JSObject { * @param args arguments to method * @return result of call */ - public Object call(final Object thiz, final Object... args) { - throw new UnsupportedOperationException("call"); - } + public Object call(final Object thiz, final Object... args); /** * Call this 'constructor' JavaScript function to create a new object. @@ -57,9 +53,7 @@ public abstract class JSObject { * @param args arguments to method * @return result of constructor call */ - public Object newObject(final Object... args) { - throw new UnsupportedOperationException("newObject"); - } + public Object newObject(final Object... args); /** * Evaluate a JavaScript expression. @@ -67,20 +61,7 @@ public abstract class JSObject { * @param s JavaScript expression to evaluate * @return evaluation result */ - public Object eval(final String s) { - throw new UnsupportedOperationException("eval"); - } - - /** - * Call a JavaScript function member of this object. - * - * @param name name of the member function to call - * @param args arguments to be passed to the member function - * @return result of call - */ - public Object callMember(final String name, final Object... args) { - throw new UnsupportedOperationException("call"); - } + public Object eval(final String s); /** * Retrieves a named member of this JavaScript object. @@ -88,9 +69,7 @@ public abstract class JSObject { * @param name of member * @return member */ - public Object getMember(final String name) { - return null; - } + public Object getMember(final String name); /** * Retrieves an indexed member of this JavaScript object. @@ -98,9 +77,7 @@ public abstract class JSObject { * @param index index slot to retrieve * @return member */ - public Object getSlot(final int index) { - return null; - } + public Object getSlot(final int index); /** * Does this object have a named member? @@ -108,9 +85,7 @@ public abstract class JSObject { * @param name name of member * @return true if this object has a member of the given name */ - public boolean hasMember(final String name) { - return false; - } + public boolean hasMember(final String name); /** * Does this object have a indexed property? @@ -118,18 +93,14 @@ public abstract class JSObject { * @param slot index to check * @return true if this object has a slot */ - public boolean hasSlot(final int slot) { - return false; - } + public boolean hasSlot(final int slot); /** * Remove a named member from this JavaScript object * * @param name name of the member */ - public void removeMember(final String name) { - //empty - } + public void removeMember(final String name); /** * Set a named member in this JavaScript object @@ -137,9 +108,7 @@ public abstract class JSObject { * @param name name of the member * @param value value of the member */ - public void setMember(final String name, final Object value) { - //empty - } + public void setMember(final String name, final Object value); /** * Set an indexed member in this JavaScript object @@ -147,9 +116,7 @@ public abstract class JSObject { * @param index index of the member slot * @param value value of the member */ - public void setSlot(final int index, final Object value) { - //empty - } + public void setSlot(final int index, final Object value); // property and value iteration @@ -158,20 +125,14 @@ public abstract class JSObject { * * @return set of property names */ - @SuppressWarnings("unchecked") - public Set keySet() { - return Collections.EMPTY_SET; - } + public Set keySet(); /** * Returns the set of all property values of this object. * * @return set of property values. */ - @SuppressWarnings("unchecked") - public Collection values() { - return Collections.EMPTY_SET; - } + public Collection values(); // JavaScript instanceof check @@ -181,9 +142,7 @@ public abstract class JSObject { * @param instance instace to check * @return true if the given 'instance' is an instance of this 'function' object */ - public boolean isInstance(final Object instance) { - return false; - } + public boolean isInstance(final Object instance); /** * Checking whether this object is an instance of the given 'clazz' object. @@ -191,56 +150,40 @@ public abstract class JSObject { * @param clazz clazz to check * @return true if this object is an instance of the given 'clazz' */ - public boolean isInstanceOf(final Object clazz) { - if (clazz instanceof JSObject) { - return ((JSObject)clazz).isInstance(this); - } - - return false; - } + public boolean isInstanceOf(final Object clazz); /** * ECMA [[Class]] property * * @return ECMA [[Class]] property value of this object */ - public String getClassName() { - return getClass().getName(); - } + public String getClassName(); /** * Is this a function object? * * @return if this mirror wraps a ECMAScript function instance */ - public boolean isFunction() { - return false; - } + public boolean isFunction(); /** * Is this a 'use strict' function object? * * @return true if this mirror represents a ECMAScript 'use strict' function */ - public boolean isStrictFunction() { - return false; - } + public boolean isStrictFunction(); /** * Is this an array object? * * @return if this mirror wraps a ECMAScript array object */ - public boolean isArray() { - return false; - } + public boolean isArray(); /** * Returns this object's numeric value. * * @return this object's numeric value. */ - public double toNumber() { - return Double.NaN; - } + public double toNumber(); } diff --git a/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java b/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java index 0da76311..ee287a2e 100644 --- a/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java +++ b/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java @@ -51,7 +51,7 @@ import jdk.nashorn.internal.runtime.ScriptRuntime; /** * Mirror object that wraps a given Nashorn Script object. */ -public final class ScriptObjectMirror extends JSObject implements Bindings { +public final class ScriptObjectMirror extends AbstractJSObject implements Bindings { private static AccessControlContext getContextAccCtxt() { final Permissions perms = new Permissions(); perms.add(new RuntimePermission(Context.NASHORN_GET_CONTEXT)); @@ -162,7 +162,6 @@ public final class ScriptObjectMirror extends JSObject implements Bindings { }); } - @Override public Object callMember(final String functionName, final Object... args) { functionName.getClass(); // null check final ScriptObject oldGlobal = Context.getGlobal(); diff --git a/src/jdk/nashorn/internal/runtime/JSType.java b/src/jdk/nashorn/internal/runtime/JSType.java index 7d8e4d53..e1b91302 100644 --- a/src/jdk/nashorn/internal/runtime/JSType.java +++ b/src/jdk/nashorn/internal/runtime/JSType.java @@ -1043,6 +1043,10 @@ public enum JSType { return toNumber((ScriptObject)obj); } + if (obj instanceof JSObject) { + return ((JSObject)obj).toNumber(); + } + return Double.NaN; } diff --git a/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java b/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java index bee2f025..f0d45317 100644 --- a/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java +++ b/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java @@ -107,8 +107,6 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker, GuardingTy return c > 2 ? findSetMethod(desc) : findSetIndexMethod(); case "call": return findCallMethod(desc); - case "callMethod": - return findCallMethodMethod(desc); case "new": return findNewMethod(desc); default: @@ -134,13 +132,6 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker, GuardingTy return new GuardedInvocation(JSOBJECTLINKER_PUT, null, IS_JSOBJECT_GUARD); } - private static GuardedInvocation findCallMethodMethod(final CallSiteDescriptor desc) { - final String methodName = desc.getNameToken(2); - MethodHandle func = MH.insertArguments(JSOBJECT_CALLMEMBER, 1, methodName); - func = MH.asCollector(func, Object[].class, desc.getMethodType().parameterCount() - 1); - return new GuardedInvocation(func, null, IS_JSOBJECT_GUARD); - } - private static GuardedInvocation findCallMethod(final CallSiteDescriptor desc) { final MethodHandle func = MH.asCollector(JSOBJECT_CALL, Object[].class, desc.getMethodType().parameterCount() - 2); return new GuardedInvocation(func, null, IS_JSOBJECT_GUARD); @@ -216,7 +207,6 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker, GuardingTy // method handles of JSObject class private static final MethodHandle JSOBJECT_GETMEMBER = findJSObjectMH("getMember", Object.class, String.class); private static final MethodHandle JSOBJECT_SETMEMBER = findJSObjectMH("setMember", Void.TYPE, String.class, Object.class); - private static final MethodHandle JSOBJECT_CALLMEMBER = findJSObjectMH("callMember", Object.class, String.class, Object[].class); private static final MethodHandle JSOBJECT_CALL = findJSObjectMH("call", Object.class, Object.class, Object[].class); private static final MethodHandle JSOBJECT_NEW = findJSObjectMH("newObject", Object.class, Object[].class); diff --git a/test/script/basic/JDK-8024847.js b/test/script/basic/JDK-8024847.js index 4a671ecd..2ead01fd 100644 --- a/test/script/basic/JDK-8024847.js +++ b/test/script/basic/JDK-8024847.js @@ -100,3 +100,9 @@ var obj = new JSObject() { var jlist = Java.to(obj, java.util.List); print(jlist instanceof java.util.List); print(jlist); + +var obj = new JSObject() { + toNumber: function() { return 42; } +}; + +print(32 + obj); diff --git a/test/script/basic/JDK-8024847.js.EXPECTED b/test/script/basic/JDK-8024847.js.EXPECTED index 015183a0..16bff3e2 100644 --- a/test/script/basic/JDK-8024847.js.EXPECTED +++ b/test/script/basic/JDK-8024847.js.EXPECTED @@ -10,3 +10,4 @@ true [hello, world] true [nashorn, js] +74 diff --git a/test/src/jdk/nashorn/api/scripting/PluggableJSObjectTest.java b/test/src/jdk/nashorn/api/scripting/PluggableJSObjectTest.java index acb57164..a574e6f6 100644 --- a/test/src/jdk/nashorn/api/scripting/PluggableJSObjectTest.java +++ b/test/src/jdk/nashorn/api/scripting/PluggableJSObjectTest.java @@ -46,7 +46,7 @@ import org.testng.annotations.Test; * JSObject implementations. */ public class PluggableJSObjectTest { - public static class MapWrapperObject extends JSObject { + public static class MapWrapperObject extends AbstractJSObject { private final HashMap map = new LinkedHashMap<>(); public HashMap getMap() { @@ -109,7 +109,7 @@ public class PluggableJSObjectTest { } } - public static class BufferObject extends JSObject { + public static class BufferObject extends AbstractJSObject { private final IntBuffer buf; public BufferObject(int size) { @@ -170,7 +170,7 @@ public class PluggableJSObjectTest { } } - public static class Adder extends JSObject { + public static class Adder extends AbstractJSObject { @Override public Object call(Object thiz, Object... args) { double res = 0.0; @@ -202,7 +202,7 @@ public class PluggableJSObjectTest { } } - public static class Factory extends JSObject { + public static class Factory extends AbstractJSObject { @Override public Object newObject(Object... args) { return new HashMap(); diff --git a/test/src/jdk/nashorn/api/scripting/ScriptObjectMirrorTest.java b/test/src/jdk/nashorn/api/scripting/ScriptObjectMirrorTest.java index c7b40c63..6c35ee40 100644 --- a/test/src/jdk/nashorn/api/scripting/ScriptObjectMirrorTest.java +++ b/test/src/jdk/nashorn/api/scripting/ScriptObjectMirrorTest.java @@ -129,7 +129,7 @@ public class ScriptObjectMirrorTest { final ScriptEngine e = m.getEngineByName("nashorn"); try { e.eval("var obj = { '1': 'world', func: function() { return this.bar; }, bar: 'hello' }"); - JSObject obj = (JSObject) e.get("obj"); + ScriptObjectMirror obj = (ScriptObjectMirror) e.get("obj"); // try basic get on existing properties if (!obj.getMember("bar").equals("hello")) { -- cgit v1.2.3 From 1ef19f37b319471f5c6a9067cc49c8586a9fd352 Mon Sep 17 00:00:00 2001 From: sundar Date: Wed, 23 Oct 2013 20:15:43 +0530 Subject: 8027150: ScriptObjectListAdapter won't work as expected Reviewed-by: jlaskey, attila --- src/jdk/nashorn/internal/runtime/ListAdapter.java | 4 +- .../internal/runtime/ScriptObjectListAdapter.java | 54 ---------------------- 2 files changed, 3 insertions(+), 55 deletions(-) delete mode 100644 src/jdk/nashorn/internal/runtime/ScriptObjectListAdapter.java diff --git a/src/jdk/nashorn/internal/runtime/ListAdapter.java b/src/jdk/nashorn/internal/runtime/ListAdapter.java index 44302462..26c22c39 100644 --- a/src/jdk/nashorn/internal/runtime/ListAdapter.java +++ b/src/jdk/nashorn/internal/runtime/ListAdapter.java @@ -33,6 +33,7 @@ import java.util.NoSuchElementException; import java.util.RandomAccess; import java.util.concurrent.Callable; import jdk.nashorn.api.scripting.JSObject; +import jdk.nashorn.api.scripting.ScriptObjectMirror; import jdk.nashorn.internal.runtime.linker.Bootstrap; import jdk.nashorn.internal.runtime.linker.InvokeByName; @@ -135,7 +136,8 @@ public abstract class ListAdapter extends AbstractList implements Random */ public static ListAdapter create(final Object obj) { if (obj instanceof ScriptObject) { - return new ScriptObjectListAdapter((ScriptObject)obj); + final Object mirror = ScriptObjectMirror.wrap(obj, Context.getGlobal()); + return new JSObjectListAdapter((JSObject)mirror); } else if (obj instanceof JSObject) { return new JSObjectListAdapter((JSObject)obj); } else { diff --git a/src/jdk/nashorn/internal/runtime/ScriptObjectListAdapter.java b/src/jdk/nashorn/internal/runtime/ScriptObjectListAdapter.java deleted file mode 100644 index 4fe2dc40..00000000 --- a/src/jdk/nashorn/internal/runtime/ScriptObjectListAdapter.java +++ /dev/null @@ -1,54 +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; - -/** - * A ListAdapter that can wrap a ScriptObject. - */ -public final class ScriptObjectListAdapter extends ListAdapter { - /** - * Creates a new list wrapper for the specified ScriptObject. - * @param obj script the object to wrap - */ - public ScriptObjectListAdapter(final ScriptObject obj) { - super(obj); - } - - @Override - public int size() { - return JSType.toInt32(((ScriptObject)obj).getLength()); - } - - @Override - protected Object getAt(int index) { - return ((ScriptObject)obj).get(index); - } - - @Override - protected void setAt(int index, Object element) { - ((ScriptObject)obj).set(index, element, false); - } -} -- cgit v1.2.3 From acbbd278e3a98c21c392f45c0f737131e84c87c0 Mon Sep 17 00:00:00 2001 From: hannesw Date: Fri, 25 Oct 2013 10:20:49 +0200 Subject: 8027042: Evaluation order for binary operators can be improved Reviewed-by: lagergren, jlaskey, attila --- .../nashorn/internal/codegen/CodeGenerator.java | 29 ++++--- src/jdk/nashorn/internal/codegen/types/Type.java | 12 ++- src/jdk/nashorn/internal/ir/BinaryNode.java | 39 ++++++++++ src/jdk/nashorn/internal/ir/Expression.java | 12 +++ src/jdk/nashorn/internal/ir/IdentNode.java | 5 ++ src/jdk/nashorn/internal/ir/LiteralNode.java | 5 ++ src/jdk/nashorn/internal/ir/TernaryNode.java | 7 ++ src/jdk/nashorn/internal/ir/UnaryNode.java | 20 +++++ test/script/basic/JDK-8027042.js | 58 ++++++++++++++ test/script/basic/JDK-8027042.js.EXPECTED | 88 ++++++++++++++++++++++ 10 files changed, 258 insertions(+), 17 deletions(-) create mode 100644 test/script/basic/JDK-8027042.js create mode 100644 test/script/basic/JDK-8027042.js.EXPECTED diff --git a/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/src/jdk/nashorn/internal/codegen/CodeGenerator.java index 7dd12de1..3ac5cd0d 100644 --- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java @@ -359,8 +359,11 @@ final class CodeGenerator extends NodeOperatorVisitor, BytecodeOps { return this.equals(Type.UNKNOWN); } + /** + * Determines whether this type represents an primitive type according to the ECMAScript specification, + * which includes Boolean, Number, and String. + * + * @return true if a JavaScript primitive type, false otherwise. + */ + public boolean isJSPrimitive() { + return !isObject() || isString(); + } + /** * Determines whether a type is the BOOLEAN type * @return true if BOOLEAN, false otherwise @@ -443,7 +453,7 @@ public abstract class Type implements Comparable, BytecodeOps { } else if (type0.isArray() != type1.isArray()) { //array and non array is always object, widest(Object[], int) NEVER returns Object[], which has most weight. that does not make sense return Type.OBJECT; - } else if (type0.isObject() && type1.isObject() && ((ObjectType)type0).getTypeClass() != ((ObjectType)type1).getTypeClass()) { + } else if (type0.isObject() && type1.isObject() && type0.getTypeClass() != type1.getTypeClass()) { // Object and Object will produce Object // TODO: maybe find most specific common superclass? return Type.OBJECT; diff --git a/src/jdk/nashorn/internal/ir/BinaryNode.java b/src/jdk/nashorn/internal/ir/BinaryNode.java index 169772d7..0a1d1bfc 100644 --- a/src/jdk/nashorn/internal/ir/BinaryNode.java +++ b/src/jdk/nashorn/internal/ir/BinaryNode.java @@ -90,6 +90,9 @@ public final class BinaryNode extends Expression implements Assignment extends Expression implements PropertyKey { public boolean isTrue() { return JSType.toBoolean(value); } + + @Override + public boolean isLocal() { + return true; + } } @Immutable diff --git a/src/jdk/nashorn/internal/ir/TernaryNode.java b/src/jdk/nashorn/internal/ir/TernaryNode.java index 70e1c726..26c14b76 100644 --- a/src/jdk/nashorn/internal/ir/TernaryNode.java +++ b/src/jdk/nashorn/internal/ir/TernaryNode.java @@ -109,6 +109,13 @@ public final class TernaryNode extends Expression { } } + @Override + public boolean isLocal() { + return getTest().isLocal() + && getTrueExpression().isLocal() + && getFalseExpression().isLocal(); + } + /** * Get the test expression for this ternary expression, i.e. "x" in x ? y : z * @return the test expression diff --git a/src/jdk/nashorn/internal/ir/UnaryNode.java b/src/jdk/nashorn/internal/ir/UnaryNode.java index 3857dd39..4923d31e 100644 --- a/src/jdk/nashorn/internal/ir/UnaryNode.java +++ b/src/jdk/nashorn/internal/ir/UnaryNode.java @@ -128,6 +128,26 @@ public final class UnaryNode extends Expression implements Assignment Date: Fri, 25 Oct 2013 15:21:12 +0200 Subject: 8027301: Optimizations for Function.prototype.apply Reviewed-by: jlaskey --- .../internal/runtime/CompiledFunctions.java | 50 +++++++++- .../internal/runtime/FinalScriptFunctionData.java | 11 ++- .../internal/runtime/ScriptFunctionData.java | 105 +++++++++------------ 3 files changed, 97 insertions(+), 69 deletions(-) diff --git a/src/jdk/nashorn/internal/runtime/CompiledFunctions.java b/src/jdk/nashorn/internal/runtime/CompiledFunctions.java index 1ddc42b5..ba5ae66c 100644 --- a/src/jdk/nashorn/internal/runtime/CompiledFunctions.java +++ b/src/jdk/nashorn/internal/runtime/CompiledFunctions.java @@ -24,6 +24,7 @@ */ package jdk.nashorn.internal.runtime; +import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodType; import java.util.Iterator; import java.util.TreeSet; @@ -35,6 +36,8 @@ import java.util.TreeSet; @SuppressWarnings("serial") final class CompiledFunctions extends TreeSet { + private CompiledFunction generic; + CompiledFunction best(final MethodType type) { final Iterator iter = iterator(); while (iter.hasNext()) { @@ -43,13 +46,10 @@ final class CompiledFunctions extends TreeSet { return next; } } - return mostGeneric(); + return generic(); } boolean needsCallee() { - for (final CompiledFunction inv : this) { - assert ScriptFunctionData.needsCallee(inv.getInvoker()) == ScriptFunctionData.needsCallee(mostGeneric().getInvoker()); - } return ScriptFunctionData.needsCallee(mostGeneric().getInvoker()); } @@ -57,6 +57,48 @@ final class CompiledFunctions extends TreeSet { return last(); } + CompiledFunction generic() { + CompiledFunction gen = this.generic; + if (gen == null) { + gen = this.generic = makeGeneric(mostGeneric()); + } + return gen; + } + + private static CompiledFunction makeGeneric(final CompiledFunction func) { + final MethodHandle invoker = composeGenericMethod(func.getInvoker()); + final MethodHandle constructor = func.hasConstructor() ? composeGenericMethod(func.getConstructor()) : null; + return new CompiledFunction(invoker.type(), invoker, constructor); + } + + /** + * Takes a method handle, and returns a potentially different method handle that can be used in + * {@code ScriptFunction#invoke(Object, Object...)} or {code ScriptFunction#construct(Object, Object...)}. + * The returned method handle will be sure to return {@code Object}, and will have all its parameters turned into + * {@code Object} as well, except for the following ones: + *
    + *
  • a last parameter of type {@code Object[]} which is used for vararg functions,
  • + *
  • the first argument, which is forced to be {@link ScriptFunction}, in case the function receives itself + * (callee) as an argument.
  • + *
+ * + * @param mh the original method handle + * + * @return the new handle, conforming to the rules above. + */ + private static MethodHandle composeGenericMethod(final MethodHandle mh) { + final MethodType type = mh.type(); + final boolean isVarArg = ScriptFunctionData.isVarArg(mh); + final int paramCount = isVarArg ? type.parameterCount() - 1 : type.parameterCount(); + + MethodType newType = MethodType.genericMethodType(paramCount, isVarArg); + + if (ScriptFunctionData.needsCallee(mh)) { + newType = newType.changeParameterType(0, ScriptFunction.class); + } + return type.equals(newType) ? mh : mh.asType(newType); + } + /** * Is the given type even more specific than this entire list? That means * we have an opportunity for more specific versions of the method diff --git a/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java b/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java index f28ed6ae..c7a410ea 100644 --- a/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java +++ b/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java @@ -40,7 +40,7 @@ final class FinalScriptFunctionData extends ScriptFunctionData { * * @param name name * @param arity arity - * @param list precompiled code + * @param functions precompiled code * @param isStrict strict * @param isBuiltin builtin * @param isConstructor constructor @@ -73,12 +73,13 @@ final class FinalScriptFunctionData extends ScriptFunctionData { } private void addInvoker(final MethodHandle mh) { - boolean needsCallee = needsCallee(mh); if (isConstructor(mh)) { - //only nasgen constructors: (boolean, self, args) are subject to binding a boolean newObj. isConstructor - //is too conservative a check. However, isConstructor(mh) always implies isConstructor param + // only nasgen constructors: (boolean, self, args) are subject to binding a boolean newObj. isConstructor + // is too conservative a check. However, isConstructor(mh) always implies isConstructor param assert isConstructor(); - code.add(new CompiledFunction(mh.type(), MH.insertArguments(mh, 0, false), composeConstructor(MH.insertArguments(mh, 0, true), needsCallee))); //make sure callee state can be determined when we reach constructor + final MethodHandle invoker = MH.insertArguments(mh, 0, false); + final MethodHandle constructor = composeConstructor(MH.insertArguments(mh, 0, true)); + code.add(new CompiledFunction(mh.type(), invoker, constructor)); } else { code.add(new CompiledFunction(mh.type(), mh)); } diff --git a/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java b/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java index 04c3ae8d..4dbbfba9 100644 --- a/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java +++ b/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java @@ -213,13 +213,13 @@ public abstract class ScriptFunctionData { */ public final MethodHandle getGenericInvoker() { ensureCodeGenerated(); - return composeGenericMethod(code.mostGeneric().getInvoker()); + return code.generic().getInvoker(); } final MethodHandle getGenericConstructor() { ensureCodeGenerated(); - ensureConstructor(code.mostGeneric()); - return composeGenericMethod(code.mostGeneric().getConstructor()); + ensureConstructor(code.generic()); + return code.generic().getConstructor(); } private CompiledFunction getBest(final MethodType callSiteType) { @@ -267,18 +267,17 @@ public abstract class ScriptFunctionData { } /** - * Compose a constructor given a primordial constructor handle - * - * @param ctor primordial constructor handle - * @param needsCallee do we need to pass a callee + * Compose a constructor given a primordial constructor handle. * + * @param ctor primordial constructor handle * @return the composed constructor */ - protected MethodHandle composeConstructor(final MethodHandle ctor, final boolean needsCallee) { + protected MethodHandle composeConstructor(final MethodHandle ctor) { // If it was (callee, this, args...), permute it to (this, callee, args...). We're doing this because having // "this" in the first argument position is what allows the elegant folded composition of // (newFilter x constructor x allocator) further down below in the code. Also, ensure the composite constructor // always returns Object. + final boolean needsCallee = needsCallee(ctor); MethodHandle composedCtor = needsCallee ? swapCalleeAndThis(ctor) : ctor; composedCtor = changeReturnTypeToObject(composedCtor); @@ -471,33 +470,6 @@ public abstract class ScriptFunctionData { return MH.insertArguments(calleeBoundConstructor, 1, boundArgs); } - /** - * Takes a method handle, and returns a potentially different method handle that can be used in - * {@code ScriptFunction#invoke(Object, Object...)} or {code ScriptFunction#construct(Object, Object...)}. - * The returned method handle will be sure to return {@code Object}, and will have all its parameters turned into - * {@code Object} as well, except for the following ones: - *
    - *
  • a last parameter of type {@code Object[]} which is used for vararg functions,
  • - *
  • the first argument, which is forced to be {@link ScriptFunction}, in case the function receives itself - * (callee) as an argument.
  • - *
- * - * @param mh the original method handle - * - * @return the new handle, conforming to the rules above. - */ - protected MethodHandle composeGenericMethod(final MethodHandle mh) { - final MethodType type = mh.type(); - MethodType newType = type.generic(); - if (isVarArg(mh)) { - newType = newType.changeParameterType(type.parameterCount() - 1, Object[].class); - } - if (needsCallee(mh)) { - newType = newType.changeParameterType(0, ScriptFunction.class); - } - return type.equals(newType) ? mh : mh.asType(newType); - } - /** * Execute this script function. * @@ -508,10 +480,9 @@ public abstract class ScriptFunctionData { * @throws Throwable if there is an exception/error with the invocation or thrown from it */ Object invoke(final ScriptFunction fn, final Object self, final Object... arguments) throws Throwable { - final MethodHandle mh = getGenericInvoker(); - - final Object selfObj = convertThisObject(self); - final Object[] args = arguments == null ? ScriptRuntime.EMPTY_ARRAY : arguments; + final MethodHandle mh = getGenericInvoker(); + final Object selfObj = convertThisObject(self); + final Object[] args = arguments == null ? ScriptRuntime.EMPTY_ARRAY : arguments; if (isVarArg(mh)) { if (needsCallee(mh)) { @@ -531,6 +502,12 @@ public abstract class ScriptFunctionData { return mh.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1)); case 5: return mh.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2)); + case 6: + return mh.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3)); + case 7: + return mh.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4)); + case 8: + return mh.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4), getArg(args, 5)); default: return mh.invokeWithArguments(withArguments(fn, selfObj, paramCount, args)); } @@ -545,15 +522,20 @@ public abstract class ScriptFunctionData { return mh.invokeExact(selfObj, getArg(args, 0), getArg(args, 1)); case 4: return mh.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2)); + case 5: + return mh.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3)); + case 6: + return mh.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4)); + case 7: + return mh.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4), getArg(args, 5)); default: return mh.invokeWithArguments(withArguments(null, selfObj, paramCount, args)); } } Object construct(final ScriptFunction fn, final Object... arguments) throws Throwable { - final MethodHandle mh = getGenericConstructor(); - - final Object[] args = arguments == null ? ScriptRuntime.EMPTY_ARRAY : arguments; + final MethodHandle mh = getGenericConstructor(); + final Object[] args = arguments == null ? ScriptRuntime.EMPTY_ARRAY : arguments; if (isVarArg(mh)) { if (needsCallee(mh)) { @@ -573,6 +555,12 @@ public abstract class ScriptFunctionData { return mh.invokeExact(fn, getArg(args, 0), getArg(args, 1)); case 4: return mh.invokeExact(fn, getArg(args, 0), getArg(args, 1), getArg(args, 2)); + case 5: + return mh.invokeExact(fn, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3)); + case 6: + return mh.invokeExact(fn, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4)); + case 7: + return mh.invokeExact(fn, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4), getArg(args, 5)); default: return mh.invokeWithArguments(withArguments(fn, paramCount, args)); } @@ -587,6 +575,12 @@ public abstract class ScriptFunctionData { return mh.invokeExact(getArg(args, 0), getArg(args, 1)); case 3: return mh.invokeExact(getArg(args, 0), getArg(args, 1), getArg(args, 2)); + case 4: + return mh.invokeExact(getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3)); + case 5: + return mh.invokeExact(getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4)); + case 6: + return mh.invokeExact(getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4), getArg(args, 5)); default: return mh.invokeWithArguments(withArguments(null, paramCount, args)); } @@ -664,20 +658,21 @@ public abstract class ScriptFunctionData { * @return the adapted handle */ private static MethodHandle changeReturnTypeToObject(final MethodHandle mh) { - return MH.asType(mh, mh.type().changeReturnType(Object.class)); + final MethodType type = mh.type(); + return (type.returnType() == Object.class) ? mh : MH.asType(mh, type.changeReturnType(Object.class)); } private void ensureConstructor(final CompiledFunction inv) { if (!inv.hasConstructor()) { - inv.setConstructor(composeConstructor(inv.getInvoker(), needsCallee(inv.getInvoker()))); + inv.setConstructor(composeConstructor(inv.getInvoker())); } } /** - * Heuristic to figure out if the method handle has a callee argument. If it's type is either - * {@code (boolean, ScriptFunction, ...)} or {@code (ScriptFunction, ...)}, then we'll assume it has - * a callee argument. We need this as the constructor above is not passed this information, and can't just blindly - * assume it's false (notably, it's being invoked for creation of new scripts, and scripts have scopes, therefore + * Heuristic to figure out if the method handle has a callee argument. If it's type is + * {@code (ScriptFunction, ...)}, then we'll assume it has a callee argument. We need this as + * the constructor above is not passed this information, and can't just blindly assume it's false + * (notably, it's being invoked for creation of new scripts, and scripts have scopes, therefore * they also always receive a callee). * * @param mh the examined method handle @@ -685,18 +680,8 @@ public abstract class ScriptFunctionData { * @return true if the method handle expects a callee, false otherwise */ protected static boolean needsCallee(final MethodHandle mh) { - final MethodType type = mh.type(); - final int length = type.parameterCount(); - - if (length == 0) { - return false; - } - - if (type.parameterType(0) == ScriptFunction.class) { - return true; - } - - return length > 1 && type.parameterType(0) == boolean.class && type.parameterType(1) == ScriptFunction.class; + final MethodType type = mh.type(); + return (type.parameterCount() > 0 && type.parameterType(0) == ScriptFunction.class); } /** -- cgit v1.2.3 From eb6ce97223bb14788453bbf120a6dd008263afad Mon Sep 17 00:00:00 2001 From: jlaskey Date: Tue, 29 Oct 2013 14:22:44 -0300 Subject: 8027447: The wrong string buffer is specified for stderr in $EXEC Reviewed-by: lagergren, sundar Contributed-by: james.laskey@oracle.com --- src/jdk/nashorn/internal/runtime/ScriptingFunctions.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java b/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java index 6bd0479f..8a03533e 100644 --- a/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java +++ b/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java @@ -190,7 +190,7 @@ public final class ScriptingFunctions { char buffer[] = new char[1024]; try (final InputStreamReader inputStream = new InputStreamReader(process.getErrorStream())) { for (int length; (length = inputStream.read(buffer, 0, buffer.length)) != -1; ) { - outBuffer.append(buffer, 0, length); + errBuffer.append(buffer, 0, length); } } catch (IOException ex) { exception[1] = ex; -- cgit v1.2.3 From 0ae9e1b4948d4a07a76488903803b9490625c86f Mon Sep 17 00:00:00 2001 From: jlaskey Date: Wed, 30 Oct 2013 11:28:46 -0300 Subject: 8027532: nashorn should only use jdk8 apis in the compact1 profile Reviewed-by: sundar, lagergren, hannesw Contributed-by: james.laskey@oracle.com --- .../internal/ir/debug/ObjectSizeCalculator.java | 59 +++++++++++++++++++--- 1 file changed, 53 insertions(+), 6 deletions(-) diff --git a/src/jdk/nashorn/internal/ir/debug/ObjectSizeCalculator.java b/src/jdk/nashorn/internal/ir/debug/ObjectSizeCalculator.java index 2d4412e7..89269d5f 100644 --- a/src/jdk/nashorn/internal/ir/debug/ObjectSizeCalculator.java +++ b/src/jdk/nashorn/internal/ir/debug/ObjectSizeCalculator.java @@ -25,10 +25,10 @@ package jdk.nashorn.internal.ir.debug; -import java.lang.management.ManagementFactory; -import java.lang.management.MemoryPoolMXBean; import java.lang.reflect.Array; import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayDeque; import java.util.ArrayList; @@ -51,9 +51,9 @@ import java.util.Map; * switch, it can not detect * this fact and will report incorrect sizes, as it will presume the default JVM * behavior. - * - * @author Attila Szegedi */ + +@SuppressWarnings("StaticNonFinalUsedInInitialization") public class ObjectSizeCalculator { /** @@ -368,6 +368,29 @@ public class ObjectSizeCalculator { type.getName()); } + // ALERT: java.lang.management is not available in compact 1. We need + // to use reflection to soft link test memory statistics. + + static Class managementFactory = null; + static Class memoryPoolMXBean = null; + static Class memoryUsage = null; + static Method getMemoryPoolMXBeans = null; + static Method getUsage = null; + static Method getMax = null; + static { + try { + managementFactory = Class.forName("java.lang.management.ManagementFactory"); + memoryPoolMXBean = Class.forName("java.lang.management.MemoryPoolMXBean"); + memoryUsage = Class.forName("java.lang.management.MemoryUsage"); + + getMemoryPoolMXBeans = managementFactory.getMethod("getMemoryPoolMXBeans"); + getUsage = memoryPoolMXBean.getMethod("getUsage"); + getMax = memoryUsage.getMethod("getMax"); + } catch (ClassNotFoundException | NoSuchMethodException | SecurityException ex) { + // Pass thru, asserts when attempting to use. + } + } + /** * Return the current memory usage * @return current memory usage derived from system configuration @@ -409,9 +432,33 @@ public class ObjectSizeCalculator { strVmVersion.indexOf('.'))); if (vmVersion >= 17) { long maxMemory = 0; - for (MemoryPoolMXBean mp : ManagementFactory.getMemoryPoolMXBeans()) { - maxMemory += mp.getUsage().getMax(); + + /* + See ALERT above. The reflection code below duplicates the following + sequence, and avoids hard coding of java.lang.management. + + for (MemoryPoolMXBean mp : ManagementFactory.getMemoryPoolMXBeans()) { + maxMemory += mp.getUsage().getMax(); + } + */ + + if (getMemoryPoolMXBeans == null) { + throw new AssertionError("java.lang.management not available in compact 1"); } + + try { + final List memoryPoolMXBeans = (List)getMemoryPoolMXBeans.invoke(managementFactory); + for (final Object mp : memoryPoolMXBeans) { + final Object usage = getUsage.invoke(mp); + final Object max = getMax.invoke(usage); + maxMemory += ((Long)max).longValue(); + } + } catch (IllegalAccessException | + IllegalArgumentException | + InvocationTargetException ex) { + throw new AssertionError("java.lang.management not available in compact 1"); + } + if (maxMemory < 30L * 1024 * 1024 * 1024) { // HotSpot 17.0 and above use compressed OOPs below 30GB of RAM total // for all memory pools (yes, including code cache). -- cgit v1.2.3 From 5e8224727d0ef50157dee66eecb138a2aea3312e Mon Sep 17 00:00:00 2001 From: sundar Date: Wed, 30 Oct 2013 20:09:44 +0530 Subject: 8027562: eval should load second and subsequent arguments for side effect Reviewed-by: jlaskey, lagergren --- .../nashorn/internal/codegen/CodeGenerator.java | 6 ++++ test/script/basic/JDK-8027562.js | 39 ++++++++++++++++++++++ test/script/basic/JDK-8027562.js.EXPECTED | 1 + 3 files changed, 46 insertions(+) create mode 100644 test/script/basic/JDK-8027562.js create mode 100644 test/script/basic/JDK-8027562.js.EXPECTED diff --git a/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/src/jdk/nashorn/internal/codegen/CodeGenerator.java index 3ac5cd0d..206433db 100644 --- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java @@ -706,6 +706,12 @@ final class CodeGenerator extends NodeOperatorVisitor args = callNode.getArgs(); + final int numArgs = args.size(); + for (int i = 1; i < numArgs; i++) { + load(args.get(i)).pop(); + } // special/extra 'eval' arguments load(evalArgs.getThis()); method.load(evalArgs.getLocation()); diff --git a/test/script/basic/JDK-8027562.js b/test/script/basic/JDK-8027562.js new file mode 100644 index 00000000..950584b4 --- /dev/null +++ b/test/script/basic/JDK-8027562.js @@ -0,0 +1,39 @@ +/* + * 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-8027562: eval should load second and subsequent arguments for side effect + * + * @test + * @run + */ + +try { + eval("", x); + fail("should have thrown ReferenceError for 'x'"); +} catch (e) { + if (! (e instanceof ReferenceError)) { + fail("Expected ReferenceError, got " + e); + } + print(e); +} diff --git a/test/script/basic/JDK-8027562.js.EXPECTED b/test/script/basic/JDK-8027562.js.EXPECTED new file mode 100644 index 00000000..c007ed7b --- /dev/null +++ b/test/script/basic/JDK-8027562.js.EXPECTED @@ -0,0 +1 @@ +ReferenceError: "x" is not defined -- cgit v1.2.3