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