001: /*
002: * @(#)CVMStringTable.java 1.38 06/10/22
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package runtime;
029:
030: import java.util.Enumeration;
031: import consts.Const;
032: import components.*;
033: import vm.*;
034: import util.*;
035:
036: public class CVMStringTable extends vm.StringTable {
037:
038: CVMStringIntern internTable;
039: private CVMInitInfo initInfo;
040:
041: CVMStringTable(CVMInitInfo initInfo) {
042: this .initInfo = initInfo;
043: }
044:
045: final boolean writeStringData(String dataName,
046: String charArrayClassBlockName, CCodeWriter out) {
047: int n = arrangeStringData();
048:
049: if (n == 0)
050: return false; // nothing to do here.
051:
052: char v[] = new char[n];
053: this .fillInChars(0, n, v, 0);
054:
055: //
056: // first typedef the structure we're about to create
057: /*
058: * The following structure has to reflect CVMArrayOfChar which
059: * has a padding field for 64 bit platforms to be sure
060: * that the membler elems has the same offset for all
061: * CVMArrayOf<type> structures.
062: */
063: out
064: .print("const struct { CVMObjectHeader hdr;\n CVMJavaInt length;\n#ifdef CVM_64\n CVMUint32 pad;\n#endif\n CVMJavaChar stringData["
065: + n + "]; } ");
066: out.print(dataName);
067: out.println(" = {");
068: //
069: // fill in the header information
070: // hdr.various = {{0}} ??
071: int hashCode = 0;
072: out.println(" CVM_ROM_OBJECT_HDR_INIT0("
073: + charArrayClassBlockName + "," + hashCode + "),");
074: out.println(" " + n + ",\n#ifdef CVM_64\n 0,\n#endif\n {");
075: //
076: // finally write the char array.
077: int mod = 0;
078: for (int i = 0; i < n; i++) {
079: if (mod == 0)
080: out.write('\t');
081: out.printHexInt(v[i]);
082: out.write(',');
083: if (++mod == 12) {
084: out.write('\n');
085: mod = 0;
086: }
087: }
088: if (mod != 0)
089: out.write('\n');
090: out.print(" } };\n\n");
091:
092: return true;
093:
094: }
095:
096: private final static int maxCom = 20;
097: private static byte cbuf[] = new byte[maxCom + 3];
098:
099: private void commentary(String s, CCodeWriter out) {
100: int m = Math.min(maxCom, s.length());
101: for (int i = 0; i < m; i++) {
102: char c = s.charAt(i);
103: if (' ' <= c && c <= '~') {
104: if (c == '*') {
105: /*
106: * Prevent damage to C comment by replacing * with ?.
107: */
108: c = '?';
109: }
110: cbuf[i] = (byte) c;
111: } else {
112: cbuf[i] = (byte) '?';
113: }
114: }
115: out.write(out.commentLeader, 0, out.commentLeader.length);
116: out.write(cbuf, 0, m);
117: if (m < s.length()) {
118: out.write('.');
119: out.write('.');
120: out.write('.');
121: }
122: out.write(out.commentTrailer, 0, out.commentTrailer.length);
123: }
124:
125: public int writeStrings(CCodeWriter out, String tableName) {
126: String dataName = tableName + "_data";
127:
128: ClassInfo charArrayClass = ClassTable.lookupClass("[C");
129: if (charArrayClass == null) {
130: System.err
131: .println(Localizer
132: .getString("javacodecompact.cannot_find_array_of_char"));
133: return 0;
134: }
135:
136: if (!writeStringData(dataName,
137: ((CVMClass) (charArrayClass.vmClass)).getNativeName()
138: + "_Classblock", out))
139: return 0;
140:
141: out.println("const CVMUint16 " + tableName + "[] = {");
142:
143: StringConstant stringTable[] = allStrings();
144:
145: internTable = new CVMStringIntern(initInfo, stringTable.length);
146:
147: int currentLength = -1;
148: int currentLengthCount = -1;
149: int numCompressedEntries = 0;
150:
151: for (int i = 0; i < stringTable.length; i++) {
152: StringConstant s = stringTable[i];
153: String string = s.str.string;
154: int hashCode = 0;
155: if (currentLength != string.length()) {
156: if (currentLengthCount >= 0) {
157: out.println("/* COUNTS: " + currentLengthCount
158: + " instances of " + currentLength
159: + "-character-long strings */");
160: out.println("\t" + currentLengthCount + ", "
161: + currentLength + ",");
162: numCompressedEntries++;
163: }
164: currentLength = string.length();
165: currentLengthCount = 0;
166: }
167: currentLengthCount++;
168: out.print("\t");
169: commentary(string, out);
170: internTable.internStringConstant(s);
171: }
172: if (currentLengthCount >= 0) {
173: out.println("/* COUNTS: " + currentLengthCount
174: + " instances of " + currentLength
175: + "-character-long strings */");
176: out.println("\t" + currentLengthCount + ", "
177: + currentLength + ",");
178: numCompressedEntries++;
179: }
180: out.println("};\n\n");
181:
182: out.println("const int CVM_nROMStringsCompressedEntries = "
183: + numCompressedEntries + ";");
184:
185: return stringTable.length;
186: }
187:
188: /*
189: * Moved global variables to CVMROMGlobals
190: * That makes it necessary to pass the global header out file into writeInternTable.
191: */
192: public void writeStringInternTable(CCodeWriter out,
193: CCodeWriter globalHeaderOut, String tableName,
194: String stringArrayName) {
195: internTable.writeInternTable(out, globalHeaderOut, tableName,
196: stringArrayName);
197: }
198: }
199:
200: class CVMInternSegment {
201: int capacity;
202: int content = 0;
203: StringConstant data[];
204:
205: private static final int primeFactors[] = { 3, 5, 7, 11, 13, 37 };
206: private static final int nPrimeFactors = primeFactors.length;
207:
208: CVMInternSegment(int size) {
209: /*
210: * apply our usual emptyness parameter.
211: * then make sure its relatively prime to
212: * the secondary hash h1, where 1 <= h1 <= 16
213: * and also to 37. This means testing against
214: * 2, 3, 5, 7, 11, 13, and 37.
215: * This loop WILL terminate, because eventually
216: * we will hit either a relative prime to all these
217: * factors, or an actual prime.
218: */
219: size = (size * 100) / 65;
220: size |= 1; /* not a multiple of 2 */
221: boolean changed = true;
222: while (changed) {
223: changed = false;
224: for (int i = 0; i < nPrimeFactors; i++) {
225: if (size % primeFactors[i] == 0) {
226: size += 2;
227: changed = true;
228: break; /* out of for loop */
229: }
230: }
231: }
232: capacity = size;
233: data = new StringConstant[size];
234: }
235:
236: void writeSegment(String segmentName, String stringArrayName,
237: String link, CCodeWriter out) {
238: //
239: // first typedef the array we're about to create
240: out
241: .print("const struct { CVM_INTERN_SEGMENT_HEADER\n\tCVMStringICell data[");
242: out.print(capacity);
243: out.print("];\n\tCVMUint8 refCount[");
244: out.print(capacity);
245: out.print("]; } ");
246: out.print(segmentName);
247: out.print(" = {\n &");
248: /*
249: * Moved globals to CVMROMGlobals.
250: */
251: out.print("CVMROMGlobals." + link);
252: out.print(", ");
253: out.print(capacity);
254: out.print(", ");
255: out.print(content);
256: out.println(", 1, {");
257:
258: //
259: // write the String reference array.
260: for (int i = 0; i < capacity; i++) {
261: StringConstant sc = data[i];
262: if (sc == null) {
263: out.println(" {0},");
264: } else {
265: /*
266: * Moved globals to CVMROMGlobals.
267: */
268: out.println(" {(CVMObject*)&CVMROMGlobals."
269: + stringArrayName + "[" + sc.unicodeIndex
270: + "]},");
271: }
272: }
273: out.print("}, {\n ");
274: // now the reference counts: all either unused or sticky
275: int perLine = 0;
276: for (int i = 0; i < capacity; i++) {
277: StringConstant sc = data[i];
278: if (sc == null) {
279: out.print("StrU, ");
280: } else {
281: out.print("StrS, ");
282: }
283: if (++perLine > 8) {
284: out.print("\n ");
285: perLine = 0;
286: }
287: }
288: out.println("\n}};");
289: }
290:
291: }
292:
293: class CVMStringIntern {
294:
295: CVMInternSegment internTable;
296: CVMInitInfo initInfo;
297:
298: CVMStringIntern(CVMInitInfo initInfo, int maxSize) {
299: this .initInfo = initInfo;
300: internTable = new CVMInternSegment(maxSize);
301: }
302:
303: StringConstant internStringConstant(StringConstant val) {
304: String s = val.str.string;
305: CVMInternSegment curseg = internTable;
306:
307: int h = 0, n;
308: // Hash function.
309: // Identical to the one in the runtime interning code.
310: n = Math.min(s.length(), 16);
311: for (int i = 0; i < n; i++) {
312: h = (h * 37) + s.charAt(i);
313: }
314:
315: int h1 = (h & 0x7fffffff) % curseg.capacity;
316: int h2 = (h & 15) + 1;
317: int i = h1;
318: StringConstant candidate;
319:
320: while ((candidate = curseg.data[i]) != null) {
321: if (val.equals(candidate)) {
322: return candidate;
323: }
324: i += h2;
325: if (i >= curseg.capacity) {
326: i -= curseg.capacity;
327: }
328: }
329: // not found in this table.
330: // insert at current location.
331: curseg.data[i] = val;
332: curseg.content += 1;
333: return val;
334: }
335:
336: /*
337: * Moved global variables to CVMROMGlobals
338: * That makes it necessary to pass the global header out file into writeInternTable.
339: */
340: public void writeInternTable(CCodeWriter out,
341: CCodeWriter globalHeaderOut, String tableName,
342: String stringArrayName) {
343: /* the StringIntern class has no EMV equivalent -- it becomes
344: * part of java.lang.String. Only the InternSegment exists.
345: * Go write it out.
346: */
347: String linkname;
348: // Note : define more compact representation of
349: // CVMInternUnused and CVMInternSticky to reduce our
350: // output volumn
351: out.print("#undef StrS\n#undef StrU\n");
352: out.print("#define StrS CVMInternSticky\n");
353: out.print("#define StrU CVMInternUnused\n");
354: //
355: // write out the indirect next cell, and see that it gets
356: // initialized.
357: linkname = tableName + "NextCell";
358: /*
359: * Moved global variables to CVMROMGlobals
360: */
361: globalHeaderOut.println(" struct CVMInternSegment * "
362: + linkname + ";");
363: initInfo.addInfo("NULL", "&CVMROMGlobals." + linkname,
364: "sizeof (CVMROMGlobals." + linkname + ")");
365: internTable.writeSegment(tableName, stringArrayName, linkname,
366: out);
367: }
368: }
|