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

com.sun.tools.jmake.BinaryProjectDatabaseWriter Maven / Gradle / Ivy

Go to download

This is the pantsbuild fork of jmake, which has a few bug-fixes that are unlikely to be accepted upstream.

There is a newer version: 1.3.8-10
Show newest version
/* Copyright (c) 2002-2008 Sun Microsystems, Inc. All rights reserved
 *
 * This program is distributed under the terms of
 * the GNU General Public License Version 2. See the LICENSE file
 * at the top of the source tree.
 */
package com.sun.tools.jmake;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Map;

/**
 * This class implements writing into a byte array representing a project database
 *
 * @author  Misha Dmitriev
 * @date 2 March 2005
 */
public class BinaryProjectDatabaseWriter extends BinaryFileWriter {

    private Map pcd = null;
    private int nOfEntries;
    private byte[] stringBuf;
    private int curStringBufPos,  stringBufInc,  curStringBufWatermark,  stringCount;
    private StringHashTable stringHashTable = null;

    public void writeProjectDatabaseToFile(File outfile, Map pcd) {
        try {
            byte[] buf = new BinaryProjectDatabaseWriter().writeProjectDatabase(pcd);
            FileOutputStream out = new FileOutputStream(outfile);
            out.write(buf);
            out.close();
        } catch (IOException e) {
            throw new PrivateException(e);
        }
    }

    public byte[] writeProjectDatabase(Map pcd) {
        this.pcd = pcd;
        nOfEntries = pcd.size();

        // So far the constant here is chosen rather arbitrarily
        initBuf(nOfEntries * 1000);

        stringBuf = new byte[nOfEntries * 300];
        stringBufInc = stringBuf.length / 5;
        curStringBufWatermark = stringBuf.length - 20;
        stringHashTable = new StringHashTable(stringBuf.length / 8);

        for (PCDEntry entry : pcd.values()) {
            writePCDEntry(entry);
        }

        // Now we have the string buffer and the main buffer. Write the end result
        byte[] mainBuf = buf;
        int mainBufSize = curBufPos;
        int preambleSize = Utils.MAGIC.length + 8;
        int stringBufSize = curStringBufPos;
        int pdbSize = stringBufSize + mainBufSize + 8;  // 8 is for nOfEntries and string table size
        initBuf(preambleSize + pdbSize);
        setBufferIncreaseMode(false);

        writePreamble(pdbSize);
        writeStringTable(stringBufSize);
        System.arraycopy(mainBuf, 0, buf, curBufPos, mainBufSize);
        return buf;
    }

    private void writePreamble(int pdbSize) {
        System.arraycopy(Utils.MAGIC, 0, buf, 0, Utils.MAGIC.length);
        curBufPos += Utils.MAGIC.length;

        writeInt(Utils.PDB_FORMAT_CODE_LATEST); // Version number
        writeInt(pdbSize);
        writeInt(pcd.size());
    }

    private void writeStringTable(int stringBufSize) {
        writeInt(stringCount);
        System.arraycopy(stringBuf, 0, buf, curBufPos, stringBufSize);
        curBufPos += stringBufSize;
    }

    private void writePCDEntry(PCDEntry entry) {
        writeStringRef(entry.className);
        writeStringRef(entry.javaFileFullPath);
        writeLong(entry.oldClassFileLastModified);
        writeLong(entry.oldClassFileFingerprint);
        writeClassInfo(entry.oldClassInfo);
    }

