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 ---