001: /*
002: * Copyright 2001-2005 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.java.util.jar.pack;
027:
028: /**
029: * A parsed bytecode instruction.
030: * Provides accessors to various relevant bits.
031: * @author John Rose
032: * @version 1.19, 05/05/07
033: */
034: class Instruction implements Constants {
035: protected byte[] bytes; // bytecodes
036: protected int pc; // location of this instruction
037: protected int bc; // opcode of this instruction
038: protected int w; // 0 if normal, 1 if a _wide prefix at pc
039: protected int length; // bytes in this instruction
040:
041: protected boolean special;
042:
043: protected Instruction(byte[] bytes, int pc, int bc, int w,
044: int length) {
045: reset(bytes, pc, bc, w, length);
046: }
047:
048: private void reset(byte[] bytes, int pc, int bc, int w, int length) {
049: this .bytes = bytes;
050: this .pc = pc;
051: this .bc = bc;
052: this .w = w;
053: this .length = length;
054: }
055:
056: public int getBC() {
057: return bc;
058: }
059:
060: public boolean isWide() {
061: return w != 0;
062: }
063:
064: public byte[] getBytes() {
065: return bytes;
066: }
067:
068: public int getPC() {
069: return pc;
070: }
071:
072: public int getLength() {
073: return length;
074: }
075:
076: public int getNextPC() {
077: return pc + length;
078: }
079:
080: public Instruction next() {
081: int npc = pc + length;
082: if (npc == bytes.length)
083: return null;
084: else
085: return Instruction.at(bytes, npc, this );
086: }
087:
088: public boolean isNonstandard() {
089: return isNonstandard(bc);
090: }
091:
092: public void setNonstandardLength(int length) {
093: assert (isNonstandard());
094: this .length = length;
095: }
096:
097: /** A fake instruction at this pc whose next() will be at nextpc. */
098: public Instruction forceNextPC(int nextpc) {
099: int length = nextpc - pc;
100: return new Instruction(bytes, pc, -1, -1, length);
101: }
102:
103: public static Instruction at(byte[] bytes, int pc) {
104: return Instruction.at(bytes, pc, null);
105: }
106:
107: public static Instruction at(byte[] bytes, int pc, Instruction reuse) {
108: int bc = getByte(bytes, pc);
109: int prefix = -1;
110: int w = 0;
111: int length = BC_LENGTH[w][bc];
112: if (length == 0) {
113: // Hard cases:
114: switch (bc) {
115: case _wide:
116: bc = getByte(bytes, pc + 1);
117: w = 1;
118: length = BC_LENGTH[w][bc];
119: if (length == 0) {
120: // unknown instruction; treat as one byte
121: length = 1;
122: }
123: break;
124: case _tableswitch:
125: return new TableSwitch(bytes, pc);
126: case _lookupswitch:
127: return new LookupSwitch(bytes, pc);
128: default:
129: // unknown instruction; treat as one byte
130: length = 1;
131: break;
132: }
133: }
134: assert (length > 0);
135: assert (pc + length <= bytes.length);
136: // Speed hack: Instruction.next reuses self if possible.
137: if (reuse != null && !reuse.special) {
138: reuse.reset(bytes, pc, bc, w, length);
139: return reuse;
140: }
141: return new Instruction(bytes, pc, bc, w, length);
142: }
143:
144: // Return the constant pool reference type, or 0 if none.
145: public byte getCPTag() {
146: return BC_TAG[w][bc];
147: }
148:
149: // Return the constant pool index, or -1 if none.
150: public int getCPIndex() {
151: int indexLoc = BC_INDEX[w][bc];
152: if (indexLoc == 0)
153: return -1;
154: assert (w == 0);
155: if (length == 2)
156: return getByte(bytes, pc + indexLoc); // _ldc opcode only
157: else
158: return getShort(bytes, pc + indexLoc);
159: }
160:
161: public void setCPIndex(int cpi) {
162: int indexLoc = BC_INDEX[w][bc];
163: assert (indexLoc != 0);
164: if (length == 2)
165: setByte(bytes, pc + indexLoc, cpi); // _ldc opcode only
166: else
167: setShort(bytes, pc + indexLoc, cpi);
168: assert (getCPIndex() == cpi);
169: }
170:
171: public ConstantPool.Entry getCPRef(ConstantPool.Entry[] cpMap) {
172: int index = getCPIndex();
173: return (index < 0) ? null : cpMap[index];
174: }
175:
176: // Return the slot of the affected local, or -1 if none.
177: public int getLocalSlot() {
178: int slotLoc = BC_SLOT[w][bc];
179: if (slotLoc == 0)
180: return -1;
181: if (w == 0)
182: return getByte(bytes, pc + slotLoc);
183: else
184: return getShort(bytes, pc + slotLoc);
185: }
186:
187: // Return the target of the branch, or -1 if none.
188: public int getBranchLabel() {
189: int branchLoc = BC_BRANCH[w][bc];
190: if (branchLoc == 0)
191: return -1;
192: assert (w == 0);
193: assert (length == 3 || length == 5);
194: int offset;
195: if (length == 3)
196: offset = (short) getShort(bytes, pc + branchLoc);
197: else
198: offset = getInt(bytes, pc + branchLoc);
199: assert (offset + pc >= 0);
200: assert (offset + pc <= bytes.length);
201: return offset + pc;
202: }
203:
204: public void setBranchLabel(int targetPC) {
205: int branchLoc = BC_BRANCH[w][bc];
206: assert (branchLoc != 0);
207: if (length == 3)
208: setShort(bytes, pc + branchLoc, targetPC - pc);
209: else
210: setInt(bytes, pc + branchLoc, targetPC - pc);
211: assert (targetPC == getBranchLabel());
212: }
213:
214: // Return the trailing constant in the instruction (as a signed value).
215: // Return 0 if there is none.
216: public int getConstant() {
217: int conLoc = BC_CON[w][bc];
218: if (conLoc == 0)
219: return 0;
220: switch (length - conLoc) {
221: case 1:
222: return (byte) getByte(bytes, pc + conLoc);
223: case 2:
224: return (short) getShort(bytes, pc + conLoc);
225: }
226: assert (false);
227: return 0;
228: }
229:
230: public void setConstant(int con) {
231: int conLoc = BC_CON[w][bc];
232: assert (conLoc != 0);
233: switch (length - conLoc) {
234: case 1:
235: setByte(bytes, pc + conLoc, con);
236: break;
237: case 2:
238: setShort(bytes, pc + conLoc, con);
239: break;
240: }
241: assert (con == getConstant());
242: }
243:
244: public abstract static class Switch extends Instruction {
245: // Each case is a (value, label) pair, indexed 0 <= n < caseCount
246: public abstract int getCaseCount();
247:
248: public abstract int getCaseValue(int n);
249:
250: public abstract int getCaseLabel(int n);
251:
252: public abstract void setCaseCount(int caseCount);
253:
254: public abstract void setCaseValue(int n, int value);
255:
256: public abstract void setCaseLabel(int n, int targetPC);
257:
258: protected abstract int getLength(int caseCount);
259:
260: public int getDefaultLabel() {
261: return intAt(0) + pc;
262: }
263:
264: public void setDefaultLabel(int targetPC) {
265: setIntAt(0, targetPC - pc);
266: }
267:
268: protected int apc; // aligned pc (table base)
269:
270: protected int intAt(int n) {
271: return getInt(bytes, apc + n * 4);
272: }
273:
274: protected void setIntAt(int n, int x) {
275: setInt(bytes, apc + n * 4, x);
276: }
277:
278: protected Switch(byte[] bytes, int pc, int bc) {
279: super (bytes, pc, bc, /*w*/0, /*length*/0);
280: this .apc = alignPC(pc + 1);
281: this .special = true;
282: length = getLength(getCaseCount());
283: }
284:
285: public int getAlignedPC() {
286: return apc;
287: }
288:
289: public String toString() {
290: String s = super .toString();
291: s += " Default:" + labstr(getDefaultLabel());
292: int caseCount = getCaseCount();
293: for (int i = 0; i < caseCount; i++) {
294: s += "\n\tCase " + getCaseValue(i) + ":"
295: + labstr(getCaseLabel(i));
296: }
297: return s;
298: }
299:
300: public static int alignPC(int apc) {
301: while (apc % 4 != 0)
302: ++apc;
303: return apc;
304: }
305: }
306:
307: public static class TableSwitch extends Switch {
308: // apc: (df, lo, hi, (hi-lo+1)*(label))
309: public int getLowCase() {
310: return intAt(1);
311: }
312:
313: public int getHighCase() {
314: return intAt(2);
315: }
316:
317: public int getCaseCount() {
318: return intAt(2) - intAt(1) + 1;
319: }
320:
321: public int getCaseValue(int n) {
322: return getLowCase() + n;
323: }
324:
325: public int getCaseLabel(int n) {
326: return intAt(3 + n) + pc;
327: }
328:
329: public void setLowCase(int val) {
330: setIntAt(1, val);
331: }
332:
333: public void setHighCase(int val) {
334: setIntAt(2, val);
335: }
336:
337: public void setCaseLabel(int n, int tpc) {
338: setIntAt(3 + n, tpc - pc);
339: }
340:
341: public void setCaseCount(int caseCount) {
342: setHighCase(getLowCase() + caseCount - 1);
343: length = getLength(caseCount);
344: }
345:
346: public void setCaseValue(int n, int val) {
347: if (n != 0)
348: throw new UnsupportedOperationException();
349: int caseCount = getCaseCount();
350: setLowCase(val);
351: setCaseCount(caseCount); // keep invariant
352: }
353:
354: TableSwitch(byte[] bytes, int pc) {
355: super (bytes, pc, _tableswitch);
356: }
357:
358: protected int getLength(int caseCount) {
359: return (apc - pc) + (3 + caseCount) * 4;
360: }
361: }
362:
363: public static class LookupSwitch extends Switch {
364: // apc: (df, nc, nc*(case, label))
365: public int getCaseCount() {
366: return intAt(1);
367: }
368:
369: public int getCaseValue(int n) {
370: return intAt(2 + n * 2 + 0);
371: }
372:
373: public int getCaseLabel(int n) {
374: return intAt(2 + n * 2 + 1) + pc;
375: }
376:
377: public void setCaseCount(int caseCount) {
378: setIntAt(1, caseCount);
379: length = getLength(caseCount);
380: }
381:
382: public void setCaseValue(int n, int val) {
383: setIntAt(2 + n * 2 + 0, val);
384: }
385:
386: public void setCaseLabel(int n, int tpc) {
387: setIntAt(2 + n * 2 + 1, tpc - pc);
388: }
389:
390: LookupSwitch(byte[] bytes, int pc) {
391: super (bytes, pc, _lookupswitch);
392: }
393:
394: protected int getLength(int caseCount) {
395: return (apc - pc) + (2 + caseCount * 2) * 4;
396: }
397: }
398:
399: /** Two insns are equal if they have the same bytes. */
400: public boolean equals(Object o) {
401: return (o instanceof Instruction) && equals((Instruction) o);
402: }
403:
404: public boolean equals(Instruction that) {
405: if (this .bc != that.bc)
406: return false;
407: if (this .w != that.w)
408: return false;
409: if (this .length != that.length)
410: return false;
411: for (int i = 1; i < length; i++) {
412: if (this .bytes[this .pc + i] != that.bytes[that.pc + i])
413: return false;
414: }
415: return true;
416: }
417:
418: static String labstr(int pc) {
419: if (pc >= 0 && pc < 100000)
420: return ((100000 + pc) + "").substring(1);
421: return pc + "";
422: }
423:
424: public String toString() {
425: return toString(null);
426: }
427:
428: public String toString(ConstantPool.Entry[] cpMap) {
429: String s = labstr(pc) + ": ";
430: if (bc >= _bytecode_limit) {
431: s += Integer.toHexString(bc);
432: return s;
433: }
434: if (w == 1)
435: s += "wide ";
436: String bcname = (bc < BC_NAME.length) ? BC_NAME[bc] : null;
437: if (bcname == null) {
438: return s + "opcode#" + bc;
439: }
440: s += bcname;
441: int tag = getCPTag();
442: if (tag != 0)
443: s += " " + ConstantPool.tagName(tag) + ":";
444: int idx = getCPIndex();
445: if (idx >= 0)
446: s += (cpMap == null) ? "" + idx : "="
447: + cpMap[idx].stringValue();
448: int slt = getLocalSlot();
449: if (slt >= 0)
450: s += " Local:" + slt;
451: int lab = getBranchLabel();
452: if (lab >= 0)
453: s += " To:" + labstr(lab);
454: int con = getConstant();
455: if (con != 0)
456: s += " Con:" + con;
457: return s;
458: }
459:
460: //public static byte constantPoolTagFor(int bc) { return BC_TAG[0][bc]; }
461:
462: /// Fetching values from byte arrays:
463:
464: public int getIntAt(int off) {
465: return getInt(bytes, pc + off);
466: }
467:
468: public int getShortAt(int off) {
469: return getShort(bytes, pc + off);
470: }
471:
472: public int getByteAt(int off) {
473: return getByte(bytes, pc + off);
474: }
475:
476: public static int getInt(byte[] bytes, int pc) {
477: return (getShort(bytes, pc + 0) << 16)
478: + (getShort(bytes, pc + 2) << 0);
479: }
480:
481: public static int getShort(byte[] bytes, int pc) {
482: return (getByte(bytes, pc + 0) << 8)
483: + (getByte(bytes, pc + 1) << 0);
484: }
485:
486: public static int getByte(byte[] bytes, int pc) {
487: return bytes[pc] & 0xFF;
488: }
489:
490: public static void setInt(byte[] bytes, int pc, int x) {
491: setShort(bytes, pc + 0, x >> 16);
492: setShort(bytes, pc + 2, x >> 0);
493: }
494:
495: public static void setShort(byte[] bytes, int pc, int x) {
496: setByte(bytes, pc + 0, x >> 8);
497: setByte(bytes, pc + 1, x >> 0);
498: }
499:
500: public static void setByte(byte[] bytes, int pc, int x) {
501: bytes[pc] = (byte) x;
502: }
503:
504: // some bytecode classifiers
505:
506: public static boolean isNonstandard(int bc) {
507: return BC_LENGTH[0][bc] < 0;
508: }
509:
510: public static int opLength(int bc) {
511: int l = BC_LENGTH[0][bc];
512: assert (l > 0);
513: return l;
514: }
515:
516: public static int opWideLength(int bc) {
517: int l = BC_LENGTH[1][bc];
518: assert (l > 0);
519: return l;
520: }
521:
522: public static boolean isLocalSlotOp(int bc) {
523: return (bc < BC_SLOT[0].length && BC_SLOT[0][bc] > 0);
524: }
525:
526: public static boolean isBranchOp(int bc) {
527: return (bc < BC_BRANCH[0].length && BC_BRANCH[0][bc] > 0);
528: }
529:
530: public static boolean isCPRefOp(int bc) {
531: if (bc < BC_INDEX[0].length && BC_INDEX[0][bc] > 0)
532: return true;
533: if (bc >= _xldc_op && bc < _xldc_limit)
534: return true;
535: return false;
536: }
537:
538: public static byte getCPRefOpTag(int bc) {
539: if (bc < BC_INDEX[0].length && BC_INDEX[0][bc] > 0)
540: return BC_TAG[0][bc];
541: if (bc >= _xldc_op && bc < _xldc_limit)
542: return CONSTANT_Literal;
543: return CONSTANT_None;
544: }
545:
546: public static boolean isFieldOp(int bc) {
547: return (bc >= _getstatic && bc <= _putfield);
548: }
549:
550: public static boolean isInvokeInitOp(int bc) {
551: return (bc >= _invokeinit_op && bc < _invokeinit_limit);
552: }
553:
554: public static boolean isSelfLinkerOp(int bc) {
555: return (bc >= _self_linker_op && bc < _self_linker_limit);
556: }
557:
558: /// Format definitions.
559:
560: static private final byte[][] BC_LENGTH = new byte[2][0x100];
561: static private final byte[][] BC_INDEX = new byte[2][0x100];
562: static private final byte[][] BC_TAG = new byte[2][0x100];
563: static private final byte[][] BC_BRANCH = new byte[2][0x100];
564: static private final byte[][] BC_SLOT = new byte[2][0x100];
565: static private final byte[][] BC_CON = new byte[2][0x100];
566: static private final String[] BC_NAME = new String[0x100]; // debug only
567: static private final String[][] BC_FORMAT = new String[2][_bytecode_limit]; // debug only
568: static {
569: for (int i = 0; i < _bytecode_limit; i++) {
570: BC_LENGTH[0][i] = -1;
571: BC_LENGTH[1][i] = -1;
572: }
573: def("b", _nop, _dconst_1);
574: def("bx", _bipush);
575: def("bxx", _sipush);
576: def("bk", _ldc); // do not pack
577: def("bkk", _ldc_w, _ldc2_w); // do not pack
578: def("blwbll", _iload, _aload);
579: def("b", _iload_0, _saload);
580: def("blwbll", _istore, _astore);
581: def("b", _istore_0, _lxor);
582: def("blxwbllxx", _iinc);
583: def("b", _i2l, _dcmpg);
584: def("boo", _ifeq, _jsr); // pack oo
585: def("blwbll", _ret);
586: def("", _tableswitch, _lookupswitch); // pack all ints, omit padding
587: def("b", _ireturn, _return);
588: def("bkf", _getstatic, _putfield); // pack kf (base=Field)
589: def("bkm", _invokevirtual, _invokestatic); // pack kn (base=Method)
590: def("bkixx", _invokeinterface); // pack ki (base=IMethod), omit xx
591: def("", _xxxunusedxxx);
592: def("bkc", _new); // pack kc
593: def("bx", _newarray);
594: def("bkc", _anewarray); // pack kc
595: def("b", _arraylength, _athrow);
596: def("bkc", _checkcast, _instanceof ); // pack kc
597: def("b", _monitorenter, _monitorexit);
598: def("", _wide);
599: def("bkcx", _multianewarray); // pack kc
600: def("boo", _ifnull, _ifnonnull); // pack oo
601: def("boooo", _goto_w, _jsr_w); // pack oooo
602: for (int i = 0; i < _bytecode_limit; i++) {
603: //System.out.println(i+": l="+BC_LENGTH[0][i]+" i="+BC_INDEX[0][i]);
604: //assert(BC_LENGTH[0][i] != -1);
605: if (BC_LENGTH[0][i] == -1) {
606: assert (i == _xxxunusedxxx);
607: continue; // unknown opcode
608: }
609:
610: // Have a complete mapping, to support spurious _wide prefixes.
611: if (BC_LENGTH[1][i] == -1)
612: BC_LENGTH[1][i] = (byte) (1 + BC_LENGTH[0][i]);
613: }
614:
615: String names = "nop aconst_null iconst_m1 iconst_0 iconst_1 iconst_2 iconst_3 iconst_4 "
616: + "iconst_5 lconst_0 lconst_1 fconst_0 fconst_1 fconst_2 dconst_0 dconst_1 "
617: + "bipush sipush ldc ldc_w ldc2_w iload lload fload dload aload iload_0 "
618: + "iload_1 iload_2 iload_3 lload_0 lload_1 lload_2 lload_3 fload_0 fload_1 "
619: + "fload_2 fload_3 dload_0 dload_1 dload_2 dload_3 aload_0 aload_1 aload_2 "
620: + "aload_3 iaload laload faload daload aaload baload caload saload istore "
621: + "lstore fstore dstore astore istore_0 istore_1 istore_2 istore_3 lstore_0 "
622: + "lstore_1 lstore_2 lstore_3 fstore_0 fstore_1 fstore_2 fstore_3 dstore_0 "
623: + "dstore_1 dstore_2 dstore_3 astore_0 astore_1 astore_2 astore_3 iastore "
624: + "lastore fastore dastore aastore bastore castore sastore pop pop2 dup "
625: + "dup_x1 dup_x2 dup2 dup2_x1 dup2_x2 swap iadd ladd fadd dadd isub lsub "
626: + "fsub dsub imul lmul fmul dmul idiv ldiv fdiv ddiv irem lrem frem drem "
627: + "ineg lneg fneg dneg ishl lshl ishr lshr iushr lushr iand land ior lor "
628: + "ixor lxor iinc i2l i2f i2d l2i l2f l2d f2i f2l f2d d2i d2l d2f i2b i2c "
629: + "i2s lcmp fcmpl fcmpg dcmpl dcmpg ifeq ifne iflt ifge ifgt ifle if_icmpeq "
630: + "if_icmpne if_icmplt if_icmpge if_icmpgt if_icmple if_acmpeq if_acmpne "
631: + "goto jsr ret tableswitch lookupswitch ireturn lreturn freturn dreturn "
632: + "areturn return getstatic putstatic getfield putfield invokevirtual "
633: + "invokespecial invokestatic invokeinterface xxxunusedxxx new newarray "
634: + "anewarray arraylength athrow checkcast instanceof monitorenter "
635: + "monitorexit wide multianewarray ifnull ifnonnull goto_w jsr_w ";
636: for (int bc = 0; names.length() > 0; bc++) {
637: int sp = names.indexOf(' ');
638: BC_NAME[bc] = names.substring(0, sp);
639: names = names.substring(sp + 1);
640: }
641: }
642:
643: public static String byteName(int bc) {
644: String iname;
645: if (bc < BC_NAME.length && BC_NAME[bc] != null) {
646: iname = BC_NAME[bc];
647: } else if (isSelfLinkerOp(bc)) {
648: int idx = (bc - _self_linker_op);
649: boolean isSuper = (idx >= _self_linker_super _flag);
650: if (isSuper)
651: idx -= _self_linker_super _flag;
652: boolean isAload = (idx >= _self_linker_aload_flag);
653: if (isAload)
654: idx -= _self_linker_aload_flag;
655: int origBC = _first_linker_op + idx;
656: assert (origBC >= _first_linker_op && origBC <= _last_linker_op);
657: iname = BC_NAME[origBC];
658: iname += (isSuper ? "_super" : "_this");
659: if (isAload)
660: iname = "aload_0&" + iname;
661: iname = "*" + iname;
662: } else if (isInvokeInitOp(bc)) {
663: int idx = (bc - _invokeinit_op);
664: switch (idx) {
665: case _invokeinit_self_option:
666: iname = "*invokespecial_init_this";
667: break;
668: case _invokeinit_super _option:
669: iname = "*invokespecial_init_super";
670: break;
671: default:
672: assert (idx == _invokeinit_new_option);
673: iname = "*invokespecial_init_new";
674: break;
675: }
676: } else {
677: switch (bc) {
678: case _ildc:
679: iname = "*ildc";
680: break;
681: case _fldc:
682: iname = "*fldc";
683: break;
684: case _ildc_w:
685: iname = "*ildc_w";
686: break;
687: case _fldc_w:
688: iname = "*fldc_w";
689: break;
690: case _dldc2_w:
691: iname = "*dldc2_w";
692: break;
693: case _cldc:
694: iname = "*cldc";
695: break;
696: case _cldc_w:
697: iname = "*cldc_w";
698: break;
699: case _byte_escape:
700: iname = "*byte_escape";
701: break;
702: case _ref_escape:
703: iname = "*ref_escape";
704: break;
705: case _end_marker:
706: iname = "*end";
707: break;
708: default:
709: iname = "*bc#" + bc;
710: break;
711: }
712: }
713: return iname;
714: }
715:
716: private static int BW = 4; // width of classification field
717:
718: private static void def(String fmt, int bc) {
719: def(fmt, bc, bc);
720: }
721:
722: private static void def(String fmt, int from_bc, int to_bc) {
723: String[] fmts = { fmt, null };
724: if (fmt.indexOf('w') > 0) {
725: fmts[1] = fmt.substring(fmt.indexOf('w'));
726: fmts[0] = fmt.substring(0, fmt.indexOf('w'));
727: }
728: for (int w = 0; w <= 1; w++) {
729: fmt = fmts[w];
730: if (fmt == null)
731: continue;
732: int length = fmt.length();
733: int index = Math.max(0, fmt.indexOf('k'));
734: int tag = CONSTANT_None;
735: int branch = Math.max(0, fmt.indexOf('o'));
736: int slot = Math.max(0, fmt.indexOf('l'));
737: int con = Math.max(0, fmt.indexOf('x'));
738: if (index > 0 && index + 1 < length) {
739: switch (fmt.charAt(index + 1)) {
740: case 'c':
741: tag = CONSTANT_Class;
742: break;
743: case 'k':
744: tag = CONSTANT_Literal;
745: break;
746: case 'f':
747: tag = CONSTANT_Fieldref;
748: break;
749: case 'm':
750: tag = CONSTANT_Methodref;
751: break;
752: case 'i':
753: tag = CONSTANT_InterfaceMethodref;
754: break;
755: }
756: assert (tag != CONSTANT_None);
757: } else if (index > 0 && length == 2) {
758: assert (from_bc == _ldc);
759: tag = CONSTANT_Literal; // _ldc opcode only
760: }
761: for (int bc = from_bc; bc <= to_bc; bc++) {
762: BC_FORMAT[w][bc] = fmt;
763: assert (BC_LENGTH[w][bc] == -1);
764: BC_LENGTH[w][bc] = (byte) length;
765: BC_INDEX[w][bc] = (byte) index;
766: BC_TAG[w][bc] = (byte) tag;
767: assert (!(index == 0 && tag != CONSTANT_None));
768: BC_BRANCH[w][bc] = (byte) branch;
769: BC_SLOT[w][bc] = (byte) slot;
770: assert (branch == 0 || slot == 0); // not both branch & local
771: assert (branch == 0 || index == 0); // not both branch & cp
772: assert (slot == 0 || index == 0); // not both local & cp
773: BC_CON[w][bc] = (byte) con;
774: }
775: }
776: }
777: }
|