Merge "Restore fastpath of Pattern#split"
diff --git a/benchmarks/src/benchmarks/XmlSerializeBenchmark.java b/benchmarks/src/benchmarks/XmlSerializeBenchmark.java
index 0ef2620..c542e87 100644
--- a/benchmarks/src/benchmarks/XmlSerializeBenchmark.java
+++ b/benchmarks/src/benchmarks/XmlSerializeBenchmark.java
@@ -88,7 +88,7 @@
String[] splitted = datasetAsString.split(" ");
dataset = new double[splitted.length];
for (int i = 0; i < splitted.length; i++) {
- dataset[i] = Double.valueOf(splitted[i]);
+ dataset[i] = Double.parseDouble(splitted[i]);
}
}
diff --git a/benchmarks/src/benchmarks/regression/StringBuilderBenchmark.java b/benchmarks/src/benchmarks/regression/StringBuilderBenchmark.java
index 07a2305..ef54432 100644
--- a/benchmarks/src/benchmarks/regression/StringBuilderBenchmark.java
+++ b/benchmarks/src/benchmarks/regression/StringBuilderBenchmark.java
@@ -63,6 +63,16 @@
}
}
+ public void timeAppendSubCharSequence(int reps) {
+ CharSequence cs = "chars";
+ for (int i = 0; i < reps; ++i) {
+ StringBuilder sb = new StringBuilder();
+ for (int j = 0; j < length; ++j) {
+ sb.append(cs);
+ }
+ }
+ }
+
public void timeAppendDouble(int reps) {
double d = 1.2;
for (int i = 0; i < reps; ++i) {
diff --git a/dex/src/main/java/com/android/dex/Dex.java b/dex/src/main/java/com/android/dex/Dex.java
index ea9b627b..d0434d6 100644
--- a/dex/src/main/java/com/android/dex/Dex.java
+++ b/dex/src/main/java/com/android/dex/Dex.java
@@ -93,7 +93,11 @@
* Creates a new dex buffer of the dex in {@code in}, and closes {@code in}.
*/
public Dex(InputStream in) throws IOException {
- loadFrom(in);
+ try {
+ loadFrom(in);
+ } finally {
+ in.close();
+ }
}
/**
@@ -104,13 +108,17 @@
ZipFile zipFile = new ZipFile(file);
ZipEntry entry = zipFile.getEntry(DexFormat.DEX_IN_JAR_NAME);
if (entry != null) {
- loadFrom(zipFile.getInputStream(entry));
+ try (InputStream inputStream = zipFile.getInputStream(entry)) {
+ loadFrom(inputStream);
+ }
zipFile.close();
} else {
throw new DexException("Expected " + DexFormat.DEX_IN_JAR_NAME + " in " + file);
}
} else if (file.getName().endsWith(".dex")) {
- loadFrom(new FileInputStream(file));
+ try (InputStream inputStream = new FileInputStream(file)) {
+ loadFrom(inputStream);
+ }
} else {
throw new DexException("unknown output extension: " + file);
}
@@ -141,6 +149,9 @@
return new Dex(data);
}
+ /**
+ * It is the caller's responsibility to close {@code in}.
+ */
private void loadFrom(InputStream in) throws IOException {
ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
byte[] buffer = new byte[8192];
@@ -149,7 +160,6 @@
while ((count = in.read(buffer)) != -1) {
bytesOut.write(buffer, 0, count);
}
- in.close();
this.data = ByteBuffer.wrap(bytesOut.toByteArray());
this.data.order(ByteOrder.LITTLE_ENDIAN);
@@ -174,9 +184,9 @@
}
public void writeTo(File dexOut) throws IOException {
- OutputStream out = new FileOutputStream(dexOut);
- writeTo(out);
- out.close();
+ try (OutputStream out = new FileOutputStream(dexOut)) {
+ writeTo(out);
+ }
}
public TableOfContents getTableOfContents() {
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/MulticastSocketTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/MulticastSocketTest.java
index 264e004..d0bb14a 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/MulticastSocketTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/MulticastSocketTest.java
@@ -71,7 +71,7 @@
// Determine if the device is marked to support multicast or not. If this propery is not
// set we assume the device has an interface capable of supporting multicast.
- supportsMulticast = Boolean.valueOf(
+ supportsMulticast = Boolean.parseBoolean(
System.getProperty("android.cts.device.multicast", "true"));
if (!supportsMulticast) {
return;
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/ServerSocketTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/ServerSocketTest.java
index dca9b74..5279464 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/ServerSocketTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/ServerSocketTest.java
@@ -378,7 +378,7 @@
try {
int portNumber = s.getLocalPort();
// In IPv6, the all-zeros-address is written as "::"
- assertEquals("ServerSocket[addr=/::,localport="
+ assertEquals("ServerSocket[addr=::/::,localport="
+ portNumber + "]", s.toString());
} finally {
s.close();
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/FileChannelTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/FileChannelTest.java
index f3b5f8b..d6dacb4 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/FileChannelTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/FileChannelTest.java
@@ -46,6 +46,8 @@
import junit.framework.TestCase;
+import libcore.io.IoUtils;
+
public class FileChannelTest extends TestCase {
private static final int CAPACITY = 100;
@@ -76,8 +78,12 @@
private FileChannel readOnlyFileChannel;
+ private FileChannel readOnlyFileChannel2;
+
private FileChannel writeOnlyFileChannel;
+ private FileChannel writeOnlyFileChannel2;
+
private FileChannel readWriteFileChannel;
private File fileOfReadOnlyFileChannel;
@@ -121,41 +127,23 @@
fileLock = null;
readOnlyFileChannel = new FileInputStream(fileOfReadOnlyFileChannel)
.getChannel();
+ readOnlyFileChannel2 = new FileInputStream(fileOfReadOnlyFileChannel)
+ .getChannel();
writeOnlyFileChannel = new FileOutputStream(fileOfWriteOnlyFileChannel)
.getChannel();
+ writeOnlyFileChannel2 = new FileOutputStream(fileOfWriteOnlyFileChannel)
+ .getChannel();
readWriteFileChannel = new RandomAccessFile(fileOfReadWriteFileChannel,
"rw").getChannel();
}
protected void tearDown() {
- if (null != readOnlyFileChannel) {
- try {
- readOnlyFileChannel.close();
- } catch (IOException e) {
- // do nothing
- }
- }
- if (null != writeOnlyFileChannel) {
- try {
- writeOnlyFileChannel.close();
- } catch (IOException e) {
- // do nothing
- }
- }
- if (null != readWriteFileChannel) {
- try {
- readWriteFileChannel.close();
- } catch (IOException e) {
- // do nothing
- }
- }
- if (null != fis) {
- try {
- fis.close();
- } catch (IOException e) {
- // do nothing
- }
- }
+ IoUtils.closeQuietly(readOnlyFileChannel);
+ IoUtils.closeQuietly(readOnlyFileChannel2);
+ IoUtils.closeQuietly(writeOnlyFileChannel);
+ IoUtils.closeQuietly(writeOnlyFileChannel2);
+ IoUtils.closeQuietly(readWriteFileChannel);
+ IoUtils.closeQuietly(fis);
if (null != fileLock) {
try {
@@ -174,56 +162,15 @@
if (null != fileOfReadWriteFileChannel) {
fileOfReadWriteFileChannel.delete();
}
- if (null != datagramChannelSender) {
- try {
- datagramChannelSender.close();
- } catch (IOException e) {
- // do nothing
- }
- }
- if (null != datagramChannelReceiver) {
- try {
- datagramChannelReceiver.close();
- } catch (IOException e) {
- // do nothing
- }
- }
- if (null != serverSocketChannel) {
- try {
- serverSocketChannel.close();
- } catch (IOException e) {
- // do nothing
- }
- }
- if (null != socketChannelSender) {
- try {
- socketChannelSender.close();
- } catch (IOException e) {
- // do nothing
- }
- }
- if (null != socketChannelReceiver) {
- try {
- socketChannelReceiver.close();
- } catch (IOException e) {
- // do nothing
- }
- }
+
+ IoUtils.closeQuietly(datagramChannelSender);
+ IoUtils.closeQuietly(datagramChannelReceiver);
+ IoUtils.closeQuietly(serverSocketChannel);
+ IoUtils.closeQuietly(socketChannelSender);
+ IoUtils.closeQuietly(socketChannelReceiver);
if (null != pipe) {
- if (null != pipe.source()) {
- try {
- pipe.source().close();
- } catch (IOException e) {
- // do nothing
- }
- }
- if (null != pipe.sink()) {
- try {
- pipe.sink().close();
- } catch (IOException e) {
- // do nothing
- }
- }
+ IoUtils.closeQuietly(pipe.source());
+ IoUtils.closeQuietly(pipe.sink());
}
}
@@ -653,14 +600,81 @@
/**
* @tests java.nio.channels.FileChannel#lock()
*/
+ public void test_lock_Closed() throws Exception {
+ readOnlyFileChannel.close();
+ try {
+ readOnlyFileChannel.lock();
+ fail("should throw ClosedChannelException");
+ } catch (ClosedChannelException expected) {}
+
+ writeOnlyFileChannel.close();
+ try {
+ writeOnlyFileChannel.lock();
+ fail("should throw ClosedChannelException");
+ } catch (ClosedChannelException expected) {}
+
+ readWriteFileChannel.close();
+ try {
+ readWriteFileChannel.lock();
+ fail("should throw ClosedChannelException");
+ } catch (ClosedChannelException expected) {}
+ }
+
+ /**
+ * @tests java.nio.channels.FileChannel#lock()
+ */
+ public void test_lock_NonWritable() throws Exception {
+ try {
+ readOnlyFileChannel.lock();
+ fail("should throw NonWritableChannelException");
+ } catch (NonWritableChannelException expected) {}
+ }
+
+ /**
+ * @tests java.nio.channels.FileChannel#lock()
+ */
public void test_lock() throws Exception {
- MockFileChannel mockFileChannel = new MockFileChannel();
- // Verify that calling lock() leads to the method
- // lock(long, long, boolean) being called with a 0 for the
- // first parameter, Long.MAX_VALUE as the second parameter and false
- // as the third parameter.
- mockFileChannel.lock();
- assertTrue(mockFileChannel.isLockCalled);
+ fileLock = writeOnlyFileChannel.lock();
+ assertTrue(fileLock.isValid());
+ assertFalse(fileLock.isShared());
+ assertSame(writeOnlyFileChannel, fileLock.channel());
+ assertEquals(Long.MAX_VALUE, fileLock.size());
+ assertEquals(0, fileLock.position());
+ }
+
+ /**
+ * @tests java.nio.channels.FileChannel#lock()
+ */
+ public void test_lock_OverlappingException() throws Exception {
+ fileLock = writeOnlyFileChannel.lock();
+ assertTrue(fileLock.isValid());
+
+ // Test the same channel cannot be locked twice.
+ try {
+ writeOnlyFileChannel.lock();
+ fail("should throw OverlappingFileLockException");
+ } catch (OverlappingFileLockException expected) {}
+
+ // Test that a different channel on the same file also cannot be locked.
+ try {
+ writeOnlyFileChannel2.lock();
+ fail("should throw OverlappingFileLockException");
+ } catch (OverlappingFileLockException expected) {}
+ }
+
+ /**
+ * @tests java.nio.channels.FileChannel#lock()
+ */
+ public void test_lock_After_Release() throws Exception {
+ fileLock = writeOnlyFileChannel.lock();
+ fileLock.release();
+ // After release file lock can be obtained again.
+ fileLock = writeOnlyFileChannel.lock();
+ assertTrue(fileLock.isValid());
+
+ // A different channel should be able to obtain a lock after it has been released
+ fileLock.release();
+ assertTrue(writeOnlyFileChannel2.lock().isValid());
}
/**
@@ -826,12 +840,17 @@
fileLock = writeOnlyFileChannel.lock(POSITION, SIZE, false);
assertTrue(fileLock.isValid());
+ // Test the same channel cannot be locked twice.
try {
writeOnlyFileChannel.lock(POSITION + 1, SIZE, false);
fail("should throw OverlappingFileLockException");
- } catch (OverlappingFileLockException e) {
- // expected
- }
+ } catch (OverlappingFileLockException expected) {}
+
+ // Test that a different channel on the same file also cannot be locked.
+ try {
+ writeOnlyFileChannel2.lock(POSITION + 1, SIZE, false);
+ fail("should throw OverlappingFileLockException");
+ } catch (OverlappingFileLockException expected) {}
}
/**
@@ -861,14 +880,88 @@
/**
* @tests java.nio.channels.FileChannel#tryLock()
*/
+ public void test_tryLock_Closed() throws Exception {
+ readOnlyFileChannel.close();
+ try {
+ readOnlyFileChannel.tryLock();
+ fail("should throw ClosedChannelException");
+ } catch (ClosedChannelException expected) {}
+
+ writeOnlyFileChannel.close();
+ try {
+ writeOnlyFileChannel.tryLock();
+ fail("should throw ClosedChannelException");
+ } catch (ClosedChannelException expected) {}
+
+ readWriteFileChannel.close();
+ try {
+ readWriteFileChannel.tryLock();
+ fail("should throw ClosedChannelException");
+ } catch (ClosedChannelException expected) {}
+ }
+
+ /**
+ * @tests java.nio.channels.FileChannel#tryLock()
+ */
+ public void test_tryLock_NonWritable() throws Exception {
+ try {
+ readOnlyFileChannel.tryLock();
+ fail("should throw NonWritableChannelException");
+ } catch (NonWritableChannelException expected) {}
+ }
+
+ /**
+ * @tests java.nio.channels.FileChannel#tryLock()
+ */
public void test_tryLock() throws Exception {
- MockFileChannel mockFileChannel = new MockFileChannel();
- // Verify that calling tryLock() leads to the method
- // tryLock(long, long, boolean) being called with a 0 for the
- // first parameter, Long.MAX_VALUE as the second parameter and false
- // as the third parameter.
- mockFileChannel.tryLock();
- assertTrue(mockFileChannel.isTryLockCalled);
+ fileLock = writeOnlyFileChannel.tryLock();
+ assertTrue(fileLock.isValid());
+ assertFalse(fileLock.isShared());
+ assertSame(writeOnlyFileChannel, fileLock.channel());
+ assertEquals(0, fileLock.position());
+ assertEquals(Long.MAX_VALUE, fileLock.size());
+ }
+
+ /**
+ * @tests java.nio.channels.FileChannel#tryLock()
+ */
+ public void test_tryLock_Overlapping() throws Exception {
+ fileLock = writeOnlyFileChannel.tryLock();
+ assertTrue(fileLock.isValid());
+
+ // Test the same channel cannot be locked twice.
+ try {
+ writeOnlyFileChannel.tryLock();
+ fail("should throw OverlappingFileLockException");
+ } catch (OverlappingFileLockException expected) {}
+
+ // Test that a different channel on the same file also cannot be locked.
+ try {
+ writeOnlyFileChannel2.tryLock();
+ fail("should throw OverlappingFileLockException");
+ } catch (OverlappingFileLockException expected) {}
+ }
+
+ /**
+ * @tests java.nio.channels.FileChannel#tryLock()
+ */
+ public void test_tryLock_After_Release() throws Exception {
+ fileLock = writeOnlyFileChannel.tryLock();
+ fileLock.release();
+
+ // After release file lock can be obtained again.
+ fileLock = writeOnlyFileChannel.tryLock();
+ assertTrue(fileLock.isValid());
+
+ // Test that the same channel can acquire the lock after it has been released
+ fileLock.release();
+ fileLock = writeOnlyFileChannel.tryLock();
+ assertTrue(fileLock.isValid());
+
+ // Test that a different channel can acquire the lock after it has been released
+ fileLock.release();
+ fileLock = writeOnlyFileChannel2.tryLock();
+ assertTrue(fileLock.isValid());
}
/**
@@ -1034,12 +1127,17 @@
fileLock = writeOnlyFileChannel.lock(POSITION, SIZE, false);
assertTrue(fileLock.isValid());
+ // Test the same channel cannot be locked twice.
try {
- writeOnlyFileChannel.lock(POSITION + 1, SIZE, false);
+ writeOnlyFileChannel.tryLock(POSITION + 1, SIZE, false);
fail("should throw OverlappingFileLockException");
- } catch (OverlappingFileLockException e) {
- // expected
- }
+ } catch (OverlappingFileLockException expected) {}
+
+ // Test that a different channel on the same file also cannot be locked.
+ try {
+ writeOnlyFileChannel2.tryLock(POSITION + 1, SIZE, false);
+ fail("should throw OverlappingFileLockException");
+ } catch (OverlappingFileLockException expected) {}
}
/**
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/ChoiceFormatTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/ChoiceFormatTest.java
index d52e586..e7acfdf 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/ChoiceFormatTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/ChoiceFormatTest.java
@@ -21,6 +21,7 @@
import java.text.FieldPosition;
import java.text.MessageFormat;
import java.text.ParsePosition;
+import java.util.Arrays;
import java.util.Locale;
import junit.framework.TestCase;
@@ -300,9 +301,11 @@
// java.text.ChoiceFormat.getFormats()
String[] orgFormats = (String[]) formats.clone();
String[] f = (String[]) f1.getFormats();
- assertTrue("Wrong formats", f.equals(formats));
+ // getFormats() documentation says "Get the formats passed in the constructor",
+ // which can be interpreted as object identity.
+ assertTrue("Wrong formats", f == formats);
f[0] = "Modified";
- assertTrue("Formats copied", !f.equals(orgFormats));
+ assertTrue("Formats copied", f != orgFormats);
}
/**
@@ -312,9 +315,11 @@
// Test for method double [] java.text.ChoiceFormat.getLimits()
double[] orgLimits = (double[]) limits.clone();
double[] l = f1.getLimits();
- assertTrue("Wrong limits", l.equals(limits));
+ // getLimits() documentation says "Get the limits passed in the constructor",
+ // which can be interpreted as object identity.
+ assertTrue("Wrong limits", l == limits);
l[0] = 3.14527;
- assertTrue("Limits copied", !l.equals(orgLimits));
+ assertTrue("Limits copied", l != orgLimits);
}
/**
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/IdentityHashMapTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/IdentityHashMapTest.java
index bf8db02..ee1a372 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/IdentityHashMapTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/IdentityHashMapTest.java
@@ -36,6 +36,7 @@
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
+import java.util.function.BiFunction;
public class IdentityHashMapTest extends junit.framework.TestCase {
private static final String ID = "hello";
@@ -1054,6 +1055,34 @@
SpliteratorTester.testSpliteratorNPE(values.spliterator());
}
+ public void test_replaceAll() {
+ IdentityHashMap<String, String> map = new IdentityHashMap<>();
+ String key1 = "key1";
+ String key2 = "key2";
+ String key3 = "key3";
+
+ map.put(key1, "1");
+ map.put(key2, "2");
+ map.put(key3, "3");
+
+ map.replaceAll((k, v) -> k + v);
+
+ assertEquals("key11", map.get(key1));
+ assertEquals("key22", map.get(key2));
+ assertEquals("key33", map.get(key3));
+ assertEquals(3, map.size());
+
+ try {
+ map.replaceAll(new BiFunction<String, String, String>() {
+ @Override
+ public String apply(String s, String s2) {
+ map.put("key4", "4");
+ return "";
+ }
+ });
+ } catch (ConcurrentModificationException expected) {}
+ }
+
// comparator for IdentityHashMap objects
private static final SerializableAssert COMPARATOR = new SerializableAssert() {
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/security/auth/callback/PasswordCallbackTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/security/auth/callback/PasswordCallbackTest.java
index 024c9e9..8682de7 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/security/auth/callback/PasswordCallbackTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/security/auth/callback/PasswordCallbackTest.java
@@ -93,7 +93,7 @@
}
pc.clearPassword();
res = pc.getPassword();
- if (res.equals(psw2)) {
+ if (Arrays.equals(res, psw2)) {
fail("Incorrect password was returned after clear");
}
pc.setPassword(psw1);
diff --git a/json/src/main/java/org/json/JSONObject.java b/json/src/main/java/org/json/JSONObject.java
index 9ea91a6..7902389 100644
--- a/json/src/main/java/org/json/JSONObject.java
+++ b/json/src/main/java/org/json/JSONObject.java
@@ -21,6 +21,7 @@
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
// Note: this class was written without inspecting the non-free org.json sourcecode.
@@ -100,6 +101,8 @@
@Override public boolean equals(Object o) {
return o == this || o == null; // API specifies this broken equals implementation
}
+ // at least make the broken equals(null) consistent with Objects.hashCode(null).
+ @Override public int hashCode() { return Objects.hashCode(null); }
@Override public String toString() {
return "null";
}
diff --git a/json/src/test/java/org/json/JSONObjectTest.java b/json/src/test/java/org/json/JSONObjectTest.java
index 9029ec6..07d1cf6 100644
--- a/json/src/test/java/org/json/JSONObjectTest.java
+++ b/json/src/test/java/org/json/JSONObjectTest.java
@@ -27,6 +27,7 @@
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
+import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
import junit.framework.TestCase;
@@ -825,6 +826,12 @@
assertTrue(object.isNull("bar"));
}
+ public void testNullValue_equalsAndHashCode() {
+ assertTrue(JSONObject.NULL.equals(null)); // guaranteed by javadoc
+ // not guaranteed by javadoc, but seems like a good idea
+ assertEquals(Objects.hashCode(null), JSONObject.NULL.hashCode());
+ }
+
public void testHas() throws JSONException {
JSONObject object = new JSONObject();
object.put("foo", 5);
diff --git a/libart/src/main/java/dalvik/system/VMRuntime.java b/libart/src/main/java/dalvik/system/VMRuntime.java
index 74aedd4..8b27ca2 100644
--- a/libart/src/main/java/dalvik/system/VMRuntime.java
+++ b/libart/src/main/java/dalvik/system/VMRuntime.java
@@ -396,4 +396,10 @@
* set.
*/
public static native boolean didPruneDalvikCache();
+
+ /**
+ * Register the current execution thread to the runtime as sensitive thread.
+ * Should be called just once. Subsequent calls are ignored.
+ */
+ public static native void registerSensitiveThread();
}
diff --git a/luni/src/main/java/java/nio/charset/CharsetDecoderICU.java b/luni/src/main/java/java/nio/charset/CharsetDecoderICU.java
index 38be0c2..0a73c9f 100644
--- a/luni/src/main/java/java/nio/charset/CharsetDecoderICU.java
+++ b/luni/src/main/java/java/nio/charset/CharsetDecoderICU.java
@@ -68,6 +68,7 @@
private CharsetDecoderICU(Charset cs, float averageCharsPerByte, long address) {
super(cs, averageCharsPerByte, MAX_CHARS_PER_BYTE);
this.converterHandle = address;
+ NativeConverter.registerConverter(this, converterHandle);
}
@Override protected void implReplaceWith(String newReplacement) {
@@ -155,14 +156,6 @@
}
}
- @Override protected void finalize() throws Throwable {
- try {
- NativeConverter.closeConverter(converterHandle);
- converterHandle = 0;
- } finally {
- super.finalize();
- }
- }
private int getArray(CharBuffer out) {
if (out.hasArray()) {
diff --git a/luni/src/main/java/java/nio/charset/CharsetEncoderICU.java b/luni/src/main/java/java/nio/charset/CharsetEncoderICU.java
index 3583e19..a981c18 100644
--- a/luni/src/main/java/java/nio/charset/CharsetEncoderICU.java
+++ b/luni/src/main/java/java/nio/charset/CharsetEncoderICU.java
@@ -21,6 +21,7 @@
import libcore.icu.ICU;
import libcore.icu.NativeConverter;
import libcore.util.EmptyArray;
+import libcore.util.NativeAllocationRegistry;
final class CharsetEncoderICU extends CharsetEncoder {
private static final Map<String, byte[]> DEFAULT_REPLACEMENTS = new HashMap<String, byte[]>();
@@ -49,7 +50,7 @@
private int[] data = new int[3];
/* handle to the ICU converter that is opened */
- private long converterHandle=0;
+ private final long converterHandle;
private char[] input = null;
private byte[] output = null;
@@ -95,6 +96,7 @@
super(cs, averageBytesPerChar, maxBytesPerChar, replacement, true);
// Our native peer needs to know what just happened...
this.converterHandle = address;
+ NativeConverter.registerConverter(this, converterHandle);
updateCallback();
}
@@ -184,15 +186,6 @@
}
}
- @Override protected void finalize() throws Throwable {
- try {
- NativeConverter.closeConverter(converterHandle);
- converterHandle=0;
- } finally {
- super.finalize();
- }
- }
-
private int getArray(ByteBuffer out) {
if (out.hasArray()) {
output = out.array();
diff --git a/luni/src/main/java/javax/xml/datatype/FactoryFinder.java b/luni/src/main/java/javax/xml/datatype/FactoryFinder.java
index 1fbca2f..c31bee3 100644
--- a/luni/src/main/java/javax/xml/datatype/FactoryFinder.java
+++ b/luni/src/main/java/javax/xml/datatype/FactoryFinder.java
@@ -61,8 +61,8 @@
File f = new File(configFile);
if (f.exists()) {
if (debug) debugPrintln("Read properties file " + f);
- try {
- cacheProps.load(new FileInputStream(f));
+ try (FileInputStream inputStream = new FileInputStream(f)) {
+ cacheProps.load(inputStream);
} catch (Exception ex) {
if (debug) {
ex.printStackTrace();
diff --git a/luni/src/main/java/javax/xml/validation/SchemaFactoryFinder.java b/luni/src/main/java/javax/xml/validation/SchemaFactoryFinder.java
index 0060612..50a644f 100644
--- a/luni/src/main/java/javax/xml/validation/SchemaFactoryFinder.java
+++ b/luni/src/main/java/javax/xml/validation/SchemaFactoryFinder.java
@@ -62,8 +62,8 @@
File f = new File(configFile);
if (f.exists()) {
if (debug) debugPrintln("Read properties file " + f);
- try {
- cacheProps.load(new FileInputStream(f));
+ try (FileInputStream inputStream = new FileInputStream(f)) {
+ cacheProps.load(inputStream);
} catch (Exception ex) {
if (debug) {
ex.printStackTrace();
diff --git a/luni/src/main/java/javax/xml/xpath/XPathFactoryFinder.java b/luni/src/main/java/javax/xml/xpath/XPathFactoryFinder.java
index 5a7663c..7a4f6b3 100644
--- a/luni/src/main/java/javax/xml/xpath/XPathFactoryFinder.java
+++ b/luni/src/main/java/javax/xml/xpath/XPathFactoryFinder.java
@@ -69,8 +69,8 @@
File f = new File(configFile);
if (f.exists()) {
if (debug) debugPrintln("Read properties file " + f);
- try {
- cacheProps.load(new FileInputStream(f));
+ try (FileInputStream inputStream = new FileInputStream(f)) {
+ cacheProps.load(inputStream);
} catch (Exception ex) {
if (debug) {
ex.printStackTrace();
diff --git a/luni/src/main/java/libcore/icu/NativeConverter.java b/luni/src/main/java/libcore/icu/NativeConverter.java
index 17be458..a2b5798 100644
--- a/luni/src/main/java/libcore/icu/NativeConverter.java
+++ b/luni/src/main/java/libcore/icu/NativeConverter.java
@@ -9,12 +9,17 @@
package libcore.icu;
+import libcore.util.NativeAllocationRegistry;
+
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CodingErrorAction;
public final class NativeConverter {
+ private static final NativeAllocationRegistry registry = new NativeAllocationRegistry(
+ getNativeFinalizer(), getNativeSize());
+
public static native int decode(long converterHandle, byte[] input, int inEnd,
char[] output, int outEnd, int[] data, boolean flush);
@@ -24,6 +29,10 @@
public static native long openConverter(String charsetName);
public static native void closeConverter(long converterHandle);
+ public static void registerConverter(Object referrent, long converterHandle) {
+ registry.registerNativeAllocation(referrent, converterHandle);
+ }
+
public static native void resetByteToChar(long converterHandle);
public static native void resetCharToByte(long converterHandle);
@@ -67,4 +76,7 @@
encoder.replacement());
}
private static native void setCallbackEncode(long converterHandle, int onMalformedInput, int onUnmappableInput, byte[] subBytes);
+
+ public static native long getNativeFinalizer();
+ public static native long getNativeSize();
}
diff --git a/luni/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java b/luni/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java
index e1b62fa..e4002ea 100644
--- a/luni/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java
+++ b/luni/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java
@@ -56,7 +56,6 @@
*/
private String documentUri;
private String inputEncoding;
- private String xmlEncoding;
private String xmlVersion = "1.0";
private boolean xmlStandalone = false;
private boolean strictErrorChecking = true;
@@ -437,7 +436,7 @@
}
public String getXmlEncoding() {
- return xmlEncoding;
+ return null;
}
public boolean getXmlStandalone() {
diff --git a/luni/src/main/java/org/xml/sax/helpers/XMLReaderFactory.java b/luni/src/main/java/org/xml/sax/helpers/XMLReaderFactory.java
index c4ff069..39dd367 100644
--- a/luni/src/main/java/org/xml/sax/helpers/XMLReaderFactory.java
+++ b/luni/src/main/java/org/xml/sax/helpers/XMLReaderFactory.java
@@ -126,9 +126,12 @@
in = loader.getResourceAsStream (service);
if (in != null) {
- reader = new BufferedReader (new InputStreamReader (in, StandardCharsets.UTF_8));
- className = reader.readLine ();
- in.close ();
+ try {
+ reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));
+ className = reader.readLine();
+ } finally {
+ in.close(); // may throw IOException
+ }
}
} catch (Exception e) {
}
diff --git a/luni/src/main/native/java_util_regex_Matcher.cpp b/luni/src/main/native/java_util_regex_Matcher.cpp
index 35d014c..3b25233 100644
--- a/luni/src/main/native/java_util_regex_Matcher.cpp
+++ b/luni/src/main/native/java_util_regex_Matcher.cpp
@@ -116,8 +116,18 @@
void operator=(const MatcherAccessor&);
};
-static void Matcher_closeImpl(JNIEnv*, jclass, jlong address) {
- delete toRegexMatcher(address);
+static void Matcher_free(void* address) {
+ delete reinterpret_cast<icu::RegexMatcher*>(address);
+}
+
+static jlong Matcher_getNativeFinalizer(JNIEnv*, jclass) {
+ return reinterpret_cast<jlong>(&Matcher_free);
+}
+
+// Return a guess of the amount of native memory to be deallocated by a typical call to
+// Matcher_free().
+static jint Matcher_nativeSize(JNIEnv*, jclass) {
+ return 200; // Very rough guess based on a quick look at the implementation.
}
static jint Matcher_findImpl(JNIEnv* env, jclass, jlong addr, jstring javaText, jint startIndex, jintArray offsets) {
@@ -198,13 +208,14 @@
}
static JNINativeMethod gMethods[] = {
- NATIVE_METHOD(Matcher, closeImpl, "(J)V"),
NATIVE_METHOD(Matcher, findImpl, "(JLjava/lang/String;I[I)Z"),
NATIVE_METHOD(Matcher, findNextImpl, "(JLjava/lang/String;[I)Z"),
+ NATIVE_METHOD(Matcher, getNativeFinalizer, "()J"),
NATIVE_METHOD(Matcher, groupCountImpl, "(J)I"),
NATIVE_METHOD(Matcher, hitEndImpl, "(J)Z"),
NATIVE_METHOD(Matcher, lookingAtImpl, "(JLjava/lang/String;[I)Z"),
NATIVE_METHOD(Matcher, matchesImpl, "(JLjava/lang/String;[I)Z"),
+ NATIVE_METHOD(Matcher, nativeSize, "()I"),
NATIVE_METHOD(Matcher, openImpl, "(J)J"),
NATIVE_METHOD(Matcher, requireEndImpl, "(J)Z"),
NATIVE_METHOD(Matcher, setInputImpl, "(JLjava/lang/String;II)V"),
diff --git a/luni/src/main/native/java_util_regex_Pattern.cpp b/luni/src/main/native/java_util_regex_Pattern.cpp
index f2c07dc..4166da03 100644
--- a/luni/src/main/native/java_util_regex_Pattern.cpp
+++ b/luni/src/main/native/java_util_regex_Pattern.cpp
@@ -27,10 +27,6 @@
// ICU documentation: http://icu-project.org/apiref/icu4c/classRegexPattern.html
-static icu::RegexPattern* toRegexPattern(jlong addr) {
- return reinterpret_cast<icu::RegexPattern*>(static_cast<uintptr_t>(addr));
-}
-
static const char* regexDetailMessage(UErrorCode status) {
// These human-readable error messages were culled from "utypes.h", and then slightly tuned
// to make more sense in context.
@@ -71,8 +67,18 @@
env->Throw(reinterpret_cast<jthrowable>(exception));
}
-static void Pattern_closeImpl(JNIEnv*, jclass, jlong addr) {
- delete toRegexPattern(addr);
+static void Pattern_free(void* addr) {
+ delete reinterpret_cast<icu::RegexPattern*>(addr);
+}
+
+static jlong Pattern_getNativeFinalizer(JNIEnv*, jclass) {
+ return reinterpret_cast<jlong>(&Pattern_free);
+}
+
+// Return a guess of the amount of native memory to be deallocated by a typical call to
+// Pattern_free().
+static jint Pattern_nativeSize(JNIEnv*, jclass) {
+ return 500; // Very rough guess based on a quick look at the implementation.
}
static jlong Pattern_compileImpl(JNIEnv* env, jclass, jstring javaRegex, jint flags) {
@@ -95,9 +101,11 @@
}
static JNINativeMethod gMethods[] = {
- NATIVE_METHOD(Pattern, closeImpl, "(J)V"),
NATIVE_METHOD(Pattern, compileImpl, "(Ljava/lang/String;I)J"),
+ NATIVE_METHOD(Pattern, getNativeFinalizer, "()J"),
+ NATIVE_METHOD(Pattern, nativeSize, "()I"),
};
+
void register_java_util_regex_Pattern(JNIEnv* env) {
jniRegisterNativeMethods(env, "java/util/regex/Pattern", gMethods, NELEM(gMethods));
}
diff --git a/luni/src/main/native/libcore_icu_NativeConverter.cpp b/luni/src/main/native/libcore_icu_NativeConverter.cpp
index 334f4c9..bf938d1 100644
--- a/luni/src/main/native/libcore_icu_NativeConverter.cpp
+++ b/luni/src/main/native/libcore_icu_NativeConverter.cpp
@@ -611,6 +611,20 @@
javaCanonicalName, icuCanonicalNameStr, javaAliases);
}
+static void FreeNativeConverter(void *converter) {
+ ucnv_close(reinterpret_cast<UConverter*>(converter));
+}
+
+static jlong NativeConverter_getNativeFinalizer(JNIEnv*, jclass) {
+ return reinterpret_cast<jlong>(&FreeNativeConverter);
+}
+
+
+static jlong NativeConverter_getNativeSize(JNIEnv*, jclass, jstring) {
+ // TODO: Improve estimate.
+ return 200;
+}
+
static JNINativeMethod gMethods[] = {
NATIVE_METHOD(NativeConverter, charsetForName, "(Ljava/lang/String;)Ljava/nio/charset/Charset;"),
NATIVE_METHOD(NativeConverter, closeConverter, "(J)V"),
@@ -628,6 +642,8 @@
NATIVE_METHOD(NativeConverter, resetCharToByte, "(J)V"),
NATIVE_METHOD(NativeConverter, setCallbackDecode, "(JIILjava/lang/String;)V"),
NATIVE_METHOD(NativeConverter, setCallbackEncode, "(JII[B)V"),
+ NATIVE_METHOD(NativeConverter, getNativeFinalizer, "()J"),
+ NATIVE_METHOD(NativeConverter, getNativeSize, "()J")
};
void register_libcore_icu_NativeConverter(JNIEnv* env) {
jniRegisterNativeMethods(env, "libcore/icu/NativeConverter", gMethods, NELEM(gMethods));
diff --git a/luni/src/test/java/libcore/java/text/DecimalFormatTest.java b/luni/src/test/java/libcore/java/text/DecimalFormatTest.java
index 0eae20a..2b8b566 100644
--- a/luni/src/test/java/libcore/java/text/DecimalFormatTest.java
+++ b/luni/src/test/java/libcore/java/text/DecimalFormatTest.java
@@ -283,6 +283,13 @@
assertEquals(expected, numberFormat.format(2.01));
}
+ // http://b/27855939
+ public void testBug27855939() {
+ DecimalFormat df = new DecimalFormat("00");
+ assertEquals("01", df.format(BigDecimal.ONE));
+ assertEquals("00", df.format(BigDecimal.ZERO));
+ }
+
// Confirm the currency symbol used by a format is determined by the locale of the format
// not the current default Locale.
public void testSetCurrency_symbolOrigin() {
diff --git a/luni/src/test/java/libcore/java/util/CollectionsTest.java b/luni/src/test/java/libcore/java/util/CollectionsTest.java
index c45b83e..f3284c0 100644
--- a/luni/src/test/java/libcore/java/util/CollectionsTest.java
+++ b/luni/src/test/java/libcore/java/util/CollectionsTest.java
@@ -32,6 +32,9 @@
public final class CollectionsTest extends TestCase {
+ private static final Object NOT_A_STRING = new Object();
+ private static final Object A_STRING = "string";
+
public void testEmptyEnumeration() {
Enumeration<Object> e = Collections.emptyEnumeration();
assertFalse(e instanceof Serializable);
@@ -599,4 +602,140 @@
public void test_SingletonList_sort() {
Collections.singletonList(1).sort((k1, k2) -> 2);
}
+
+ public void test_CheckedMap_replaceAll() {
+ Map<Integer, Integer> map = new HashMap<>();
+ Map checkedMap = Collections.checkedMap(map, Integer.class, Integer.class);
+ checkedMap.put(1, 10);
+ checkedMap.put(2, 20);
+ checkedMap.put(3, 30);
+ checkedMap.replaceAll((k, v) -> (Integer)k + (Integer)v);
+ assertEquals(11, checkedMap.get(1));
+ assertEquals(22, checkedMap.get(2));
+ assertEquals(33, checkedMap.get(3));
+ assertEquals(3, checkedMap.size());
+ }
+
+ public void test_CheckedMap_putIfAbsent() {
+ Map<Integer, Double> map = new HashMap<>();
+ Map checkedMap = Collections.checkedMap(map, Integer.class, Double.class);
+ MapDefaultMethodTester.test_putIfAbsent(checkedMap, true /* acceptsNullKey */,
+ true /* acceptsNullValue */);
+
+ // Without generics to check the typeCheck implementation
+ Map checkedMap2 = Collections.checkedMap(new HashMap<>(), Integer.class, String.class);
+
+ // When key is present
+ checkedMap2.putIfAbsent(1, A_STRING);
+ try {
+ checkedMap2.putIfAbsent(1, NOT_A_STRING);
+ } catch (ClassCastException expected) {}
+
+ // When key is absent
+ checkedMap2.clear();
+ try {
+ checkedMap2.putIfAbsent(1, NOT_A_STRING);
+ } catch (ClassCastException expected) {}
+ }
+
+ public void test_CheckedMap_remove() {
+ Map<Integer, Double> map = new HashMap<>();
+ Map checkedMap = Collections.checkedMap(map, Integer.class, Double.class);
+ MapDefaultMethodTester.test_remove(checkedMap, true /* acceptsNullKey */,
+ true /* acceptsNullValue */);
+ }
+
+ public void test_CheckedMap_replace$K$V$V() {
+ Map<Integer, Double> map = new HashMap<>();
+ Map checkedMap = Collections.checkedMap(map, Integer.class, Double.class);
+ MapDefaultMethodTester.test_replace$K$V$V(checkedMap, true /* acceptsNullKey */,
+ true /* acceptsNullValue */);
+
+ // Without generics to check the typeCheck implementation
+ Map checkedMap2 = Collections.checkedMap(new HashMap<>(), Integer.class, String.class);
+ checkedMap2.put(1, A_STRING);
+
+ try {
+ checkedMap2.replace(1, NOT_A_STRING);
+ } catch (ClassCastException expected) {}
+ }
+
+ public void test_CheckedMap_replace$K$V() {
+ Map<Integer, Double> map = new HashMap<>();
+ Map checkedMap = Collections.checkedMap(map, Integer.class, Double.class);
+ MapDefaultMethodTester.test_replace$K$V(checkedMap, true /* acceptsNullKey */,
+ true /* acceptsNullValue */);
+
+ // Without generics to check the typeCheck implementation
+ Map checkedMap2 = Collections.checkedMap(new HashMap<>(), Integer.class, String.class);
+ checkedMap2.put(1, A_STRING);
+
+ try {
+ checkedMap2.replace(1, 1, NOT_A_STRING);
+ } catch (ClassCastException expected) {}
+ }
+
+ public void test_CheckedMap_computeIfAbsent() {
+ Map<Integer, Double> map = new HashMap<>();
+ Map checkedMap = Collections.checkedMap(map, Integer.class, Double.class);
+ MapDefaultMethodTester.test_computeIfAbsent(checkedMap, true /* acceptsNullKey */,
+ true /* acceptsNullValue */);
+
+ // Without generics to check the typeCheck implementation
+ Map checkedMap2 = Collections.checkedMap(new HashMap<>(), Integer.class, String.class);
+ checkedMap2.put(1, A_STRING);
+
+ // When key is present
+ try {
+ checkedMap2.computeIfAbsent(1, k -> NOT_A_STRING);
+ } catch (ClassCastException expected) {}
+
+ // When key is absent
+ checkedMap2.clear();
+ try {
+ checkedMap2.computeIfAbsent(1, k -> NOT_A_STRING);
+ } catch (ClassCastException expected) {}
+ }
+
+ public void test_CheckedMap_computeIfPresent() {
+ Map<Integer, Double> map = new HashMap<>();
+ Map checkedMap = Collections.checkedMap(map, Integer.class, Double.class);
+ MapDefaultMethodTester.test_computeIfPresent(checkedMap, true /* acceptsNullKey */);
+
+ // Without generics to check the typeCheck implementation
+ Map m = new HashMap();
+ Map checkedMap2 = Collections.checkedMap(m, Integer.class, String.class);
+ checkedMap2.put(1, A_STRING);
+
+ try {
+ checkedMap2.computeIfPresent(1, (k, v) -> NOT_A_STRING);
+ } catch (ClassCastException expected) {}
+ }
+
+ public void test_CheckedMap_compute() {
+ Map<Integer, Double> map = new HashMap<>();
+ Map checkedMap = Collections.checkedMap(map, Integer.class, Double.class);
+ MapDefaultMethodTester.test_compute(checkedMap, true /* acceptsNullKey */);
+
+ Map checkedMap2 = Collections.checkedMap(new HashMap(), Integer.class, String.class);
+ checkedMap2.put(1, A_STRING);
+ try {
+ checkedMap2.compute(1, (k, v) -> NOT_A_STRING);
+ } catch (ClassCastException expected) {}
+ }
+
+ public void test_CheckedMap_merge() {
+ Map<Integer, Double> map = new HashMap<>();
+ Map checkedMap = Collections.checkedMap(map, Integer.class, Double.class);
+ MapDefaultMethodTester.test_merge(checkedMap, true /* acceptsNullKey */);
+
+ // Without generics to check the typeCheck implementation
+ Map checkedMap2 =
+ Collections.checkedMap(new HashMap<>(), Integer.class, String.class);
+ checkedMap2.put(1, A_STRING);
+
+ try {
+ checkedMap2.merge(1, A_STRING, (v1, v2) -> NOT_A_STRING);
+ } catch (ClassCastException expected) {}
+ }
}
diff --git a/luni/src/test/java/libcore/java/util/TreeMapTest.java b/luni/src/test/java/libcore/java/util/TreeMapTest.java
index a358ef8..355d29d 100644
--- a/luni/src/test/java/libcore/java/util/TreeMapTest.java
+++ b/luni/src/test/java/libcore/java/util/TreeMapTest.java
@@ -596,4 +596,14 @@
fail();
} catch(ConcurrentModificationException expected) {}
}
+
+ public void test_replace$K$V$V() {
+ MapDefaultMethodTester.test_replace$K$V$V(new TreeMap<>(), false /* acceptsNullKey */,
+ true /* acceptsNullValue */);
+ }
+
+ public void test_replace$K$V() {
+ MapDefaultMethodTester.test_replace$K$V(new TreeMap<>(), false /* acceptsNullKey */,
+ true /* acceptsNullValue */);
+ }
}
diff --git a/luni/src/test/java/tests/security/cert/X509CertSelectorTest.java b/luni/src/test/java/tests/security/cert/X509CertSelectorTest.java
index a6eaf05..1616efb 100644
--- a/luni/src/test/java/tests/security/cert/X509CertSelectorTest.java
+++ b/luni/src/test/java/tests/security/cert/X509CertSelectorTest.java
@@ -397,7 +397,8 @@
selector.setIssuer(iss1);
assertTrue("The returned issuer should be equal to specified",
Arrays.equals(name1, selector.getIssuerAsBytes()));
- assertFalse("The returned issuer should differ", name2.equals(selector.getIssuerAsBytes()));
+ assertFalse("The returned issuer should differ",
+ Arrays.equals(name2, selector.getIssuerAsBytes()));
selector.setIssuer(iss2);
assertTrue("The returned issuer should be equal to specified",
Arrays.equals(name2, selector.getIssuerAsBytes()));
@@ -682,7 +683,7 @@
assertTrue("The returned issuer should be equal to specified",
Arrays.equals(name1, selector.getSubjectAsBytes()));
assertFalse("The returned issuer should differ",
- name2.equals(selector.getSubjectAsBytes()));
+ Arrays.equals(name2, selector.getSubjectAsBytes()));
selector.setSubject(sub2);
assertTrue("The returned issuer should be equal to specified",
Arrays.equals(name2, selector.getSubjectAsBytes()));
diff --git a/ojluni/src/main/java/java/lang/AbstractStringBuilder.java b/ojluni/src/main/java/java/lang/AbstractStringBuilder.java
index e11ae3c..dfc2c6b 100755
--- a/ojluni/src/main/java/java/lang/AbstractStringBuilder.java
+++ b/ojluni/src/main/java/java/lang/AbstractStringBuilder.java
@@ -478,8 +478,16 @@
+ s.length());
int len = end - start;
ensureCapacityInternal(count + len);
- for (int i = start, j = count; i < end; i++, j++)
- value[j] = s.charAt(i);
+ if (s instanceof String) {
+ ((String) s).getCharsNoCheck(start, end, value, count);
+ } else if (s instanceof AbstractStringBuilder) {
+ AbstractStringBuilder other = (AbstractStringBuilder) s;
+ System.arraycopy(other.value, start, value, count, len);
+ } else {
+ for (int i = start, j = count; i < end; i++, j++) {
+ value[j] = s.charAt(i);
+ }
+ }
count += len;
return this;
}
diff --git a/ojluni/src/main/java/java/lang/String.java b/ojluni/src/main/java/java/lang/String.java
index 2781546..8a83df9 100755
--- a/ojluni/src/main/java/java/lang/String.java
+++ b/ojluni/src/main/java/java/lang/String.java
@@ -2211,17 +2211,13 @@
sb = new StringBuilder(count);
}
- for (int i = lastMatch; i < currentMatch; ++i) {
- sb.append(charAt(i));
- }
+ sb.append(this, lastMatch, currentMatch);
sb.append(replacementStr);
lastMatch = currentMatch + targetStr.count;
}
if (sb != null) {
- for (int i = lastMatch; i < count; ++i) {
- sb.append(charAt(i));
- }
+ sb.append(this, lastMatch, count);
return sb.toString();
} else {
return this;
diff --git a/ojluni/src/main/java/java/net/Inet6Address.java b/ojluni/src/main/java/java/net/Inet6Address.java
index a46223d..f66b68d 100755
--- a/ojluni/src/main/java/java/net/Inet6Address.java
+++ b/ojluni/src/main/java/java/net/Inet6Address.java
@@ -171,7 +171,7 @@
/** @hide */
public static final InetAddress ANY =
- new Inet6Address(null, new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0);
+ new Inet6Address("::", new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0);
/** @hide */
public static final InetAddress LOOPBACK = new Inet6Address("localhost",
diff --git a/ojluni/src/main/java/java/text/ChoiceFormat.java b/ojluni/src/main/java/java/text/ChoiceFormat.java
index f513cd9..ccbd24f 100755
--- a/ojluni/src/main/java/java/text/ChoiceFormat.java
+++ b/ojluni/src/main/java/java/text/ChoiceFormat.java
@@ -208,7 +208,7 @@
} else if (tempBuffer.equals("-\u221E")) {
startValue = Double.NEGATIVE_INFINITY;
} else {
- startValue = Double.valueOf(segments[0].toString()).doubleValue();
+ startValue = Double.parseDouble(segments[0].toString());
}
} catch (Exception e) {
throw new IllegalArgumentException();
diff --git a/ojluni/src/main/java/java/text/DecimalFormat.java b/ojluni/src/main/java/java/text/DecimalFormat.java
index b8eade3..bcc9e8b 100755
--- a/ojluni/src/main/java/java/text/DecimalFormat.java
+++ b/ojluni/src/main/java/java/text/DecimalFormat.java
@@ -465,10 +465,7 @@
private void init(String pattern) {
this.icuDecimalFormat = new android.icu.text.DecimalFormat(pattern,
symbols.getIcuDecimalFormatSymbols());
- maximumIntegerDigits = icuDecimalFormat.getMaximumIntegerDigits();
- minimumIntegerDigits = icuDecimalFormat.getMinimumIntegerDigits();
- maximumFractionDigits = icuDecimalFormat.getMaximumFractionDigits();
- minimumFractionDigits = icuDecimalFormat.getMinimumFractionDigits();
+ updateFieldsFromIcu();
}
/**
@@ -1169,6 +1166,12 @@
}
private void updateFieldsFromIcu() {
+ // Imitate behaviour of ICU4C NumberFormat that Android used up to M.
+ // If the pattern doesn't enforce a different value (some exponential
+ // patterns do), then set the maximum integer digits to 2 billion.
+ if (icuDecimalFormat.getMaximumIntegerDigits() == DOUBLE_INTEGER_DIGITS) {
+ icuDecimalFormat.setMaximumIntegerDigits(2000000000);
+ }
maximumIntegerDigits = icuDecimalFormat.getMaximumIntegerDigits();
minimumIntegerDigits = icuDecimalFormat.getMinimumIntegerDigits();
maximumFractionDigits = icuDecimalFormat.getMaximumFractionDigits();
diff --git a/ojluni/src/main/java/java/util/Collections.java b/ojluni/src/main/java/java/util/Collections.java
index 6b19738..1a9f83a 100644
--- a/ojluni/src/main/java/java/util/Collections.java
+++ b/ojluni/src/main/java/java/util/Collections.java
@@ -1796,7 +1796,6 @@
// Synch Wrappers
- // TODO: Replace {@code stream} with {@link Stream} once we have them.
/**
* Returns a synchronized (thread-safe) collection backed by the specified
* collection. In order to guarantee serial access, it is critical that
@@ -1805,7 +1804,7 @@
*
* It is imperative that the user manually synchronize on the returned
* collection when traversing it via {@link Iterator}, {@link Spliterator}
- * or {@code Stream}:
+ * or {@link Stream}:
* <pre>
* Collection c = Collections.synchronizedCollection(myCollection);
* ...
@@ -2884,14 +2883,6 @@
public boolean addAll(int index, Collection<? extends E> c) {
return list.addAll(index, checkedCopyOf(c));
}
- @Override
- public void replaceAll(UnaryOperator<E> operator) {
- list.replaceAll(operator);
- }
- @Override
- public void sort(Comparator<? super E> c) {
- list.sort(c);
- }
public ListIterator<E> listIterator() { return listIterator(0); }
public ListIterator<E> listIterator(final int index) {
@@ -2926,6 +2917,32 @@
public List<E> subList(int fromIndex, int toIndex) {
return new CheckedList<>(list.subList(fromIndex, toIndex), type);
}
+
+ /**
+ * {@inheritDoc}
+ *
+ * @throws ClassCastException if the class of an element returned by the
+ * operator prevents it from being added to this collection. The
+ * exception may be thrown after some elements of the list have
+ * already been replaced.
+ */
+ @Override
+ public void replaceAll(UnaryOperator<E> operator) {
+ Objects.requireNonNull(operator);
+
+ // Android-changed: Modified from OpenJDK 8 code because typeCheck returns void in
+ // OpenJDK 7.
+ list.replaceAll(e -> {
+ E newValue = operator.apply(e);
+ typeCheck(newValue);
+ return newValue;
+ });
+ }
+
+ @Override
+ public void sort(Comparator<? super E> c) {
+ list.sort(c);
+ }
}
/**
@@ -3088,6 +3105,68 @@
m.forEach(action);
}
+ @Override
+ public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+ m.replaceAll(typeCheck(function));
+ }
+
+ @Override
+ public V putIfAbsent(K key, V value) {
+ typeCheck(key, value);
+ return m.putIfAbsent(key, value);
+ }
+
+ @Override
+ public boolean remove(Object key, Object value) {
+ return m.remove(key, value);
+ }
+
+ @Override
+ public boolean replace(K key, V oldValue, V newValue) {
+ typeCheck(key, newValue);
+ return m.replace(key, oldValue, newValue);
+ }
+
+ @Override
+ public V replace(K key, V value) {
+ typeCheck(key, value);
+ return m.replace(key, value);
+ }
+
+ @Override
+ public V computeIfAbsent(K key,
+ Function<? super K, ? extends V> mappingFunction) {
+ Objects.requireNonNull(mappingFunction);
+ return m.computeIfAbsent(key, k -> {
+ V value = mappingFunction.apply(k);
+ typeCheck(k, value);
+ return value;
+ });
+ }
+
+ @Override
+ public V computeIfPresent(K key,
+ BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+ return m.computeIfPresent(key, typeCheck(remappingFunction));
+ }
+
+ @Override
+ public V compute(K key,
+ BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+ return m.compute(key, typeCheck(remappingFunction));
+ }
+
+ @Override
+ public V merge(K key, V value,
+ BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+ Objects.requireNonNull(remappingFunction);
+ return m.merge(key, value, (v1, v2) -> {
+ V newValue = remappingFunction.apply(v1, v2);
+ typeCheck(null, newValue);
+ return newValue;
+ });
+ }
+
/**
* We need this class in addition to CheckedSet as Map.Entry permits
* modification of the backing Map via the setValue operation. This
diff --git a/ojluni/src/main/java/java/util/ComparableTimSort.java b/ojluni/src/main/java/java/util/ComparableTimSort.java
index e7c7ac0..36c8d90 100755
--- a/ojluni/src/main/java/java/util/ComparableTimSort.java
+++ b/ojluni/src/main/java/java/util/ComparableTimSort.java
@@ -144,10 +144,14 @@
* large) stack lengths for smaller arrays. The "magic numbers" in the
* computation below must be changed if MIN_MERGE is decreased. See
* the MIN_MERGE declaration above for more information.
+ * The maximum value of 49 allows for an array up to length
+ * Integer.MAX_VALUE-4, if array is filled by the worst case stack size
+ * increasing scenario. More explanations are given in section 4 of:
+ * http://envisage-project.eu/wp-content/uploads/2015/02/sorting.pdf
*/
int stackLen = (len < 120 ? 5 :
len < 1542 ? 10 :
- len < 119151 ? 24 : 40);
+ len < 119151 ? 24 : 49);
runBase = new int[stackLen];
runLen = new int[stackLen];
}
diff --git a/ojluni/src/main/java/java/util/IdentityHashMap.java b/ojluni/src/main/java/java/util/IdentityHashMap.java
index ea1948d..b860cca 100755
--- a/ojluni/src/main/java/java/util/IdentityHashMap.java
+++ b/ojluni/src/main/java/java/util/IdentityHashMap.java
@@ -28,6 +28,7 @@
import java.io.*;
import java.lang.reflect.Array;
import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
import java.util.function.Consumer;
/**
@@ -1359,6 +1360,25 @@
}
}
+ @SuppressWarnings("unchecked")
+ @Override
+ public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+ Objects.requireNonNull(function);
+ int expectedModCount = modCount;
+
+ Object[] t = table;
+ for (int index = 0; index < t.length; index += 2) {
+ Object k = t[index];
+ if (k != null) {
+ t[index + 1] = function.apply((K) unmaskNull(k), (V) t[index + 1]);
+ }
+
+ if (modCount != expectedModCount) {
+ throw new ConcurrentModificationException();
+ }
+ }
+ }
+
/**
* Similar form as array-based Spliterators, but skips blank elements,
* and guestimates size as decreasing by half per split.
diff --git a/ojluni/src/main/java/java/util/Spliterators.java b/ojluni/src/main/java/java/util/Spliterators.java
index 3f97a83..79c0ef3 100644
--- a/ojluni/src/main/java/java/util/Spliterators.java
+++ b/ojluni/src/main/java/java/util/Spliterators.java
@@ -384,7 +384,7 @@
*/
private static void checkFromToBounds(int arrayLength, int origin, int fence) {
if (origin > fence) {
- throw new IllegalArgumentException(
+ throw new ArrayIndexOutOfBoundsException(
"origin(" + origin + ") > fence(" + fence + ")");
}
if (origin < 0) {
diff --git a/ojluni/src/main/java/java/util/TimSort.java b/ojluni/src/main/java/java/util/TimSort.java
index 9966f74..ea0d58f 100755
--- a/ojluni/src/main/java/java/util/TimSort.java
+++ b/ojluni/src/main/java/java/util/TimSort.java
@@ -174,10 +174,14 @@
* large) stack lengths for smaller arrays. The "magic numbers" in the
* computation below must be changed if MIN_MERGE is decreased. See
* the MIN_MERGE declaration above for more information.
+ * The maximum value of 49 allows for an array up to length
+ * Integer.MAX_VALUE-4, if array is filled by the worst case stack size
+ * increasing scenario. More explanations are given in section 4 of:
+ * http://envisage-project.eu/wp-content/uploads/2015/02/sorting.pdf
*/
int stackLen = (len < 120 ? 5 :
len < 1542 ? 10 :
- len < 119151 ? 24 : 40);
+ len < 119151 ? 24 : 49);
runBase = new int[stackLen];
runLen = new int[stackLen];
}
diff --git a/ojluni/src/main/java/java/util/TreeMap.java b/ojluni/src/main/java/java/util/TreeMap.java
index 49346ca..5e26f0f 100755
--- a/ojluni/src/main/java/java/util/TreeMap.java
+++ b/ojluni/src/main/java/java/util/TreeMap.java
@@ -998,6 +998,27 @@
}
@Override
+ public boolean replace(K key, V oldValue, V newValue) {
+ TreeMapEntry<K,V> p = getEntry(key);
+ if (p!=null && Objects.equals(oldValue, p.value)) {
+ p.value = newValue;
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public V replace(K key, V value) {
+ TreeMapEntry<K,V> p = getEntry(key);
+ if (p!=null) {
+ V oldValue = p.value;
+ p.value = value;
+ return oldValue;
+ }
+ return null;
+ }
+
+ @Override
public void forEach(BiConsumer<? super K, ? super V> action) {
Objects.requireNonNull(action);
int expectedModCount = modCount;
@@ -1014,6 +1035,7 @@
public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
Objects.requireNonNull(function);
int expectedModCount = modCount;
+
for (TreeMapEntry<K, V> e = getFirstEntry(); e != null; e = successor(e)) {
e.value = function.apply(e.key, e.value);
diff --git a/ojluni/src/main/java/java/util/logging/Logger.java b/ojluni/src/main/java/java/util/logging/Logger.java
index e9728de..3652914 100755
--- a/ojluni/src/main/java/java/util/logging/Logger.java
+++ b/ojluni/src/main/java/java/util/logging/Logger.java
@@ -329,7 +329,7 @@
return System.getProperty(key);
}
});
- return Boolean.valueOf(s);
+ return Boolean.parseBoolean(s);
}
}
diff --git a/ojluni/src/main/java/java/util/regex/Matcher.java b/ojluni/src/main/java/java/util/regex/Matcher.java
index 47062d7..dc37946 100755
--- a/ojluni/src/main/java/java/util/regex/Matcher.java
+++ b/ojluni/src/main/java/java/util/regex/Matcher.java
@@ -26,6 +26,7 @@
package java.util.regex;
+import libcore.util.NativeAllocationRegistry;
/**
* An engine that performs match operations on a {@link java.lang.CharSequence
@@ -115,6 +116,14 @@
private long address;
/**
+ * If non-null, a Runnable that can be used to explicitly deallocate address.
+ */
+ private Runnable nativeFinalizer;
+
+ private static final NativeAllocationRegistry registry = new NativeAllocationRegistry(
+ getNativeFinalizer(), nativeSize());
+
+ /**
* Holds the input text.
*/
private String input;
@@ -211,11 +220,13 @@
this.pattern = newPattern;
synchronized (this) {
- if (address != 0) {
- closeImpl(address);
+ if (nativeFinalizer != null) {
+ nativeFinalizer.run();
address = 0; // In case openImpl throws.
+ nativeFinalizer = null;
}
address = openImpl(pattern.address);
+ nativeFinalizer = registry.registerNativeAllocation(this, address);
}
if (input != null) {
@@ -1041,16 +1052,6 @@
}
}
- @Override protected void finalize() throws Throwable {
- try {
- synchronized (this) {
- closeImpl(address);
- }
- } finally {
- super.finalize();
- }
- }
-
/**
* Returns the start index of the previous match. </p>
*
@@ -1093,13 +1094,14 @@
return matchOffsets[group * 2];
}
- private static native void closeImpl(long addr);
private static native boolean findImpl(long addr, String s, int startIndex, int[] offsets);
private static native boolean findNextImpl(long addr, String s, int[] offsets);
+ private static native long getNativeFinalizer();
private static native int groupCountImpl(long addr);
private static native boolean hitEndImpl(long addr);
private static native boolean lookingAtImpl(long addr, String s, int[] offsets);
private static native boolean matchesImpl(long addr, String s, int[] offsets);
+ private static native int nativeSize();
private static native long openImpl(long patternAddr);
private static native boolean requireEndImpl(long addr);
private static native void setInputImpl(long addr, String s, int start, int end);
diff --git a/ojluni/src/main/java/java/util/regex/Pattern.java b/ojluni/src/main/java/java/util/regex/Pattern.java
index 442e22b..1d772d9 100755
--- a/ojluni/src/main/java/java/util/regex/Pattern.java
+++ b/ojluni/src/main/java/java/util/regex/Pattern.java
@@ -26,6 +26,8 @@
package java.util.regex;
+import libcore.util.NativeAllocationRegistry;
+
import java.util.Iterator;
import java.util.ArrayList;
import java.util.NoSuchElementException;
@@ -927,6 +929,9 @@
transient long address;
+ private static final NativeAllocationRegistry registry = new NativeAllocationRegistry(
+ getNativeFinalizer(), nativeSize());
+
/**
* Compiles the given regular expression into a pattern. </p>
@@ -1333,21 +1338,12 @@
// They even have the same value in native code.
int icuFlags = flags & (CASE_INSENSITIVE | COMMENTS | MULTILINE | DOTALL | UNIX_LINES);
address = compileImpl(icuPattern, icuFlags);
+ registry.registerNativeAllocation(this, address);
}
-
- @Override
- protected void finalize() throws Throwable {
- try {
- closeImpl(address);
- } finally {
- super.finalize();
- }
- }
-
- private static native void closeImpl(long addr);
private static native long compileImpl(String regex, int flags);
-
+ private static native long getNativeFinalizer();
+ private static native int nativeSize();
/**
* Creates a predicate which can be used to match a string.
diff --git a/ojluni/src/main/java/sun/misc/VM.java b/ojluni/src/main/java/sun/misc/VM.java
index e8af1d1..b57eb4a 100755
--- a/ojluni/src/main/java/sun/misc/VM.java
+++ b/ojluni/src/main/java/sun/misc/VM.java
@@ -295,7 +295,7 @@
allowGetCallerClass = (s != null
? (s.isEmpty() || Boolean.parseBoolean(s))
: true) ||
- Boolean.valueOf(props.getProperty("jdk.logging.allowStackWalkSearch"));
+ Boolean.parseBoolean(props.getProperty("jdk.logging.allowStackWalkSearch"));
// Remove other private system properties
// used by java.lang.Integer.IntegerCache
diff --git a/ojluni/src/main/java/sun/misc/Version.java b/ojluni/src/main/java/sun/misc/Version.java
index 0a7de82..2908005 100644
--- a/ojluni/src/main/java/sun/misc/Version.java
+++ b/ojluni/src/main/java/sun/misc/Version.java
@@ -280,7 +280,7 @@
int nextChar = 3;
try {
String uu = cs.subSequence(1, 3).toString();
- jvm_update_version = Integer.valueOf(uu).intValue();
+ jvm_update_version = Integer.parseInt(uu);
if (cs.length() >= 4) {
char c = cs.charAt(3);
if (c >= 'a' && c <= 'z') {
@@ -305,7 +305,7 @@
Character.isDigit(s.charAt(1)) &&
Character.isDigit(s.charAt(2))) {
jvm_build_number =
- Integer.valueOf(s.substring(1, 3)).intValue();
+ Integer.parseInt(s.substring(1, 3));
break;
}
}
diff --git a/ojluni/src/main/java/sun/net/www/http/HttpClient.java b/ojluni/src/main/java/sun/net/www/http/HttpClient.java
index b5a4329..09e0dbb 100755
--- a/ojluni/src/main/java/sun/net/www/http/HttpClient.java
+++ b/ojluni/src/main/java/sun/net/www/http/HttpClient.java
@@ -150,13 +150,13 @@
new sun.security.action.GetPropertyAction("sun.net.http.retryPost"));
if (keepAlive != null) {
- keepAliveProp = Boolean.valueOf(keepAlive).booleanValue();
+ keepAliveProp = Boolean.parseBoolean(keepAlive);
} else {
keepAliveProp = true;
}
if (retryPost != null) {
- retryPostProp = Boolean.valueOf(retryPost).booleanValue();
+ retryPostProp = Boolean.parseBoolean(retryPost);
} else
retryPostProp = true;
diff --git a/ojluni/src/main/java/sun/nio/ch/EPollSelectorImpl.java b/ojluni/src/main/java/sun/nio/ch/EPollSelectorImpl.java
index aac539b..113f84b 100755
--- a/ojluni/src/main/java/sun/nio/ch/EPollSelectorImpl.java
+++ b/ojluni/src/main/java/sun/nio/ch/EPollSelectorImpl.java
@@ -159,7 +159,7 @@
if (closed)
throw new ClosedSelectorException();
SelChImpl ch = ski.channel;
- int fd = Integer.valueOf(ch.getFDVal());
+ Integer fd = Integer.valueOf(ch.getFDVal());
fdToKey.put(fd, ski);
pollWrapper.add(fd);
keys.add(ski);
diff --git a/ojluni/src/main/java/sun/security/ssl/SSLSessionContextImpl.java b/ojluni/src/main/java/sun/security/ssl/SSLSessionContextImpl.java
index 51fac9b..756a48e 100755
--- a/ojluni/src/main/java/sun/security/ssl/SSLSessionContextImpl.java
+++ b/ojluni/src/main/java/sun/security/ssl/SSLSessionContextImpl.java
@@ -207,7 +207,7 @@
"javax.net.ssl.sessionCacheSize");
}
});
- cacheLimit = (s != null) ? Integer.valueOf(s).intValue() : 0;
+ cacheLimit = (s != null) ? Integer.parseInt(s) : 0;
} catch (Exception e) {
}
diff --git a/support/src/test/java/libcore/java/security/CpuFeatures.java b/support/src/test/java/libcore/java/security/CpuFeatures.java
index 30ca868..319056a 100644
--- a/support/src/test/java/libcore/java/security/CpuFeatures.java
+++ b/support/src/test/java/libcore/java/security/CpuFeatures.java
@@ -19,6 +19,8 @@
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
@@ -39,6 +41,19 @@
return true;
}
+ // If we're in an emulated ABI, Conscrypt's NativeCrypto might bridge to
+ // a library that has accelerated AES instructions. See if Conscrypt
+ // detects that condition.
+ try {
+ Class<?> nativeCrypto = Class.forName("com.android.org.conscrypt.NativeCrypto");
+ Method EVP_has_aes_hardware = nativeCrypto.getDeclaredMethod("EVP_has_aes_hardware");
+ return ((Integer) EVP_has_aes_hardware.invoke(null)) == 1;
+ } catch (ClassNotFoundException | NoSuchMethodException | SecurityException
+ | IllegalAccessException | IllegalArgumentException ignored) {
+ } catch (InvocationTargetException e) {
+ throw new IllegalArgumentException(e);
+ }
+
return false;
}