Merge "Restore threshold to 200 as a temporary workaround"
diff --git a/libcore/icu/src/main/java/com/ibm/icu4jni/util/Resources.java b/libcore/icu/src/main/java/com/ibm/icu4jni/util/Resources.java
index efc55d1..f1c50e3 100644
--- a/libcore/icu/src/main/java/com/ibm/icu4jni/util/Resources.java
+++ b/libcore/icu/src/main/java/com/ibm/icu4jni/util/Resources.java
@@ -91,17 +91,6 @@
         return result;
     }
 
-    // TODO: fix remaining caller and remove this.
-    public static ResourceBundle getInstance(String bundleName, String locale) {
-        if (locale == null) {
-            locale = Locale.getDefault().toString();
-        }
-        if (bundleName.startsWith("Currency")) {
-            return new CurrencyResourceBundle(locale);
-        }
-        throw new AssertionError("bundle="+bundleName+" locale="+locale);
-    }
-
     /**
      * Returns an array of ISO language names (two-letter codes), fetched either
      * from ICU's database or from our memory cache.
@@ -275,36 +264,6 @@
         return result;
     }
 
-    // --- Specialized ResourceBundle subclasses ------------------------------
-
-    /**
-     * Internal ResourceBundle mimicking the Harmony "Currency_*" bundles. Keys
-     * are the three-letter ISO currency codes. Values are the printable
-     * currency names in terms of the specified locale. An example entry is
-     * "USD"->"$" (for inside the US) and "USD->"US$" (for outside the US).
-     */
-    private static final class CurrencyResourceBundle extends ResourceBundle {
-
-        private String locale;
-
-        public CurrencyResourceBundle(String locale) {
-            super();
-            this.locale = locale;
-        }
-
-        @Override
-        public Enumeration<String> getKeys() {
-            // Won't get used
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        protected Object handleGetObject(String key) {
-            return getCurrencySymbolNative(locale, key);
-        }
-
-    }
-
     // --- Native methods accessing ICU's database ----------------------------
 
     public static native String getDisplayCountryNative(String countryCode, String locale);
diff --git a/libcore/luni/src/main/java/java/util/Currency.java b/libcore/luni/src/main/java/java/util/Currency.java
index 9ce92f6..e6b0202 100644
--- a/libcore/luni/src/main/java/java/util/Currency.java
+++ b/libcore/luni/src/main/java/java/util/Currency.java
@@ -105,7 +105,7 @@
             country = country + "_" + variant;
         }
 