    private void writeClassInfo(ClassInfo ci) {
        int i, j, len;

        writeStringRef(ci.name);
        writeInt(ci.javacTargetRelease);

        len = ci.cpoolRefsToClasses != null ? ci.cpoolRefsToClasses.length : 0;
        writeChar(len);
        if (len > 0) {
            String cpoolRefsToClasses[] = ci.cpoolRefsToClasses;
            for (i = 0; i < len; i++) {
                writeStringRef(cpoolRefsToClasses[i]);
            }
            boolean isRefClassArray[] = ci.isRefClassArray;
            for (i = 0; i < len; i++) {
                byte b = isRefClassArray[i] ? (byte) 1 : (byte) 0;
                writeByte(b);
            }
        }

        len = ci.cpoolRefsToFieldClasses != null ? ci.cpoolRefsToFieldClasses.length
                : 0;
        writeChar(len);
        if (len > 0) {
            String cpoolRefsToFieldClasses[] = ci.cpoolRefsToFieldClasses;
            for (i = 0; i < len; i++) {
                writeStringRef(cpoolRefsToFieldClasses[i]);
            }
            String cpoolRefsToFieldNames[] = ci.cpoolRefsToFieldNames;
            for (i = 0; i < len; i++) {
                writeStringRef(cpoolRefsToFieldNames[i]);
            }
            String cpoolRefsToFieldSignatures[] = ci.cpoolRefsToFieldSignatures;
            for (i = 0; i < len; i++) {
                writeStringRef(cpoolRefsToFieldSignatures[i]);
            }
        }

        len = ci.cpoolRefsToMethodClasses != null ? ci.cpoolRefsToMethodClasses.length
                : 0;
        writeChar(len);
        if (len > 0) {
            String cpoolRefsToMethodClasses[] = ci.cpoolRefsToMethodClasses;
            for (i = 0; i < len; i++) {
                writeStringRef(cpoolRefsToMethodClasses[i]);
            }
            String cpoolRefsToMethodNames[] = ci.cpoolRefsToMethodNames;
            for (i = 0; i < len; i++) {
                writeStringRef(cpoolRefsToMethodNames[i]);
            }
            String cpoolRefsToMethodSignatures[] =
                    ci.cpoolRefsToMethodSignatures;
            for (i = 0; i < len; i++) {
                writeStringRef(cpoolRefsToMethodSignatures[i]);
            }
        }

        writeChar(ci.accessFlags);
        byte b = ci.isNonMemberNestedClass ? (byte) 1 : (byte) 0;
        writeByte(b);
        if (!"java/lang/Object".equals(ci.name)) {
            writeStringRef(ci.superName);
        }

        len = ci.interfaces != null ? ci.interfaces.length : 0;
        writeChar(len);
        if (len > 0) {
            String interfaces[] = ci.interfaces;
            for (i = 0; i < len; i++) {
                writeStringRef(interfaces[i]);
            }
        }

        len = ci.fieldNames != null ? ci.fieldNames.length : 0;
        writeChar(len);
        if (len > 0) {
            String fieldNames[] = ci.fieldNames;
            for (i = 0; i < len; i++) {
                writeStringRef(fieldNames[i]);
            }
            String fieldSignatures[] = ci.fieldSignatures;
            for (i = 0; i < len; i++) {
                writeStringRef(fieldSignatures[i]);
            }
            char fieldAccessFlags[] = ci.fieldAccessFlags;
            for (i = 0; i < len; i++) {
                writeChar(fieldAccessFlags[i]);
            }
        }

        len = ci.primitiveConstantInitValues != null ? ci.primitiveConstantInitValues.length
                : 0;
        writeChar(len);
        if (len > 0) {
            Object primitiveConstantInitValues[] =
                    ci.primitiveConstantInitValues;
            for (i = 0; i < len; i++) {
                Object pc = primitiveConstantInitValues[i];
                if (pc != null) {
                    if (pc instanceof String) {
                        writeByte((byte)1);
                        writeStringRef((String) pc);
                    } else if (pc instanceof Integer) {
                        writeByte((byte)2);
                        writeInt(((Integer) pc).intValue());
                    } else if (pc instanceof Long) {
                        writeByte((byte)3);
                        writeLong(((Long) pc).longValue());
                    } else if (pc instanceof Float) {
                        writeByte((byte)4);
                        writeFloat(((Float) pc).floatValue());
                    } else if (pc instanceof Double) {
                        writeByte((byte)5);
                        writeDouble(((Double) pc).doubleValue());
                    }
                } else {
                    writeByte((byte)0);
                }
            }
        }

        len = ci.methodNames != null ? ci.methodNames.length : 0;
        writeChar(len);
        if (len > 0) {
            String methodNames[] = ci.methodNames;
            for (i = 0; i < len; i++) {
                writeStringRef(methodNames[i]);
            }
            String methodSignatures[] = ci.methodSignatures;
            for (i = 0; i < len; i++) {
                writeStringRef(methodSignatures[i]);
            }
            char methodAccessFlags[] = ci.methodAccessFlags;
            for (i = 0; i < len; i++) {
                writeChar(methodAccessFlags[i]);
            }
        }

        len = ci.checkedExceptions != null ? ci.checkedExceptions.length : 0;
        writeChar(len);
        if (len > 0) {
            String checkedExceptions[][] = ci.checkedExceptions;
            for (i = 0; i < len; i++) {
                int lenl = checkedExceptions[i] != null ? checkedExceptions[i].length
                        : 0;
                writeChar(lenl);
                if (lenl > 0) {
                    for (j = 0; j < lenl; j++) {
                        writeStringRef(checkedExceptions[i][j]);
                    }
                }
            }
        }

        len = ci.nestedClasses != null ? ci.nestedClasses.length : 0;
        writeChar(len);
        if (len > 0) {
            String nestedClasses[] = ci.nestedClasses;
            for (i = 0; i < len; i++) {
                writeStringRef(nestedClasses[i]);
            }
        }
    }

