001 package serp.bytecode; 002 003 import serp.bytecode.lowlevel.*; 004 import serp.bytecode.visitor.*; 005 006 /** 007 * Represents an instruction that manipulates the stack of the current 008 * frame. Using the {@link #setType} methods is a hint about the type being 009 * manipulated that might cause this instruction to use the wide version 010 * of the opcode it represents (if manipulating a long or double). This 011 * saves the developer from having to decide at compile time whether to 012 * use <code>pop</code> or <code>pop2</code>, etc. 013 * 014 * @author Abe White 015 */ 016 public class StackInstruction extends TypedInstruction { 017 StackInstruction(Code owner, int opcode) { 018 super(owner, opcode); 019 } 020 021 public int getStackChange() { 022 switch (getOpcode()) { 023 case Constants.POP: 024 return -1; 025 case Constants.POP2: 026 return -2; 027 case Constants.DUP: 028 case Constants.DUPX1: 029 case Constants.DUPX2: 030 return 1; 031 case Constants.DUP2: 032 case Constants.DUP2X1: 033 case Constants.DUP2X2: 034 return 2; 035 default: 036 return 0; 037 } 038 } 039 040 /** 041 * This method will always return null; use {@link #isWide} to determine 042 * if this is pop2, dup2, etc. 043 */ 044 public String getTypeName() { 045 return null; 046 } 047 048 public TypedInstruction setType(String type) { 049 type = getProject().getNameCache().getExternalForm(type, false); 050 return setWide(long.class.getName().equals(type) 051 || double.class.getName().equals(type)); 052 } 053 054 /** 055 * Return whether to use the wide form of the current opcode for 056 * operations on longs or doubles. 057 */ 058 public boolean isWide() { 059 switch (getOpcode()) { 060 case Constants.POP2: 061 case Constants.DUP2: 062 case Constants.DUP2X1: 063 case Constants.DUP2X2: 064 return true; 065 default: 066 return false; 067 } 068 } 069 070 /** 071 * Set whether to use the wide form of the current opcode for operations 072 * on longs or doubles. 073 * 074 * @return this instruction, for method chaining 075 */ 076 public StackInstruction setWide(boolean wide) { 077 switch (getOpcode()) { 078 case Constants.POP: 079 if (wide) 080 setOpcode(Constants.POP2); 081 break; 082 case Constants.POP2: 083 if (!wide) 084 setOpcode(Constants.POP); 085 break; 086 case Constants.DUP: 087 if (wide) 088 setOpcode(Constants.DUP2); 089 break; 090 case Constants.DUP2: 091 if (!wide) 092 setOpcode(Constants.DUP); 093 break; 094 case Constants.DUPX1: 095 if (wide) 096 setOpcode(Constants.DUP2X1); 097 break; 098 case Constants.DUP2X1: 099 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 }