001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.commons.nabla.forward.analysis;
018    
019    import java.util.HashSet;
020    import java.util.Set;
021    
022    import org.objectweb.asm.Type;
023    import org.objectweb.asm.tree.AbstractInsnNode;
024    import org.objectweb.asm.tree.analysis.Value;
025    
026    /** A value that keep track of both instructions producing and consuming it.
027     * @version $Id$
028     */
029    public class TrackingValue implements Value {
030    
031        /** Special value for uninitialized values. */
032        public static final TrackingValue UNINITIALIZED_VALUE = new TrackingValue(null);
033    
034        /** Value type. */
035        private final Type type;
036    
037        /** Instructions that consume this value. */
038        private Set<AbstractInsnNode> consumers;
039    
040        /** Instructions that produce this value. */
041        private Set<AbstractInsnNode> producers;
042    
043        /** Values that are merged with this value (including the instance itself). */
044        private Set<TrackingValue> merged;
045    
046        /** Build a new value without any link to instructions.
047         * @param type value type
048         */
049        public TrackingValue(final Type type) {
050            this.type  = type;
051            consumers  = new HashSet<AbstractInsnNode>();
052            producers  = new HashSet<AbstractInsnNode>();
053            merged     = new HashSet<TrackingValue>();
054            merged.add(this);
055        }
056    
057        /** Build a new value produced by a specified instruction.
058         * @param type value type
059         * @param producer producer for this value
060         */
061        public TrackingValue(final Type type, final AbstractInsnNode producer) {
062            this(type);
063            producers.add(producer);
064        }
065    
066        /** Get the value type.
067         * @return value type
068         */
069        public Type getType() {
070            return type;
071        }
072    
073        /** {@inheritDoc} */
074        public int getSize() {
075            return type == Type.LONG_TYPE || type == Type.DOUBLE_TYPE ? 2 : 1;
076        }
077    
078        /** Add a consumer for this value.
079         * @param consumer consumer for this value
080         */
081        public void addConsumer(final AbstractInsnNode consumer) {
082            consumers.add(consumer);
083        }
084    
085        /** Get the consumers for this value and all values it is merged with.
086         * @return the instructions consuming either this value or the values
087         * it has been merged with
088         */
089        public Set<AbstractInsnNode> getConsumers() {
090            return consumers;
091        }
092    
093        /** Add a producer for this value.
094         * @param producer producer for this value
095         */
096        public void addProducer(final AbstractInsnNode producer) {
097            producers.add(producer);
098        }
099    
100        /** Get the producers for this value and all values it is merged with.
101         * @return the instructions producing either this value or the values
102         * it has been merged with
103         */
104        public Set<AbstractInsnNode> getProducers() {
105            return producers;
106        }
107    
108        /** Merge two instances.
109         * <p>Once merged, values share the same producers and consumers sets.</p>
110         * @param value1 first value to merge
111         * @param value2 second value to merge
112         */
113        public static void merge(final TrackingValue value1, final TrackingValue value2) {
114    
115            if (value1.merged.contains(value2)) {
116                // the values have already been merged
117                return;
118            }
119    
120            // merge the sets
121            value1.consumers.addAll(value2.consumers);
122            value1.producers.addAll(value2.producers);
123            value1.merged.addAll(value2.merged);
124    
125            // share the merged sets
126            for (final TrackingValue value : value2.merged) {
127                value.consumers = value1.consumers;
128                value.producers = value1.producers;
129                value.merged    = value1.merged;
130            }
131    
132        }
133    
134    }