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);
+    }
 }