[PATCH 1/2] Class local storage

David M. Lloyd david.lloyd at redhat.com
Thu Feb 26 16:05:30 UTC 2009


This first patch adds a ClassLocal mechanism.  The cost is one reference 
per loaded class, plus one WeakHashMap for every loaded class which has 
local information associated with it.  The map has one key for every 
ClassLocal which is currently storing data on this ClassLocal.

- DML

--
diff -r dde3fe2e8164 src/share/classes/java/lang/Class.java
--- a/src/share/classes/java/lang/Class.java	Wed Feb 25 14:32:01 2009 +0000
+++ b/src/share/classes/java/lang/Class.java	Thu Feb 26 09:53:00 2009 -0600
@@ -52,6 +52,7 @@
  import java.util.Set;
  import java.util.Map;
  import java.util.HashMap;
+import java.util.WeakHashMap;
  import sun.misc.Unsafe;
  import sun.reflect.ConstantPool;
  import sun.reflect.Reflection;
@@ -3113,4 +3114,18 @@
      AnnotationType getAnnotationType() {
          return annotationType;
      }
+
+    // Class local variables use this storage
+
+    private transient Map<Object, Object> classLocalData;
+
+    // Callers must synchronize on this class instance.
+    Map<Object, Object> getClassLocalMap() {
+        final Map<Object, Object> classLocalData = this.classLocalData;
+        if (classLocalData != null) {
+            return classLocalData;
+        } else {
+            return (this.classLocalData = new WeakHashMap<Object, Object>());
+        }
+    }
  }
diff -r dde3fe2e8164 src/share/classes/java/lang/ClassLocal.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/lang/ClassLocal.java	Thu Feb 26 09:53:00 2009 
-0600
@@ -0,0 +1,205 @@
+/*
+ * Copyright 1994-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package java.lang;
+
+import java.util.Map;
+
+/**
+ * This class provides class local variables.  Data stored in a class local
+ * variable is strongly referenced by the class it is associated with.
+ *
+ * @author David M. Lloyd
+ * @param <T> the type of the value of this class local variable
+ * @since 1.7
+ */
+public final class ClassLocal<T> {
+    private volatile Object key = new Object();
+
+    /**
+     * Construct a new instance.  A new instance will contain no mappings.
+     */
+    public ClassLocal() {
+    }
+
+    /**
+     * Determine whether the given class has a mapping for this variable (even
+     * if it is {@code null}).
+     *
+     * @param clazz the class to check
+     *
+     * @return {@code true} if the given class contains a value for this
+     *         class-local
+     */
+    public boolean hasValue(Class<?> clazz) {
+        synchronized (clazz) {
+            return clazz.getClassLocalMap().containsKey(key);
+        }
+    }
+
+    /**
+     * Get the value associated with the given class for this variable.
+     *
+     * @return the value associated with the given class, or {@code null} if
+     *         there is no mapping (a {@code null} return could also indicate
+     *         that a {@code null} value is stored in this variable)
+     */
+    public T get(Class<?> clazz) {
+        synchronized (clazz) {
+            return (T) clazz.getClassLocalMap().get(key);
+        }
+    }
+
+    /**
+     * Associate a new value with the given class for this variable.
+     *
+     * @param clazz the class to update
+     * @param value the value to associate
+     *
+     * @return the previous value associated with this variable, or {@code 
null}
+     *         if there was no mapping (a {@code null} return could also
+     *         indicate that a {@code null} value was stored in this variable)
+     */
+    public T put(Class<?> clazz, T value) {
+        synchronized (clazz) {
+            return (T) clazz.getClassLocalMap().put(key, value);
+        }
+    }
+
+    /**
+     * Associate a value with the given class for this variable if there was
+     * previously no mapping.
+     *
+     * @param clazz the class to update
+     * @param value the value to associate
+     *
+     * @return the previous value associated with this variable, or {@code 
null}
+     *         if there was no mapping (a {@code null} return could also
+     *         indicate that a {@code null} value was stored in this variable)
+     */
+    public T putIfAbsent(Class<?> clazz, T value) {
+        synchronized (clazz) {
+            final Object key = this.key;
+            final Map<Object, Object> cldMap = clazz.getClassLocalMap();
+            if (cldMap.containsKey(key)) {
+                return (T) cldMap.get(key);
+            } else {
+                cldMap.put(key, value);
+                return null;
+            }
+        }
+    }
+
+    /**
+     * Get and remove the value of this variable.  After this method returns,
+     * there will be no value stored in this variable for the given class
+     * (calling {@code hasValue(clazz)} for this class and variable will 
return
+     * {@code false}).
+     *
+     * @param clazz the class to update
+     *
+     * @return the previous value associated with this variable, or {@code 
null}
+     *         if there was no mapping (a {@code null} return could also
+     *         indicate that a {@code null} value was stored in this variable)
+     */
+    public T remove(Class<?> clazz) {
+        synchronized (clazz) {
+            return (T) clazz.getClassLocalMap().remove(key);
+        }
+    }
+
+    /**
+     * Remove the entry for this variable only if it is currently set to a 
given
+     * value.
+     *
+     * @param clazz the class to update
+     * @param oldValue the value expected to be associated with the variable
+     *
+     * @return {@code true} if the value was removed
+     */
+    public boolean remove(Class<?> clazz, T oldValue) {
+        synchronized (clazz) {
+            final Map<Object, Object> clMap = clazz.getClassLocalMap();
+            final Object key = this.key;
+            if (clMap.containsKey(key) && clMap.get(key).equals(oldValue)) {
+                clMap.remove(key);
+                return true;
+            } else {
+                return false;
+            }
+        }
+    }
+
+    /**
+     * Replace the entry for this variable, returning the old value.
+     *
+     * @param clazz the class to update
+     * @param newValue the value to associate with this variable
+     *
+     * @return the previous value associated with this variable, or {@code 
null}
+     *         if there was no mapping (a {@code null} return could also
+     *         indicate that a {@code null} value was stored in this variable)
+     */
+    public T replace(Class<?> clazz, T newValue) {
+        synchronized (clazz) {
+            final Map<Object, Object> clMap = clazz.getClassLocalMap();
+            if (clMap.containsKey(key)) {
+                return (T) clMap.put(key, newValue);
+            } else {
+                return null;
+            }
+        }
+    }
+
+    /**
+     * Replace the entry for this variable, if it was previously set to a 
given
+     * value.
+     *
+     * @param clazz the class to update
+     * @param oldValue the value expected to be associated with the variable
+     * @param newValue the value to associate with this variable
+     *
+     * @return {@code true} if the value was replaced
+     */
+    public boolean replace(Class<?> clazz, T oldValue, T newValue) {
+        synchronized (clazz) {
+            final Map<Object, Object> clMap = clazz.getClassLocalMap();
+            final Object key = this.key;
+            if (clMap.containsKey(key) && clMap.get(key).equals(oldValue)) {
+                clMap.put(key, newValue);
+                return true;
+            } else {
+                return false;
+            }
+        }
+    }
+
+    /**
+     * Cause all existing mappings to be cleared.  Once this method is called,
+     * prior values are no longer retrievable.
+     */
+    public void clear() {
+        key = new Object();
+    }
+}






More information about the core-libs-dev mailing list