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;