SharedNameTable.java revision 2571:10fc81ac75b4
1/* 2 * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package com.sun.tools.javac.util; 27 28import java.lang.ref.SoftReference; 29 30/** 31 * Implementation of Name.Table that stores all names in a single shared 32 * byte array, expanding it as needed. This avoids the overhead incurred 33 * by using an array of bytes for each name. 34 * 35 * <p><b>This is NOT part of any supported API. 36 * If you write code that depends on this, you do so at your own risk. 37 * This code and its internal interfaces are subject to change or 38 * deletion without notice.</b> 39 */ 40public class SharedNameTable extends Name.Table { 41 // maintain a freelist of recently used name tables for reuse. 42 private static List<SoftReference<SharedNameTable>> freelist = List.nil(); 43 44 static public synchronized SharedNameTable create(Names names) { 45 while (freelist.nonEmpty()) { 46 SharedNameTable t = freelist.head.get(); 47 freelist = freelist.tail; 48 if (t != null) { 49 return t; 50 } 51 } 52 return new SharedNameTable(names); 53 } 54 55 static private synchronized void dispose(SharedNameTable t) { 56 freelist = freelist.prepend(new SoftReference<>(t)); 57 } 58 59 /** The hash table for names. 60 */ 61 private NameImpl[] hashes; 62 63 /** The shared byte array holding all encountered names. 64 */ 65 public byte[] bytes; 66 67 /** The mask to be used for hashing 68 */ 69 private int hashMask; 70 71 /** The number of filled bytes in `names'. 72 */ 73 private int nc = 0; 74 75 /** Allocator 76 * @param names The main name table 77 * @param hashSize the (constant) size to be used for the hash table 78 * needs to be a power of two. 79 * @param nameSize the initial size of the name table. 80 */ 81 public SharedNameTable(Names names, int hashSize, int nameSize) { 82 super(names); 83 hashMask = hashSize - 1; 84 hashes = new NameImpl[hashSize]; 85 bytes = new byte[nameSize]; 86 87 } 88 89 public SharedNameTable(Names names) { 90 this(names, 0x8000, 0x20000); 91 } 92 93 @Override 94 public Name fromChars(char[] cs, int start, int len) { 95 int nc = this.nc; 96 byte[] bytes = this.bytes = ArrayUtils.ensureCapacity(this.bytes, nc + len * 3); 97 int nbytes = Convert.chars2utf(cs, start, bytes, nc, len) - nc; 98 int h = hashValue(bytes, nc, nbytes) & hashMask; 99 NameImpl n = hashes[h]; 100 while (n != null && 101 (n.getByteLength() != nbytes || 102 !equals(bytes, n.index, bytes, nc, nbytes))) { 103 n = n.next; 104 } 105 if (n == null) { 106 n = new NameImpl(this); 107 n.index = nc; 108 n.length = nbytes; 109 n.next = hashes[h]; 110 hashes[h] = n; 111 this.nc = nc + nbytes; 112 if (nbytes == 0) { 113 this.nc++; 114 } 115 } 116 return n; 117 } 118 119 @Override 120 public Name fromUtf(byte[] cs, int start, int len) { 121 int h = hashValue(cs, start, len) & hashMask; 122 NameImpl n = hashes[h]; 123 byte[] names = this.bytes; 124 while (n != null && 125 (n.getByteLength() != len || !equals(names, n.index, cs, start, len))) { 126 n = n.next; 127 } 128 if (n == null) { 129 int nc = this.nc; 130 names = this.bytes = ArrayUtils.ensureCapacity(names, nc + len); 131 System.arraycopy(cs, start, names, nc, len); 132 n = new NameImpl(this); 133 n.index = nc; 134 n.length = len; 135 n.next = hashes[h]; 136 hashes[h] = n; 137 this.nc = nc + len; 138 if (len == 0) { 139 this.nc++; 140 } 141 } 142 return n; 143 } 144 145 @Override 146 public void dispose() { 147 dispose(this); 148 } 149 150 static class NameImpl extends Name { 151 /** The next name occupying the same hash bucket. 152 */ 153 NameImpl next; 154 155 /** The index where the bytes of this name are stored in the global name 156 * buffer `byte'. 157 */ 158 int index; 159 160 /** The number of bytes in this name. 161 */ 162 int length; 163 164 NameImpl(SharedNameTable table) { 165 super(table); 166 } 167 168 @Override 169 public int getIndex() { 170 return index; 171 } 172 173 @Override 174 public int getByteLength() { 175 return length; 176 } 177 178 @Override 179 public byte getByteAt(int i) { 180 return getByteArray()[index + i]; 181 } 182 183 @Override 184 public byte[] getByteArray() { 185 return ((SharedNameTable) table).bytes; 186 } 187 188 @Override 189 public int getByteOffset() { 190 return index; 191 } 192 193 /** Return the hash value of this name. 194 */ 195 public int hashCode() { 196 return index; 197 } 198 199 /** Is this name equal to other? 200 */ 201 public boolean equals(Object other) { 202 if (other instanceof Name) 203 return 204 table == ((Name)other).table && index == ((Name) other).getIndex(); 205 else return false; 206 } 207 208 } 209 210} 211