< prev index next >

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

Print this page

        

*** 38,50 **** import java.lang.ref.SoftReference; import java.lang.ref.WeakReference; import java.util.Arrays; import java.util.BitSet; import java.util.Collection; ! import java.util.HashMap; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.WeakHashMap; import java.util.concurrent.atomic.LongAdder; import jdk.nashorn.internal.runtime.options.Options; import jdk.nashorn.internal.scripts.JO; --- 38,51 ---- import java.lang.ref.SoftReference; import java.lang.ref.WeakReference; import java.util.Arrays; import java.util.BitSet; import java.util.Collection; ! import java.util.Collections; import java.util.Iterator; import java.util.NoSuchElementException; + import java.util.Set; import java.util.WeakHashMap; import java.util.concurrent.atomic.LongAdder; import jdk.nashorn.internal.runtime.options.Options; import jdk.nashorn.internal.scripts.JO;
*** 93,113 **** /** A reference to the expected shared prototype property map. If this is set this * property map should only be used if it the same as the actual prototype map. */ private transient SharedPropertyMap sharedProtoMap; - /** {@link SwitchPoint}s for gets on inherited properties. */ - private transient HashMap<Object, SwitchPoint> protoSwitches; - /** History of maps, used to limit map duplication. */ private transient WeakHashMap<Property, Reference<PropertyMap>> history; /** History of prototypes, used to limit map duplication. */ private transient WeakHashMap<ScriptObject, SoftReference<PropertyMap>> protoHistory; ! /** property listeners */ ! private transient PropertyListeners listeners; private transient BitSet freeSlots; private static final long serialVersionUID = -7041836752008732533L; --- 94,111 ---- /** A reference to the expected shared prototype property map. If this is set this * property map should only be used if it the same as the actual prototype map. */ private transient SharedPropertyMap sharedProtoMap; /** History of maps, used to limit map duplication. */ private transient WeakHashMap<Property, Reference<PropertyMap>> history; /** History of prototypes, used to limit map duplication. */ private transient WeakHashMap<ScriptObject, SoftReference<PropertyMap>> protoHistory; ! /** SwitchPoints for properties inherited form this map */ ! private transient PropertySwitchPoints propertySwitchPoints; private transient BitSet freeSlots; private static final long serialVersionUID = -7041836752008732533L;
*** 145,156 **** this.flags = flags; this.spillLength = spillLength; this.fieldCount = fieldCount; this.fieldMaximum = propertyMap.fieldMaximum; this.className = propertyMap.className; ! // We inherit the parent property listeners instance. It will be cloned when a new listener is added. ! this.listeners = propertyMap.listeners; this.freeSlots = propertyMap.freeSlots; this.sharedProtoMap = propertyMap.sharedProtoMap; this.softReferenceDerivationLimit = softReferenceDerivationLimit; if (Context.DEBUG) { --- 143,154 ---- this.flags = flags; this.spillLength = spillLength; this.fieldCount = fieldCount; this.fieldMaximum = propertyMap.fieldMaximum; this.className = propertyMap.className; ! // We inherit the parent property propertySwitchPoints instance. It will be cloned when a new listener is added. ! this.propertySwitchPoints = propertyMap.propertySwitchPoints; this.freeSlots = propertyMap.freeSlots; this.sharedProtoMap = propertyMap.sharedProtoMap; this.softReferenceDerivationLimit = softReferenceDerivationLimit; if (Context.DEBUG) {
*** 243,388 **** public int size() { return properties.size(); } /** ! * Get the number of listeners of this map * ! * @return the number of listeners */ ! public int getListenerCount() { ! return listeners == null ? 0 : listeners.getListenerCount(); } /** ! * Add {@code listenerMap} as a listener to this property map for the given {@code key}. * * @param key the property name ! * @param listenerMap the listener map */ ! public void addListener(final String key, final PropertyMap listenerMap) { ! if (listenerMap != this) { // We need to clone listener instance when adding a new listener since we share ! // the listeners instance with our parent maps that don't need to see the new listener. ! listeners = PropertyListeners.addListener(listeners, key, listenerMap); ! } ! } ! ! /** ! * A new property is being added. ! * ! * @param property The new Property added. ! * @param isSelf was the property added to this map? ! */ ! public void propertyAdded(final Property property, final boolean isSelf) { ! if (!isSelf) { ! invalidateProtoSwitchPoint(property.getKey()); ! } ! if (listeners != null) { ! listeners.propertyAdded(property); ! } } /** ! * An existing property is being deleted. * ! * @param property The property being deleted. ! * @param isSelf was the property deleted from this map? */ ! public void propertyDeleted(final Property property, final boolean isSelf) { ! if (!isSelf) { ! invalidateProtoSwitchPoint(property.getKey()); ! } ! if (listeners != null) { ! listeners.propertyDeleted(property); ! } ! } ! ! /** ! * An existing property is being redefined. ! * ! * @param oldProperty The old property ! * @param newProperty The new property ! * @param isSelf was the property modified on this map? ! */ ! public void propertyModified(final Property oldProperty, final Property newProperty, final boolean isSelf) { ! if (!isSelf) { ! invalidateProtoSwitchPoint(oldProperty.getKey()); ! } ! if (listeners != null) { ! listeners.propertyModified(oldProperty, newProperty); } } /** * The prototype of an object associated with this {@link PropertyMap} is changed. - * - * @param isSelf was the prototype changed on the object using this map? */ ! public void protoChanged(final boolean isSelf) { ! if (!isSelf) { ! invalidateAllProtoSwitchPoints(); ! } else if (sharedProtoMap != null) { sharedProtoMap.invalidateSwitchPoint(); } ! if (listeners != null) { ! listeners.protoChanged(); } } /** ! * Return a SwitchPoint used to track changes of a property in a prototype. * * @param key Property key. ! * @return A shared {@link SwitchPoint} for the property. */ public synchronized SwitchPoint getSwitchPoint(final String key) { ! if (protoSwitches == null) { ! protoSwitches = new HashMap<>(); ! } ! ! SwitchPoint switchPoint = protoSwitches.get(key); ! if (switchPoint == null) { ! switchPoint = new SwitchPoint(); ! protoSwitches.put(key, switchPoint); ! } ! return switchPoint; } - - /** - * Indicate that a prototype property has changed. - * - * @param key {@link Property} key to invalidate. - */ - synchronized void invalidateProtoSwitchPoint(final Object key) { - if (protoSwitches != null) { - final SwitchPoint sp = protoSwitches.get(key); - if (sp != null) { - protoSwitches.remove(key); - if (Context.DEBUG) { - protoInvalidations.increment(); - } - SwitchPoint.invalidateAll(new SwitchPoint[]{sp}); - } } } ! /** ! * Indicate that proto itself has changed in hierarchy somewhere. ! */ ! synchronized void invalidateAllProtoSwitchPoints() { ! if (protoSwitches != null) { ! final int size = protoSwitches.size(); ! if (size > 0) { ! if (Context.DEBUG) { ! protoInvalidations.add(size); ! } ! SwitchPoint.invalidateAll(protoSwitches.values().toArray(new SwitchPoint[0])); ! protoSwitches.clear(); ! } ! } } /** * Add a property to the map, re-binding its getters and setters, * if available, to a given receiver. This is typically the global scope. See --- 241,310 ---- public int size() { return properties.size(); } /** ! * Get the number of property SwitchPoints of this map * ! * @return the number of property SwitchPoints */ ! public int getSwitchPointCount() { ! return propertySwitchPoints == null ? 0 : propertySwitchPoints.getSwitchPointCount(); } /** ! * Add a property switchpoint to this property map for the given {@code key}. * * @param key the property name ! * @param switchPoint the switchpoint */ ! public void addSwitchPoint(final String key, final SwitchPoint switchPoint) { // We need to clone listener instance when adding a new listener since we share ! // the propertySwitchPoints instance with our parent maps that don't need to see the new listener. ! propertySwitchPoints = PropertySwitchPoints.addSwitchPoint(propertySwitchPoints, key, switchPoint); } /** ! * A property is about to change - invalidate all prototype switchpoints for the given property. * ! * @param property The modified property. */ ! public void invalidateProperty(final Property property) { ! if (propertySwitchPoints != null) { ! propertySwitchPoints.invalidateProperty(property); } } /** * The prototype of an object associated with this {@link PropertyMap} is changed. */ ! void protoChanged() { ! if (sharedProtoMap != null) { sharedProtoMap.invalidateSwitchPoint(); } ! if (propertySwitchPoints != null) { ! propertySwitchPoints.invalidateAll(); } } /** ! * Return a SwitchPoint for tracking a property in this map, if one exists. * * @param key Property key. ! * @return A {@link SwitchPoint} for the property, or null. */ public synchronized SwitchPoint getSwitchPoint(final String key) { ! if (propertySwitchPoints != null) { ! final Set<SwitchPoint> existingSwitchPoints = propertySwitchPoints.getSwitchPoints(key); ! for (final SwitchPoint switchPoint : existingSwitchPoints) { ! if (switchPoint != null && !switchPoint.hasBeenInvalidated()) { return switchPoint; } } } ! return null; } /** * Add a property to the map, re-binding its getters and setters, * if available, to a given receiver. This is typically the global scope. See
*** 450,460 **** * * @param property {@link Property} being added. * @return New {@link PropertyMap} with {@link Property} added. */ public final PropertyMap addPropertyNoHistory(final Property property) { ! propertyAdded(property, true); return addPropertyInternal(property); } /** * Add a property to the map. Cloning or using an existing map if available. --- 372,382 ---- * * @param property {@link Property} being added. * @return New {@link PropertyMap} with {@link Property} added. */ public final PropertyMap addPropertyNoHistory(final Property property) { ! invalidateProperty(property); return addPropertyInternal(property); } /** * Add a property to the map. Cloning or using an existing map if available.
*** 462,472 **** * @param property {@link Property} being added. * * @return New {@link PropertyMap} with {@link Property} added. */ public final synchronized PropertyMap addProperty(final Property property) { ! propertyAdded(property, true); PropertyMap newMap = checkHistory(property); if (newMap == null) { newMap = addPropertyInternal(property); addToHistory(property, newMap); --- 384,394 ---- * @param property {@link Property} being added. * * @return New {@link PropertyMap} with {@link Property} added. */ public final synchronized PropertyMap addProperty(final Property property) { ! invalidateProperty(property); PropertyMap newMap = checkHistory(property); if (newMap == null) { newMap = addPropertyInternal(property); addToHistory(property, newMap);
*** 492,502 **** * @param property {@link Property} being removed. * * @return New {@link PropertyMap} with {@link Property} removed or {@code null} if not found. */ public final synchronized PropertyMap deleteProperty(final Property property) { ! propertyDeleted(property, true); PropertyMap newMap = checkHistory(property); final Object key = property.getKey(); if (newMap == null && properties.containsKey(key)) { final PropertyHashMap newProperties = properties.immutableRemove(key); --- 414,424 ---- * @param property {@link Property} being removed. * * @return New {@link PropertyMap} with {@link Property} removed or {@code null} if not found. */ public final synchronized PropertyMap deleteProperty(final Property property) { ! invalidateProperty(property); PropertyMap newMap = checkHistory(property); final Object key = property.getKey(); if (newMap == null && properties.containsKey(key)) { final PropertyHashMap newProperties = properties.immutableRemove(key);
*** 527,537 **** * @param newProperty New {@link Property}. * * @return New {@link PropertyMap} with {@link Property} replaced. */ public final PropertyMap replaceProperty(final Property oldProperty, final Property newProperty) { ! propertyModified(oldProperty, newProperty, true); /* * See ScriptObject.modifyProperty and ScriptObject.setUserAccessors methods. * * This replaceProperty method is called only for the following three cases: * --- 449,459 ---- * @param newProperty New {@link Property}. * * @return New {@link PropertyMap} with {@link Property} replaced. */ public final PropertyMap replaceProperty(final Property oldProperty, final Property newProperty) { ! invalidateProperty(oldProperty); /* * See ScriptObject.modifyProperty and ScriptObject.setUserAccessors methods. * * This replaceProperty method is called only for the following three cases: *
< prev index next >