All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.mat.hprof.HprofRandomAccessParser Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 * Copyright (c) 2008 SAP AG.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    SAP AG - initial API and implementation
 *******************************************************************************/
package org.eclipse.mat.hprof;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.eclipse.mat.SnapshotException;
import org.eclipse.mat.parser.io.BufferedRandomAccessInputStream;
import org.eclipse.mat.parser.io.PositionInputStream;
import org.eclipse.mat.parser.model.ClassImpl;
import org.eclipse.mat.parser.model.ClassLoaderImpl;
import org.eclipse.mat.parser.model.InstanceImpl;
import org.eclipse.mat.parser.model.ObjectArrayImpl;
import org.eclipse.mat.parser.model.PrimitiveArrayImpl;
import org.eclipse.mat.snapshot.ISnapshot;
import org.eclipse.mat.snapshot.model.Field;
import org.eclipse.mat.snapshot.model.FieldDescriptor;
import org.eclipse.mat.snapshot.model.IArray;
import org.eclipse.mat.snapshot.model.IClass;
import org.eclipse.mat.snapshot.model.IObject;
import org.eclipse.mat.snapshot.model.IPrimitiveArray;
import org.eclipse.mat.util.MessageUtil;

public class HprofRandomAccessParser extends AbstractParser {
    public static final int LAZY_LOADING_LIMIT = 256;

    public HprofRandomAccessParser(File file, Version version, int identifierSize) throws IOException {
        this.in = new PositionInputStream(new BufferedRandomAccessInputStream(new RandomAccessFile(file, "r"), 512)); //$NON-NLS-1$
        this.version = version;
        this.idSize = identifierSize;
    }

    public synchronized void close() throws IOException {
        in.close();
    }

    public synchronized IObject read(int objectId, long position, ISnapshot dump) throws IOException, SnapshotException {
        in.seek(position);
        int segmentType = in.readUnsignedByte();
        switch (segmentType) {
            case Constants.DumpSegment.INSTANCE_DUMP:
                return readInstanceDump(objectId, dump);
            case Constants.DumpSegment.OBJECT_ARRAY_DUMP:
                return readObjectArrayDump(objectId, dump);
            case Constants.DumpSegment.PRIMITIVE_ARRAY_DUMP:
                return readPrimitiveArrayDump(objectId, dump);
            default:
                throw new IOException(MessageUtil.format(Messages.HprofRandomAccessParser_Error_IllegalDumpSegment,
                        segmentType));
        }

    }

    public List resolveClassHierarchy(ISnapshot snapshot, IClass clazz) throws SnapshotException {
        List answer = new ArrayList();
        answer.add(clazz);
        while (clazz.hasSuperClass()) {
            clazz = (IClass) snapshot.getObject(clazz.getSuperClassId());
            if (clazz == null)
                return null;
            answer.add(clazz);
        }

        return answer;
    }

    private IObject readInstanceDump(int objectId, ISnapshot dump) throws IOException, SnapshotException {
        long address = readID();
        if (in.skipBytes(8 + idSize) != 8 + idSize)
            throw new IOException();

        // check if we need to defer reading the class
        List hierarchy = resolveClassHierarchy(dump, dump.getClassOf(objectId));
        if (hierarchy == null) {
            throw new IOException(Messages.HprofRandomAccessParser_Error_DumpIncomplete);
        } else {
            List instanceFields = new ArrayList();
            for (IClass clazz : hierarchy) {
                List fields = clazz.getFieldDescriptors();
                for (int ii = 0; ii < fields.size(); ii++) {
                    FieldDescriptor field = fields.get(ii);
                    int type = field.getType();
                    Object value = readValue(dump, type);
                    instanceFields.add(new Field(field.getName(), field.getType(), value));
                }
            }

            ClassImpl classImpl = (ClassImpl) hierarchy.get(0);

            if (dump.isClassLoader(objectId))
                return new ClassLoaderImpl(objectId, address, classImpl, instanceFields);
            else
                return new InstanceImpl(objectId, address, classImpl, instanceFields);
        }
    }

    private IArray readObjectArrayDump(int objectId, ISnapshot dump) throws IOException, SnapshotException {
        long id = readID();

        in.skipBytes(4);
        int size = in.readInt();

        long arrayClassObjectID = readID();

        IClass arrayType = (IClass) dump.getObject(dump.mapAddressToId(arrayClassObjectID));
        if (arrayType == null)
            throw new RuntimeException(Messages.HprofRandomAccessParser_Error_MissingFakeClass);

        Object content = null;
        if (size * idSize < LAZY_LOADING_LIMIT) {
            long[] data = new long[size];
            for (int ii = 0; ii < data.length; ii++)
                data[ii] = readID();
            content = data;
        } else {
            content = new ArrayDescription.Offline(false, in.position(), 0, size);
        }

        ObjectArrayImpl array = new ObjectArrayImpl(objectId, id, (ClassImpl) arrayType, size);
        array.setInfo(content);
        return array;
    }

    private IArray readPrimitiveArrayDump(int objectId, ISnapshot dump) throws IOException, SnapshotException {
        long id = readID();

        in.skipBytes(4);
        int arraySize = in.readInt();

        long elementType = in.readByte();
        if ((elementType < IPrimitiveArray.Type.BOOLEAN) || (elementType > IPrimitiveArray.Type.LONG))
            throw new IOException(Messages.Pass1Parser_Error_IllegalType);

        int elementSize = IPrimitiveArray.ELEMENT_SIZE[(int) elementType];
        int len = elementSize * arraySize;

        Object content = null;
        if (len < LAZY_LOADING_LIMIT) {
            byte[] data = new byte[len];
            in.readFully(data);
            content = elementType == IObject.Type.BYTE ? data : new ArrayDescription.Raw(data);
        } else {
            content = new ArrayDescription.Offline(true, in.position(), elementSize, arraySize);
        }

        // lookup class by name
        IClass clazz = null;
        String name = IPrimitiveArray.TYPE[(int) elementType];
        Collection classes = dump.getClassesByName(name, false);
        if (classes == null || classes.isEmpty())
            throw new IOException(MessageUtil.format(Messages.HprofRandomAccessParser_Error_MissingClass, name));
        else if (classes.size() > 1)
            throw new IOException(MessageUtil.format(Messages.HprofRandomAccessParser_Error_DuplicateClass, name));
        else
            clazz = classes.iterator().next();

        PrimitiveArrayImpl array = new PrimitiveArrayImpl(objectId, id, (ClassImpl) clazz, arraySize, (int) elementType);
        array.setInfo(content);

        return array;
    }

    public synchronized long[] readObjectArray(ArrayDescription.Offline descriptor, int offset, int length)
            throws IOException {
        int elementSize = this.idSize;

        in.seek(descriptor.getPosition() + (offset * elementSize));
        long[] data = new long[length];
        for (int ii = 0; ii < data.length; ii++)
            data[ii] = readID();
        return data;
    }

    public synchronized byte[] readPrimitiveArray(ArrayDescription.Offline descriptor, int offset, int length)
            throws IOException {
        int elementSize = descriptor.getElementSize();

        in.seek(descriptor.getPosition() + (offset * elementSize));

        byte[] data = new byte[length * elementSize];
        in.readFully(data);
        return data;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy