001: /* Instruction Copyright (C) 1999-2002 Jochen Hoenicke.
002: *
003: * This program is free software; you can redistribute it and/or modify
004: * it under the terms of the GNU Lesser General Public License as published by
005: * the Free Software Foundation; either version 2, or (at your option)
006: * any later version.
007: *
008: * This program is distributed in the hope that it will be useful,
009: * but WITHOUT ANY WARRANTY; without even the implied warranty of
010: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
011: * GNU General Public License for more details.
012: *
013: * You should have received a copy of the GNU Lesser General Public License
014: * along with this program; see the file COPYING.LESSER. If not, write to
015: * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
016: *
017: * $Id: Instruction.java,v 1.9.2.1 2002/05/28 17:34:00 hoenicke Exp $
018: */
019:
020: package jode.bytecode;
021:
022: /**
023: * This class represents an instruction in the byte code.
024: *
025: */
026: public final class Instruction implements Opcodes {
027: /**
028: * The opcode of the instruction. We map some opcodes, e.g.
029: * <pre>
030: * iload_[0-3] -> iload, ldc_w -> ldc, wide iinc -> iinc.
031: * </pre>
032: */
033: // a byte would be enough, but then we would need an unsigned convert.
034: private int opcode;
035: /**
036: * If this opcode uses a local this gives the slot. For multianewarray
037: * this gives the dimension.
038: */
039: private int shortData;
040: /**
041: * The address of this opcode.
042: */
043: private int addr;
044: /**
045: * Optional object data for this opcode. There are four different
046: * usages of this field:
047: * <dl>
048: * <dt>opc_ldc / opc_ldc2_w</dt>
049: * <dd>The constant of type Integer/Long/Float/Double/String. </dd>
050: * <dt>opc_invokexxx / opc_xxxfield / opc_xxxstatic</dt>
051: * <dd>The field/method Reference</dd>
052: * <dt>opc_new / opc_checkcast / opc_instanceof / opc_multianewarray</dt>
053: * <dd>The typesignature of the class/array</dd>
054: * <dt>opc_lookupswitch</dt>
055: * <dd>The array of values of type int[]</dd>
056: * </dl>
057: */
058: private Object objData;
059: /**
060: * The successors of this opcodes, where flow may lead to
061: * (except that nextByAddr is implicit if !alwaysJump). The
062: * value null means no successor, if there is one succesor, this
063: * is of type Instruction, otherwise, this is an array of Instruction.
064: */
065: private Object succs;
066: /**
067: * The predecessors of this opcode, orthogonal to the succs array.
068: * This must be null or a non empty array.
069: */
070: private Instruction[] preds;
071: /**
072: * The next instruction in code order.
073: */
074: Instruction nextByAddr;
075: /**
076: * The previous instruction in code order, useful when changing
077: * the order.
078: */
079: Instruction prevByAddr;
080:
081: /**
082: * You can use this field to add some info to each instruction.
083: * After using, you must set it to null again.
084: * @XXX Do we really need this. Every field here can quickly take
085: * half a megabyte!
086: */
087: private Object tmpInfo;
088:
089: public Instruction(int opcode) {
090: this .opcode = opcode;
091: }
092:
093: /**
094: * Returns the opcode of the instruction. We map some opcodes:
095: * <pre>
096: * [iflda]load_x -> [iflda]load
097: * [iflda]store_x -> [iflda]store
098: * [ifa]const_xx, ldc_w -> ldc
099: * [dl]const_xx -> ldc2_w
100: * wide opcode -> opcode
101: * tableswitch -> lookupswitch
102: * [a]newarray -> multianewarray
103: * </pre>
104: */
105: public final int getOpcode() {
106: return opcode;
107: }
108:
109: /**
110: * Returns the address of this opcode. As long as you don't remove
111: * or insert instructions, you can be sure, that the addresses of the
112: * opcodes are unique, and that
113: * <pre>
114: * instr.getAddr() + instr.getLength() == instr.getNextByAddr().getAddr()
115: * <pre>
116: *
117: * If you insert/remove Instructions, you should be aware that the
118: * above property is not guaranteed anymore.
119: */
120: public final int getAddr() {
121: return addr;
122: }
123:
124: public final int getNextAddr() {
125: return nextByAddr.addr;
126: }
127:
128: /**
129: * Returns the length of this opcode. See getAddr() for some
130: * notes. Note that the length doesn't necessarily reflect the
131: * real length, when this bytecode is written again, since the
132: * length of an ldc instruction depends on the number of entries
133: * in constant pool, and the order they are allocated.
134: */
135: public final int getLength() {
136: return getNextAddr() - addr;
137: }
138:
139: final void setAddr(int addr) {
140: this .addr = addr;
141: }
142:
143: public final boolean hasLocalSlot() {
144: return opcode == opc_iinc || opcode == opc_ret
145: || opcode >= opc_iload && opcode <= opc_aload
146: || opcode >= opc_istore && opcode <= opc_astore;
147: }
148:
149: public final int getLocalSlot()
150: /*{ require { hasLocalSlot()
151: :: "Instruction has no slot" } }*/
152: {
153: return shortData;
154: }
155:
156: public final void setLocalSlot(int slot)
157: /*{ require { hasLocalSlot()
158: :: "Instruction has no slot" } }*/
159: {
160: shortData = slot;
161: }
162:
163: /**
164: * Optional integer data for this opcode. There are various uses
165: * for this:
166: * <dl>
167: * <dt>opc_iinc</dt>
168: * <dd>The value by which the constant is increased/decreased. (short)</dd>
169: * <dt>opc_multianewarray</dt>
170: * <dd>The number of dimensions (1..255)</dd>
171: * </dl>
172: */
173: public final int getIncrement()
174: /*{ require { opcode == opc_iinc || opcode == opc_multianewarray
175: || opcode == opc_tableswitch
176: :: "Instruction has no int data" } }*/
177: {
178: /* shortData already used for local slot */
179: return ((Short) objData).shortValue();
180: }
181:
182: /**
183: * Optional integer data for this opcode. There are various uses
184: * for this:
185: * <dl>
186: * <dt>opc_iinc</dt>
187: * <dd>The value by which the constant is increased/decreased. (short)</dd>
188: * <dt>opc_multianewarray</dt>
189: * <dd>The number of dimensions (1..255)</dd>
190: * </dl>
191: */
192: public final void setIncrement(int incr)
193: /*{ require { opcode == opc_iinc || opcode == opc_multianewarray
194: :: "Instruction has no int data" } }*/
195: {
196: /* shortData already used for local slot */
197: objData = new Short((short) incr);
198: }
199:
200: /**
201: *
202: */
203: public final int getDimensions()
204: /*{ require { opcode == opc_multianewarray
205: :: "Instruction has no dimensions" } }*/
206: {
207: return shortData;
208: }
209:
210: /**
211: *
212: */
213: public final void setDimensions(int dims)
214: /*{ require { opcode == opc_multianewarray
215: :: "Instruction has no dimensions" } }*/
216: {
217: shortData = dims;
218: }
219:
220: public final Object getConstant()
221: /*{ require { opcode == opc_ldc || opcode == opc_ldc2_w
222: :: "Instruction has no constant" } }*/
223: {
224: return objData;
225: }
226:
227: public final void setConstant(Object constant)
228: /*{ require { opcode == opc_ldc || opcode == opc_ldc2_w
229: :: "Instruction has no constant" } }*/
230: {
231: objData = constant;
232: }
233:
234: public final Reference getReference()
235: /*{ require { opcode >= opc_getstatic && opcode <= opc_invokeinterface
236: :: "Instruction has no reference" } }*/
237: {
238: return (Reference) objData;
239: }
240:
241: public final void setReference(Reference ref)
242: /*{ require { opcode >= opc_getstatic && opcode <= opc_invokeinterface
243: :: "Instruction has no reference" } }*/
244: {
245: objData = ref;
246: }
247:
248: public final String getClazzType()
249: /*{ require { opcode == opc_new
250: || opcode == opc_checkcast
251: || opcode == opc_instanceof
252: || opcode == opc_multianewarray
253: :: "Instruction has no typesig" } }*/
254: {
255: return (String) objData;
256: }
257:
258: public final void setClazzType(String type)
259: /*{ require { opcode == opc_new
260: || opcode == opc_checkcast
261: || opcode == opc_instanceof
262: || opcode == opc_multianewarray
263: :: "Instruction has no typesig" } }*/
264: {
265: objData = type;
266: }
267:
268: public final int[] getValues()
269: /*{ require { opcode == opc_lookupswitch
270: :: "Instruction has no values" } }*/
271: {
272: return (int[]) objData;
273: }
274:
275: public final void setValues(int[] values)
276: /*{ require { opcode == opc_lookupswitch
277: :: "Instruction has no values" } }*/
278: {
279: objData = values;
280: }
281:
282: public final boolean doesAlwaysJump() {
283: switch (opcode) {
284: case opc_ret:
285: case opc_goto:
286: case opc_jsr:
287: case opc_tableswitch:
288: case opc_lookupswitch:
289: case opc_ireturn:
290: case opc_lreturn:
291: case opc_freturn:
292: case opc_dreturn:
293: case opc_areturn:
294: case opc_return:
295: case opc_athrow:
296: return true;
297: default:
298: return false;
299: }
300: }
301:
302: public final Instruction[] getPreds() {
303: return preds;
304: }
305:
306: /**
307: * Returns true if this opcode has successors, other than the implicit
308: * getNextByAddr().
309: */
310: public boolean hasSuccs() {
311: return succs != null;
312: }
313:
314: /**
315: * Returns the successors of this opcodes, where flow may lead to
316: * (except that nextByAddr is implicit if !alwaysJump). The
317: * value null means that there is no successor.
318: */
319: public final Instruction[] getSuccs() {
320: if (succs instanceof Instruction)
321: return new Instruction[] { (Instruction) succs };
322: return (Instruction[]) succs;
323: }
324:
325: /**
326: * Returns the single successor of this opcodes. This gives the
327: * target of a goto, jsr, or if opcode.
328: * @return null if there is no successor, otherwise the successor.
329: * @exception ClassCastException if this has more than one succ.
330: */
331: public final Instruction getSingleSucc() {
332: return (Instruction) succs;
333: }
334:
335: public final Instruction getPrevByAddr() {
336: if (prevByAddr.opcode == opc_impdep1)
337: return null;
338: return prevByAddr;
339: }
340:
341: public final Instruction getNextByAddr() {
342: if (nextByAddr.opcode == opc_impdep1)
343: return null;
344: return nextByAddr;
345: }
346:
347: public final Object getTmpInfo() {
348: return tmpInfo;
349: }
350:
351: public final void setTmpInfo(Object info) {
352: tmpInfo = info;
353: }
354:
355: // INTERNAL FUNCTIONS TO KEEP PREDS AND SUCCS CONSISTENT
356:
357: final void removeSuccs() {
358: if (succs == null)
359: return;
360: if (succs instanceof Instruction[]) {
361: Instruction[] ss = (Instruction[]) succs;
362: for (int i = 0; i < ss.length; i++)
363: if (ss[i] != null)
364: ss[i].removePredecessor(this );
365: } else
366: ((Instruction) succs).removePredecessor(this );
367: succs = null;
368: }
369:
370: /**
371: * @param to may be null
372: */
373: private final void promoteSuccs(Instruction from, Instruction to) {
374: if (succs == from)
375: succs = to;
376: else if (succs instanceof Instruction[]) {
377: Instruction[] ss = (Instruction[]) succs;
378: for (int i = 0; i < ss.length; i++)
379: if (ss[i] == from)
380: ss[i] = to;
381: }
382: }
383:
384: /**
385: * @exception ClassCastException if newSuccs is neither an Instruction
386: * nor an array of instructions.
387: */
388: public final void setSuccs(Object newSuccs) {
389: if (succs == newSuccs)
390: return;
391: removeSuccs();
392: if (newSuccs == null)
393: return;
394: if (newSuccs instanceof Instruction[]) {
395: Instruction[] ns = (Instruction[]) newSuccs;
396: switch (ns.length) {
397: case 0:
398: break;
399: case 1:
400: succs = ns[0];
401: ns[0].addPredecessor(this );
402: break;
403: default:
404: succs = ns;
405: for (int i = 0; i < ns.length; i++)
406: ns[i].addPredecessor(this );
407: break;
408: }
409: } else {
410: succs = newSuccs;
411: ((Instruction) newSuccs).addPredecessor(this );
412: }
413: }
414:
415: void addPredecessor(Instruction pred) {
416: if (preds == null) {
417: preds = new Instruction[] { pred };
418: return;
419: }
420: int predsLength = preds.length;
421: Instruction[] newPreds = new Instruction[predsLength + 1];
422: System.arraycopy(preds, 0, newPreds, 0, predsLength);
423: newPreds[predsLength] = pred;
424: preds = newPreds;
425: }
426:
427: void removePredecessor(Instruction pred) {
428: /* Hopefully it doesn't matter if this is slow */
429: int predLength = preds.length;
430: if (predLength == 1) {
431: if (preds[0] != pred)
432: throw new jode.AssertError(
433: "removing not existing predecessor");
434: preds = null;
435: } else {
436: Instruction[] newPreds = new Instruction[predLength - 1];
437: int j;
438: for (j = 0; preds[j] != pred; j++)
439: newPreds[j] = preds[j];
440: System.arraycopy(preds, j + 1, newPreds, j, predLength - j
441: - 1);
442: preds = newPreds;
443: }
444: }
445:
446: // ADDING, REMOVING AND REPLACING INSTRUCTIONS
447:
448: /**
449: * Replaces the opcode of this instruction. You should only use the
450: * mapped opcodes:
451: * <pre>
452: * [iflda]load_x -> [iflda]load
453: * [iflda]store_x -> [iflda]store
454: * [ifa]const_xx, ldc_w -> ldc
455: * [dl]const_xx -> ldc2_w
456: * wide opcode -> opcode
457: * tableswitch -> lookupswitch
458: * [a]newarray -> multianewarray
459: * </pre>
460: */
461: public final void replaceInstruction(Instruction newInstr,
462: BytecodeInfo codeinfo) {
463: /* remove predecessors of successors */
464: removeSuccs();
465:
466: newInstr.addr = addr;
467: nextByAddr.prevByAddr = newInstr;
468: newInstr.nextByAddr = nextByAddr;
469: prevByAddr.nextByAddr = newInstr;
470: newInstr.prevByAddr = prevByAddr;
471: prevByAddr = null;
472: nextByAddr = null;
473:
474: /* promote the successors of the predecessors to newInstr */
475: if (preds != null) {
476: for (int j = 0; j < preds.length; j++)
477: preds[j].promoteSuccs(this , newInstr);
478: newInstr.preds = preds;
479: preds = null;
480: }
481:
482: /* adjust exception handlers */
483: Handler[] handlers = codeinfo.getExceptionHandlers();
484: for (int i = 0; i < handlers.length; i++) {
485: if (handlers[i].start == this )
486: handlers[i].start = newInstr;
487: if (handlers[i].end == this )
488: handlers[i].end = newInstr;
489: if (handlers[i].catcher == this )
490: handlers[i].catcher = newInstr;
491: }
492:
493: /* adjust local variable table and line number table */
494: LocalVariableInfo[] lvt = codeinfo.getLocalVariableTable();
495: if (lvt != null) {
496: for (int i = 0; i < lvt.length; i++) {
497: if (lvt[i].start == this )
498: lvt[i].start = newInstr;
499: if (lvt[i].end == this )
500: lvt[i].end = newInstr;
501: }
502: }
503: LineNumber[] lnt = codeinfo.getLineNumberTable();
504: if (lnt != null) {
505: for (int i = 0; i < lnt.length; i++) {
506: if (lnt[i].start == this )
507: lnt[i].start = newInstr;
508: }
509: }
510: }
511:
512: void appendInstruction(Instruction newInstr, BytecodeInfo codeinfo) {
513: newInstr.addr = nextByAddr.addr;
514:
515: newInstr.nextByAddr = nextByAddr;
516: nextByAddr.prevByAddr = newInstr;
517: newInstr.prevByAddr = this ;
518: nextByAddr = newInstr;
519:
520: /* adjust exception handlers end */
521: Handler[] handlers = codeinfo.getExceptionHandlers();
522: if (handlers != null) {
523: for (int i = 0; i < handlers.length; i++) {
524: if (handlers[i].end == this )
525: handlers[i].end = newInstr;
526: }
527: }
528: }
529:
530: /**
531: * Removes this instruction (as if it would be replaced by a nop).
532: */
533: void removeInstruction(BytecodeInfo codeinfo) {
534:
535: /* remove from chained list and adjust addr / length */
536: prevByAddr.nextByAddr = nextByAddr;
537: nextByAddr.prevByAddr = prevByAddr;
538:
539: /* remove predecessors of successors */
540: removeSuccs();
541:
542: /* promote the predecessors to next instruction */
543: if (preds != null) {
544: for (int j = 0; j < preds.length; j++)
545: preds[j].promoteSuccs(this , nextByAddr);
546: if (nextByAddr.preds == null)
547: nextByAddr.preds = preds;
548: else {
549: Instruction[] newPreds = new Instruction[nextByAddr.preds.length
550: + preds.length];
551: System.arraycopy(nextByAddr.preds, 0, newPreds, 0,
552: nextByAddr.preds.length);
553: System.arraycopy(preds, 0, newPreds,
554: nextByAddr.preds.length, preds.length);
555: nextByAddr.preds = newPreds;
556: }
557: preds = null;
558: }
559:
560: /* adjust exception handlers */
561: Handler[] handlers = codeinfo.getExceptionHandlers();
562: for (int i = 0; i < handlers.length; i++) {
563: if (handlers[i].start == this && handlers[i].end == this ) {
564: /* Remove the handler.
565: * This is very seldom, so we can make it slow */
566: Handler[] newHandlers = new Handler[handlers.length - 1];
567: System.arraycopy(handlers, 0, newHandlers, 0, i);
568: System.arraycopy(handlers, i + 1, newHandlers, i,
569: handlers.length - (i + 1));
570: handlers = newHandlers;
571: codeinfo.setExceptionHandlers(newHandlers);
572: i--;
573: } else {
574: if (handlers[i].start == this )
575: handlers[i].start = nextByAddr;
576: if (handlers[i].end == this )
577: handlers[i].end = prevByAddr;
578: if (handlers[i].catcher == this )
579: handlers[i].catcher = nextByAddr;
580: }
581: }
582:
583: /* adjust local variable table and line number table */
584: LocalVariableInfo[] lvt = codeinfo.getLocalVariableTable();
585: if (lvt != null) {
586: for (int i = 0; i < lvt.length; i++) {
587: if (lvt[i].start == this && lvt[i].end == this ) {
588: /* Remove the local variable info.
589: * This is very seldom, so we can make it slow
590: */
591: LocalVariableInfo[] newLVT = new LocalVariableInfo[lvt.length - 1];
592: System.arraycopy(lvt, 0, newLVT, 0, i);
593: System.arraycopy(lvt, i + 1, newLVT, i,
594: newLVT.length - i);
595: lvt = newLVT;
596: codeinfo.setLocalVariableTable(newLVT);
597: i--;
598: } else {
599: if (lvt[i].start == this )
600: lvt[i].start = nextByAddr;
601: if (lvt[i].end == this )
602: lvt[i].end = prevByAddr;
603: }
604: }
605: }
606: LineNumber[] lnt = codeinfo.getLineNumberTable();
607: if (lnt != null) {
608: for (int i = 0; i < lnt.length; i++) {
609: if (lnt[i].start == this ) {
610: if (nextByAddr.opcode == opc_impdep1
611: || (i + 1 < lnt.length && lnt[i + 1].start == nextByAddr)) {
612: /* Remove the line number.
613: * This is very seldom, so we can make it slow */
614: LineNumber[] newLNT = new LineNumber[lnt.length - 1];
615: System.arraycopy(lnt, 0, newLNT, 0, i);
616: System.arraycopy(lnt, i + 1, newLNT, i,
617: newLNT.length - i);
618: lnt = newLNT;
619: codeinfo.setLineNumberTable(newLNT);
620: i--;
621: } else
622: lnt[i].start = nextByAddr;
623: }
624: }
625: }
626:
627: prevByAddr = null;
628: nextByAddr = null;
629: }
630:
631: public int compareTo(Instruction instr) {
632: if (addr != instr.addr)
633: return addr - instr.addr;
634: if (this == instr)
635: return 0;
636: do {
637: instr = instr.nextByAddr;
638: if (instr.addr > addr)
639: return -1;
640: } while (instr != this );
641: return 1;
642: }
643:
644: /**
645: * This returns the number of stack entries this instruction
646: * pushes and pops from the stack. The result fills the given
647: * array.
648: *
649: * @param poppush an array of two ints. The first element will
650: * get the number of pops, the second the number of pushes.
651: */
652: public void getStackPopPush(int[] poppush)
653: /*{ require { poppush != null && poppush.length == 2
654: :: "poppush must be an array of two ints" } } */
655: {
656: byte delta = (byte) stackDelta.charAt(opcode);
657: if (delta < 0x40) {
658: poppush[0] = delta & 7;
659: poppush[1] = delta >> 3;
660: } else {
661: switch (opcode) {
662: case opc_invokevirtual:
663: case opc_invokespecial:
664: case opc_invokestatic:
665: case opc_invokeinterface: {
666: Reference ref = getReference();
667: String typeSig = ref.getType();
668: poppush[0] = opcode != opc_invokestatic ? 1 : 0;
669: poppush[0] += TypeSignature.getArgumentSize(typeSig);
670: poppush[1] = TypeSignature.getReturnSize(typeSig);
671: break;
672: }
673:
674: case opc_putfield:
675: case opc_putstatic: {
676: Reference ref = getReference();
677: poppush[1] = 0;
678: poppush[0] = TypeSignature.getTypeSize(ref.getType());
679: if (opcode == opc_putfield)
680: poppush[0]++;
681: break;
682: }
683: case opc_getstatic:
684: case opc_getfield: {
685: Reference ref = getReference();
686: poppush[1] = TypeSignature.getTypeSize(ref.getType());
687: poppush[0] = opcode == opc_getfield ? 1 : 0;
688: break;
689: }
690:
691: case opc_multianewarray: {
692: poppush[1] = 1;
693: poppush[0] = getDimensions();
694: break;
695: }
696: default:
697: throw new jode.AssertError("Unknown Opcode: " + opcode);
698: }
699: }
700: }
701:
702: public Instruction findMatchingPop() {
703: int poppush[] = new int[2];
704: getStackPopPush(poppush);
705:
706: int count = poppush[1];
707: Instruction instr = this ;
708: while (true) {
709: if (instr.succs != null || instr.doesAlwaysJump())
710: return null;
711: instr = instr.nextByAddr;
712: if (instr.preds != null)
713: return null;
714:
715: instr.getStackPopPush(poppush);
716: if (count == poppush[0])
717: return instr;
718: count += poppush[1] - poppush[0];
719: }
720: }
721:
722: public Instruction findMatchingPush() {
723: int count = 0;
724: Instruction instr = this ;
725: int poppush[] = new int[2];
726: while (true) {
727: if (instr.preds != null)
728: return null;
729: instr = instr.prevByAddr;
730: if (instr == null || instr.succs != null
731: || instr.doesAlwaysJump())
732: return null;
733:
734: instr.getStackPopPush(poppush);
735: if (count < poppush[1]) {
736: return count == 0 ? instr : null;
737: }
738: count += poppush[0] - poppush[1];
739: }
740: }
741:
742: public String getDescription() {
743: StringBuffer result = new StringBuffer(String.valueOf(addr))
744: .append('_').append(Integer.toHexString(hashCode()))
745: .append(": ").append(opcodeString[opcode]);
746: if (opcode != opc_lookupswitch) {
747: if (hasLocalSlot())
748: result.append(' ').append(getLocalSlot());
749: if (succs != null)
750: result.append(' ').append(((Instruction) succs).addr);
751: if (objData != null)
752: result.append(' ').append(objData);
753: if (opcode == opc_multianewarray)
754: result.append(' ').append(getDimensions());
755: } else {
756: int[] values = getValues();
757: Instruction[] succs = getSuccs();
758: for (int i = 0; i < values.length; i++) {
759: result.append(' ').append(values[i]).append("->")
760: .append(((Instruction) succs[i]).addr);
761: }
762: result.append(' ').append("default: ").append(
763: ((Instruction) succs[values.length]).addr);
764: }
765: return result.toString();
766: }
767:
768: public String toString() {
769: return "" + addr + "_" + Integer.toHexString(hashCode());
770: }
771:
772: private final static String stackDelta = "\000\010\010\010\010\010\010\010\010\020\020\010\010\010\020\020\010\010\010\010\020\010\020\010\020\010\010\010\010\010\020\020\020\020\010\010\010\010\020\020\020\020\010\010\010\010\012\022\012\022\012\012\012\012\001\002\001\002\001\001\001\001\001\002\002\002\002\001\001\001\001\002\002\002\002\001\001\001\001\003\004\003\004\003\003\003\003\001\002\021\032\043\042\053\064\022\012\024\012\024\012\024\012\024\012\024\012\024\012\024\012\024\012\024\012\024\011\022\011\022\012\023\012\023\012\023\012\024\012\024\012\024\000\021\011\021\012\012\022\011\021\021\012\022\012\011\011\011\014\012\012\014\014\001\001\001\001\001\001\002\002\002\002\002\002\002\002\000\010\000\001\001\001\002\001\002\001\000\100\100\100\100\100\100\100\100\177\010\011\011\011\001\011\011\001\001\177\100\001\001\000\010";
773:
774: /* stackDelta contains \100 if stack count of opcode is variable
775: * \177 if opcode is illegal, or 8*stack_push + stack_pop otherwise
776: * The above values are extracted from following list with:
777: * perl -ne'/"(.*)"/ and print $1'
778: *
779: * "\000" // nop
780: * "\010\010\010\010\010\010\010\010" // aconst_null, iconst_m?[0-5]
781: * "\020\020\010\010\010\020\020" // [lfd]const_[0-2]
782: * "\010\010\010\010\020" // sipush bipush ldcx
783: * "\010\020\010\020\010" // [ilfda]load
784: * "\010\010\010\010"
785: * "\020\020\020\020"
786: * "\010\010\010\010"
787: * "\020\020\020\020"
788: * "\010\010\010\010"
789: * "\012\022\012\022\012\012\012\012" // [ilfdabcs]aload
790: * "\001\002\001\002\001" // [ilfda]store
791: * "\001\001\001\001"
792: * "\002\002\002\002"
793: * "\001\001\001\001"
794: * "\002\002\002\002"
795: * "\001\001\001\001"
796: * "\003\004\003\004\003\003\003\003" // [ilfdabcs]astore
797: * "\001\002" // pop
798: * "\021\032\043\042\053\064" // dup2?(_x[12])?
799: * "\022" // swap
800: * "\012\024\012\024" // [ilfd]add
801: * "\012\024\012\024" // [ilfd]sub
802: * "\012\024\012\024" // [ilfd]mul
803: * "\012\024\012\024" // [ilfd]div
804: * "\012\024\012\024" // [ilfd]rem
805: * "\011\022\011\022" // [ilfd]neg
806: * "\012\023\012\023\012\023" // [il]u?sh[lr]
807: * "\012\024\012\024\012\024" // [il](and|or|xor)
808: * "\000" // opc_iinc
809: * "\021\011\021" // i2[lfd]
810: * "\012\012\022" // l2[ifd]
811: * "\011\021\021" // f2[ild]
812: * "\012\022\012" // d2[ilf]
813: * "\011\011\011" // i2[bcs]
814: * "\014\012\012\014\014" // [lfd]cmp.?
815: * "\001\001\001\001\001\001" // if..
816: * "\002\002\002\002\002\002" // if_icmp..
817: * "\002\002" // if_acmp..
818: * "\000\010\000\001\001" // goto,jsr,ret, .*switch
819: * "\001\002\001\002\001\000" // [ilfda]?return
820: * "\100\100\100\100" // (get/put)(static|field)
821: * "\100\100\100\100" // invoke.*
822: * "\177\010\011\011\011" // 186 - 190
823: * "\001\011\011\001\001" // 191 - 195
824: * "\177\100\001\001" // 196 - 199
825: * "\000\010" // goto_w, jsr_w
826: */
827: }
|