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 }