    private void writeString(String s) {
        byte sb[] = s.getBytes();
        int len = sb.length;
        if (curStringBufPos + len > curStringBufWatermark) {
            // May need to adapt stringBufInc
            if (len >= stringBufInc) {
                stringBufInc = (stringBufInc + len) * 2;
            } else {
                stringBufInc = (stringBufInc * 5) / 4;  // Still increase a little - observations show that otherwise we usually get here 20 more times
            }
            byte newStringBuf[] = new byte[stringBuf.length + stringBufInc];
            System.arraycopy(stringBuf, 0, newStringBuf, 0, curStringBufPos);
            stringBuf = newStringBuf;
            curStringBufWatermark = stringBuf.length - 20;
        }
        stringBuf[curStringBufPos++] = (byte) ((len >> 8) & 255);
        stringBuf[curStringBufPos++] = (byte) (len & 255);
        System.arraycopy(sb, 0, stringBuf, curStringBufPos, len);
        curStringBufPos += len;
    }

    private void writeStringRef(String s) {
        int stringRef = stringHashTable.get(s);
        if (stringRef == -1) {
            stringHashTable.add(s, stringCount);
            stringRef = stringCount;
            writeString(s);
            stringCount++;
        }
        writeInt(stringRef);
    }

    /** Maps Strings to integer numbers (their positions in String table) */
    static class StringHashTable {

        String keys[];
        int values[];
        int size, nOfElements, watermark;

        StringHashTable(int size) {
            size = makeLikePrimeNumber(size);
            this.size = size;
            keys = new String[size];
            values = new int[size];
            nOfElements = 0;
            watermark = size * 3 / 4;
        }

        final int get(String key) {
            int pos = (key.hashCode() & 0x7FFFFFFF) % size;

            while (keys[pos] != null && !keys[pos].equals(key)) {
                pos = (pos + 3) % size; // Relies on the fact that size % 3 != 0
            }
            if (key.equals(keys[pos])) {
                return values[pos];
            } else {
                return -1;
            }
        }

        final void add(String key, int value) {
            if (nOfElements > watermark) {
                rehash();
            }

            int pos = (key.hashCode() & 0x7FFFFFFF) % size;
            while (keys[pos] != null) {
                pos = (pos + 3) % size;  // Relies on the fact that size % 3 != 0
            }
            keys[pos] = key;
            values[pos] = value;
            nOfElements++;
        }

        private final void rehash() {
            String oldKeys[] = keys;
            int oldValues[] = values;
            int oldSize = size;
            size = makeLikePrimeNumber(size * 3 / 2);
            keys = new String[size];
            values = new int[size];
            nOfElements = 0;
            watermark = size * 3 / 4;

            for (int i = 0; i < oldSize; i++) {
                if (oldKeys[i] != null) {
                    add(oldKeys[i], oldValues[i]);
                }
            }
        }

        private final int makeLikePrimeNumber(int no) {
            no = (no / 2) * 2 + 1;  // Make it an odd number
            // Find the nearest "approximately prime" number
            boolean prime = false;
            do {
                no += 2;
                prime =
                        (no % 3 != 0 && no % 5 != 0 && no % 7 != 0 && no % 11 != 0 &&
                        no % 13 != 0 && no % 17 != 0 && no % 19 != 0 && no % 23 != 0 &&
                        no % 29 != 0 && no % 31 != 0 && no % 37 != 0 && no % 41 != 0);
            } while (!prime);
            return no;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy