001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.insane.model;
043:
044: import java.io.*;
045: import java.nio.ByteBuffer;
046: import java.nio.channels.FileChannel;
047: import java.util.*;
048:
049: // TODO: provide lazy iterators
050:
051: /**
052: * A HeapModel based on the Insane binary heap dump.
053: *
054: * @author Nenik
055: */
056: class BinaryHeapModel implements HeapModel {
057:
058: public static HeapModel open(File file) throws Exception {
059: HeapModel model = new BinaryHeapModel(file);
060: return model;
061: }
062:
063: private Map<Integer, Item> createdObjects = new HashMap<Integer, Item>();
064: private Map<Integer, Cls> createdClasses = new HashMap<Integer, Cls>();
065:
066: ByteBuffer buffer;
067: int refsOffset;
068: int objsOffset;
069:
070: BinaryHeapModel(File data) throws Exception {
071: // mmap it
072: long len = data.length();
073: buffer = new FileInputStream(data).getChannel().map(
074: FileChannel.MapMode.READ_ONLY, 0, len);
075: System.err.println("magic=" + buffer.getInt(0));
076:
077: // prepare pointers
078: refsOffset = buffer.getInt(4);
079: objsOffset = buffer.getInt(8);
080: System.err.println("refs=" + refsOffset);
081: System.err.println("objs=" + objsOffset);
082:
083: // prescan classes?
084: }
085:
086: public Iterator<Item> getAllItems() {
087: ArrayList<Item> all = new ArrayList<Item>();
088:
089: int actOffset = objsOffset;
090: while (actOffset < buffer.limit()) {
091: HItem act = (HItem) getItem(actOffset);
092: all.add(act);
093: actOffset = act.getNextOffset();
094: }
095: return all.iterator();
096: }
097:
098: public Collection<Item> getObjectsOfType(String type) {
099: Cls cls = getClsByName(type);
100: return cls == null ? Collections.<Item> emptyList() : cls
101: .getInstances();
102: }
103:
104: public Collection<String> getRoots() {
105: ArrayList<String> all = new ArrayList<String>();
106:
107: int actOffset = refsOffset;
108: while (actOffset < objsOffset) {
109: RefType act = new RefType(actOffset);
110: if (act.isStatic())
111: all.add(act.getReferenceName());
112: actOffset = act.getNextOffset();
113: }
114: return all;
115: }
116:
117: public Item getObjectAt(String staticRefName) {
118: RefType type = getRefTypeByName(staticRefName);
119: return type.getInstance();
120: }
121:
122: public Item getItem(int id) {
123: Integer key = Integer.valueOf(id);
124: Item ret = createdObjects.get(key);
125: if (ret == null) {
126: ret = new HItem(id);
127: createdObjects.put(key, ret);
128: }
129: return ret;
130: }
131:
132: private Cls getClsByName(String name) {
133: int actOffset = 12;
134: while (actOffset < refsOffset) {
135: Cls act = getCls(actOffset);
136: if (name.equals(act.getClassName()))
137: return act;
138: actOffset = act.getNextOffset();
139: }
140: return null;
141: }
142:
143: private Cls getCls(int offset) {
144: Integer key = Integer.valueOf(offset);
145: Cls ret = createdClasses.get(key);
146: if (ret == null) {
147: ret = new Cls(offset);
148: createdClasses.put(key, ret);
149: }
150: return ret;
151: }
152:
153: private class Cls {
154: int offset;
155:
156: private Cls(int offset) {
157: this .offset = offset;
158: }
159:
160: public String getClassName() {
161: ByteBuffer local = (ByteBuffer) buffer.duplicate()
162: .position(offset);
163: int len = local.getInt();
164: byte[] data = new byte[len];
165: local.get(data);
166: return new String(data);
167: }
168:
169: public Collection<Item> getInstances() {
170: ByteBuffer local = (ByteBuffer) buffer.duplicate()
171: .position(offset);
172: local.position(local.getInt() + local.position());
173: int count = local.getInt();
174:
175: ArrayList<Item> list = new ArrayList<Item>(count);
176: while (--count >= 0)
177: list.add(getItem(local.getInt()));
178: return list;
179: }
180:
181: private int getNextOffset() {
182: ByteBuffer local = ((ByteBuffer) buffer.duplicate()
183: .position(offset)).slice();
184: int strLen = local.getInt();
185:
186: return offset + 4 + strLen + 4 + 4
187: * local.getInt(4 + strLen);
188: }
189: }
190:
191: private RefType getRefTypeByName(String name) {
192: int actOffset = refsOffset;
193: while (actOffset < objsOffset) {
194: RefType act = new RefType(actOffset);
195: if (name.equals(act.getReferenceName()))
196: return act;
197: actOffset = act.getNextOffset();
198: }
199: return null;
200: }
201:
202: private class RefType {
203: int offset;
204:
205: private RefType(int offset) {
206: this .offset = offset;
207: }
208:
209: // REF_TYPE:
210: // STR referenceName
211: // INT staticOffset (0 for null static ref, -1 for nonstatic ref)
212: public String getReferenceName() {
213: ByteBuffer local = (ByteBuffer) buffer.duplicate()
214: .position(offset);
215: int len = local.getInt();
216: byte[] data = new byte[len];
217: local.get(data);
218: return new String(data);
219: }
220:
221: public boolean isStatic() {
222: ByteBuffer local = (ByteBuffer) buffer.duplicate()
223: .position(offset);
224: local.position(local.getInt() + local.position());
225: int instOffset = local.getInt();
226: return (instOffset != -1);
227: }
228:
229: public Item getInstance() {
230: ByteBuffer local = (ByteBuffer) buffer.duplicate()
231: .position(offset);
232: local.position(local.getInt() + local.position());
233: int instOffset = local.getInt();
234: if (instOffset > 0)
235: return getItem(instOffset);
236: return null;
237: }
238:
239: private int getNextOffset() {
240: ByteBuffer local = ((ByteBuffer) buffer.duplicate()
241: .position(offset));
242: int strLen = local.getInt();
243: return offset + 4 + strLen + 4;
244: }
245: }
246:
247: public class HItem implements Item {
248: int offset;
249:
250: private HItem(int offset) {
251: this .offset = offset;
252: }
253:
254: private ByteBuffer prepareBuffer() {
255: return ((ByteBuffer) buffer.duplicate().position(offset))
256: .slice();
257: }
258:
259: public String getType() {
260: return getCls(prepareBuffer().getInt()).getClassName();
261: }
262:
263: public int getSize() {
264: return prepareBuffer().getInt(4);
265: }
266:
267: public String getValue() {
268: return "unknown"; // TODO: Add [C content to the file
269: }
270:
271: public Enumeration<Object> incomming() {
272: ByteBuffer buff = prepareBuffer();
273: buff.position(8);
274: int out = buff.getInt();
275: int inc = buff.getInt();
276:
277: buff.position(16 + 8 * out);
278: Vector<Object> v = new Vector<Object>(inc);
279:
280: while (--inc >= 0) {
281: int refOffset = buff.getInt();
282: int objOffset = buff.getInt();
283:
284: if (objOffset != 0) { // normal ref
285: v.add(getItem(objOffset));
286: } else { // static ref
287: v.add(new RefType(refOffset).getReferenceName());
288: }
289: }
290:
291: return v.elements(); // XXX - eager
292: }
293:
294: public Enumeration<Item> outgoing() {
295: ByteBuffer buff = prepareBuffer();
296: int out = buff.getInt(8);
297: buff.position(16);
298:
299: Vector<Item> v = new Vector<Item>(out);
300:
301: while (--out >= 0) {
302: int refOffset = buff.getInt();
303: int objOffset = buff.getInt();
304:
305: v.add(getItem(objOffset));
306: }
307:
308: return v.elements(); // XXX - eager
309: }
310:
311: public String toString() {
312: return getType() + "@" + Integer.toHexString(getId());
313: }
314:
315: public int getId() {
316: return offset; // XXX - different ID
317: }
318:
319: private int getNextOffset() {
320: ByteBuffer buff = prepareBuffer();
321:
322: return offset + 16 + 8 * buff.getInt(8) + 8
323: * buff.getInt(12);
324: }
325: }
326: }
|