001: /* Copyright (C) 2004 - 2007 db4objects Inc. http://www.db4o.com
002:
003: This file is part of the db4o open source object database.
004:
005: db4o is free software; you can redistribute it and/or modify it under
006: the terms of version 2 of the GNU General Public License as published
007: by the Free Software Foundation and as clarified by db4objects' GPL
008: interpretation policy, available at
009: http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
010: Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
011: Suite 350, San Mateo, CA 94403, USA.
012:
013: db4o is distributed in the hope that it will be useful, but WITHOUT ANY
014: WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: for more details.
017:
018: You should have received a copy of the GNU General Public License along
019: with this program; if not, write to the Free Software Foundation, Inc.,
020: 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
021: package EDU.purdue.cs.bloat.trans;
022:
023: import java.util.*;
024:
025: import EDU.purdue.cs.bloat.editor.*;
026:
027: /**
028: * <tt>CompactArrayInitializer</tt> optimizes the initialization of arrays by
029: * transforming the initialization code into a loop that loads the array
030: * elements from a string in the class's constant pool.
031: */
032: public class CompactArrayInitializer implements Opcode {
033: public static boolean DEBUG = false;
034:
035: private static final MemberRef GET_CHARS;
036:
037: // Various states that the analyzer can be in. The state indicates
038: // what kind of instruction the analyzer expects to see next.
039: private static final int EXPECT_SIZE = 0;
040:
041: private static final int EXPECT_NEW = 1;
042:
043: private static final int EXPECT_DUP = 2;
044:
045: private static final int EXPECT_INDEX_OR_SIZE = 3;
046:
047: private static final int EXPECT_VALUE_OR_SIZE_OR_NEW = 4;
048:
049: private static final int EXPECT_STORE_OR_NEW = 5;
050:
051: private static final int EXPECT_PUT_OR_DUP = 6;
052:
053: private static final int THRESHOLD = 16;
054:
055: private static final String[] STATES = { "EXPECT_SIZE",
056: "EXPECT_NEW", "EXPECT_DUP", "EXPECT_INDEX_OR_SIZE",
057: "EXPECT_VALUE_OR_SIZE_OR_NEW", "EXPECT_STORE_OR_NEW",
058: "EXPECT_PUT_OR_DUP" };
059:
060: static {
061:
062: // void String.getChars(int srcBegin, int scrEnd, char dst[],
063: // int dstBegin);
064: // Copies characters from a String object into a char array.
065:
066: GET_CHARS = new MemberRef(Type.STRING, new NameAndType(
067: "getChars", Type.getType("(II[CI)V")));
068: }
069:
070: /**
071: * Some Java compilers initialize arrays using straight-line code. For
072: * classes that have large, initialized arrays this results in unnecessarily
073: * large classfiles. <tt>CompactArrayInitializer</tt> examines a method
074: * (via its <tt>MethodEditor</tt>) creates a string in the method's
075: * class's constant pool that contains all of the elements of the
076: * initialized array. After the old initialization code is removed from the
077: * method, new code is inserted that essentially is a loop that loads each
078: * element from the string into the array. Note that only arrays of
079: * <tt>int</tt>, <tt>short</tt>, <tt>char</tt>, <tt>byte</tt>,
080: * and <tt>boolean</tt> are compacted.
081: *
082: * @param method
083: * The method whose array initializations are to be compacted.
084: */
085:
086: public static boolean transform(final MethodEditor method) {
087: if (CompactArrayInitializer.DEBUG) {
088: System.out.println("Compacting array initializer in "
089: + method);
090: }
091:
092: boolean filled = false; // Was the constant string generated and
093: // entered?
094:
095: int state = CompactArrayInitializer.EXPECT_SIZE; // The state that we
096: // are currently in
097:
098: int size = 0; // Size of the array
099: int value = 0; // A value in the array
100: int index = 0; // Current index into the array
101: int[] data = null; // Contents of the array whose initialization is
102: // being optimized.
103: Type elementType = null; // Of what Type is the array?
104:
105: // Keep track of all the Instructions and Labels that deal with array
106: // initialization.
107: final ArrayList2 buf = new ArrayList2(method.code().size());
108:
109: // Get the code (Labels and Instructions) for the method we're editing
110: final Iterator iter = method.code().iterator();
111:
112: while (iter.hasNext()) {
113: final Object ce = iter.next();
114:
115: if (CompactArrayInitializer.DEBUG) {
116: System.out.println("Examining " + ce);
117: // if (false) {
118: System.out.println("state = "
119: + CompactArrayInitializer.STATES[state]);
120: // }
121: }
122:
123: if (ce instanceof Instruction) {
124: final Instruction inst = (Instruction) ce;
125:
126: switch (state) {
127: case EXPECT_SIZE:
128: switch (inst.opcodeClass()) {
129: case opcx_ldc:
130: if ((inst.operand() instanceof Byte)
131: || (inst.operand() instanceof Short)
132: || (inst.operand() instanceof Integer)) {
133: size = ((Number) inst.operand()).intValue();
134: state = CompactArrayInitializer.EXPECT_NEW;
135: }
136: break;
137: default:
138: state = CompactArrayInitializer.EXPECT_SIZE;
139: break;
140: }
141: break;
142: case EXPECT_NEW:
143: switch (inst.opcodeClass()) {
144: case opcx_newarray:
145: elementType = (Type) inst.operand();
146:
147: if (elementType.isIntegral()) {
148: data = new int[size];
149: state = CompactArrayInitializer.EXPECT_DUP;
150: } else {
151: state = CompactArrayInitializer.EXPECT_SIZE;
152: }
153: break;
154: case opcx_ldc:
155: if ((inst.operand() instanceof Byte)
156: || (inst.operand() instanceof Short)
157: || (inst.operand() instanceof Integer)) {
158: size = ((Number) inst.operand()).intValue();
159: state = CompactArrayInitializer.EXPECT_NEW;
160: } else {
161: state = CompactArrayInitializer.EXPECT_SIZE;
162: }
163: break;
164: default:
165: state = CompactArrayInitializer.EXPECT_SIZE;
166: break;
167: }
168: break;
169: case EXPECT_DUP:
170: switch (inst.opcodeClass()) {
171: case opcx_dup:
172: state = CompactArrayInitializer.EXPECT_INDEX_OR_SIZE;
173: break;
174: case opcx_ldc:
175: if ((inst.operand() instanceof Byte)
176: || (inst.operand() instanceof Short)
177: || (inst.operand() instanceof Integer)) {
178: size = ((Number) inst.operand()).intValue();
179: state = CompactArrayInitializer.EXPECT_NEW;
180: } else {
181: state = CompactArrayInitializer.EXPECT_SIZE;
182: }
183: break;
184: default:
185: state = CompactArrayInitializer.EXPECT_SIZE;
186: break;
187: }
188: break;
189: case EXPECT_INDEX_OR_SIZE:
190: switch (inst.opcodeClass()) {
191: case opcx_ldc:
192: if ((inst.operand() instanceof Byte)
193: || (inst.operand() instanceof Short)
194: || (inst.operand() instanceof Integer)) {
195:
196: index = ((Number) inst.operand())
197: .intValue();
198:
199: if (index < data.length) {
200: state = CompactArrayInitializer.EXPECT_VALUE_OR_SIZE_OR_NEW;
201: } else {
202: // Out of range. Can't be an index,
203: // so assume it's a size.
204: size = index;
205: state = CompactArrayInitializer.EXPECT_NEW;
206: }
207: } else {
208: state = CompactArrayInitializer.EXPECT_SIZE;
209: }
210: break;
211: default:
212: state = CompactArrayInitializer.EXPECT_SIZE;
213: break;
214: }
215: break;
216: case EXPECT_VALUE_OR_SIZE_OR_NEW:
217: switch (inst.opcodeClass()) {
218: case opcx_ldc:
219: if ((inst.operand() instanceof Byte)
220: || (inst.operand() instanceof Short)
221: || (inst.operand() instanceof Integer)) {
222:
223: value = ((Number) inst.operand())
224: .intValue();
225: state = CompactArrayInitializer.EXPECT_STORE_OR_NEW;
226: } else if (inst.operand() instanceof Character) {
227: final Character ch = (Character) inst
228: .operand();
229: value = ch.charValue();
230: state = CompactArrayInitializer.EXPECT_STORE_OR_NEW;
231: } else {
232: state = CompactArrayInitializer.EXPECT_SIZE;
233: }
234: break;
235: case opcx_newarray:
236: size = index;
237: elementType = (Type) inst.operand();
238:
239: if (elementType.isIntegral()) {
240: data = new int[size];
241: state = CompactArrayInitializer.EXPECT_DUP;
242: } else {
243: state = CompactArrayInitializer.EXPECT_SIZE;
244: }
245: break;
246: default:
247: state = CompactArrayInitializer.EXPECT_SIZE;
248: break;
249: }
250: break;
251: case EXPECT_STORE_OR_NEW:
252: switch (inst.opcodeClass()) {
253: case opcx_bastore:
254: if (elementType.equals(Type.BYTE)
255: || elementType.equals(Type.BOOLEAN)) {
256: data[index] = value;
257: state = CompactArrayInitializer.EXPECT_PUT_OR_DUP;
258: }
259: break;
260: case opcx_castore:
261: if (elementType.equals(Type.CHARACTER)) {
262: data[index] = value;
263: state = CompactArrayInitializer.EXPECT_PUT_OR_DUP;
264: }
265: break;
266: case opcx_sastore:
267: if (elementType.equals(Type.SHORT)) {
268: data[index] = value;
269: state = CompactArrayInitializer.EXPECT_PUT_OR_DUP;
270: }
271: break;
272: case opcx_iastore:
273: if (elementType.equals(Type.INTEGER)) {
274: data[index] = value;
275: state = CompactArrayInitializer.EXPECT_PUT_OR_DUP;
276: }
277: break;
278: case opcx_ldc:
279: if ((inst.operand() instanceof Byte)
280: || (inst.operand() instanceof Short)
281: || (inst.operand() instanceof Integer)) {
282:
283: size = ((Number) inst.operand()).intValue();
284: state = CompactArrayInitializer.EXPECT_NEW;
285: } else {
286: state = CompactArrayInitializer.EXPECT_SIZE;
287: }
288: break;
289: case opcx_newarray:
290: size = value;
291: elementType = (Type) inst.operand();
292:
293: if (elementType.isIntegral()) {
294: data = new int[size];
295: state = CompactArrayInitializer.EXPECT_DUP;
296: } else {
297: state = CompactArrayInitializer.EXPECT_SIZE;
298: }
299: break;
300: default:
301: state = CompactArrayInitializer.EXPECT_SIZE;
302: break;
303: }
304: break;
305: case EXPECT_PUT_OR_DUP:
306: switch (inst.opcodeClass()) {
307: case opcx_dup:
308: state = CompactArrayInitializer.EXPECT_INDEX_OR_SIZE;
309: break;
310: case opcx_ldc:
311: if ((inst.operand() instanceof Byte)
312: || (inst.operand() instanceof Short)
313: || (inst.operand() instanceof Integer)) {
314: size = ((Number) inst.operand()).intValue();
315: state = CompactArrayInitializer.EXPECT_NEW;
316: } else {
317: state = CompactArrayInitializer.EXPECT_SIZE;
318: }
319: break;
320: case opcx_astore:
321: case opcx_aastore:
322: case opcx_putstatic:
323: case opcx_putstatic_nowb:
324: case opcx_putfield:
325: case opcx_putfield_nowb:
326: if (data.length >= CompactArrayInitializer.THRESHOLD) {
327: CompactArrayInitializer.fillArray(method,
328: buf, elementType, data);
329: filled = true;
330: }
331: state = CompactArrayInitializer.EXPECT_SIZE;
332: break;
333: default:
334: state = CompactArrayInitializer.EXPECT_SIZE;
335: break;
336: }
337: break;
338: }
339: } else {
340: final Label label = (Label) ce;
341:
342: if (label.startsBlock()) {
343: state = CompactArrayInitializer.EXPECT_SIZE;
344: }
345: }
346:
347: if (CompactArrayInitializer.DEBUG /* && false */) {
348: System.out.println(" -> "
349: + CompactArrayInitializer.STATES[state]);
350: }
351:
352: buf.add(ce);
353: }
354:
355: if (filled) {
356: method.code().clear();
357: method.code().addAll(buf);
358:
359: if (CompactArrayInitializer.DEBUG) {
360: for (int i = 0; i < method.code().size(); i++) {
361: System.out.println("code[" + i + "] "
362: + method.code().get(i));
363: }
364: }
365: }
366:
367: return filled;
368: }
369:
370: /**
371: * Construct a UTF8 string that stores the contents of an integral (int,
372: * char, or byte/boolean) array. Each element of the UTF8 string is 16 bits
373: * wide meaning that an int is stored into two elements, a char is store in
374: * one element, and two bytes/booleans are stored in one element.
375: * Essentially each integer in the <tt>data</tt> parmeter is converted
376: * into a character and placed in an array.
377: * <p>
378: * A UTF8 string cannot be larger than 64K. To be on the safe side, we do
379: * not generate UTF8 strings that are larger than 32K.
380: * <p>
381: * We then remove all of the old initialization code, so that the previous
382: * instruction is a <tt>newarray</tt> opcode (meaning that the array
383: * object will be on top of the stack).
384: * <p>
385: * Then new code is generated for loading data from the UTF8 string. Loading
386: * character data is relatively straightforward. The <tt>getChars</tt>
387: * method is invoked on the UTF8 string (an instance of <tt>String</tt>)
388: * to copy characters from the string into a character array.
389: * <p>
390: * A little more work has to be done for non-character data types. First,
391: * the UTF8 string is read into a (local) character array. Then, the data is
392: * extracted from the character array and placed in the new array. For some
393: * data types, labels are added to the program.
394: *
395: * @param m
396: * The method that contains the array
397: * @param buf
398: * Instructions from the method that are used in array
399: * initialization
400: * @param elementType
401: * The Type of the array
402: * @param data
403: * The contents of the array
404: *
405: */
406: private static void fillArray(final MethodEditor m,
407: final ArrayList2 buf, final Type elementType,
408: final int[] data) {
409: // Max UTF8 constant size is 65535 bytes. We divide this in 2 to
410: // prevent DataOutputStream from crashing. Since our arrays can be
411: // longer than 32767, we break the image into segments.
412:
413: char[] c; // string that will be entered into the constant pool
414:
415: if (elementType.equals(Type.CHARACTER)) {
416: // Fill the string with char data (16-bits). Each char in string
417: // holds a single char.
418: c = new char[data.length];
419:
420: for (int i = 0; i < data.length; i++) {
421: c[i] = (char) data[i];
422: }
423: } else if (elementType.equals(Type.BYTE)
424: || elementType.equals(Type.BOOLEAN)) {
425: // Fill the string with 8-bit data. Each char in string holds
426: // two 8-bit data.
427: c = new char[(data.length + 1) / 2];
428:
429: int j = 0;
430:
431: for (int i = 0; i + 1 < data.length; i += 2) {
432: c[j++] = (char) ((data[i] << 8) | (data[i + 1] & 0xff));
433: }
434:
435: if (j != c.length) {
436: c[j++] = (char) (data[data.length - 1] << 8);
437: }
438: } else if (elementType.equals(Type.SHORT)) {
439: // Fill the string with short (16-bit) data. I don't know why we
440: // add 0x8000 to it, but we subtract 32768 (0x8000) in the
441: // generated byetcode. Mysteries of BLOAT...
442:
443: c = new char[data.length];
444:
445: for (int i = 0; i < data.length; i++) {
446: c[i] = (char) (data[i] + 0x8000);
447: }
448: } else if (elementType.equals(Type.INTEGER)) {
449: // Fill the string with int (32-bit) data. ints are stored as
450: // chars in big-endian format
451: c = new char[data.length * 2];
452:
453: int j = 0;
454:
455: for (int i = 0; i < data.length; i++) {
456: final int n = data[i];
457: c[j++] = (char) ((n >>> 16) & 0xffff);
458: c[j++] = (char) ((n >>> 0) & 0xffff);
459: }
460: } else {
461: return;
462: }
463:
464: // The Strings of data divided into 32K chunks. Each chunk is an
465: // element in the ArrayList
466: final ArrayList image = new ArrayList();
467:
468: // The start index in the array for each segment of the image.
469: final ArrayList startIndex = new ArrayList();
470:
471: // The end index+1 in the array for each segment of the image.
472: final ArrayList endIndex = new ArrayList();
473:
474: StringBuffer sb = new StringBuffer();
475: int utfLength = 0;
476: startIndex.add(new Integer(0));
477:
478: // Iterate over every character in the array buffer. Use a
479: // StringBuffer to create String of length less than 32K.
480: for (int i = 0; i < c.length; i++) {
481: final char n = c[i];
482: int len = 0;
483:
484: if (n == '\u0000') {
485: len = 2;
486: } else if (n < '\u0800') {
487: len = 1;
488: } else if (n < '\u8000') {
489: len = 2;
490: } else {
491: len = 3;
492: }
493:
494: if (utfLength + len > 32767) {
495: // We've reached the limit on the size of the constant pool
496: // string.
497: // Add the current string buffer, and make a new one.
498: image.add(sb.toString());
499: endIndex.add(new Integer(i));
500:
501: sb = new StringBuffer();
502: utfLength = 0;
503: startIndex.add(new Integer(i));
504: }
505:
506: sb.append(n);
507: utfLength += len;
508: }
509:
510: if (sb.length() > 0) {
511: // If we've got leftovers, add it to the end of the current image
512: // entry.
513: image.add(sb.toString());
514: endIndex.add(new Integer(data.length));
515: } else {
516: startIndex.remove(startIndex.size() - 1);
517: }
518:
519: int bufStart = -1;
520:
521: // Remove the old code, leaving just the creation of the array!!!!!
522:
523: for (int i = buf.size() - 1; i >= 0; i--) {
524: final Instruction inst = (Instruction) buf.get(i);
525: if (inst.opcodeClass() == Opcode.opcx_newarray) {
526: // ..., ldc, new, dup ldc ldc store, dup ldc ldc store, ...
527: buf.removeRange(i + 1, buf.size());
528: bufStart = i;
529: break;
530: }
531: }
532:
533: if (bufStart == -1) {
534: // There was no code to remove? Something went wrong. Run away!
535: return;
536: }
537:
538: // Insert the new:
539: if (elementType.equals(Type.CHARACTER)) {
540: // We envoke the method String.getChars() to copy characters from
541: // a String object (the UTF8 constant in the constant pool) to
542: // a character array. Remember that the destination array is on
543: // the top of the stack.
544:
545: final LocalVariable array = m.newLocal(Type.OBJECT); // character
546: // array
547:
548: buf.add(new Instruction(Opcode.opcx_dup, array));
549: buf.add(new Instruction(Opcode.opcx_astore, array));
550:
551: // Call getChars() for every image
552:
553: for (int i = 0; i < image.size(); i++) {
554: final String im = (String) image.get(i);
555: final Integer start = (Integer) startIndex.get(i);
556:
557: // void getChars(int srcBegin, int srcEnd, char dst[],
558: // int dstBegin)
559:
560: buf.add(new Instruction(Opcode.opcx_ldc, im)); // String
561: buf
562: .add(new Instruction(Opcode.opcx_ldc,
563: new Integer(0)));
564: buf.add(new Instruction(Opcode.opcx_ldc, new Integer(im
565: .length())));
566: buf.add(new Instruction(Opcode.opcx_aload, array));
567: buf.add(new Instruction(Opcode.opcx_ldc, start)); // dstBegin
568: buf.add(new Instruction(Opcode.opcx_invokevirtual,
569: CompactArrayInitializer.GET_CHARS));
570: }
571:
572: } else {
573:
574: // Loading and storing non-character data is a little more
575: // tricky. First we must read the UTF8 string into a character
576: // array. The we must go through the array and pick out the
577: // elements of the int, short, byte/boolean array.
578:
579: // array is a character array used to hold the UTF8 string
580: // index1 is an index into the destination (int, boolean, etc.)
581: // array and index2 is an index into the char array from the
582: // constant pool. tmp is a temporary char local variable that
583: // is used because booleans and bytes need to be left shifted.
584:
585: final LocalVariable array = m.newLocal(Type.OBJECT); // char
586: // array
587: final LocalVariable index1 = m.newLocal(Type.INTEGER);
588: final LocalVariable index2 = m.newLocal(Type.INTEGER);
589: LocalVariable tmp = null;
590:
591: if (elementType.equals(Type.BYTE)
592: || elementType.equals(Type.BOOLEAN)) {
593: tmp = m.newLocal(Type.CHARACTER);
594: }
595:
596: // Call getChars() to read the UTF8 string from the constant
597: // pool into an array of characters, array.
598:
599: for (int i = 0; i < image.size(); i++) {
600: final Label top = m.newLabel();
601: top.setStartsBlock(true);
602:
603: final Label bottom = m.newLabel();
604: bottom.setStartsBlock(true);
605:
606: final String im = (String) image.get(i);
607: final Integer start = (Integer) startIndex.get(i);
608: final Integer end = (Integer) endIndex.get(i);
609:
610: if (CompactArrayInitializer.DEBUG) {
611: System.out.println("image " + im);
612: System.out.println("start " + start);
613: System.out.println("end " + end);
614: }
615:
616: buf.add(new Instruction(Opcode.opcx_ldc, start));
617: buf.add(new Instruction(Opcode.opcx_istore, index1));
618:
619: buf
620: .add(new Instruction(Opcode.opcx_ldc,
621: new Integer(0)));
622: buf.add(new Instruction(Opcode.opcx_istore, index2));
623:
624: // Create a new array of characters and copy the UTF8 string
625: // into it.
626: buf.add(new Instruction(Opcode.opcx_ldc, new Integer(im
627: .length())));
628: buf.add(new Instruction(Opcode.opcx_newarray,
629: Type.CHARACTER));
630: buf.add(new Instruction(Opcode.opcx_astore, array));
631: buf.add(new Instruction(Opcode.opcx_ldc, im));
632: buf
633: .add(new Instruction(Opcode.opcx_ldc,
634: new Integer(0)));
635: buf.add(new Instruction(Opcode.opcx_ldc, new Integer(im
636: .length())));
637: buf.add(new Instruction(Opcode.opcx_aload, array));
638: buf
639: .add(new Instruction(Opcode.opcx_ldc,
640: new Integer(0)));
641: buf.add(new Instruction(Opcode.opcx_invokevirtual,
642: CompactArrayInitializer.GET_CHARS));
643:
644: // Start the fill loop for [start[i], end[i]).
645: buf.add(top);
646:
647: // Store the image data into the data array
648: // (at the top of the stack).
649: if (elementType.equals(Type.SHORT)) {
650: // Load an integer from the character array and then
651: // subtract
652: // 32768 (0x8000) from it. Convert the integer to a short
653: // and store it in the destination array (which happens to
654: // be
655: // on the top of the stack).
656:
657: buf.add(new Instruction(Opcode.opcx_dup));
658: buf.add(new Instruction(Opcode.opcx_iload, index1));
659: buf.add(new Instruction(Opcode.opcx_iinc,
660: new IncOperand(index1, 1)));
661: buf.add(new Instruction(Opcode.opcx_aload, array));
662: buf.add(new Instruction(Opcode.opcx_iload, index2));
663: buf.add(new Instruction(Opcode.opcx_iinc,
664: new IncOperand(index2, 1)));
665: buf.add(new Instruction(Opcode.opcx_caload));
666: buf.add(new Instruction(Opcode.opcx_ldc,
667: new Integer(32768)));
668: buf.add(new Instruction(Opcode.opcx_isub));
669: buf.add(new Instruction(Opcode.opcx_i2s));
670: buf.add(new Instruction(Opcode.opcx_sastore));
671:
672: } else if (elementType.equals(Type.BYTE)
673: || elementType.equals(Type.BOOLEAN)) {
674: // For byte (and boolean) arrays we need to use a temporary
675: // variable to hold the character because it needs to be
676: // shifted. Recall that two bytes were glued together into
677: // one character.
678:
679: // Incremenet index2 and load the character from the
680: // character array and store it in tmp.
681: // t = c[j++]
682: buf.add(new Instruction(Opcode.opcx_aload, array));
683: buf.add(new Instruction(Opcode.opcx_iload, index2));
684: buf.add(new Instruction(Opcode.opcx_iinc,
685: new IncOperand(index2, 1)));
686: buf.add(new Instruction(Opcode.opcx_caload));
687: buf.add(new Instruction(Opcode.opcx_istore, tmp));
688:
689: // Store the higher 8 bits of tmp into the byte array
690: // b[i++] = (byte) (t >>> 8)
691: buf.add(new Instruction(Opcode.opcx_dup));
692: buf.add(new Instruction(Opcode.opcx_iload, index1));
693: buf.add(new Instruction(Opcode.opcx_iinc,
694: new IncOperand(index1, 1)));
695: buf.add(new Instruction(Opcode.opcx_iload, tmp));
696: buf.add(new Instruction(Opcode.opcx_ldc,
697: new Integer(8)));
698: buf.add(new Instruction(Opcode.opcx_iushr));
699: buf.add(new Instruction(Opcode.opcx_i2b));
700: buf.add(new Instruction(Opcode.opcx_bastore));
701:
702: // If we've read the last byte, go home
703: // if (i >= end) break
704: buf.add(new Instruction(Opcode.opcx_iload, index1));
705: buf.add(new Instruction(Opcode.opcx_ldc, end));
706: buf.add(new Instruction(Opcode.opcx_if_icmpge,
707: bottom));
708:
709: // Add a new label because we're starting a new basic
710: // block(?)
711: final Label nobreak = m.newLabel();
712: nobreak.setStartsBlock(true);
713: buf.add(nobreak);
714:
715: // Store the lower order 8 bits of tmp into the byte array
716: // b[i++] = (byte) (t & 0xff)
717: buf.add(new Instruction(Opcode.opcx_dup));
718: buf.add(new Instruction(Opcode.opcx_iload, index1));
719: buf.add(new Instruction(Opcode.opcx_iinc,
720: new IncOperand(index1, 1)));
721: buf.add(new Instruction(Opcode.opcx_iload, tmp));
722: buf.add(new Instruction(Opcode.opcx_ldc,
723: new Integer(0xff)));
724: buf.add(new Instruction(Opcode.opcx_iand));
725: buf.add(new Instruction(Opcode.opcx_i2b));
726: buf.add(new Instruction(Opcode.opcx_bastore));
727:
728: } else if (elementType.equals(Type.INTEGER)) {
729: // Recall that an integer is 32 bits and is therefore
730: // contained in two characters. So, read the first, then
731: // read the second.
732:
733: // Increment index1 and index2 and load the character from
734: // the character array.
735: buf.add(new Instruction(Opcode.opcx_dup));
736: buf.add(new Instruction(Opcode.opcx_iload, index1));
737: buf.add(new Instruction(Opcode.opcx_iinc,
738: new IncOperand(index1, 1)));
739:
740: buf.add(new Instruction(Opcode.opcx_aload, array));
741: buf.add(new Instruction(Opcode.opcx_iload, index2));
742: buf.add(new Instruction(Opcode.opcx_iinc,
743: new IncOperand(index2, 1)));
744: buf.add(new Instruction(Opcode.opcx_caload));
745:
746: // Isolate the high-order 16 bits by shifting left
747: buf.add(new Instruction(Opcode.opcx_ldc,
748: new Integer(16)));
749: buf.add(new Instruction(Opcode.opcx_ishl));
750:
751: // Increment index2 and obtain the character containing the
752: // low-order 16 bits of the integer
753: buf.add(new Instruction(Opcode.opcx_aload, array));
754: buf.add(new Instruction(Opcode.opcx_iload, index2));
755: buf.add(new Instruction(Opcode.opcx_iinc,
756: new IncOperand(index2, 1)));
757: buf.add(new Instruction(Opcode.opcx_caload));
758:
759: // Or the higher-order bits and the lower-order bits
760: // together
761: // and store the result in the integer array.
762: buf.add(new Instruction(Opcode.opcx_ior));
763: buf.add(new Instruction(Opcode.opcx_iastore));
764: }
765:
766: // Branch back if we're not out of the loop.
767: // while (i < end)
768: buf.add(new Instruction(Opcode.opcx_iload, index1));
769: buf.add(new Instruction(Opcode.opcx_ldc, end));
770: buf.add(new Instruction(Opcode.opcx_if_icmplt, top));
771:
772: buf.add(bottom);
773: }
774: }
775:
776: if (CompactArrayInitializer.DEBUG) {
777: for (int i = bufStart; i < buf.size(); i++) {
778: System.out.println("fill[" + i + "] " + buf.get(i));
779: }
780: }
781: }
782: }
783:
784: /**
785: * Recall that Nate used beta versions of the JDK1.2 util classes to build
786: * BLOAT. While most of the conversion to the final util API was simple, there
787: * were a couple of changes made that force us to make some changes.
788: *
789: * The final version of the API makes the ArrayList.removeRange() method
790: * protected. So, we have to make this silly wrapper class in order to access
791: * it. Silly.
792: */
793: class ArrayList2 extends ArrayList {
794: public ArrayList2(final int initialCapacity) {
795: super (initialCapacity);
796: }
797:
798: public void removeRange(final int fromIndex, final int toIndex) {
799: super.removeRange(fromIndex, toIndex);
800: }
801: }
|