-        String currencyCode = com.ibm.icu4jni.util.Resources.getCurrencyCodeNative(country);
+        String currencyCode = Resources.getCurrencyCodeNative(country);
         if (currencyCode == null) {
             throw new IllegalArgumentException(Msg.getString("K0323", locale.toString()));
         } else if (currencyCode.equals("None")) {
@@ -138,18 +138,14 @@
 
     /**
      * Returns the symbol for this currency in the given {@code Locale}.
+     * That is, given "USD" and Locale.US, you'd get "$", but given "USD" and a non-US locale,
+     * you'd get "US$".
      * <p>
-     * If the locale doesn't have any countries (e.g.
+     * If the locale only specifies a language rather than a language and a countries (e.g.
      * {@code Locale.JAPANESE, new Locale("en","")}), the the ISO
      * 4217 currency code is returned.
      * <p>
-     * First the locale's resource bundle is checked, if the locale has the same currency,
-     * the CurrencySymbol in this locale bundle is returned.
-     * <p>
-     * Then a currency bundle for this locale is searched.
-     * <p>
-     * If a currency bundle for this locale does not exist, or there is no
-     * symbol for this currency in this bundle, then the
+     * If there is no currency symbol specific to this locale does not exist, the
      * ISO 4217 currency code is returned.
      * <p>
      *
@@ -165,32 +161,12 @@
         }
 
         // Check the locale first, in case the locale has the same currency.
-        LocaleData localeData = com.ibm.icu4jni.util.Resources.getLocaleData(locale);
+        LocaleData localeData = Resources.getLocaleData(locale);
         if (localeData.internationalCurrencySymbol.equals(currencyCode)) {
             return localeData.currencySymbol;
         }
 
-        // check if the currency bundle for this locale has an entry for this currency
-        try {
-            ResourceBundle currencyBundle = getCurrencyBundle(locale);
-
-            // is the bundle found for a different country? (for instance the
-            // default locale's currency bundle)
-            if (!currencyBundle.getLocale().getCountry().equals(locale.getCountry())) {
-                // TODO: the fact I never see output from this when running the tests suggests we
-                // don't have a test for this. Does it ever even happen? If it does, can we just
-                // ask ICU a slightly different question to get the behavior we want?
-                Logger.global.info("currencyBundle " + currencyBundle + " for " + locale +
-                        " came back with locale " + currencyBundle.getLocale());
-                return currencyCode;
-            }
-
-            // Return the currency bundle's value, or currencyCode.
-            String result = (String) currencyBundle.handleGetObject(currencyCode);
-            return (result != null) ? result : currencyCode;
-        } catch (MissingResourceException e) {
-            return currencyCode;
-        }
+        return Resources.getCurrencySymbolNative(locale.toString(), currencyCode);
         // END android-changed
     }
 
diff --git a/libcore/luni/src/main/java/java/util/ResourceBundle.java b/libcore/luni/src/main/java/java/util/ResourceBundle.java
index 218d3f3..ec669d6 100644
--- a/libcore/luni/src/main/java/java/util/ResourceBundle.java
+++ b/libcore/luni/src/main/java/java/util/ResourceBundle.java
@@ -24,7 +24,6 @@
 
 // BEGIN android-changed
 // import org.apache.harmony.kernel.vm.VM;
-import com.ibm.icu4jni.util.Resources;
 import dalvik.system.VMStack;
 // END android-changed
 import org.apache.harmony.luni.util.Msg;
@@ -355,25 +354,11 @@
         }
 
         try {
-            // BEGIN android-changed
-            /*
-             * Intercept loading of ResourceBundles that contain Harmony
-             * I18N data. Deliver our special, ICU-based bundles in this case.
-             * All other ResourceBundles use the ordinary mechanism, so user
-             * code behaves as it should.
-             */
-            if(bundleName.startsWith("org.apache.harmony.luni.internal.locale.")) {
-                String icuBundleName = bundleName.substring(40);
-                String icuLocale = (locale.length() > 0 ? locale.substring(1) : locale);
-                // we know that Resources will deliver an assignable class
-                bundle = Resources.getInstance(icuBundleName, icuLocale);
-            } else {
-                Class<?> bundleClass = Class.forName(bundleName, true, loader);
-                if (ResourceBundle.class.isAssignableFrom(bundleClass)) {
-                    bundle = (ResourceBundle) bundleClass.newInstance();
-                }
+            Class<?> bundleClass = Class.forName(bundleName, true, loader);
+            
+            if (ResourceBundle.class.isAssignableFrom(bundleClass)) {
+                bundle = (ResourceBundle) bundleClass.newInstance();
             }
-            // END android-changed
         } catch (LinkageError e) {
         } catch (Exception e) {
         }
diff --git a/tests/004-annotations/expected.txt b/tests/004-annotations/expected.txt
index 724b0eb..6caef04 100644
--- a/tests/004-annotations/expected.txt
+++ b/tests/004-annotations/expected.txt
@@ -1,4 +1,6 @@
 TestAnnotations...
+java.lang.String android.test.anno.TestAnnotations.thing1: @android.test.anno.AnnoArrayField(bb=[], cc=[a, b], dd=[0.987654321], ff=[3.1415927], ii=[], jj=[], ss=[], str=[], zz=[])
+java.lang.String android.test.anno.TestAnnotations.thing2: @android.test.anno.AnnoArrayField(bb=[-1, 0, 1], cc=[Q], dd=[0.3, 0.6, 0.9], ff=[1.1, 1.2, 1.3], ii=[1, 2, 3, 4], jj=[-5, 0, 5], ss=[12, 13, 14, 15, 16, 17], str=[hickory, dickory, dock], zz=[true, false, true])
 mapping is class [Landroid.test.anno.IntToString;
   0='@android.test.anno.IntToString(from=0, to=NORMAL_FOCUS)'
   1='@android.test.anno.IntToString(from=2, to=WEAK_FOCUS)'
@@ -85,7 +87,7 @@
   annotations on FIELD int android.test.anno.FullyNoted.mBar:
     @android.test.anno.AnnoFancyField(nombre=fubar)
       interface android.test.anno.AnnoFancyField
-    aff: @android.test.anno.AnnoFancyField(nombre=fubar) / class $Proxy16
+    aff: @android.test.anno.AnnoFancyField(nombre=fubar) / class $Proxy17
     --> nombre is 'fubar'
 
 SimplyNoted.get(AnnoSimpleType) = @android.test.anno.AnnoSimpleType()
diff --git a/tests/004-annotations/src/android/test/anno/AnnoArrayField.java b/tests/004-annotations/src/android/test/anno/AnnoArrayField.java
new file mode 100644
index 0000000..d929aac
--- /dev/null
+++ b/tests/004-annotations/src/android/test/anno/AnnoArrayField.java
@@ -0,0 +1,20 @@
+package android.test.anno;
+
+import java.lang.annotation.*;
+
+@Documented
+@Inherited
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface AnnoArrayField {
+    boolean[] zz() default {};
+    byte[] bb() default {};
+    char[] cc() default {'a', 'b'};
+    short[] ss() default {};
+    int[] ii() default {};
+    float[] ff() default {3.141592654f};
+    long[] jj() default {};
+    double[] dd() default {0.987654321};
+    String[] str() default {};
+}
+
diff --git a/tests/004-annotations/src/android/test/anno/TestAnnotations.java b/tests/004-annotations/src/android/test/anno/TestAnnotations.java
index d1150f4..d7b0b14 100644
--- a/tests/004-annotations/src/android/test/anno/TestAnnotations.java
+++ b/tests/004-annotations/src/android/test/anno/TestAnnotations.java
@@ -81,6 +81,41 @@
         return 2;
     }
 
+
+    @AnnoArrayField
+    String thing1;
+
+    @AnnoArrayField(
+            zz = {true,false,true},
+            bb = {-1,0,1},
+            cc = {'Q'},
+            ss = {12,13,14,15,16,17},
+            ii = {1,2,3,4},
+            ff = {1.1f,1.2f,1.3f},
+            jj = {-5,0,5},
+            dd = {0.3,0.6,0.9},
+            str = {"hickory","dickory","dock"}
+            )
+    String thing2;
+
+    public static void testArrays() {
+        TestAnnotations ta = new TestAnnotations();
+        Field field;
+        Annotation[] annotations;
+
+        try {
+            field = TestAnnotations.class.getDeclaredField("thing1");
+            annotations = field.getAnnotations();
+            System.out.println(field + ": " + annotations[0].toString());
+
+            field = TestAnnotations.class.getDeclaredField("thing2");
+            annotations = field.getAnnotations();
+            System.out.println(field + ": " + annotations[0].toString());
+        } catch (NoSuchFieldException nsfe) {
+            throw new RuntimeException(nsfe);
+        }
+    }
+
     public static void testArrayProblem() {
         Method meth;
         ExportedProperty property;
@@ -105,6 +140,7 @@
     public static void main(String[] args) {
         System.out.println("TestAnnotations...");
 
+        testArrays();
         testArrayProblem();
         //System.exit(0);
 
diff --git a/vm/Sync.c b/vm/Sync.c
index c0b3d08..c9c039e 100644
--- a/vm/Sync.c
+++ b/vm/Sync.c
@@ -176,14 +176,6 @@
 }
 
 /*
- * Release a Monitor.
- */
-static void releaseMonitor(Monitor* mon)
-{
-    // TODO
-}
-
-/*
  * Free the monitor list.  Only used when shutting the VM down.
  */
 void dvmFreeMonitorList(void)
@@ -271,21 +263,19 @@
  * Free the monitor associated with an object and make the object's lock
  * thin again.  This is called during garbage collection.
  */
-void dvmFreeObjectMonitor_internal(u4 *lock)
+static void freeObjectMonitor(Object* obj)
 {
     Monitor *mon;
 
-    /* The macro that wraps this function checks IS_LOCK_FAT() first.
-     */
-    assert(IS_LOCK_FAT(lock));
+    assert(LW_SHAPE(obj->lock) == LW_SHAPE_FAT);
 
 #ifdef WITH_DEADLOCK_PREDICTION
     if (gDvm.deadlockPredictMode != kDPOff)
-        removeCollectedObject(LW_MONITOR(*lock)->obj);
+        removeCollectedObject(obj);
 #endif
 
-    mon = LW_MONITOR(*lock);
-    *lock = DVM_LOCK_INITIAL_THIN_VALUE;
+    mon = LW_MONITOR(obj->lock);
+    obj->lock = DVM_LOCK_INITIAL_THIN_VALUE;
 
     /* This lock is associated with an object
      * that's being swept.  The only possible way
@@ -296,24 +286,40 @@
      */
     assert(pthread_mutex_trylock(&mon->lock) == 0);
     pthread_mutex_destroy(&mon->lock);
-#if 1
-//TODO: unlink from the monitor list (would require a lock)
-// (might not -- the GC suspension may be enough)
-    {
-        Monitor *next;
-        next = mon->next;
 #ifdef WITH_DEADLOCK_PREDICTION
-        expandObjClear(&mon->historyChildren);
-        expandObjClear(&mon->historyParents);
-        free(mon->historyRawStackTrace);
+    expandObjClear(&mon->historyChildren);
+    expandObjClear(&mon->historyParents);
+    free(mon->historyRawStackTrace);
 #endif
-        memset(mon, 0, sizeof (*mon));
-        mon->next = next;
-    }
-//free(mon);
-#endif
+    free(mon);
 }
 
+/*
+ * Frees monitor objects belonging to unmarked objects.
+ */
+void dvmSweepMonitorList(Monitor** mon, int (*isUnmarkedObject)(void*))
+{
+    Monitor handle;
+    Monitor *prev, *curr;
+    Object *obj;
+
+    assert(mon != NULL);
+    assert(*mon != NULL);
+    assert(isUnmarkedObject != NULL);
+    prev = &handle;
+    prev->next = curr = *mon;
+    while (curr != NULL) {
+        obj = curr->obj;
+        if (obj != NULL && (*isUnmarkedObject)(obj) != 0) {
+            prev->next = curr = curr->next;
+            freeObjectMonitor(obj);
+        } else {
+            prev = curr;
+            curr = curr->next;
+        }
+    }
+    *mon = handle.next;
+}
 
 /*
  * Lock a monitor.
diff --git a/vm/Sync.h b/vm/Sync.h
index 9524b69..12423ae 100644
--- a/vm/Sync.h
+++ b/vm/Sync.h
@@ -101,15 +101,12 @@
 /* create a new Monitor struct */
 Monitor* dvmCreateMonitor(struct Object* obj);
 
-/* free an object's monitor during GC */
-void dvmFreeObjectMonitor_internal(u4 *lock);
-#define dvmFreeObjectMonitor(obj) \
-    do { \
-        Object *DFM_obj_ = (obj); \
-        if (IS_LOCK_FAT(&DFM_obj_->lock)) { \
-            dvmFreeObjectMonitor_internal(&DFM_obj_->lock); \
-        } \
-    } while (0)
+/*
+ * Frees unmarked monitors from the monitor list.  The given callback
+ * routine should return a non-zero value when passed a pointer to an
+ * unmarked object.
+ */
+void dvmSweepMonitorList(Monitor** mon, int (*isUnmarkedObject)(void*));
 
 /* free monitor list */
 void dvmFreeMonitorList(void);
diff --git a/vm/alloc/MarkSweep.c b/vm/alloc/MarkSweep.c
index 84750ff..6f41f88 100644
--- a/vm/alloc/MarkSweep.c
+++ b/vm/alloc/MarkSweep.c
@@ -1147,10 +1147,6 @@
         hc = (DvmHeapChunk *)*ptrs++;
         obj = (Object *)chunk2ptr(hc);
 
-        /* Free the monitor associated with the object.
-         */
-        dvmFreeObjectMonitor(obj);
-
         /* NOTE: Dereferencing clazz is dangerous.  If obj was the last
          * one to reference its class object, the class object could be
          * on the sweep list, and could already have been swept, leaving
@@ -1192,8 +1188,7 @@
     return true;
 }
 
-/* A function suitable for passing to dvmHashForeachRemove()
- * to clear out any unmarked objects.  Clears the low bits
+/* Returns true if the given object is unmarked.  Ignores the low bits
  * of the pointer because the intern table may set them.
  */
 static int isUnmarkedObject(void *object)
@@ -1242,6 +1237,8 @@
     hprofDumpUnmarkedObjects(markBitmaps, objectBitmaps, numBitmaps);
 #endif
 
+    dvmSweepMonitorList(&gDvm.monitorList, isUnmarkedObject);
+
     dvmHeapBitmapXorWalkLists(markBitmaps, objectBitmaps, numBitmaps,
             sweepBitmapCallback, NULL);
 
diff --git a/vm/oo/Array.c b/vm/oo/Array.c
index 60da683..4af03a9 100644
--- a/vm/oo/Array.c
+++ b/vm/oo/Array.c
@@ -689,6 +689,82 @@
 }
 
 /*
+ * Copy the entire contents of an array of boxed primitives into an
+ * array of primitives.  The boxed value must fit in the primitive (i.e.
+ * narrowing conversions are not allowed).
+ */
+bool dvmUnboxObjectArray(ArrayObject* dstArray, const ArrayObject* srcArray,
+    ClassObject* dstElemClass)
+{
+    Object** src = (Object**)srcArray->contents;
+    void* dst = (void*)dstArray->contents;
+    u4 count = dstArray->length;
+    PrimitiveType typeIndex = dstElemClass->primitiveType;
+
+    assert(typeIndex != PRIM_NOT);
+    assert(srcArray->length == dstArray->length);
+
+    while (count--) {
+        JValue result;
+
+        /*
+         * This will perform widening conversions as appropriate.  It
+         * might make sense to be more restrictive and require that the
+         * primitive type exactly matches the box class, but it's not
+         * necessary for correctness.
+         */
+        if (!dvmUnwrapPrimitive(*src, dstElemClass, &result)) {
+            LOGW("dvmCopyObjectArray: can't store %s in %s\n",
+                (*src)->clazz->descriptor, dstElemClass->descriptor);
+            return false;
+        }
+
+        /* would be faster with 4 loops, but speed not crucial here */
+        switch (typeIndex) {
+        case PRIM_BOOLEAN:
+        case PRIM_BYTE:
+            {
+                u1* tmp = dst;
+                *tmp++ = result.b;
+                dst = tmp;
+            }
+            break;
+        case PRIM_CHAR:
+        case PRIM_SHORT:
+            {
+                u2* tmp = dst;
+                *tmp++ = result.s;
+                dst = tmp;
+            }
+            break;
+        case PRIM_FLOAT:
+        case PRIM_INT:
+            {
+                u4* tmp = dst;
+                *tmp++ = result.i;
+                dst = tmp;
+            }
+            break;
+        case PRIM_DOUBLE:
+        case PRIM_LONG:
+            {
+                u8* tmp = dst;
+                *tmp++ = result.j;
+                dst = tmp;
+            }
+            break;
+        default:
+            /* should not be possible to get here */
+            dvmAbort();
+        }
+
+        src++;
+    }
+
+    return true;
+}
+
+/*
  * Add all primitive classes to the root set of objects.
 TODO: do these belong to the root class loader?
  */
diff --git a/vm/oo/Array.h b/vm/oo/Array.h
index 868e48a..018f3d7 100644
--- a/vm/oo/Array.h
+++ b/vm/oo/Array.h
@@ -132,4 +132,12 @@
 bool dvmCopyObjectArray(ArrayObject* dstArray, const ArrayObject* srcArray,
     ClassObject* dstElemClass);
 
+/*
+ * Copy the entire contents of an array of boxed primitives into an
+ * array of primitives.  The boxed value must fit in the primitive (i.e.
+ * narrowing conversions are not allowed).
+ */
+bool dvmUnboxObjectArray(ArrayObject* dstArray, const ArrayObject* srcArray,
+    ClassObject* dstElemClass);
+
 #endif /*_DALVIK_OO_ARRAY*/
diff --git a/vm/reflect/Annotation.c b/vm/reflect/Annotation.c
index 109c7fb..fb4b83f 100644
--- a/vm/reflect/Annotation.c
+++ b/vm/reflect/Annotation.c
@@ -617,10 +617,8 @@
  *
  * For an array annotation, the type of the extracted object will always
  * be java.lang.Object[], but we want it to match the type that the
- * annotation member is expected to return.  In theory we can just stomp
- * the object's class to have the correct type, but this strikes me as a
- * risky proposition (at the very least we would need to call instanceof()
- * on every element).
+ * annotation member is expected to return.  In some cases this may
+ * involve un-boxing primitive values.
  *
  * We allocate a second array with the correct type, then copy the data
  * over.  This releases the tracked allocation on "valueObj" and returns
@@ -642,18 +640,26 @@
     ClassObject* dstElemClass;
 
     /*
-     * Strip off one '[' to get element class.  Note this is not the
-     * same as clazz->elementClass.
+     * We always extract kDexAnnotationArray into Object[], so we expect to
+     * find that here.  This means we can skip the FindClass on
+     * (valueObj->clazz->descriptor+1, valueObj->clazz->classLoader).
      */
-    srcElemClass = dvmFindClass(valueObj->clazz->descriptor+1,
-        valueObj->clazz->classLoader);
-    dstElemClass = dvmFindClass(methodReturn->descriptor+1,
-        methodReturn->classLoader);
-    if (srcElemClass->primitiveType != PRIM_NOT ||
-        dstElemClass->primitiveType != PRIM_NOT)
-    {
-        LOGE("ERROR: array of primitives not expected here\n");
-        dvmAbort();
+    if (strcmp(valueObj->clazz->descriptor, "[Ljava/lang/Object;") != 0) {
+        LOGE("Unexpected src type class (%s)\n", valueObj->clazz->descriptor);
+        return NULL;
+    }
+    srcElemClass = gDvm.classJavaLangObject;
+
+    /*
+     * Skip past the '[' to get element class name.  Note this is not always
+     * the same as methodReturn->elementClass.
+     */
+    char firstChar = methodReturn->descriptor[1];
+    if (firstChar == 'L' || firstChar == '[') {
+        dstElemClass = dvmFindClass(methodReturn->descriptor+1,
+            methodReturn->classLoader);
+    } else {
+        dstElemClass = dvmFindPrimitiveClass(firstChar);
     }
     LOGV("HEY: converting valueObj from [%s to [%s\n",
         srcElemClass->descriptor, dstElemClass->descriptor);
@@ -669,7 +675,13 @@
         goto bail;
     }
 
-    if (!dvmCopyObjectArray(newArray, srcArray, dstElemClass)) {
+    bool success;
+    if (dstElemClass->primitiveType == PRIM_NOT) {
+        success = dvmCopyObjectArray(newArray, srcArray, dstElemClass);
+    } else {
+        success = dvmUnboxObjectArray(newArray, srcArray, dstElemClass);
+    }
+    if (!success) {
         LOGE("Annotation array copy failed\n");
         dvmReleaseTrackedAlloc((Object*)newArray, self);
         newArray = NULL;