001/*
002 * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.debug.internal;
024
025import java.util.*;
026
027/**
028 * A node in a tree of {@link DebugValue}s.
029 */
030public class DebugValueMap {
031
032    private static final List<DebugValueMap> topLevelMaps = new ArrayList<>();
033
034    private long[] values;
035    private List<DebugValueMap> children;
036    private String name;
037
038    public DebugValueMap(String name) {
039        this.name = name;
040    }
041
042    public void setCurrentValue(int index, long l) {
043        ensureSize(index);
044        values[index] = l;
045    }
046
047    public long getCurrentValue(int index) {
048        ensureSize(index);
049        return values[index];
050    }
051
052    public void clearChildren() {
053        if (children != null) {
054            children.clear();
055        }
056    }
057
058    public void reset() {
059        if (values != null) {
060            Arrays.fill(values, 0L);
061        }
062        if (children != null) {
063            for (DebugValueMap child : children) {
064                child.reset();
065            }
066        }
067    }
068
069    private void ensureSize(int index) {
070        if (values == null) {
071            values = new long[index + 1];
072        }
073        if (values.length <= index) {
074            values = Arrays.copyOf(values, index + 1);
075        }
076    }
077
078    private int capacity() {
079        return (values == null) ? 0 : values.length;
080    }
081
082    public void addChild(DebugValueMap map) {
083        if (children == null) {
084            children = new ArrayList<>(4);
085        }
086        children.add(map);
087    }
088
089    public List<DebugValueMap> getChildren() {
090        if (children == null) {
091            return Collections.emptyList();
092        } else {
093            return Collections.unmodifiableList(children);
094        }
095    }
096
097    public boolean hasChildren() {
098        return children != null && !children.isEmpty();
099    }
100
101    public String getName() {
102        return this.name;
103    }
104
105    @Override
106    public String toString() {
107        return "DebugValueMap<" + getName() + ">";
108    }
109
110    public static synchronized void registerTopLevel(DebugValueMap map) {
111        topLevelMaps.add(map);
112    }
113
114    public static synchronized List<DebugValueMap> getTopLevelMaps() {
115        return topLevelMaps;
116    }
117
118    public void normalize() {
119        if (hasChildren()) {
120            Map<String, DebugValueMap> occurred = new HashMap<>();
121            for (DebugValueMap map : children) {
122                String mapName = map.getName();
123                if (!occurred.containsKey(mapName)) {
124                    occurred.put(mapName, map);
125                    map.normalize();
126                } else {
127                    occurred.get(mapName).mergeWith(map);
128                    occurred.get(mapName).normalize();
129                }
130            }
131
132            if (occurred.values().size() < children.size()) {
133                // At least one duplicate was found.
134                children.clear();
135                for (DebugValueMap map : occurred.values()) {
136                    addChild(map);
137                    map.normalize();
138                }
139            }
140        }
141    }
142
143    private void mergeWith(DebugValueMap map) {
144        if (map.hasChildren()) {
145            if (hasChildren()) {
146                children.addAll(map.children);
147            } else {
148                children = map.children;
149            }
150            map.children = null;
151        }
152
153        int size = Math.max(this.capacity(), map.capacity());
154        ensureSize(size);
155        for (int i = 0; i < size; ++i) {
156            long curValue = getCurrentValue(i);
157            long otherValue = map.getCurrentValue(i);
158            setCurrentValue(i, curValue + otherValue);
159        }
160    }
161
162    public void group() {
163        if (this.hasChildren()) {
164            List<DebugValueMap> oldChildren = new ArrayList<>(this.children);
165            this.children.clear();
166            for (DebugValueMap map : oldChildren) {
167                mergeWith(map);
168            }
169        }
170    }
171}