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