summaryrefslogtreecommitdiff
path: root/libjava/gnu/gcj/runtime/PersistentByteMap.java
diff options
context:
space:
mode:
authorAndrew Haley <aph@redhat.com>2016-09-30 16:24:48 +0000
committerAndrew Haley <aph@gcc.gnu.org>2016-09-30 16:24:48 +0000
commit07b78716af6a9d7c9fd1e94d9baf94a52c873947 (patch)
tree3f22b3241c513ad168c8353805614ae1249410f4 /libjava/gnu/gcj/runtime/PersistentByteMap.java
parenteae993948bae8b788c53772bcb9217c063716f93 (diff)
Makefile.def: Remove libjava.
2016-09-30 Andrew Haley <aph@redhat.com> * Makefile.def: Remove libjava. * Makefile.tpl: Likewise. * Makefile.in: Regenerate. * configure.ac: Likewise. * configure: Likewise. * gcc/java: Remove. * libjava: Likewise. From-SVN: r240662
Diffstat (limited to 'libjava/gnu/gcj/runtime/PersistentByteMap.java')
-rw-r--r--libjava/gnu/gcj/runtime/PersistentByteMap.java619
1 files changed, 0 insertions, 619 deletions
diff --git a/libjava/gnu/gcj/runtime/PersistentByteMap.java b/libjava/gnu/gcj/runtime/PersistentByteMap.java
deleted file mode 100644
index fec30806f81..00000000000
--- a/libjava/gnu/gcj/runtime/PersistentByteMap.java
+++ /dev/null
@@ -1,619 +0,0 @@
-/* Copyright (C) 2004, 2005 Free Software Foundation
-
- This file is part of libgcj.
-
-This software is copyrighted work licensed under the terms of the
-Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
-details. */
-
-
-
-/* A PersistentByteMap maps a byte array to another byte array. It
-uses a file that does not need to be serialized but may be
-memory-mapped and read in-place. So, even if there are many instances
-of gcj applications running, they can share PersistentByteMaps.
-
-The idea is to make searches as fast as possible: opening a
-PersistentByteMap is cheap and search time doesn't grow with the
-number of entries in the table. On the other hand, enumerating the
-map is slow, but that is a relatively uncommon operation.
-
-The main use of this class is to provide a way to map the
-MessageDigest of a class file to the location of a DSO that contains
-the compiled version of that class. It is up the the installer of an
-application to keep the DSO up to date with the jar.
-
-USAGE:
- MessageDigest md = MessageDigest.getInstance("MD5");
- digest = md.digest(bytes);
-
- PersistentByteMap map
- = new PersistentByteMap
- (fileName, PersistentByteMap.AccessMode.READ_ONLY);
-
- byte[] soName = map.get(digest);
- if (soName)
- {
- String SharedLibraryName = new String(soName);
-
-BUGS/FEATURES:
- remove() isn't written yet.
-
- capacity is fixed once the map has been created.
-
- We use linear probing to resolve collisions. It might be
- better to use a scheme that results in fewer probes to
- determine that an item isn't found. However, even when the
- table is half full there are only on average 1.5 probes for a
- successful search and 2.5 probes for an unsuccessful one.
-
- We don't do any locking at all: adding to a PersistentByteMap
- at runtime is possible, but it requires filesystem locks
- around get(), put(), and remove().
-*/
-
-package gnu.gcj.runtime;
-
-import java.io.*;
-import java.nio.*;
-import java.nio.channels.*;
-import java.util.*;
-import java.security.MessageDigest;
-import java.math.BigInteger;
-
-public class PersistentByteMap
-{
- private MappedByteBuffer buf;
-
- static private final int MAGIC = 0;
- static private final int VERSION = 4;
- static private final int CAPACITY = 8;
- static private final int TABLE_BASE = 12;
- static private final int STRING_BASE = 16;
- static private final int STRING_SIZE = 20;
- static private final int FILE_SIZE = 24;
- static private final int ELEMENTS = 28;
-
- static private final int INT_SIZE = 4;
-
- static private final int TABLE_ENTRY_SIZE = 2 * INT_SIZE;
-
- private int capacity; // number of entries
- private int table_base; // offset from start of file, in bytes
- private int string_base; // offset from start of file, in bytes
- private int string_size; // size of string table, in bytes
- private int file_size; // size of file, in bytes;
- private int elements; // number of elements in table
-
- private long length; // the length of the underlying file
-
- private final File name; // The name of the underlying file
-
- static private final int UNUSED_ENTRY = -1;
-
- static public final int KEYS = 0;
- static public final int VALUES = 1;
- static public final int ENTRIES = 2;
-
- private HashMap values; // A map of strings in the string table.
-
- FileChannel fc; // The underlying file channel.
-
- static final public class AccessMode
- {
- private final FileChannel.MapMode mapMode;
-
- static
- {
- READ_ONLY = new AccessMode(FileChannel.MapMode.READ_ONLY);
- READ_WRITE = new AccessMode(FileChannel.MapMode.READ_WRITE);
- PRIVATE = new AccessMode(FileChannel.MapMode.PRIVATE);
- }
-
- public static final AccessMode READ_ONLY;
- public static final AccessMode READ_WRITE;
- public static final AccessMode PRIVATE;
-
- private AccessMode(FileChannel.MapMode mode)
- {
- this.mapMode = mode;
- }
- }
-
- private PersistentByteMap(File name)
- {
- this.name = name;
- }
-
- public PersistentByteMap(String filename, AccessMode mode)
- throws IOException
- {
- this(new File(filename), mode);
- }
-
- public PersistentByteMap(File f, AccessMode mode)
- throws IOException
- {
- name = f;
-
- if (mode == AccessMode.READ_ONLY)
- {
- FileInputStream fis = new FileInputStream(f);
- fc = fis.getChannel();
- }
- else
- {
- RandomAccessFile fos = new RandomAccessFile(f, "rw");
- fc = fos.getChannel();
- }
-
- length = fc.size();
- buf = fc.map(mode.mapMode, 0, length);
-
- int magic = getWord (MAGIC);
- if (magic != 0x67636a64) /* "gcjd" */
- throw new IllegalArgumentException(f.getName());
-
- table_base = getWord (TABLE_BASE);
- capacity = getWord (CAPACITY);
- string_base = getWord (STRING_BASE);
- string_size = getWord (STRING_SIZE);
- file_size = getWord (FILE_SIZE);
- elements = getWord (ELEMENTS);
-
- // FIXME: Insert a bunch of sanity checks here
- }
-
- private void init (PersistentByteMap m, File f, int capacity, int strtabSize)
- throws IOException
- {
- f.createNewFile();
- RandomAccessFile raf = new RandomAccessFile(f, "rw");
-
- {
- // The user has explicitly provided a size for the table.
- // We're going to make that size prime. This isn't
- // strictly necessary but it can't hurt.
- //
- // We expand the size by 3/2 and round the result because the
- // hash table is intolerably slow when more than 2/3 full.
-
- BigInteger size = new BigInteger(Integer.toString(((capacity*3)+1)/2));
- BigInteger two = BigInteger.ONE.add(BigInteger.ONE);
-
- if (size.getLowestSetBit() != 0) // A hard way to say isEven()
- size = size.add(BigInteger.ONE);
-
- while (! size.isProbablePrime(10))
- size = size.add(two);
-
- this.capacity = capacity = size.intValue();
- }
-
- table_base = 64;
- string_base = table_base + capacity * TABLE_ENTRY_SIZE;
- string_size = 0;
- file_size = string_base;
- elements = 0;
-
- int totalFileSize = string_base + strtabSize;
-
- // Create the file; this rounds up the size of the file to a fixed
- // number of 4k pages.
- byte[] _4k = new byte[4096];
- for (long i = 0; i < totalFileSize; i+= 4096)
- raf.write(_4k);
-
- fc = raf.getChannel();
- buf = fc.map(FileChannel.MapMode.READ_WRITE, 0, raf.length());
-
- for (int i = 0; i < capacity; i++)
- putKeyPos(UNUSED_ENTRY, i);
-
- putWord(0x67636a64, MAGIC);
- putWord(0x01, VERSION);
- putWord(capacity, CAPACITY);
- putWord(table_base, TABLE_BASE);
- putWord(string_base, STRING_BASE);
- putWord(file_size, FILE_SIZE);
- putWord(elements, ELEMENTS);
- buf.force();
-
- length = fc.size();
- string_size = 0;
- }
-
- static public PersistentByteMap
- emptyPersistentByteMap(File name, int capacity, int strtabSize)
- throws IOException
- {
- PersistentByteMap m = new PersistentByteMap(name);
- m.init(m, name, capacity, strtabSize);
- return m;
- }
-
- private int getWord (int index)
- {
- buf.position(index);
- byte[] wordBuf = new byte[4];
- buf.get(wordBuf);
-
- int result = (int)wordBuf[0]&0xff;
- result += ((int)wordBuf[1]&0xff) << 8;
- result += ((int)wordBuf[2]&0xff) << 16;
- result += ((int)wordBuf[3]&0xff) << 24;
- return result;
- }
-
- private void putWord (int word, int index)
- {
- buf.position(index);
- byte[] wordBuf = new byte[4];
- wordBuf[0] = (byte)(word);
- wordBuf[1] = (byte)(word >>> 8);
- wordBuf[2] = (byte)(word >>> 16);
- wordBuf[3] = (byte)(word >>> 24);
- buf.put(wordBuf);
- }
-
- public Set entrySet()
- {
- return null;
- }
-
- private int getBucket(int n)
- {
- return table_base + (2*n * INT_SIZE);
- }
-
- private int getKeyPos(int n)
- {
- return getWord(getBucket(n));
- }
-
- private int getValuePos(int n)
- {
- return getWord(getBucket(n) + INT_SIZE);
- }
-
- private void putKeyPos(int index, int n)
- {
- putWord(index, getBucket(n));
- }
-
- private void putValuePos(int index, int n)
- {
- putWord(index, getBucket(n) + INT_SIZE);
- }
-
- private byte[] getBytes(int n)
- {
- int len = getWord (string_base + n);
- int base = string_base + n + INT_SIZE;
- byte[] key = new byte[len];
- buf.position(base);
- buf.get(key, 0, len);
- return key;
- }
-
- private int hash (byte[] b)
- {
- // We assume that the message digest is evenly distributed, so we
- // only need to use a few bytes of it as the hash function.
- long hashIndex
- = ((b[0]&0xffL)
- + ((b[1]&0xffL)<<8)
- + ((b[2]&0xffL)<<16)
- + ((b[3]&0xffL)<<24));
- long result = hashIndex % (long)capacity;
- return (int)result;
- }
-
- public byte[] get(byte[] digest)
- {
- int hashIndex = hash(digest);
-
- do
- {
- int k = getKeyPos(hashIndex);
- if (k == UNUSED_ENTRY)
- return null;
-
- if (Arrays.equals ((byte[])digest, getBytes(k)))
- return getBytes(getValuePos(hashIndex));
-
- // Use linear probing to resolve hash collisions. This may
- // not be theoretically as good as open addressing, but it has
- // good cache behviour.
- hashIndex++;
- hashIndex %= capacity;
- }
- while (true);
- }
-
- public void put(byte[] digest, byte[] value)
- throws IllegalAccessException
- {
- int hashIndex = hash(digest);
-
- if (elements >= capacity())
- throw new IllegalAccessException("Table Full: " + elements);
-
- do
- {
- int k = getKeyPos(hashIndex);
- if (k == UNUSED_ENTRY)
- {
- int newKey = addBytes(digest);
- putKeyPos(newKey, hashIndex);
- int newValue = addBytes(value);
- putValuePos(newValue, hashIndex);
- elements++;
- putWord(elements, ELEMENTS);
- return;
- }
- else if (Arrays.equals (digest, getBytes(k)))
- {
- int newValue = addBytes((byte[])value);
- putValuePos(newValue, hashIndex);
- return;
- }
-
- hashIndex++;
- hashIndex %= capacity;
- }
- while (true);
- }
-
- private int addBytes (byte[] data)
- throws IllegalAccessException
- {
- if (data.length > 16)
- {
- // Keep track of long strings in the hope that we will be able
- // to re-use them.
- if (values == null)
- {
- values = new HashMap();
-
- for (int i = 0; i < capacity; i++)
- if (getKeyPos(i) != UNUSED_ENTRY)
- {
- int pos = getValuePos(i);
- ByteWrapper bytes = new ByteWrapper(getBytes(pos));
- values.put(bytes, new Integer(pos));
- }
- }
-
- {
- Object result = values.get(new ByteWrapper(data));
- if (result != null)
- {
- // We already have this value in the string table
- return ((Integer)result).intValue();
- }
- }
- }
-
- if (data.length + INT_SIZE >= this.length)
- throw new IllegalAccessException("String table Full");
-
- int extent = string_base+string_size;
- int top = extent;
- putWord(data.length, extent);
- extent += INT_SIZE;
- buf.position(extent);
- buf.put(data, 0, data.length);
- extent += data.length;
- extent += INT_SIZE-1;
- extent &= ~(INT_SIZE-1); // align
- string_size = extent - string_base;
- file_size = extent;
- putWord (string_size, STRING_SIZE);
- putWord (file_size, FILE_SIZE);
-
- if (data.length > 16)
- values.put(new ByteWrapper(data), new Integer(top - string_base));
-
- return top - string_base;
- }
-
- public Iterator iterator(int type)
- {
- return new HashIterator(type);
- }
-
- public int size()
- {
- return elements;
- }
-
- public int stringTableSize()
- {
- return string_size;
- }
-
- public int capacity()
- {
- // With the the table 2/3 full there will be on average 2 probes
- // for a successful search and 5 probes for an unsuccessful one.
- return capacity * 2/3;
- }
-
- public void force()
- {
- buf.force();
- }
-
- public File getFile()
- {
- return name;
- }
-
- // Close the map. Once this has been done, the map can no longer be
- // used.
- public void close() throws IOException
- {
- force();
- fc.close();
- }
-
- public void
- putAll(PersistentByteMap t)
- throws IllegalAccessException
- {
- // We can use a fast copy if the size of a map has not changed.
- if (this.elements == 0 && t.capacity == this.capacity
- && t.length == this.length)
- {
- this.buf.position(0);
- t.buf.position(0);
- this.buf.put(t.buf);
- this.table_base = t.table_base;
- this.string_base = t.string_base;
- this.string_size = t.string_size;
- this.file_size = t.file_size;
- this.elements = t.elements;
- if (t.values != null)
- this.values = (HashMap)t.values.clone();
- return;
- }
-
- // Otherwise do it the hard way.
- Iterator iterator = t.iterator(PersistentByteMap.ENTRIES);
- while (iterator.hasNext())
- {
- PersistentByteMap.MapEntry entry
- = (PersistentByteMap.MapEntry)iterator.next();
- this.put((byte[])entry.getKey(), (byte[])entry.getValue());
- }
- }
-
-
- private final class HashIterator implements Iterator
- {
- /** Current index in the physical hash table. */
-
- private int idx;
- private int count;
- private final int type;
-
- /**
- * Construct a new HashIterator with the supplied type.
- * @param type {@link #KEYS}, {@link #VALUES}, or {@link #ENTRIES}
- */
- HashIterator(int type)
- {
- this.type = type;
- count = elements;
- idx = 0;
- }
-
- /**
- * Returns true if the Iterator has more elements.
- * @return true if there are more elements
- * @throws ConcurrentModificationException if the HashMap was modified
- */
- public boolean hasNext()
- {
- return count > 0;
- }
-
- /**
- * Returns the next element in the Iterator's sequential view.
- * @return the next element
- * @throws ConcurrentModificationException if the HashMap was modified
- * @throws NoSuchElementException if there is none
- */
- public Object next()
- {
- count--;
- for (int i = idx; i < capacity; i++)
- if (getKeyPos(i) != UNUSED_ENTRY)
- {
- idx = i+1;
- if (type == VALUES)
- return getBytes(getValuePos(i));
- if (type == KEYS)
- return getBytes(getKeyPos(i));
- return new MapEntry(i,
- getBytes(getKeyPos(i)),
- getBytes(getValuePos(i)));
- }
- return null;
- }
-
- /**
- * Remove from the underlying collection the last element returned
- * by next (optional operation). This method can be called only
- * once after each call to <code>next()</code>. It does not affect
- * what will be returned by subsequent calls to next.
- *
- * @throws IllegalStateException if next has not yet been called
- * or remove has already been called since the last call
- * to next.
- * @throws UnsupportedOperationException if this Iterator does not
- * support the remove operation.
- */
- public void remove()
- {
- throw new UnsupportedOperationException();
- }
- }
-
- static public final class MapEntry
- {
- private final Object key;
- private final Object value;
- private final int bucket;
-
- public MapEntry(int bucket, Object newKey, Object newValue)
- {
- this.key = newKey;
- this.value = newValue;
- this.bucket = bucket;
- }
-
- public final Object getKey()
- {
- return key;
- }
-
- public final Object getValue()
- {
- return value;
- }
-
- public final int getBucket()
- {
- return bucket;
- }
- }
-
- // A wrapper class for a byte array that allows collections to be
- // made.
- private final class ByteWrapper
- {
- final byte[] bytes;
- final int hash;
-
- public ByteWrapper (byte[] bytes)
- {
- int sum = 0;
- this.bytes = bytes;
- for (int i = 0; i < bytes.length; i++)
- sum += bytes[i];
- hash = sum;
- }
-
- public int hashCode()
- {
- return hash;
- }
-
- public boolean equals(Object obj)
- {
- return Arrays.equals(bytes, ((ByteWrapper)obj).bytes);
- }
- }
-}