< prev index next >

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

Print this page

        

*** 1,7 **** /* ! * Copyright (c) 2010, 2014, Oracle and/or its affiliates. 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. Oracle designates this --- 1,7 ---- /* ! * Copyright (c) 2010, 2017, Oracle and/or its affiliates. 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. Oracle designates this
*** 23,260 **** * questions. */ package jdk.nashorn.internal.runtime; import java.util.Map; import java.util.Set; import java.util.WeakHashMap; import java.util.concurrent.atomic.LongAdder; /** ! * Helper class to manage property listeners and notification. */ ! public class PropertyListeners { ! private Map<Object, WeakPropertyMapSet> listeners; // These counters are updated in debug mode ! private static LongAdder listenersAdded; ! private static LongAdder listenersRemoved; static { if (Context.DEBUG) { ! listenersAdded = new LongAdder(); ! listenersRemoved = new LongAdder(); } } /** * Copy constructor ! * @param listener listener to copy */ ! PropertyListeners(final PropertyListeners listener) { ! if (listener != null && listener.listeners != null) { ! this.listeners = new WeakHashMap<>(); // We need to copy the nested weak sets in order to avoid concurrent modification issues, see JDK-8146274 ! synchronized (listener) { ! for (final Map.Entry<Object, WeakPropertyMapSet> entry : listener.listeners.entrySet()) { ! this.listeners.put(entry.getKey(), new WeakPropertyMapSet(entry.getValue())); } } } } /** ! * Return aggregate listeners added to all PropertyListenerManagers ! * @return the listenersAdded */ ! public static long getListenersAdded() { ! return listenersAdded.longValue(); } /** ! * Return aggregate listeners removed from all PropertyListenerManagers ! * @return the listenersRemoved */ ! public static long getListenersRemoved() { ! return listenersRemoved.longValue(); } /** ! * Return number of listeners added to a ScriptObject. * @param obj the object ! * @return the listener count */ ! public static int getListenerCount(final ScriptObject obj) { ! return obj.getMap().getListenerCount(); } /** ! * Return the number of listeners added to this PropertyListeners instance. ! * @return the listener count; */ ! public int getListenerCount() { ! return listeners == null ? 0 : listeners.size(); } - // Property listener management methods - /** ! * Add {@code propertyMap} as property listener to {@code listeners} using key {@code key} by ! * creating and returning a new {@code PropertyListeners} instance. * ! * @param listeners the original property listeners instance, may be null * @param key the property key ! * @param propertyMap the property map ! * @return the new property map */ ! public static PropertyListeners addListener(final PropertyListeners listeners, final String key, final PropertyMap propertyMap) { ! final PropertyListeners newListeners; ! if (listeners == null || !listeners.containsListener(key, propertyMap)) { ! newListeners = new PropertyListeners(listeners); ! newListeners.addListener(key, propertyMap); ! return newListeners; } ! return listeners; } /** ! * Checks whether {@code propertyMap} is registered as listener with {@code key}. * * @param key the property key ! * @param propertyMap the property map ! * @return true if property map is registered with property key */ ! synchronized boolean containsListener(final String key, final PropertyMap propertyMap) { ! if (listeners == null) { ! return false; ! } ! final WeakPropertyMapSet set = listeners.get(key); ! return set != null && set.contains(propertyMap); } ! /** ! * Add a property listener to this object. ! * ! * @param propertyMap The property listener that is added. ! */ ! synchronized final void addListener(final String key, final PropertyMap propertyMap) { if (Context.DEBUG) { ! listenersAdded.increment(); ! } ! if (listeners == null) { ! listeners = new WeakHashMap<>(); } ! WeakPropertyMapSet set = listeners.get(key); if (set == null) { ! set = new WeakPropertyMapSet(); ! listeners.put(key, set); ! } ! if (!set.contains(propertyMap)) { ! set.add(propertyMap); ! } } ! /** ! * A new property is being added. ! * ! * @param prop The new Property added. ! */ ! public synchronized void propertyAdded(final Property prop) { ! if (listeners != null) { ! final WeakPropertyMapSet set = listeners.get(prop.getKey()); ! if (set != null) { ! for (final PropertyMap propertyMap : set.elements()) { ! propertyMap.propertyAdded(prop, false); ! } ! listeners.remove(prop.getKey()); ! if (Context.DEBUG) { ! listenersRemoved.increment(); ! } } } } /** ! * An existing property is being deleted. * ! * @param prop The property being deleted. */ ! public synchronized void propertyDeleted(final Property prop) { ! if (listeners != null) { ! final WeakPropertyMapSet set = listeners.get(prop.getKey()); if (set != null) { - for (final PropertyMap propertyMap : set.elements()) { - propertyMap.propertyDeleted(prop, false); - } - listeners.remove(prop.getKey()); if (Context.DEBUG) { ! listenersRemoved.increment(); ! } } } } /** ! * An existing Property is being replaced with a new Property. ! * ! * @param oldProp The old property that is being replaced. ! * @param newProp The new property that replaces the old property. * */ ! public synchronized void propertyModified(final Property oldProp, final Property newProp) { ! if (listeners != null) { ! final WeakPropertyMapSet set = listeners.get(oldProp.getKey()); ! if (set != null) { ! for (final PropertyMap propertyMap : set.elements()) { ! propertyMap.propertyModified(oldProp, newProp, false); } - listeners.remove(oldProp.getKey()); if (Context.DEBUG) { ! listenersRemoved.increment(); ! } } } } ! /** ! * Callback for when a proto is changed ! */ ! public synchronized void protoChanged() { ! if (listeners != null) { ! for (final WeakPropertyMapSet set : listeners.values()) { ! for (final PropertyMap propertyMap : set.elements()) { ! propertyMap.protoChanged(false); ! } ! } ! listeners.clear(); ! } ! } ! ! private static class WeakPropertyMapSet { ! private final WeakHashMap<PropertyMap, Boolean> map; ! WeakPropertyMapSet() { ! this.map = new WeakHashMap<>(); } ! WeakPropertyMapSet(final WeakPropertyMapSet set) { ! this.map = new WeakHashMap<>(set.map); } ! void add(final PropertyMap propertyMap) { ! map.put(propertyMap, Boolean.TRUE); } ! boolean contains(final PropertyMap propertyMap) { ! return map.containsKey(propertyMap); } ! Set<PropertyMap> elements() { return map.keySet(); } } } --- 23,226 ---- * questions. */ package jdk.nashorn.internal.runtime; + import java.lang.invoke.SwitchPoint; + import java.util.Collections; + import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.WeakHashMap; import java.util.concurrent.atomic.LongAdder; /** ! * Helper class for tracking and invalidation of switchpoints for inherited properties. */ ! public class PropertySwitchPoints { ! private final Map<Object, WeakSwitchPointSet> switchPointMap = new HashMap<>(); ! ! private final static SwitchPoint[] EMPTY_SWITCHPOINT_ARRAY = new SwitchPoint[0]; // These counters are updated in debug mode ! private static LongAdder switchPointsAdded; ! private static LongAdder switchPointsInvalidated; static { if (Context.DEBUG) { ! switchPointsAdded = new LongAdder(); ! switchPointsInvalidated = new LongAdder(); } } /** * Copy constructor ! * ! * @param switchPoints Proto switchpoints to copy */ ! private PropertySwitchPoints(final PropertySwitchPoints switchPoints) { ! if (switchPoints != null) { // We need to copy the nested weak sets in order to avoid concurrent modification issues, see JDK-8146274 ! synchronized (switchPoints) { ! for (final Map.Entry<Object, WeakSwitchPointSet> entry : switchPoints.switchPointMap.entrySet()) { ! this.switchPointMap.put(entry.getKey(), new WeakSwitchPointSet(entry.getValue())); } } } } /** ! * Return aggregate switchpoints added to all ProtoSwitchPoints ! * @return the number of switchpoints added */ ! public static long getSwitchPointsAdded() { ! return switchPointsAdded.longValue(); } /** ! * Return aggregate switchPointMap invalidated in all ProtoSwitchPoints ! * @return the number of switchpoints invalidated */ ! public static long getSwitchPointsInvalidated() { ! return switchPointsInvalidated.longValue(); } /** ! * Return number of property switchPoints added to a ScriptObject. * @param obj the object ! * @return the switchpoint count */ ! public static int getSwitchPointCount(final ScriptObject obj) { ! return obj.getMap().getSwitchPointCount(); } /** ! * Return the number of switchpoints added to this ProtoSwitchPoints instance. ! * @return the switchpoint count; */ ! int getSwitchPointCount() { ! return switchPointMap.size(); } /** ! * Add {@code switchPoint} to the switchpoints for for property {@code key}, creating ! * and returning a new {@code ProtoSwitchPoints} instance if the switchpoint was not already contained * ! * @param oldSwitchPoints the original PropertySwitchPoints instance. May be null * @param key the property key ! * @param switchPoint the switchpoint to be added ! * @return the new PropertySwitchPoints instance, or this instance if switchpoint was already contained */ ! static PropertySwitchPoints addSwitchPoint(final PropertySwitchPoints oldSwitchPoints, final String key, final SwitchPoint switchPoint) { ! if (oldSwitchPoints == null || !oldSwitchPoints.contains(key, switchPoint)) { ! final PropertySwitchPoints newSwitchPoints = new PropertySwitchPoints(oldSwitchPoints); ! newSwitchPoints.add(key, switchPoint); ! return newSwitchPoints; } ! return oldSwitchPoints; } /** ! * Checks whether {@code switchPoint} is contained in {@code key}'s set. * * @param key the property key ! * @param switchPoint the switchPoint ! * @return true if switchpoint is already contained for key */ ! private synchronized boolean contains(final String key, final SwitchPoint switchPoint) { ! final WeakSwitchPointSet set = this.switchPointMap.get(key); ! return set != null && set.contains(switchPoint); } ! private synchronized void add(final String key, final SwitchPoint switchPoint) { if (Context.DEBUG) { ! switchPointsAdded.increment(); } ! WeakSwitchPointSet set = this.switchPointMap.get(key); if (set == null) { ! set = new WeakSwitchPointSet(); ! this.switchPointMap.put(key, set); } ! set.add(switchPoint); } + + Set<SwitchPoint> getSwitchPoints(final Object key) { + WeakSwitchPointSet switchPointSet = switchPointMap.get(key); + if (switchPointSet != null) { + return switchPointSet.elements(); } + + return Collections.emptySet(); } /** ! * Invalidate all switchpoints for the given property. This is called when that ! * property is created, deleted, or modified in a script object. * ! * @param prop The property to invalidate. */ ! synchronized void invalidateProperty(final Property prop) { ! final WeakSwitchPointSet set = switchPointMap.get(prop.getKey()); if (set != null) { if (Context.DEBUG) { ! switchPointsInvalidated.add(set.size()); } + final SwitchPoint[] switchPoints = set.elements().toArray(EMPTY_SWITCHPOINT_ARRAY); + SwitchPoint.invalidateAll(switchPoints); + this.switchPointMap.remove(prop.getKey()); } } + /** ! * Invalidate all switchpoints except those defined in {@code map}. This is called ! * when the prototype of a script object is changed. * + * @param map map of properties to exclude from invalidation */ ! synchronized void invalidateInheritedProperties(final PropertyMap map) { ! for (final Map.Entry<Object, WeakSwitchPointSet> entry : switchPointMap.entrySet()) { ! if (map.findProperty(entry.getKey()) != null) { ! continue; } if (Context.DEBUG) { ! switchPointsInvalidated.add(entry.getValue().size()); } + final SwitchPoint[] switchPoints = entry.getValue().elements().toArray(EMPTY_SWITCHPOINT_ARRAY); + SwitchPoint.invalidateAll(switchPoints); } + switchPointMap.clear(); } ! private static class WeakSwitchPointSet { ! private final WeakHashMap<SwitchPoint, Void> map; ! WeakSwitchPointSet() { ! map = new WeakHashMap<>(); } ! WeakSwitchPointSet(final WeakSwitchPointSet set) { ! map = new WeakHashMap<>(set.map); } ! void add(final SwitchPoint switchPoint) { ! map.put(switchPoint, null); } ! boolean contains(final SwitchPoint switchPoint) { ! return map.containsKey(switchPoint); } ! Set<SwitchPoint> elements() { return map.keySet(); } + int size() { + return map.size(); + } + } }
< prev index next >