1 package serp.bytecode; 2 3 import serp.bytecode.lowlevel.*; 4 import serp.bytecode.visitor.*; 5 6 /*** 7 * Represents an instruction that manipulates the stack of the current 8 * frame. Using the {@link #setType} methods is a hint about the type being 9 * manipulated that might cause this instruction to use the wide version 10 * of the opcode it represents (if manipulating a long or double). This 11 * saves the developer from having to decide at compile time whether to 12 * use <code>pop</code> or <code>pop2</code>, etc. 13 * 14 * @author Abe White 15 */ 16 public class StackInstruction extends TypedInstruction { 17 StackInstruction(Code owner, int opcode) { 18 super(owner, opcode); 19 } 20 21 public int getStackChange() { 22 switch (getOpcode()) { 23 case Constants.POP: 24 return -1; 25 case Constants.POP2: 26 return -2; 27 case Constants.DUP: 28 case Constants.DUPX1: 29 case Constants.DUPX2: 30 return 1; 31 case Constants.DUP2: 32 case Constants.DUP2X1: 33 case Constants.DUP2X2: 34 return 2; 35 default: 36 return 0; 37 } 38 } 39 40 /*** 41 * This method will always return null; use {@link #isWide} to determine 42 * if this is pop2, dup2, etc. 43 */ 44 public String getTypeName() { 45 return null; 46 } 47 48 public TypedInstruction setType(String type) { 49 type = getProject().getNameCache().getExternalForm(type, false); 50 return setWide(long.class.getName().equals(type) 51 || double.class.getName().equals(type)); 52 } 53 54 /*** 55 * Return whether to use the wide form of the current opcode for 56 * operations on longs or doubles. 57 */ 58 public boolean isWide() { 59 switch (getOpcode()) { 60 case Constants.POP2: 61 case Constants.DUP2: 62 case Constants.DUP2X1: 63 case Constants.DUP2X2: 64 return true; 65 default: 66 return false; 67 } 68 } 69 70 /*** 71 * Set whether to use the wide form of the current opcode for operations 72 * on longs or doubles. 73 * 74 * @return this instruction, for method chaining 75 */ 76 public StackInstruction setWide(boolean wide) { 77 switch (getOpcode()) { 78 case Constants.POP: 79 if (wide) 80 setOpcode(Constants.POP2); 81 break; 82 case Constants.POP2: 83 if (!wide) 84 setOpcode(Constants.POP); 85 break; 86 case Constants.DUP: 87 if (wide) 88 setOpcode(Constants.DUP2); 89 break; 90 case Constants.DUP2: 91 if (!wide) 92 setOpcode(Constants.DUP); 93 break; 94 case Constants.DUPX1: 95 if (wide) 96 setOpcode(Constants.DUP2X1); 97 break; 98 case Constants.DUP2X1: 99 if (!wide) 100 setOpcode(Constants.DUPX1); 101 break; 102 case Constants.DUPX2: 103 if (wide) 104 setOpcode(Constants.DUP2X2); 105 break; 106 case Constants.DUP2X2: 107 if (!wide) 108 setOpcode(Constants.DUPX2); 109 break; 110 } 111 return this; 112 } 113 114 public void acceptVisit(BCVisitor visit) { 115 visit.enterStackInstruction(this); 116 visit.exitStackInstruction(this); 117 } 118 }