< prev index next >

src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/PropertySwitchPoints.java

Print this page




   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package jdk.nashorn.internal.runtime;
  27 


  28 import java.util.Map;
  29 import java.util.Set;
  30 import java.util.WeakHashMap;
  31 import java.util.concurrent.atomic.LongAdder;
  32 
  33 /**
  34  * Helper class to manage property listeners and notification.
  35  */
  36 public class PropertyListeners {
  37 
  38     private Map<Object, WeakPropertyMapSet> listeners;


  39 
  40     // These counters are updated in debug mode
  41     private static LongAdder listenersAdded;
  42     private static LongAdder listenersRemoved;
  43 
  44     static {
  45         if (Context.DEBUG) {
  46             listenersAdded = new LongAdder();
  47             listenersRemoved = new LongAdder();
  48         }
  49     }
  50 
  51     /**
  52      * Copy constructor
  53      * @param listener listener to copy

  54      */
  55     PropertyListeners(final PropertyListeners listener) {
  56         if (listener != null && listener.listeners != null) {
  57             this.listeners = new WeakHashMap<>();
  58             // We need to copy the nested weak sets in order to avoid concurrent modification issues, see JDK-8146274
  59             synchronized (listener) {
  60                 for (final Map.Entry<Object, WeakPropertyMapSet> entry : listener.listeners.entrySet()) {
  61                     this.listeners.put(entry.getKey(), new WeakPropertyMapSet(entry.getValue()));
  62                 }
  63             }
  64         }
  65     }
  66 
  67     /**
  68      * Return aggregate listeners added to all PropertyListenerManagers
  69      * @return the listenersAdded
  70      */
  71     public static long getListenersAdded() {
  72         return listenersAdded.longValue();
  73     }
  74 
  75     /**
  76      * Return aggregate listeners removed from all PropertyListenerManagers
  77      * @return the listenersRemoved
  78      */
  79     public static long getListenersRemoved() {
  80         return listenersRemoved.longValue();
  81     }
  82 
  83     /**
  84      * Return number of listeners added to a ScriptObject.
  85      * @param obj the object
  86      * @return the listener count
  87      */
  88     public static int getListenerCount(final ScriptObject obj) {
  89         return obj.getMap().getListenerCount();
  90     }
  91 
  92     /**
  93      * Return the number of listeners added to this PropertyListeners instance.
  94      * @return the listener count;
  95      */
  96     public int getListenerCount() {
  97         return listeners == null ? 0 : listeners.size();
  98     }
  99 
 100     // Property listener management methods
 101 
 102     /**
 103      * Add {@code propertyMap} as property listener to {@code listeners} using key {@code key} by
 104      * creating and returning a new {@code PropertyListeners} instance.
 105      *
 106      * @param listeners the original property listeners instance, may be null
 107      * @param key the property key
 108      * @param propertyMap the property map
 109      * @return the new property map
 110      */
 111     public static PropertyListeners addListener(final PropertyListeners listeners, final String key, final PropertyMap propertyMap) {
 112         final PropertyListeners newListeners;
 113         if (listeners == null || !listeners.containsListener(key, propertyMap)) {
 114             newListeners = new PropertyListeners(listeners);
 115             newListeners.addListener(key, propertyMap);
 116             return newListeners;
 117         }
 118         return listeners;
 119     }
 120 
 121     /**
 122      * Checks whether {@code propertyMap} is registered as listener with {@code key}.
 123      *
 124      * @param key the property key
 125      * @param propertyMap the property map
 126      * @return true if property map is registered with property key
 127      */
 128     synchronized boolean containsListener(final String key, final PropertyMap propertyMap) {
 129         if (listeners == null) {
 130             return false;
 131         }
 132         final WeakPropertyMapSet set = listeners.get(key);
 133         return set != null && set.contains(propertyMap);
 134     }
 135 
 136     /**
 137      * Add a property listener to this object.
 138      *
 139      * @param propertyMap The property listener that is added.
 140      */
 141     synchronized final void addListener(final String key, final PropertyMap propertyMap) {
 142         if (Context.DEBUG) {
 143             listenersAdded.increment();
 144         }
 145         if (listeners == null) {
 146             listeners = new WeakHashMap<>();
 147         }
 148 
 149         WeakPropertyMapSet set = listeners.get(key);
 150         if (set == null) {
 151             set = new WeakPropertyMapSet();
 152             listeners.put(key, set);
 153         }
 154         if (!set.contains(propertyMap)) {
 155             set.add(propertyMap);
 156         }
 157     }
 158 
 159     /**
 160      * A new property is being added.
 161      *
 162      * @param prop The new Property added.
 163      */
 164     public synchronized void propertyAdded(final Property prop) {
 165         if (listeners != null) {
 166             final WeakPropertyMapSet set = listeners.get(prop.getKey());
 167             if (set != null) {
 168                 for (final PropertyMap propertyMap : set.elements()) {
 169                     propertyMap.propertyAdded(prop, false);
 170                 }
 171                 listeners.remove(prop.getKey());
 172                 if (Context.DEBUG) {
 173                     listenersRemoved.increment();
 174                 }
 175             }
 176         }
 177     }
 178 
 179     /**
 180      * An existing property is being deleted.
 181      *
 182      * @param prop The property being deleted.
 183      */
 184     public synchronized void propertyDeleted(final Property prop) {
 185         if (listeners != null) {
 186             final WeakPropertyMapSet set = listeners.get(prop.getKey());
 187             if (set != null) {
 188                 for (final PropertyMap propertyMap : set.elements()) {
 189                     propertyMap.propertyDeleted(prop, false);
 190                 }
 191                 listeners.remove(prop.getKey());
 192                 if (Context.DEBUG) {
 193                     listenersRemoved.increment();
 194                 }
 195             }
 196         }


 197     }
 198 
 199     /**
 200      * An existing Property is being replaced with a new Property.
 201      *
 202      * @param oldProp The old property that is being replaced.
 203      * @param newProp The new property that replaces the old property.
 204      *

 205      */
 206     public synchronized void propertyModified(final Property oldProp, final Property newProp) {
 207         if (listeners != null) {
 208             final WeakPropertyMapSet set = listeners.get(oldProp.getKey());
 209             if (set != null) {
 210                 for (final PropertyMap propertyMap : set.elements()) {
 211                     propertyMap.propertyModified(oldProp, newProp, false);
 212                 }
 213                 listeners.remove(oldProp.getKey());
 214                 if (Context.DEBUG) {
 215                     listenersRemoved.increment();
 216                 }
 217             }



 218         }
 219     }
 220 

 221     /**
 222      * Callback for when a proto is changed
 223      */
 224     public synchronized void protoChanged() {
 225         if (listeners != null) {
 226             for (final WeakPropertyMapSet set : listeners.values()) {
 227                 for (final PropertyMap propertyMap : set.elements()) {
 228                     propertyMap.protoChanged(false);
 229                 }
 230             }
 231             listeners.clear();

 232         }

 233     }
 234 
 235     private static class WeakPropertyMapSet {
 236 
 237         private final WeakHashMap<PropertyMap, Boolean> map;
 238 
 239         WeakPropertyMapSet() {
 240             this.map = new WeakHashMap<>();
 241         }
 242 
 243         WeakPropertyMapSet(final WeakPropertyMapSet set) {
 244             this.map = new WeakHashMap<>(set.map);
 245         }
 246 
 247         void add(final PropertyMap propertyMap) {
 248             map.put(propertyMap, Boolean.TRUE);
 249         }
 250 
 251         boolean contains(final PropertyMap propertyMap) {
 252             return map.containsKey(propertyMap);
 253         }
 254 
 255         Set<PropertyMap> elements() {
 256             return map.keySet();
 257         }
 258 




 259     }
 260 }


   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package jdk.nashorn.internal.runtime;
  27 
  28 import java.lang.invoke.SwitchPoint;
  29 import java.util.Collections;
  30 import java.util.Map;
  31 import java.util.Set;
  32 import java.util.WeakHashMap;
  33 import java.util.concurrent.atomic.LongAdder;
  34 
  35 /**
  36  * Helper class for tracking and invalidation of switchpoints for inherited properties.
  37  */
  38 public class PropertySwitchPoints {
  39 
  40     private final Map<Object, WeakSwitchPointSet> switchPointMap = new WeakHashMap<>();
  41 
  42     private final static SwitchPoint[] EMPTY_SWITCHPOINT_ARRAY = new SwitchPoint[0];
  43 
  44     // These counters are updated in debug mode
  45     private static LongAdder switchPointsAdded;
  46     private static LongAdder switchPointsInvalidated;
  47 
  48     static {
  49         if (Context.DEBUG) {
  50             switchPointsAdded = new LongAdder();
  51             switchPointsInvalidated = new LongAdder();
  52         }
  53     }
  54 
  55     /**
  56      * Copy constructor
  57      *
  58      * @param switchPoints Proto switchpoints to copy
  59      */
  60     private PropertySwitchPoints(final PropertySwitchPoints switchPoints) {
  61         if (switchPoints != null) {

  62             // We need to copy the nested weak sets in order to avoid concurrent modification issues, see JDK-8146274
  63             synchronized (switchPoints) {
  64                 for (final Map.Entry<Object, WeakSwitchPointSet> entry : switchPoints.switchPointMap.entrySet()) {
  65                     this.switchPointMap.put(entry.getKey(), new WeakSwitchPointSet(entry.getValue()));
  66                 }
  67             }
  68         }
  69     }
  70 
  71     /**
  72      * Return aggregate switchpoints added to all ProtoSwitchPoints
  73      * @return the number of switchpoints added
  74      */
  75     public static long getSwitchPointsAdded() {
  76         return switchPointsAdded.longValue();
  77     }
  78 
  79     /**
  80      * Return aggregate switchPointMap invalidated in all ProtoSwitchPoints
  81      * @return the number of switchpoints invalidated
  82      */
  83     public static long getSwitchPointsInvalidated() {
  84         return switchPointsInvalidated.longValue();
  85     }
  86 
  87     /**
  88      * Return number of property switchPoints added to a ScriptObject.
  89      * @param obj the object
  90      * @return the switchpoint count
  91      */
  92     public static int getSwitchPointCount(final ScriptObject obj) {
  93         return obj.getMap().getSwitchPointCount();
  94     }
  95 
  96     /**
  97      * Return the number of switchpoints added to this ProtoSwitchPoints instance.
  98      * @return the switchpoint count;
  99      */
 100     int getSwitchPointCount() {
 101         return switchPointMap.size();
 102     }
 103 


 104     /**
 105      * Add {@code switchPoint} to the switchpoints for the property identified by {@code key}, creating
 106      * and returning a new {@code ProtoSwitchPoints} instance if the switchpoint was not already contained
 107      *
 108      * @param oldSwitchPoints the original PropertySwitchPoints instance. May be null
 109      * @param key the property key
 110      * @param switchPoint the switchpoint to be added
 111      * @return the new PropertySwitchPoints instance, or this instance if switchpoint was already contained
 112      */
 113     static PropertySwitchPoints addSwitchPoint(final PropertySwitchPoints oldSwitchPoints, final String key, final SwitchPoint switchPoint) {
 114         if (oldSwitchPoints == null || !oldSwitchPoints.contains(key, switchPoint)) {
 115             final PropertySwitchPoints newSwitchPoints = new PropertySwitchPoints(oldSwitchPoints);
 116             newSwitchPoints.add(key, switchPoint);
 117             return newSwitchPoints;

 118         }
 119         return oldSwitchPoints;
 120     }
 121 
 122     /**
 123      * Checks whether {@code switchPoint} is contained in {@code key}'s set.
 124      *
 125      * @param key the property key
 126      * @param switchPoint the switchPoint
 127      * @return true if switchpoint is already contained for key
 128      */
 129     private synchronized boolean contains(final String key, final SwitchPoint switchPoint) {
 130         final WeakSwitchPointSet set = this.switchPointMap.get(key);
 131         return set != null && set.contains(switchPoint);



 132     }
 133 
 134     private synchronized void add(final String key, final SwitchPoint switchPoint) {





 135         if (Context.DEBUG) {
 136             switchPointsAdded.increment();



 137         }
 138 
 139         WeakSwitchPointSet set = this.switchPointMap.get(key);
 140         if (set == null) {
 141             set = new WeakSwitchPointSet();
 142             this.switchPointMap.put(key, set);




 143         }
 144 
 145         set.add(switchPoint);

















 146     }
 147 
 148     Set<SwitchPoint> getSwitchPoints(final Object key) {
 149         WeakSwitchPointSet switchPointSet = switchPointMap.get(key);
 150         if (switchPointSet != null) {
 151             return switchPointSet.elements();













 152         }
 153 
 154         return Collections.emptySet();
 155     }
 156 
 157     /**
 158      * Invalidate all switchpoints for the given property.



 159      *
 160      * @param prop The property to invalidate.
 161      */
 162     synchronized void invalidateProperty(final Property prop) {
 163         final WeakSwitchPointSet set = switchPointMap.get(prop.getKey());

 164         if (set != null) {




 165             if (Context.DEBUG) {
 166                 switchPointsInvalidated.add(set.size());

 167             }
 168             final SwitchPoint[] switchPoints = set.elements().toArray(EMPTY_SWITCHPOINT_ARRAY);
 169             SwitchPoint.invalidateAll(switchPoints);
 170             this.switchPointMap.remove(prop.getKey());
 171         }
 172     }
 173 
 174 
 175     /**
 176      * Invalidate all our switchpoints.
 177      */
 178     synchronized void invalidateAll() {
 179         for (final WeakSwitchPointSet set : switchPointMap.values()) {
 180             if (Context.DEBUG) {
 181                 switchPointsInvalidated.add(set.size());


 182             }
 183             final SwitchPoint[] switchPoints = set.elements().toArray(EMPTY_SWITCHPOINT_ARRAY);
 184             SwitchPoint.invalidateAll(switchPoints);
 185         }
 186         switchPointMap.clear();
 187     }
 188 
 189     private static class WeakSwitchPointSet {
 190 
 191         private final WeakHashMap<SwitchPoint, Void> map;
 192 
 193         WeakSwitchPointSet() {
 194             map = new WeakHashMap<>();
 195         }
 196 
 197         WeakSwitchPointSet(final WeakSwitchPointSet set) {
 198             map = new WeakHashMap<>(set.map);
 199         }
 200 
 201         void add(final SwitchPoint switchPoint) {
 202             map.put(switchPoint, null);
 203         }
 204 
 205         boolean contains(final SwitchPoint switchPoint) {
 206             return map.containsKey(switchPoint);
 207         }
 208 
 209         Set<SwitchPoint> elements() {
 210             return map.keySet();
 211         }
 212 
 213         int size() {
 214             return map.size();
 215         }
 216 
 217     }
 218 }
< prev index next >