diff options
-rw-r--r-- | include/ScopedGlobalRef.h | 5 | ||||
-rw-r--r-- | include/ScopedLocalRef.h | 54 | ||||
-rw-r--r-- | luni/src/main/java/com/ibm/icu4jni/util/ICU.java | 26 | ||||
-rw-r--r-- | luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/Header.java | 7 | ||||
-rw-r--r-- | luni/src/main/native/ICU.cpp | 119 |
5 files changed, 127 insertions, 84 deletions
diff --git a/include/ScopedGlobalRef.h b/include/ScopedGlobalRef.h index 15a9055..1fbeabb 100644 --- a/include/ScopedGlobalRef.h +++ b/include/ScopedGlobalRef.h @@ -19,7 +19,8 @@ #include "JNIHelp.h" -// A smart pointer that provides access to a JNI global reference +// A smart pointer that creates a JNI global reference from a weak reference. +// The global reference is deleted when the smart pointer goes out of scope. class ScopedGlobalRef { public: ScopedGlobalRef(JNIEnv* env, jobject localRef) @@ -39,7 +40,7 @@ public: } } - jobject get () const { + jobject get() const { return mGlobalRef; } diff --git a/include/ScopedLocalRef.h b/include/ScopedLocalRef.h new file mode 100644 index 0000000..2cf4673 --- /dev/null +++ b/include/ScopedLocalRef.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SCOPED_LOCAL_REF_H_included +#define SCOPED_LOCAL_REF_H_included + +#include "JNIHelp.h" + +// A smart pointer that deletes a JNI local reference when it goes out of scope. +class ScopedLocalRef { +public: + ScopedLocalRef(JNIEnv* env, jobject localRef) + : mEnv(env), mLocalRef(localRef) + { + } + + ~ScopedLocalRef() { + reset(); + } + + void reset() { + if (mLocalRef != NULL) { + mEnv->DeleteLocalRef(mLocalRef); + mLocalRef = NULL; + } + } + + jobject get() const { + return mLocalRef; + } + +private: + JNIEnv* mEnv; + jobject mLocalRef; + + // Disallow copy and assignment. + ScopedLocalRef(const ScopedLocalRef&); + void operator=(const ScopedLocalRef&); +}; + +#endif // SCOPED_LOCAL_REF_H_included diff --git a/luni/src/main/java/com/ibm/icu4jni/util/ICU.java b/luni/src/main/java/com/ibm/icu4jni/util/ICU.java index b684068..30e7001 100644 --- a/luni/src/main/java/com/ibm/icu4jni/util/ICU.java +++ b/luni/src/main/java/com/ibm/icu4jni/util/ICU.java @@ -16,6 +16,7 @@ package com.ibm.icu4jni.util; +import java.util.HashMap; import java.util.Locale; import java.util.TimeZone; import java.util.logging.Logger; @@ -157,21 +158,24 @@ public final class ICU { arrayToFill[3] = new String[availableTimezones.length]; arrayToFill[4] = new String[availableTimezones.length]; - /* - * Fill in the zone names in native. - */ + // Don't be distracted by all the code either side of this line: this is the expensive bit! getTimeZonesNative(arrayToFill, locale); - /* - * Finally we need to reorder the entries so we get the expected result. - */ + // Reorder the entries so we get the expected result. + // We also take the opportunity to de-duplicate the names (http://b/2672057). + HashMap<String, String> internTable = new HashMap<String, String>(); String[][] result = new String[availableTimezones.length][5]; - for (int i = 0; i < availableTimezones.length; i++) { + for (int i = 0; i < availableTimezones.length; ++i) { result[i][0] = arrayToFill[0][i]; - result[i][1] = arrayToFill[1][i]; - result[i][2] = arrayToFill[2][i]; - result[i][3] = arrayToFill[3][i]; - result[i][4] = arrayToFill[4][i]; + for (int j = 1; j <= 4; ++j) { + String original = arrayToFill[j][i]; + String nonDuplicate = internTable.get(original); + if (nonDuplicate == null) { + internTable.put(original, original); + nonDuplicate = original; + } + result[i][j] = nonDuplicate; + } } Logger.global.info("Loaded time zone names for " + locale + " in " diff --git a/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/Header.java b/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/Header.java index f919b39..2c4aaf7 100644 --- a/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/Header.java +++ b/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/Header.java @@ -187,12 +187,7 @@ public class Header implements Cloneable { } /** - * Returns the value corresponding to the specified key. - * - * @param key - * the key to look up. - * @return Answers the value for the given key, or <code>null</code> if no - * such key exists. + * Returns the value corresponding to the specified key, or null. */ public String get(String key) { LinkedList<String> result = keyTable.get(key); diff --git a/luni/src/main/native/ICU.cpp b/luni/src/main/native/ICU.cpp index 1945b69..63f62dd 100644 --- a/luni/src/main/native/ICU.cpp +++ b/luni/src/main/native/ICU.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "ICU" #include "JNIHelp.h" +#include "ScopedLocalRef.h" #include "ScopedUtfChars.h" #include "UniquePtr.h" #include "cutils/log.h" @@ -215,9 +216,8 @@ static jobjectArray toStringArray(JNIEnv* env, const char* const* strings) { } jobjectArray result = env->NewObjectArray(count, string_class, NULL); for (size_t i = 0; i < count; ++i) { - jstring s = env->NewStringUTF(strings[i]); - env->SetObjectArrayElement(result, i, s); - env->DeleteLocalRef(s); + ScopedLocalRef s(env, env->NewStringUTF(strings[i])); + env->SetObjectArrayElement(result, i, s.get()); } return result; } @@ -235,9 +235,8 @@ static jobjectArray getAvailableLocales(JNIEnv* env, Counter* counter, Getter* g size_t count = (*counter)(); jobjectArray result = env->NewObjectArray(count, string_class, NULL); for (size_t i = 0; i < count; ++i) { - jstring s = env->NewStringUTF((*getter)(i)); - env->SetObjectArrayElement(result, i, s); - env->DeleteLocalRef(s); + ScopedLocalRef s(env, env->NewStringUTF((*getter)(i))); + env->SetObjectArrayElement(result, i, s.get()); } return result; } @@ -279,37 +278,34 @@ static jstring formatDate(JNIEnv* env, const SimpleDateFormat& fmt, const UDate& return env->NewString(str.getBuffer(), str.length()); } -static void getTimeZonesNative(JNIEnv* env, jclass, jobjectArray outerArray, jstring locale) { - // get all timezone objects - jobjectArray zoneIdArray = (jobjectArray) env->GetObjectArrayElement(outerArray, 0); - int count = env->GetArrayLength(zoneIdArray); - TimeZone* zones[count]; - for(int i = 0; i < count; i++) { - jstring id = (jstring) env->GetObjectArrayElement(zoneIdArray, i); - zones[i] = timeZoneFromId(env, id); - env->DeleteLocalRef(id); - } - - Locale loc = getLocale(env, locale); - +static void getTimeZonesNative(JNIEnv* env, jclass, jobjectArray outerArray, jstring localeName) { + Locale locale = getLocale(env, localeName); + + // We could use TimeZone::getDisplayName, but that's way too slow. + // The cost of this method goes from 0.5s to 4.5s on a Nexus One. + // Much of the saving comes from caching SimpleDateFormat instances. UErrorCode status = U_ZERO_ERROR; - UnicodeString longPattern("zzzz",""); - SimpleDateFormat longFormat(longPattern, loc, status); - UnicodeString shortPattern("z",""); - SimpleDateFormat shortFormat(shortPattern, loc, status); + UnicodeString longPattern("zzzz", ""); + SimpleDateFormat longFormat(longPattern, locale, status); + UnicodeString shortPattern("z", ""); + SimpleDateFormat shortFormat(shortPattern, locale, status); - jobjectArray longStdTimeArray = (jobjectArray) env->GetObjectArrayElement(outerArray, 1); - jobjectArray shortStdTimeArray = (jobjectArray) env->GetObjectArrayElement(outerArray, 2); - jobjectArray longDlTimeArray = (jobjectArray) env->GetObjectArrayElement(outerArray, 3); - jobjectArray shortDlTimeArray = (jobjectArray) env->GetObjectArrayElement(outerArray, 4); + jobjectArray longStdArray = (jobjectArray) env->GetObjectArrayElement(outerArray, 1); + jobjectArray shortStdArray = (jobjectArray) env->GetObjectArrayElement(outerArray, 2); + jobjectArray longDstArray = (jobjectArray) env->GetObjectArrayElement(outerArray, 3); + jobjectArray shortDstArray = (jobjectArray) env->GetObjectArrayElement(outerArray, 4); // 15th January 2008 UDate date1 = 1203105600000.0; // 15th July 2008 UDate date2 = 1218826800000.0; - for (int i = 0; i < count; ++i) { - TimeZone* tz = zones[i]; + jobjectArray zoneIds = (jobjectArray) env->GetObjectArrayElement(outerArray, 0); + int zoneIdCount = env->GetArrayLength(zoneIds); + for (int i = 0; i < zoneIdCount; ++i) { + ScopedLocalRef id(env, env->GetObjectArrayElement(zoneIds, i)); + UniquePtr<TimeZone> tz(timeZoneFromId(env, reinterpret_cast<jstring>(id.get()))); + longFormat.setTimeZone(*tz); shortFormat.setTimeZone(*tz); @@ -328,24 +324,23 @@ static void getTimeZonesNative(JNIEnv* env, jclass, jobjectArray outerArray, jst standardDate = date1; daylightSavingDate = date2; } - - jstring content = formatDate(env, shortFormat, daylightSavingDate); - env->SetObjectArrayElement(shortDlTimeArray, i, content); - env->DeleteLocalRef(content); - - content = formatDate(env, shortFormat, standardDate); - env->SetObjectArrayElement(shortStdTimeArray, i, content); - env->DeleteLocalRef(content); - - content = formatDate(env, longFormat, daylightSavingDate); - env->SetObjectArrayElement(longDlTimeArray, i, content); - env->DeleteLocalRef(content); - - content = formatDate(env, longFormat, standardDate); - env->SetObjectArrayElement(longStdTimeArray, i, content); - env->DeleteLocalRef(content); - - delete tz; + + ScopedLocalRef shortStd(env, formatDate(env, shortFormat, standardDate)); + env->SetObjectArrayElement(shortStdArray, i, shortStd.get()); + + ScopedLocalRef longStd(env, formatDate(env, longFormat, standardDate)); + env->SetObjectArrayElement(longStdArray, i, longStd.get()); + + if (tz->useDaylightTime()) { + ScopedLocalRef shortDst(env, formatDate(env, shortFormat, daylightSavingDate)); + env->SetObjectArrayElement(shortDstArray, i, shortDst.get()); + + ScopedLocalRef longDst(env, formatDate(env, longFormat, daylightSavingDate)); + env->SetObjectArrayElement(longDstArray, i, longDst.get()); + } else { + env->SetObjectArrayElement(shortDstArray, i, shortStd.get()); + env->SetObjectArrayElement(longDstArray, i, longStd.get()); + } } } @@ -395,12 +390,10 @@ static jobjectArray getAmPmMarkers(JNIEnv* env, UResourceBundle* gregorian) { } jobjectArray amPmMarkers = env->NewObjectArray(2, string_class, NULL); - jstring amU = env->NewString(am, lengthAm); - env->SetObjectArrayElement(amPmMarkers, 0, amU); - env->DeleteLocalRef(amU); - jstring pmU = env->NewString(pm, lengthPm); - env->SetObjectArrayElement(amPmMarkers, 1, pmU); - env->DeleteLocalRef(pmU); + ScopedLocalRef amU(env, env->NewString(am, lengthAm)); + env->SetObjectArrayElement(amPmMarkers, 0, amU.get()); + ScopedLocalRef pmU(env, env->NewString(pm, lengthPm)); + env->SetObjectArrayElement(amPmMarkers, 1, pmU.get()); return amPmMarkers; } @@ -427,9 +420,8 @@ static jobjectArray getEras(JNIEnv* env, UResourceBundle* gregorian) { if (U_FAILURE(status)) { return NULL; } - jstring eraU = env->NewString(era, eraLength); - env->SetObjectArrayElement(eras, i, eraU); - env->DeleteLocalRef(eraU); + ScopedLocalRef eraU(env, env->NewString(era, eraLength)); + env->SetObjectArrayElement(eras, i, eraU.get()); } return eras; } @@ -461,14 +453,12 @@ static jobjectArray getMonthNames(JNIEnv* env, UResourceBundle* gregorian, bool if (U_FAILURE(status)) { return NULL; } - jstring monthU = env->NewString(month, monthNameLength); - env->SetObjectArrayElement(months, i, monthU); - env->DeleteLocalRef(monthU); + ScopedLocalRef monthU(env, env->NewString(month, monthNameLength)); + env->SetObjectArrayElement(months, i, monthU.get()); } - jstring monthU = env->NewStringUTF(""); - env->SetObjectArrayElement(months, monthCount, monthU); - env->DeleteLocalRef(monthU); + ScopedLocalRef monthU(env, env->NewStringUTF("")); + env->SetObjectArrayElement(months, monthCount, monthU.get()); return months; } @@ -509,9 +499,8 @@ static jobjectArray getWeekdayNames(JNIEnv* env, UResourceBundle* gregorian, boo if(U_FAILURE(status)) { return NULL; } - jstring dayU = env->NewString(day, dayNameLength); - env->SetObjectArrayElement(weekdays, i + 1, dayU); - env->DeleteLocalRef(dayU); + ScopedLocalRef dayU(env, env->NewString(day, dayNameLength)); + env->SetObjectArrayElement(weekdays, i + 1, dayU.get()); } return weekdays; } |