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 26 package com.sun.tools.javac.util; 27 28 import java.lang.ref.SoftReference; 29 30 import com.sun.tools.javac.util.DefinedBy.Api; 31 32 /** 33 * Implementation of Name.Table that stores all names in a single shared 34 * byte array, expanding it as needed. This avoids the overhead incurred 35 * by using an array of bytes for each name. 36 * 37 * <p><b>This is NOT part of any supported API. 38 * If you write code that depends on this, you do so at your own risk. 39 * This code and its internal interfaces are subject to change or 40 * deletion without notice.</b> 41 */ 42 public class SharedNameTable extends Name.Table { 43 // maintain a freelist of recently used name tables for reuse. 44 private static List<SoftReference<SharedNameTable>> freelist = List.nil(); 45 create(Names names)46 static public synchronized SharedNameTable create(Names names) { 47 while (freelist.nonEmpty()) { 48 SharedNameTable t = freelist.head.get(); 49 freelist = freelist.tail; 50 if (t != null) { 51 return t; 52 } 53 } 54 return new SharedNameTable(names); 55 } 56 dispose(SharedNameTable t)57 static private synchronized void dispose(SharedNameTable t) { 58 freelist = freelist.prepend(new SoftReference<>(t)); 59 } 60 61 /** The hash table for names. 62 */ 63 private NameImpl[] hashes; 64 65 /** The shared byte array holding all encountered names. 66 */ 67 public byte[] bytes; 68 69 /** The mask to be used for hashing 70 */ 71 private int hashMask; 72 73 /** The number of filled bytes in `names'. 74 */ 75 private int nc = 0; 76 77 /** Allocator 78 * @param names The main name table 79 * @param hashSize the (constant) size to be used for the hash table 80 * needs to be a power of two. 81 * @param nameSize the initial size of the name table. 82 */ SharedNameTable(Names names, int hashSize, int nameSize)83 public SharedNameTable(Names names, int hashSize, int nameSize) { 84 super(names); 85 hashMask = hashSize - 1; 86 hashes = new NameImpl[hashSize]; 87 bytes = new byte[nameSize]; 88 89 } 90 SharedNameTable(Names names)91 public SharedNameTable(Names names) { 92 this(names, 0x8000, 0x20000); 93 } 94 95 @Override fromChars(char[] cs, int start, int len)96 public Name fromChars(char[] cs, int start, int len) { 97 int nc = this.nc; 98 byte[] bytes = this.bytes = ArrayUtils.ensureCapacity(this.bytes, nc + len * 3); 99 int nbytes = Convert.chars2utf(cs, start, bytes, nc, len) - nc; 100 int h = hashValue(bytes, nc, nbytes) & hashMask; 101 NameImpl n = hashes[h]; 102 while (n != null && 103 (n.getByteLength() != nbytes || 104 !equals(bytes, n.index, bytes, nc, nbytes))) { 105 n = n.next; 106 } 107 if (n == null) { 108 n = new NameImpl(this); 109 n.index = nc; 110 n.length = nbytes; 111 n.next = hashes[h]; 112 hashes[h] = n; 113 this.nc = nc + nbytes; 114 if (nbytes == 0) { 115 this.nc++; 116 } 117 } 118 return n; 119 } 120 121 @Override fromUtf(byte[] cs, int start, int len)122 public Name fromUtf(byte[] cs, int start, int len) { 123 int h = hashValue(cs, start, len) & hashMask; 124 NameImpl n = hashes[h]; 125 byte[] names = this.bytes; 126 while (n != null && 127 (n.getByteLength() != len || !equals(names, n.index, cs, start, len))) { 128 n = n.next; 129 } 130 if (n == null) { 131 int nc = this.nc; 132 names = this.bytes = ArrayUtils.ensureCapacity(names, nc + len); 133 System.arraycopy(cs, start, names, nc, len); 134 n = new NameImpl(this); 135 n.index = nc; 136 n.length = len; 137 n.next = hashes[h]; 138 hashes[h] = n; 139 this.nc = nc + len; 140 if (len == 0) { 141 this.nc++; 142 } 143 } 144 return n; 145 } 146 147 @Override dispose()148 public void dispose() { 149 dispose(this); 150 } 151 152 static class NameImpl extends Name { 153 /** The next name occupying the same hash bucket. 154 */ 155 NameImpl next; 156 157 /** The index where the bytes of this name are stored in the global name 158 * buffer `byte'. 159 */ 160 int index; 161 162 /** The number of bytes in this name. 163 */ 164 int length; 165 NameImpl(SharedNameTable table)166 NameImpl(SharedNameTable table) { 167 super(table); 168 } 169 170 @Override getIndex()171 public int getIndex() { 172 return index; 173 } 174 175 @Override getByteLength()176 public int getByteLength() { 177 return length; 178 } 179 180 @Override getByteAt(int i)181 public byte getByteAt(int i) { 182 return getByteArray()[index + i]; 183 } 184 185 @Override getByteArray()186 public byte[] getByteArray() { 187 return ((SharedNameTable) table).bytes; 188 } 189 190 @Override getByteOffset()191 public int getByteOffset() { 192 return index; 193 } 194 195 /** Return the hash value of this name. 196 */ 197 @DefinedBy(Api.LANGUAGE_MODEL) hashCode()198 public int hashCode() { 199 return index; 200 } 201 202 /** Is this name equal to other? 203 */ 204 @DefinedBy(Api.LANGUAGE_MODEL) equals(Object other)205 public boolean equals(Object other) { 206 if (other instanceof Name) 207 return 208 table == ((Name)other).table && index == ((Name) other).getIndex(); 209 else return false; 210 } 211 212 } 213 214 } 215