8010697: DeletedArrayFilter seems to leak memory
Reviewed-by: hannesw, sundar
Contributed-by: james.laskey@oracle.com
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java Tue Jun 18 18:43:05 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java Wed Jun 19 09:10:49 2013 -0300
@@ -856,8 +856,12 @@
}
// delete missing elements - which are at the end of sorted array
- sobj.setArray(array.delete(sorted.length, len - 1));
- }
+ if (sorted.length != len) {
+ array = array.delete(sorted.length, len - 1);
+ }
+
+ sobj.setArray(array);
+ }
return sobj;
} catch (final ClassCastException | NullPointerException e) {
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java Tue Jun 18 18:43:05 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java Wed Jun 19 09:10:49 2013 -0300
@@ -295,6 +295,29 @@
public abstract ArrayData set(int index, double value, boolean strict);
/**
+ * Set an empty value at a given index. Should only affect Object array.
+ *
+ * @param index the index
+ * @return new array data (or same)
+ */
+ public ArrayData setEmpty(final int index) {
+ // Do nothing.
+ return this;
+ }
+
+ /**
+ * Set an empty value for a given range. Should only affect Object array.
+ *
+ * @param lo range low end
+ * @param hi range high end
+ * @return new array data (or same)
+ */
+ public ArrayData setEmpty(final long lo, final long hi) {
+ // Do nothing.
+ return this;
+ }
+
+ /**
* Get an int value from a given index
*
* @param index the index
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayFilter.java Tue Jun 18 18:43:05 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayFilter.java Wed Jun 19 09:10:49 2013 -0300
@@ -129,6 +129,18 @@
}
@Override
+ public ArrayData setEmpty(final int index) {
+ underlying.setEmpty(index);
+ return this;
+ }
+
+ @Override
+ public ArrayData setEmpty(final long lo, final long hi) {
+ underlying.setEmpty(lo, hi);
+ return this;
+ }
+
+ @Override
public int getInt(final int index) {
return underlying.getInt(index);
}
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/DeletedArrayFilter.java Tue Jun 18 18:43:05 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/DeletedArrayFilter.java Wed Jun 19 09:10:49 2013 -0300
@@ -142,6 +142,7 @@
final long longIndex = ArrayIndex.toLongIndex(index);
assert longIndex >= 0 && longIndex < length();
deleted.set(longIndex);
+ underlying.setEmpty(index);
return this;
}
@@ -149,6 +150,7 @@
public ArrayData delete(final long fromIndex, final long toIndex) {
assert fromIndex >= 0 && fromIndex <= toIndex && toIndex < length();
deleted.setRange(fromIndex, toIndex + 1);
+ underlying.setEmpty(fromIndex, toIndex);
return this;
}
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/DeletedRangeArrayFilter.java Tue Jun 18 18:43:05 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/DeletedRangeArrayFilter.java Wed Jun 19 09:10:49 2013 -0300
@@ -202,6 +202,8 @@
@Override
public ArrayData delete(final int index) {
final long longIndex = ArrayIndex.toLongIndex(index);
+ underlying.setEmpty(index);
+
if (longIndex + 1 == lo) {
lo = longIndex;
} else if (longIndex - 1 == hi) {
@@ -220,6 +222,7 @@
}
lo = Math.min(fromIndex, lo);
hi = Math.max(toIndex, hi);
+ underlying.setEmpty(lo, hi);
return this;
}
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java Tue Jun 18 18:43:05 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java Wed Jun 19 09:10:49 2013 -0300
@@ -139,6 +139,18 @@
}
@Override
+ public ArrayData setEmpty(final int index) {
+ array[index] = ScriptRuntime.EMPTY;
+ return this;
+ }
+
+ @Override
+ public ArrayData setEmpty(final long lo, final long hi) {
+ Arrays.fill(array, (int)Math.max(lo, 0L), (int)Math.min(hi, (long)Integer.MAX_VALUE), ScriptRuntime.EMPTY);
+ return this;
+ }
+
+ @Override
public int getInt(final int index) {
return JSType.toInt32(array[index]);
}
@@ -165,11 +177,13 @@
@Override
public ArrayData delete(final int index) {
+ setEmpty(index);
return new DeletedRangeArrayFilter(this, index, index);
}
@Override
public ArrayData delete(final long fromIndex, final long toIndex) {
+ setEmpty(fromIndex, toIndex);
return new DeletedRangeArrayFilter(this, fromIndex, toIndex);
}
@@ -181,7 +195,7 @@
final int newLength = (int) (length() - 1);
final Object elem = array[newLength];
- array[newLength] = 0;
+ setEmpty(newLength);
setLength(newLength);
return elem;
}
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java Tue Jun 18 18:43:05 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java Wed Jun 19 09:10:49 2013 -0300
@@ -204,6 +204,18 @@
}
@Override
+ public ArrayData setEmpty(final int index) {
+ underlying.setEmpty(index);
+ return this;
+ }
+
+ @Override
+ public ArrayData setEmpty(final long lo, final long hi) {
+ underlying.setEmpty(lo, hi);
+ return this;
+ }
+
+ @Override
public int getInt(final int index) {
if (index >= 0 && index < maxDenseLength) {
return underlying.getInt(index);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8010697.js Wed Jun 19 09:10:49 2013 -0300
@@ -0,0 +1,59 @@
+/*
+ * 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-8010697: DeletedArrayFilter seems to leak memory
+ *
+ * @test
+ * @run
+ */
+
+var N = 1000;
+
+var array = new Array(N);
+var WeakReferenceArray = Java.type("java.lang.ref.WeakReference[]");
+var refArray = new WeakReferenceArray(N);
+
+for (var i = 0; i < N; i ++) {
+ var object = new java.lang.Object();
+ array[i] = object;
+ refArray[i] = new java.lang.ref.WeakReference(object);
+}
+
+object = null;
+
+for (var i = 0; i < N; i ++) {
+ delete array[i];
+}
+
+java.lang.System.gc();
+java.lang.System.gc();
+
+for (var i = 0; i < N; i ++) {
+ if (refArray[i].get() != null) {
+ print("Reference found at " + i);
+ exit(0);
+ }
+}
+
+print("All references gone");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8010697.js.EXPECTED Wed Jun 19 09:10:49 2013 -0300
@@ -0,0 +1,1 @@
+All references gone