com.sun.tools.jmake.BinaryProjectDatabaseWriter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jmake Show documentation
Show all versions of jmake Show documentation
This is the pantsbuild fork of jmake, which has a few bug-fixes
that are unlikely to be accepted upstream.
/* 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