Merge "Removing differences between AOSP and internal" into lmp-dev
diff --git a/dalvik/src/main/java/dalvik/system/ZygoteHooks.java b/dalvik/src/main/java/dalvik/system/ZygoteHooks.java
index fa4f392..dc730e6 100644
--- a/dalvik/src/main/java/dalvik/system/ZygoteHooks.java
+++ b/dalvik/src/main/java/dalvik/system/ZygoteHooks.java
@@ -28,6 +28,19 @@
private long token;
/**
+ * Temporary hack: check time since start time and log if over a fixed threshold.
+ *
+ */
+ private static void checkTime(long startTime, String where) {
+ long now = System.nanoTime();
+ long msDuration = (now - startTime) / (1000 * 1000);
+ if (msDuration > 1000) {
+ // If we are taking more than a second, log about it.
+ System.logW("Slow operation: " + msDuration + "ms so far, now at " + where);
+ }
+ }
+
+ /**
* Called by the zygote prior to every fork. Each call to {@code preFork}
* is followed by a matching call to {@link #postForkChild(int)} on the child
* process and {@link #postForkCommon()} on both the parent and the child
@@ -35,17 +48,22 @@
* the child process.
*/
public void preFork() {
+ long startTime = System.nanoTime();
Daemons.stop();
+ checkTime(startTime, "ZygoteHooks.Daemons.stop");
waitUntilAllThreadsStopped();
+ checkTime(startTime, "ZygoteHooks.waituntilallthreadsstopped");
token = nativePreFork();
+ checkTime(startTime, "ZygoteHooks.Daemons.nativePreFork");
}
/**
* Called by the zygote in the child process after every fork. The debug
- * flags from {@code debugFlags} are applied to the child process.
+ * flags from {@code debugFlags} are applied to the child process. The string
+ * {@code instructionSet} determines whether to use a native bridge.
*/
- public void postForkChild(int debugFlags) {
- nativePostForkChild(token, debugFlags);
+ public void postForkChild(int debugFlags, String instructionSet) {
+ nativePostForkChild(token, debugFlags, instructionSet);
}
/**
@@ -58,7 +76,8 @@
}
private static native long nativePreFork();
- private static native void nativePostForkChild(long token, int debugFlags);
+ private static native void nativePostForkChild(long token, int debugFlags,
+ String instructionSet);
/**
* We must not fork until we're single-threaded again. Wait until /proc shows we're
diff --git a/expectations/knownfailures.txt b/expectations/knownfailures.txt
index 3de387a..175fe03 100644
--- a/expectations/knownfailures.txt
+++ b/expectations/knownfailures.txt
@@ -1458,5 +1458,12 @@
names: [
"com.squareup.okhttp.internal.http.HttpResponseCacheTest#setIfModifiedSince"
]
+},
+{
+ description: "libcore.java.text.DecimalFormatSymbolsTest#test_getInstance_unknown_or_invalid_locale assumes fallback to locale other than en_US_POSIX.",
+ bug: 17374604,
+ names: [
+ "libcore.java.text.DecimalFormatSymbolsTest#test_getInstance_unknown_or_invalid_locale"
+ ]
}
]
diff --git a/libart/src/main/java/java/lang/Daemons.java b/libart/src/main/java/java/lang/Daemons.java
index 1422c13..6f94f7f 100644
--- a/libart/src/main/java/java/lang/Daemons.java
+++ b/libart/src/main/java/java/lang/Daemons.java
@@ -35,20 +35,47 @@
private static final int NANOS_PER_SECOND = NANOS_PER_MILLI * 1000;
private static final long MAX_FINALIZE_NANOS = 10L * NANOS_PER_SECOND;
+ /**
+ * Temporary hack: check time since start time and log if over a fixed threshold.
+ *
+ * @return void
+ */
+ private static void checkTime(long startTime, String where) {
+ long now = System.nanoTime();
+ long msDuration = (now - startTime) / (1000 * 1000);
+ if (msDuration > 1000) {
+ // If we are taking more than a second, log about it.
+ System.logW("Slow operation: " + msDuration + "ms so far, now at " + where);
+ }
+ }
+
+
public static void start() {
+ long startTime = System.nanoTime();
ReferenceQueueDaemon.INSTANCE.start();
+ checkTime(startTime, "Daemons.ReferenceQueueDaemonStart");
FinalizerDaemon.INSTANCE.start();
+ checkTime(startTime, "Daemons.FinalizerQueueDaemonStart");
FinalizerWatchdogDaemon.INSTANCE.start();
+ checkTime(startTime, "Daemons.FinalizerWatchdogQueueDaemonStart");
HeapTrimmerDaemon.INSTANCE.start();
+ checkTime(startTime, "Daemons.HeapTrimmerDaemonStart");
GCDaemon.INSTANCE.start();
+ checkTime(startTime, "Daemons.GCDaemonStart");
}
public static void stop() {
+ long startTime = System.nanoTime();
ReferenceQueueDaemon.INSTANCE.stop();
+ checkTime(startTime, "Daemons.ReferenceQueueDaemonStop");
FinalizerDaemon.INSTANCE.stop();
+ checkTime(startTime, "Daemons.FinalizerDaemonStop");
FinalizerWatchdogDaemon.INSTANCE.stop();
+ checkTime(startTime, "Daemons.FinalizerWatchdogDaemonStop");
HeapTrimmerDaemon.INSTANCE.stop();
+ checkTime(startTime, "Daemons.HeapTrimmerDaemonStop");
GCDaemon.INSTANCE.stop();
+ checkTime(startTime, "Daemons.GCDaemonStop");
}
/**
diff --git a/libart/src/main/java/java/lang/Object.java b/libart/src/main/java/java/lang/Object.java
index acae8ca..20fdbf9 100644
--- a/libart/src/main/java/java/lang/Object.java
+++ b/libart/src/main/java/java/lang/Object.java
@@ -273,6 +273,12 @@
* @see #equals
*/
public int hashCode() {
+ int lockWord = shadow$_monitor_;
+ final int lockWordMask = 0xC0000000; // Top 2 bits.
+ final int lockWordStateHash = 0x80000000; // Top 2 bits are value 2 (kStateHash).
+ if ((lockWord & lockWordMask) == lockWordStateHash) {
+ return lockWord & ~lockWordMask;
+ }
return System.identityHashCode(this);
}
diff --git a/luni/src/main/java/java/lang/ref/FinalizerReference.java b/luni/src/main/java/java/lang/ref/FinalizerReference.java
index 14eaae4..47dc0b4 100644
--- a/luni/src/main/java/java/lang/ref/FinalizerReference.java
+++ b/luni/src/main/java/java/lang/ref/FinalizerReference.java
@@ -98,7 +98,13 @@
FinalizerReference<Sentinel> sentinelReference = (FinalizerReference<Sentinel>) r;
sentinelReference.referent = null;
sentinelReference.zombie = sentinel;
- sentinelReference.enqueueInternal();
+ // Make a single element list, then enqueue the reference on the daemon unenqueued
+ // list. This is required instead of enqueuing directly on the finalizer queue
+ // since there could be recently freed objects in the unqueued list which are not
+ // yet on the finalizer queue. This could cause the sentinel to run before the
+ // objects are finalized. b/17381967
+ sentinelReference.pendingNext = sentinelReference;
+ ReferenceQueue.add(sentinelReference);
return;
}
}
diff --git a/luni/src/main/java/java/lang/ref/ReferenceQueue.java b/luni/src/main/java/java/lang/ref/ReferenceQueue.java
index 7ddd97d..4c78fbf 100644
--- a/luni/src/main/java/java/lang/ref/ReferenceQueue.java
+++ b/luni/src/main/java/java/lang/ref/ReferenceQueue.java
@@ -153,9 +153,18 @@
if (unenqueued == null) {
unenqueued = list;
} else {
- Reference<?> next = unenqueued.pendingNext;
- unenqueued.pendingNext = list.pendingNext;
- list.pendingNext = next;
+ // Find the last element in unenqueued.
+ Reference<?> last = unenqueued;
+ while (last.pendingNext != unenqueued) {
+ last = last.pendingNext;
+ }
+ // Add our list to the end. Update the pendingNext to point back to enqueued.
+ last.pendingNext = list;
+ last = list;
+ while (last.pendingNext != list) {
+ last = last.pendingNext;
+ }
+ last.pendingNext = unenqueued;
}
ReferenceQueue.class.notifyAll();
}
diff --git a/luni/src/main/java/java/text/DecimalFormatSymbols.java b/luni/src/main/java/java/text/DecimalFormatSymbols.java
index 6e25c1b..fba2d6e 100644
--- a/luni/src/main/java/java/text/DecimalFormatSymbols.java
+++ b/luni/src/main/java/java/text/DecimalFormatSymbols.java
@@ -81,6 +81,10 @@
* the locale.
*/
public DecimalFormatSymbols(Locale locale) {
+ if (locale == null) {
+ throw new NullPointerException("locale == null");
+ }
+
locale = LocaleData.mapInvalidAndNullLocales(locale);
LocaleData localeData = LocaleData.get(locale);
this.zeroDigit = localeData.zeroDigit;
diff --git a/luni/src/main/java/libcore/reflect/GenericArrayTypeImpl.java b/luni/src/main/java/libcore/reflect/GenericArrayTypeImpl.java
index ef22576..5919a19 100644
--- a/luni/src/main/java/libcore/reflect/GenericArrayTypeImpl.java
+++ b/luni/src/main/java/libcore/reflect/GenericArrayTypeImpl.java
@@ -18,6 +18,7 @@
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Type;
+import java.util.Objects;
public final class GenericArrayTypeImpl implements GenericArrayType {
private final Type componentType;
@@ -34,6 +35,20 @@
}
}
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof GenericArrayType)) {
+ return false;
+ }
+ GenericArrayType that = (GenericArrayType) o;
+ return Objects.equals(getGenericComponentType(), that.getGenericComponentType());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(getGenericComponentType());
+ }
+
public String toString() {
return componentType.toString() + "[]";
}
diff --git a/luni/src/main/java/libcore/reflect/ParameterizedTypeImpl.java b/luni/src/main/java/libcore/reflect/ParameterizedTypeImpl.java
index 99dfe8b..2cd5ac3 100644
--- a/luni/src/main/java/libcore/reflect/ParameterizedTypeImpl.java
+++ b/luni/src/main/java/libcore/reflect/ParameterizedTypeImpl.java
@@ -18,17 +18,22 @@
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
+import java.util.Arrays;
+import java.util.Objects;
public final class ParameterizedTypeImpl implements ParameterizedType {
private final ListOfTypes args;
private final ParameterizedTypeImpl ownerType0; // Potentially unresolved.
- private Type ownerTypeRes;
- private Class rawType; // Already resolved.
+ private Type ownerTypeRes; // Potentially unresolved.
+ private Class rawType; // Potentially unresolved.
private final String rawTypeName;
- private ClassLoader loader;
+ private final ClassLoader loader;
public ParameterizedTypeImpl(ParameterizedTypeImpl ownerType, String rawTypeName,
ListOfTypes args, ClassLoader loader) {
+ if (args == null) {
+ throw new NullPointerException();
+ }
this.ownerType0 = ownerType;
this.rawTypeName = rawTypeName;
this.args = args;
@@ -37,7 +42,6 @@
public Type[] getActualTypeArguments() {
- // ASSUMPTION: args is never null!!!
return args.getResolvedTypes().clone();
}
@@ -76,6 +80,23 @@
}
@Override
+ public boolean equals(Object o) {
+ if (!(o instanceof ParameterizedType)) {
+ return false;
+ }
+ ParameterizedType that = (ParameterizedType) o;
+ return Objects.equals(getRawType(), that.getRawType()) &&
+ Objects.equals(getOwnerType(), that.getOwnerType()) &&
+ Arrays.equals(args.getResolvedTypes(), that.getActualTypeArguments());
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * (31 * Objects.hashCode(getRawType()) + Objects.hashCode(getOwnerType())) +
+ Arrays.hashCode(args.getResolvedTypes());
+ }
+
+ @Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(rawTypeName);
diff --git a/luni/src/test/java/libcore/java/text/DecimalFormatSymbolsTest.java b/luni/src/test/java/libcore/java/text/DecimalFormatSymbolsTest.java
index 8b24c6d..619c38e 100644
--- a/luni/src/test/java/libcore/java/text/DecimalFormatSymbolsTest.java
+++ b/luni/src/test/java/libcore/java/text/DecimalFormatSymbolsTest.java
@@ -24,18 +24,21 @@
import java.util.Locale;
public class DecimalFormatSymbolsTest extends junit.framework.TestCase {
+ public void test_getInstance_unknown_or_invalid_locale() throws Exception {
+ // http://b/17374604: this test passes on the host but fails on the target.
+ // ICU uses setlocale(3) to determine its default locale, and glibc (on my box at least)
+ // returns "en_US.UTF-8". bionic before L returned NULL and in L returns "C.UTF-8", both
+ // of which get treated as "en_US_POSIX". What that means for this test is that you get
+ // "INF" for infinity instead of "\u221e".
+ // On the RI, this test fails for a different reason: their DecimalFormatSymbols.equals
+ // appears to be broken. It could be that they're accidentally checking the Locale field?
+ checkLocaleIsEquivalentToRoot(new Locale("xx", "XX"));
+ checkLocaleIsEquivalentToRoot(new Locale("not exist language", "not exist country"));
+ }
private void checkLocaleIsEquivalentToRoot(Locale locale) {
DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(locale);
assertEquals(DecimalFormatSymbols.getInstance(Locale.ROOT), dfs);
}
- public void test_getInstance_unknown_or_invalid_locale() throws Exception {
- // TODO: we fail these tests because ROOT has "INF" for infinity but 'dfs' has "\u221e".
- // On the RI, ROOT has "\u221e" too, but DecimalFormatSymbols.equals appears to be broken;
- // it returns false for objects that -- if you compare their externally visible state --
- // are equal. It could be that they're accidentally checking the Locale.
- checkLocaleIsEquivalentToRoot(new Locale("xx", "XX"));
- checkLocaleIsEquivalentToRoot(new Locale("not exist language", "not exist country"));
- }
// http://code.google.com/p/android/issues/detail?id=14495
public void testSerialization() throws Exception {
diff --git a/luni/src/test/java/libcore/java/util/CalendarTest.java b/luni/src/test/java/libcore/java/util/CalendarTest.java
index b2f6b94..e0e1a35 100644
--- a/luni/src/test/java/libcore/java/util/CalendarTest.java
+++ b/luni/src/test/java/libcore/java/util/CalendarTest.java
@@ -17,6 +17,7 @@
package libcore.java.util;
import java.util.Calendar;
+import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.TimeZone;
@@ -245,14 +246,21 @@
// here. We should add a targetSdkVersion based check and throw for each of these
// cases.
public void test_nullLocale() {
- assertEquals(
+ assertCalendarConfigEquals(
Calendar.getInstance(Locale.getDefault()),
Calendar.getInstance((Locale) null));
- assertEquals(
+ assertCalendarConfigEquals(
Calendar.getInstance(TimeZone.getDefault(), Locale.getDefault()),
Calendar.getInstance(TimeZone.getDefault(), null));
- assertEquals(
+ assertCalendarConfigEquals(
new GregorianCalendar(Locale.getDefault()),
new GregorianCalendar((Locale) null));
}
+
+ public void assertCalendarConfigEquals(Calendar a, Calendar b) {
+ Date d = new Date();
+ a.setTime(d);
+ b.setTime(d);
+ assertEquals(a, b);
+ }
}