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

com.facebook.presto.jdbc.internal.jol.info.ClassLayout Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package com.facebook.presto.jdbc.internal.jol.info;

import com.facebook.presto.jdbc.internal.jol.layouters.CurrentLayouter;
import com.facebook.presto.jdbc.internal.jol.layouters.Layouter;
import com.facebook.presto.jdbc.internal.jol.util.VMSupport;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.SortedSet;

/**
 * Handles the class data *with* the layout information.
 */
public class ClassLayout {

    /**
     * Produce the class layout for the given class.
     * This produces the layout for the current VM.
     *
     * @param klass class to work on
     * @return class layout
     */
    public static ClassLayout parseClass(Class klass) {
        return parseClass(klass, new CurrentLayouter());
    }

    /**
     * Produce the class layout for the given class, and given layouter.
     *
     * @param klass    class to work on
     * @param layouter class layouter
     * @return class layout
     */
    public static ClassLayout parseClass(Class klass, Layouter layouter) {
        return layouter.layout(ClassData.parseClass(klass));
    }

    private final ClassData classData;
    private final SortedSet fields;
    private final int headerSize;
    private final int size;

    /**
     * Builds the class layout.
     *
     * @param classData    class data
     * @param fields       field layouts
     * @param headerSize   header size
     * @param instanceSize instance size
     * @param check        whether to check important invariants
     */
    public ClassLayout(ClassData classData, SortedSet fields, int headerSize, int instanceSize, boolean check) {
        this.classData = classData;
        this.fields = fields;
        this.headerSize = headerSize;
        this.size = instanceSize;
        if (check) {
            checkInvariants();
        }
    }

    private void checkInvariants() {
        long lastOffset = 0;
        for (FieldLayout f : fields) {
            if (f.offset() % f.size() != 0) {
                throw new IllegalStateException("Field " + f + " is not aligned");
            }
            if (f.offset() + f.size() > instanceSize()) {
                throw new IllegalStateException("Field " + f + " is overflowing the object of size " + instanceSize());
            }
            if (f.offset() < lastOffset) {
                throw new IllegalStateException("Field " + f + " overlaps with the previous field");
            }
            lastOffset = f.offset() + f.size();
        }
    }

    /**
     * Answer the set of fields, including those in superclasses
     *
     * @return sorted set of fields
     */
    public SortedSet fields() {
        return fields;
    }

    /**
     * Answer instance size
     *
     * @return instance size
     */
    public int instanceSize() {
        return size;
    }

    /**
     * Answer header size
     *
     * @return header size
     */
    public int headerSize() {
        return headerSize;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        for (FieldLayout f : fields()) {
            sb.append(f).append("\n");
        }
        sb.append("size = ").append(size).append("\n");
        return sb.toString();
    }

    /**
     * Produce printable stringly representation of class layout.
     * This method does not require alive instance, just the class.
     *
     * @return human-readable layout info
     */
    public String toPrintable() {
        return toPrintable(null);
    }

    /**
     * Produce printable stringly representation of class layout.
     * This method accepts instance to read the actual data from.
     *
     * @param instance instance to work on
     * @return human-readable layout info
     */
    public String toPrintable(Object instance) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);

        int maxTypeLen = 5;
        for (FieldLayout f : fields()) {
            maxTypeLen = Math.max(f.typeClass().length(), maxTypeLen);
        }

        int maxDescrLen = 30;
        for (FieldLayout f : fields()) {
            maxDescrLen = Math.max((f.hostClass() + "" + f.name()).length(), maxDescrLen);
        }

        pw.println(classData.name() + " object internals:");
        pw.printf(" %6s %5s %" + maxTypeLen + "s %-" + maxDescrLen + "s %s%n", "OFFSET", "SIZE", "TYPE", "DESCRIPTION", "VALUE");
        if (instance != null) {
            for (long off = 0; off < headerSize(); off += 4) {
                pw.printf(" %6d %5d %" + maxTypeLen + "s %-" + maxDescrLen + "s %s%n", off, 4, "", "(object header)",
                        toHex(VMSupport.U.getByte(instance, off + 0) & 0xFF) + " " +
                                toHex(VMSupport.U.getByte(instance, off + 1) & 0xFF) + " " +
                                toHex(VMSupport.U.getByte(instance, off + 2) & 0xFF) + " " +
                                toHex(VMSupport.U.getByte(instance, off + 3) & 0xFF) + " " +
                                "(" +
                                toBinary(VMSupport.U.getByte(instance, off + 0) & 0xFF) + " " +
                                toBinary(VMSupport.U.getByte(instance, off + 1) & 0xFF) + " " +
                                toBinary(VMSupport.U.getByte(instance, off + 2) & 0xFF) + " " +
                                toBinary(VMSupport.U.getByte(instance, off + 3) & 0xFF) + ")"
                );
            }
        } else {
            pw.printf(" %6d %5d %" + maxTypeLen + "s %-" + maxDescrLen + "s %s%n", 0, headerSize(), "", "(object header)", "N/A");
        }

        int nextFree = headerSize();

        int interLoss = 0;
        int exterLoss = 0;

        for (FieldLayout f : fields()) {
            if (f.offset() > nextFree) {
                pw.printf(" %6d %5d %" + maxTypeLen + "s %-" + maxDescrLen + "s %s%n", nextFree, (f.offset() - nextFree), "", "(alignment/padding gap)", "N/A");
                interLoss += (f.offset() - nextFree);
            }
            pw.printf(" %6d %5d %" + maxTypeLen + "s %-" + maxDescrLen + "s %s%n",
                    f.offset(),
                    f.size(),
                    f.typeClass(),
                    f.hostClass() + "." + f.name(),
                    (instance != null) ? f.safeValue(instance) : "N/A"
            );

            nextFree = f.offset() + f.size();
        }

        VMSupport.SizeInfo info = VMSupport.tryExactObjectSize(instance, this);

        if (info.instanceSize() != nextFree) {
            exterLoss = info.instanceSize() - nextFree;
            pw.printf(" %6d %5s %" + maxTypeLen + "s %s%n", nextFree, exterLoss, "", "(loss due to the next object alignment)");
        }

        if (info.exactSize()) {
            pw.printf("Instance size: %d bytes (reported by VM agent)%n", info.instanceSize());
        } else {
            if (instance != null) {
                pw.printf("Instance size: %d bytes (estimated, add this JAR via -javaagent: to get accurate result)%n", info.instanceSize());
            } else {
                pw.printf("Instance size: %d bytes (estimated, the sample instance is not available)%n", info.instanceSize());
            }
        }

        pw.printf("Space losses: %d bytes internal + %d bytes external = %d bytes total%n", interLoss, exterLoss, interLoss + exterLoss);

        pw.close();

        return sw.toString();
    }

    // very ineffective, so what?
    private static String toBinary(int x) {
        String s = Integer.toBinaryString(x);
        int deficit = 8 - s.length();
        for (int c = 0; c < deficit; c++) {
            s = "0" + s;
        }

        return s.substring(0, 4) + " " + s.substring(4);
    }

    // very ineffective, so what?
    private static String toHex(int x) {
        String s = Integer.toHexString(x);
        int deficit = 2 - s.length();
        for (int c = 0; c < deficit; c++) {
            s = "0" + s;
        }
        return s;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy