You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@xerces.apache.org by le...@locus.apache.org on 2000/08/30 02:22:32 UTC

cvs commit: xml-xerces/java/src/org/apache/xerces/dom DocumentImpl.java NodeImpl.java

lehors      00/08/29 17:22:30

  Modified:    java/src/org/apache/xerces/dom DocumentImpl.java
                        NodeImpl.java
  Log:
  Moved storage of event listeners from NodeImpl to DocumentImpl.
  They are now stored in a hashtable where the node they are registered on is
  the key. That way we save one pointer on *every* node.
  Tests show a gain of 3 to 5% in memory and around 12% in performance!
  Of course this is in the case where there isn't any listener. In case the
  mutation events mechanism is actually used this is going to be slower,
  since event listeners need to be looked for in the hashtable on the document.
  But the code was broken for months without anybody noticing, so only a few
  if any will see a difference. While everybody will gain from the
  improvement in memory and speed.
  One more drawback is that, just like with userData, a node with listeners
  won't be GC'ed until the document is. Weak references would solve that.
  
  Revision  Changes    Path
  1.40      +41 -1     xml-xerces/java/src/org/apache/xerces/dom/DocumentImpl.java
  
  Index: DocumentImpl.java
  ===================================================================
  RCS file: /home/cvs/xml-xerces/java/src/org/apache/xerces/dom/DocumentImpl.java,v
  retrieving revision 1.39
  retrieving revision 1.40
  diff -u -r1.39 -r1.40
  --- DocumentImpl.java	2000/08/18 01:58:34	1.39
  +++ DocumentImpl.java	2000/08/30 00:22:28	1.40
  @@ -131,9 +131,12 @@
       /** Table for quick check of child insertion. */
       protected static int[] kidOK;
   
  -    /** Table for quick check of child insertion. */
  +    /** Table for user data attached to this document nodes. */
       protected Hashtable userData;
   
  +    /** Table for event listeners registered to this document nodes. */
  +    protected Hashtable eventListeners;
  +
       /**
        * Number of alterations made to this document since its creation.
        * Serves as a "dirty bit" so that live objects such as NodeList can
  @@ -302,6 +305,7 @@
           newdoc.iterators = null;
           newdoc.ranges = null;
           newdoc.userData = null;
  +        newdoc.eventListeners = null;
   
           // experimental
           newdoc.allowGrammarAccess = allowGrammarAccess;
  @@ -1521,6 +1525,9 @@
   
       /**
        * Store user data related to a given node
  +     * This is a place where we could use weak references! Indeed, the node
  +     * here won't be GC'ed as long as some user data is attached to it, since
  +     * the userData table will have a reference to the node.
        */
       protected void setUserData(NodeImpl n, Object data) {
           if (userData == null) {
  @@ -1541,6 +1548,39 @@
               return null;
           }
           return userData.get(n);
  +    }
  +
  +    /**
  +     * Store event listener registered on a given node
  +     * This is another place where we could use weak references! Indeed, the
  +     * node here won't be GC'ed as long as some listener is registered on it,
  +     * since the eventsListeners table will have a reference to the node.
  +     */
  +    protected void setEventListeners(NodeImpl n, Vector listeners) {
  +        if (eventListeners == null) {
  +            eventListeners = new Hashtable();
  +        }
  +        if (listeners == null) {
  +            eventListeners.remove(n);
  +            if (eventListeners.isEmpty()) {
  +                // stop firing events when there isn't any listener
  +                mutationEvents = false;
  +            }
  +        } else {
  +            eventListeners.put(n, listeners);
  +            // turn mutation events on
  +            mutationEvents = true;
  +        }
  +    }
  +
  +    /**
  +     * Retreive event listener registered on a given node
  +     */
  +    protected Vector getEventListeners(NodeImpl n) {
  +        if (eventListeners == null) {
  +            return null;
  +        }
  +        return (Vector) eventListeners.get(n);
       }
   
       //
  
  
  
  1.32      +34 -22    xml-xerces/java/src/org/apache/xerces/dom/NodeImpl.java
  
  Index: NodeImpl.java
  ===================================================================
  RCS file: /home/cvs/xml-xerces/java/src/org/apache/xerces/dom/NodeImpl.java,v
  retrieving revision 1.31
  retrieving revision 1.32
  diff -u -r1.31 -r1.32
  --- NodeImpl.java	2000/08/29 22:29:34	1.31
  +++ NodeImpl.java	2000/08/30 00:22:28	1.32
  @@ -678,10 +678,6 @@
   	protected final static int MUTATION_LOCAL=0x01;
   	protected final static int MUTATION_AGGREGATE=0x02;
   	protected final static int MUTATION_ALL=0xffff;
  -	/** NON-DOM INTERNAL: EventListeners currently registered at
  -	 * THIS NODE; preferably null if none.
  -	 */
  -    Vector nodeListeners=null;
   	
   	/* NON-DOM INTERNAL: Class LEntry is just a struct used to represent
   	 * event listeners registered with this node. Copies of this object
  @@ -730,7 +726,11 @@
   	    // Simplest way to code that is to zap the previous entry, if any.
   	    removeEventListener(type,listener,useCapture);
   	    
  -	    if(nodeListeners==null) nodeListeners=new Vector();
  +            Vector nodeListeners = ownerDocument().getEventListeners(this);
  +	    if(nodeListeners==null) {
  +                nodeListeners=new Vector();
  +                ownerDocument().setEventListeners(this, nodeListeners);
  +            }
   	    nodeListeners.addElement(new LEntry(type,listener,useCapture));
   	    
   	    // Record active listener
  @@ -740,9 +740,6 @@
   	    else
   	        ++lc.bubbles;
   
  -            // turn mutation events on
  -            ownerDocument().mutationEvents = true;
  -
   	} // addEventListener(String,EventListener,boolean) :void
   	
   	/** Introduced in DOM Level 2. <p>
  @@ -758,6 +755,7 @@
   	public void removeEventListener(String type,EventListener listener,boolean useCapture)
   	{
   	    // If this couldn't be a valid listener registration, ignore request
  +            Vector nodeListeners = ownerDocument().getEventListeners(this);
     	    if(nodeListeners==null || type==null || type.equals("") || listener==null)
   	        return;
   
  @@ -771,21 +769,29 @@
               {
                   nodeListeners.removeElementAt(i);
                   // Storage management: Discard empty listener lists
  -                if(nodeListeners.size()==0) nodeListeners=null;
  +                if(nodeListeners.size()==0)
  +                    ownerDocument().setEventListeners(this, null);
   
  -	            // Remove active listener
  -	            LCount lc=LCount.lookup(type);
  -        	    if(useCapture)
  -	                --lc.captures;
  -        	    else
  -	                --lc.bubbles;
  -	                
  +                // Remove active listener
  +                LCount lc=LCount.lookup(type);
  +                if(useCapture)
  +                    --lc.captures;
  +                else
  +                    --lc.bubbles;
  +
                   break;  // Found it; no need to loop farther.
               }
           }
   	} // removeEventListener(String,EventListener,boolean) :void
   	
  -	/** NON-DOM INTERNAL:
  +	/** COMMENTED OUT **
  +            Now that event listeners are stored on the document with the node
  +            as the key, nodes can't be finalized if they have any event
  +            listener. This finalize method becomes useless... This is a place
  +            where we could definitely use weak references!! If we did, then
  +            this finalize method could be put back in (which is why I don't
  +            remove if completely). - ALH
  +         ** NON-DOM INTERNAL:
   	    A finalizer has added to NodeImpl in order to correct the event-usage
   	    counts of any remaining listeners before discarding the Node.
   	    This isn't absolutely required, and finalizers are of dubious
  @@ -793,7 +799,7 @@
   	    But given the expense of event generation and distribution it 
   	    seems a worthwhile safety net.
   	    ***** RECONSIDER at some future point.
  -	   */
  +
   	protected void finalize() throws Throwable
   	{
   	    super.finalize();
  @@ -808,6 +814,7 @@
   	                --lc.bubbles;
   	        }
   	}	
  +	   */
   
       /**
        * Introduced in DOM Level 2. <p>
  @@ -917,9 +924,10 @@
                   // Handle all capturing listeners on this node
                   NodeImpl nn=(NodeImpl)pv.elementAt(j);
                   evt.currentNode=nn;
  -                if(nn.nodeListeners!=null)
  +                Vector nodeListeners = ownerDocument().getEventListeners(nn);
  +                if(nodeListeners!=null)
                   {
  -                    Vector nl=(Vector)(nn.nodeListeners.clone());
  +                    Vector nl=(Vector)(nodeListeners.clone());
                       for(int i=nl.size()-1;i>=0;--i) // count-down more efficient
                       {
   	                    LEntry le=(LEntry)(nl.elementAt(i));
  @@ -945,6 +953,7 @@
               //are _not_ invoked, even during the capture phase.
               evt.eventPhase=Event.AT_TARGET;
               evt.currentNode=this;
  +            Vector nodeListeners = ownerDocument().getEventListeners(this);
               if(!evt.stopPropagation && nodeListeners!=null)
               {
                   Vector nl=(Vector)nodeListeners.clone();
  @@ -978,9 +987,10 @@
                       // Handle all bubbling listeners on this node
                       NodeImpl nn=(NodeImpl)pv.elementAt(j);
                       evt.currentNode=nn;
  -                    if(nn.nodeListeners!=null)
  +                    nodeListeners = ownerDocument().getEventListeners(nn);
  +                    if(nodeListeners!=null)
                       {
  -                        Vector nl=(Vector)(nn.nodeListeners.clone());
  +                        Vector nl=(Vector)(nodeListeners.clone());
                           for(int i=nl.size()-1;i>=0;--i) // count-down more efficient
       	                {
   	                        LEntry le=(LEntry)(nl.elementAt(i));
  @@ -1030,6 +1040,7 @@
       {
         if(MUTATIONEVENTS && ownerDocument().mutationEvents)
         {
  +          Vector nodeListeners = ownerDocument().getEventListeners(this);
   	    if(nodeListeners==null || n==null)
               return;
   
  @@ -1130,6 +1141,7 @@
   	{
         if(MUTATIONEVENTS && ownerDocument().mutationEvents)
         {
  +          Vector nodeListeners = ownerDocument().getEventListeners(this);
   	    if(nodeListeners==null)
               return;