1 /*
   2  * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   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 }
--- EOF ---