< prev index next >

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

Print this page

        

@@ -38,13 +38,14 @@
 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.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,21 +94,18 @@
 
     /** 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;
+    /** SwitchPoints for properties inherited form this map */
+    private transient PropertySwitchPoints propertySwitchPoints;
 
     private transient BitSet freeSlots;
 
     private static final long serialVersionUID = -7041836752008732533L;
 

@@ -145,12 +143,12 @@
         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;
+        // 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,146 +241,70 @@
     public int size() {
         return properties.size();
     }
 
     /**
-     * Get the number of listeners of this map
+     * Get the number of property SwitchPoints of this map
      *
-     * @return the number of listeners
+     * @return the number of property SwitchPoints
      */
-    public int getListenerCount() {
-        return listeners == null ? 0 : listeners.getListenerCount();
+    public int getSwitchPointCount() {
+        return propertySwitchPoints == null ? 0 : propertySwitchPoints.getSwitchPointCount();
     }
 
     /**
-     * Add {@code listenerMap} as a listener to this property map for the given {@code key}.
+     * Add a property switchpoint to this property map for the given {@code key}.
      *
      * @param key the property name
-     * @param listenerMap the listener map
+     * @param switchPoint the switchpoint
      */
-    public void addListener(final String key, final PropertyMap listenerMap) {
-        if (listenerMap != this) {
+    public void addSwitchPoint(final String key, final SwitchPoint switchPoint) {
             // 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);
-        }
+        // the propertySwitchPoints instance with our parent maps that don't need to see the new listener.
+        propertySwitchPoints = PropertySwitchPoints.addSwitchPoint(propertySwitchPoints, key, switchPoint);
     }
 
     /**
-     * An existing property is being deleted.
+     * A property is about to change - invalidate all prototype switchpoints for the given property.
      *
-     * @param property The property being deleted.
-     * @param isSelf was the property deleted from this map?
+     * @param property The modified property.
      */
-    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);
+    public void invalidateProperty(final Property property) {
+        if (propertySwitchPoints != null) {
+            propertySwitchPoints.invalidateProperty(property);
         }
     }
 
     /**
      * 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) {
+    void protoChanged() {
+        if (sharedProtoMap != null) {
             sharedProtoMap.invalidateSwitchPoint();
         }
-        if (listeners != null) {
-            listeners.protoChanged();
+        if (propertySwitchPoints != null) {
+            propertySwitchPoints.invalidateAll();
         }
     }
 
     /**
-     * Return a SwitchPoint used to track changes of a property in a prototype.
+     * Return a SwitchPoint for tracking a property in this map, if one exists.
      *
      * @param key Property key.
-     * @return A shared {@link SwitchPoint} for the property.
+     * @return A {@link SwitchPoint} for the property, or null.
      */
     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);
-        }
-
+        if (propertySwitchPoints != null) {
+            final Set<SwitchPoint> existingSwitchPoints = propertySwitchPoints.getSwitchPoints(key);
+            for (final SwitchPoint switchPoint : existingSwitchPoints) {
+                if (switchPoint != null && !switchPoint.hasBeenInvalidated()) {
         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();
-            }
-        }
+        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,11 +372,11 @@
      *
      * @param property {@link Property} being added.
      * @return New {@link PropertyMap} with {@link Property} added.
      */
     public final PropertyMap addPropertyNoHistory(final Property property) {
-        propertyAdded(property, true);
+        invalidateProperty(property);
         return addPropertyInternal(property);
     }
 
     /**
      * Add a property to the map.  Cloning or using an existing map if available.

@@ -462,11 +384,11 @@
      * @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);
+        invalidateProperty(property);
         PropertyMap newMap = checkHistory(property);
 
         if (newMap == null) {
             newMap = addPropertyInternal(property);
             addToHistory(property, newMap);

@@ -492,11 +414,11 @@
      * @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);
+        invalidateProperty(property);
         PropertyMap newMap = checkHistory(property);
         final Object key = property.getKey();
 
         if (newMap == null && properties.containsKey(key)) {
             final PropertyHashMap newProperties = properties.immutableRemove(key);

@@ -527,11 +449,11 @@
      * @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);
+        invalidateProperty(oldProperty);
         /*
          * See ScriptObject.modifyProperty and ScriptObject.setUserAccessors methods.
          *
          * This replaceProperty method is called only for the following three cases:
          *
< prev index next >