This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Patch: FYI: Calendar.newInstance() optimization


This patch speeds up the Calendar.newInstance() by avoiding Class.forName() calls and reflection instantiation of the calendar class in the most common case. It does this by keeping a cache of Locale->Calendar class mappings, and constructing the calendar object directly if it sees GregorianCalendar.class - by far the most common case.

This further speeds up the DateTester.java test case, from 17s to 10s on my machine.

Regards

Bryce

2004-07-09  Bryce McKinlay  <mckinlay@redhat.com>

	* java.util.Calendar.java (cache): New private static field. Cached
	mappings of locales->calendar classes.
	(ctorArgTypes): New private static field. Singleton argument for
	calendar class constructor lookup.
	(getInstance): Cache Locale->Calendar class mappings using HashMap.
	Optimize by bypassing reflection instantiation for the 
	GregorianCalendar case.

Index: Calendar.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/util/Calendar.java,v
retrieving revision 1.20
diff -u -r1.20 Calendar.java
--- Calendar.java	14 Jun 2004 15:51:36 -0000	1.20
+++ Calendar.java	10 Jul 2004 02:25:35 -0000
@@ -42,6 +42,7 @@
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
 import java.io.Serializable;
+import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 
 /**
@@ -436,6 +437,16 @@
     return getInstance(TimeZone.getDefault(), locale);
   }
 
+  /** 
+   * Cache of locale->calendar-class mappings. This avoids having to do a ResourceBundle
+   * lookup for every getInstance call.  
+   */
+  private static HashMap cache = new HashMap();
+
+  /** Preset argument types for calendar-class constructor lookup.  */
+  private static Class[] ctorArgTypes
+    = new Class[] {TimeZone.class, Locale.class};
+
   /**
    * Creates a calendar representing the actual time, using the given
    * time zone and locale.
@@ -444,29 +455,58 @@
    */
   public static synchronized Calendar getInstance(TimeZone zone, Locale locale)
   {
-    String calendarClassName = null;
-    ResourceBundle rb = getBundle(locale);
-    calendarClassName = rb.getString("calendarClass");
-    if (calendarClassName != null)
+    Class calendarClass = (Class) cache.get(locale);
+    Throwable exception = null;
+
+    try
       {
-	try
+	if (calendarClass == null)
 	  {
-	    Class calendarClass = Class.forName(calendarClassName);
-	    if (Calendar.class.isAssignableFrom(calendarClass))
+	    ResourceBundle rb = getBundle(locale);
+	    String calendarClassName = rb.getString("calendarClass");
+
+	    if (calendarClassName != null)
 	      {
-		return (Calendar) calendarClass.getConstructor(
-		  new Class[] { TimeZone.class, Locale.class}
-		).newInstance(new Object[] {zone, locale} );
+		calendarClass = Class.forName(calendarClassName);
+		if (Calendar.class.isAssignableFrom(calendarClass))
+		  cache.put(locale, calendarClass);
 	      }
 	  }
-	catch (ClassNotFoundException ex) {}
-	catch (IllegalAccessException ex) {}
-	catch (NoSuchMethodException ex) {}
-	catch (InstantiationException ex) {}
-	catch (InvocationTargetException ex) {}
-	// XXX should we ignore these errors or throw an exception ?
+
+        // GregorianCalendar is by far the most common case. Optimize by 
+	// avoiding reflection.
+	if (calendarClass == GregorianCalendar.class)
+	  return new GregorianCalendar(zone, locale);
+
+	if (Calendar.class.isAssignableFrom(calendarClass))
+	  {
+	    Constructor ctor = calendarClass.getConstructor(ctorArgTypes);
+	    return (Calendar) ctor.newInstance(new Object[] {zone, locale});
+	  }
+      }
+    catch (ClassNotFoundException ex)
+      {
+	exception = ex;
+      }
+    catch (IllegalAccessException ex)
+      {
+	exception = ex;
+      }
+    catch (NoSuchMethodException ex)
+      {
+	exception = ex;
+      }
+    catch (InstantiationException ex)
+      {
+	exception = ex;
+      }
+    catch (InvocationTargetException ex)
+      {
+	exception = ex;
       }
-    return new GregorianCalendar(zone, locale);
+    
+    throw new RuntimeException("Error instantiating calendar for locale " +
+			       locale, exception);
   }
 
   /**
import java.util.Date;

public class DateTester {
  static final int N = 250000;
  public static String[] s = new String[N];

  public static void main(String[] args) 
  {
    long start = System.currentTimeMillis();
    for (int i=0; i<N; i++) 
      {
	s[i] = new Date().toString();
	if (i % 5000 == 0)
	  System.out.print(".");
      }
    System.out.println((System.currentTimeMillis() - start) + "ms");
  }
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]