001    package serp.bytecode;
002    
003    import java.io.*;
004    
005    import serp.bytecode.visitor.*;
006    
007    /**
008     * An instruction to store a value from a local variable onto the stack.
009     *
010     * @author Abe White
011     */
012    public class StoreInstruction extends LocalVariableInstruction {
013        private static final Class[][] _mappings = new Class[][] {
014            { byte.class, int.class },
015            { boolean.class, int.class },
016            { char.class, int.class },
017            { short.class, int.class },
018            { void.class, int.class },
019        };
020        String _type = null;
021    
022        StoreInstruction(Code owner) {
023            super(owner);
024        }
025    
026        StoreInstruction(Code owner, int opcode) {
027            super(owner, opcode);
028        }
029    
030        int getLength() {
031            switch (getOpcode()) {
032            case Constants.ISTORE:
033            case Constants.LSTORE:
034            case Constants.FSTORE:
035            case Constants.DSTORE:
036            case Constants.ASTORE:
037                return super.getLength() + 1;
038            default:
039                return super.getLength();
040            }
041        }
042    
043        public int getLogicalStackChange() {
044            switch (getOpcode()) {
045            case Constants.NOP:
046                return 0;
047            default:
048                return -1;
049            }
050        }
051    
052        public int getStackChange() {
053            switch (getOpcode()) {
054            case Constants.LSTORE:
055            case Constants.LSTORE0:
056            case Constants.LSTORE1:
057            case Constants.LSTORE2:
058            case Constants.LSTORE3:
059            case Constants.DSTORE:
060            case Constants.DSTORE0:
061            case Constants.DSTORE1:
062            case Constants.DSTORE2:
063            case Constants.DSTORE3:
064                return -2;
065            case Constants.NOP:
066                return 0;
067            default:
068                return -1;
069            }
070        }
071    
072        public String getTypeName() {
073            switch (getOpcode()) {
074            case Constants.ISTORE:
075            case Constants.ISTORE0:
076            case Constants.ISTORE1:
077            case Constants.ISTORE2:
078            case Constants.ISTORE3:
079                return int.class.getName();
080            case Constants.LSTORE:
081            case Constants.LSTORE0:
082            case Constants.LSTORE1:
083            case Constants.LSTORE2:
084            case Constants.LSTORE3:
085                return long.class.getName();
086            case Constants.FSTORE:
087            case Constants.FSTORE0:
088            case Constants.FSTORE1:
089            case Constants.FSTORE2:
090            case Constants.FSTORE3:
091                return float.class.getName();
092            case Constants.DSTORE:
093            case Constants.DSTORE0:
094            case Constants.DSTORE1:
095            case Constants.DSTORE2:
096            case Constants.DSTORE3:
097                return double.class.getName();
098            case Constants.ASTORE:
099            case Constants.ASTORE0:
100            case Constants.ASTORE1:
101            case Constants.ASTORE2:
102            case Constants.ASTORE3:
103                return Object.class.getName();
104            default:
105                return _type;
106            }
107        }
108    
109        public TypedInstruction setType(String type) {
110            type = mapType(type, _mappings, true);
111            int local = getLocal();
112            int len = getLength();
113    
114            // if an invalid type or local, revert to nop
115            if ((type == null) || (local < 0)) {
116                _type = type;
117                setOpcode(Constants.NOP);
118            } else {
119                // valid opcode, unset saved type
120                _type = null;
121                switch (type.charAt(0)) {
122                case 'i':
123                    setOpcode((local > 3) ? Constants.ISTORE
124                        : (Constants.ISTORE0 + local));
125                    break;
126                case 'l':
127                    setOpcode((local > 3) ? Constants.LSTORE
128                        : (Constants.LSTORE0 + local));
129                    break;
130                case 'f':
131                    setOpcode((local > 3) ? Constants.FSTORE
132                        : (Constants.FSTORE0 + local));
133                    break;
134                case 'd':
135                    setOpcode((local > 3) ? Constants.DSTORE
136                        : (Constants.DSTORE0 + local));
137                    break;
138                default:
139                    setOpcode((local > 3) ? Constants.ASTORE
140                        : (Constants.ASTORE0 + local));
141                    break;
142                }
143            }
144            if (len != getLength())
145                invalidateByteIndexes();
146            return this;
147        }
148    
149        /**
150         * StoreInstructions are equal if the type they reference the same
151         * type and locals index or if either is unset.
152         */
153        public boolean equalsInstruction(Instruction other) {
154            if (other == this)
155                return true;
156            if (!super.equalsInstruction(other))
157                return false;
158    
159            String type = getTypeName();
160            String otherType = ((StoreInstruction) other).getTypeName();
161            return type == null || otherType == null || type.equals(otherType);
162        }
163    
164        public void acceptVisit(BCVisitor visit) {
165            visit.enterStoreInstruction(this);
166            visit.exitStoreInstruction(this);
167        }
168    
169        void read(Instruction orig) {
170            super.read(orig);
171            StoreInstruction ins = (StoreInstruction) orig;
172            _type = ins._type;
173        }
174    
175        void read(DataInput in) throws IOException {
176            super.read(in);
177            switch (getOpcode()) {
178            case Constants.ISTORE:
179            case Constants.LSTORE:
180            case Constants.FSTORE:
181            case Constants.DSTORE:
182            case Constants.ASTORE:
183                setLocal(in.readUnsignedByte());
184                break;
185            }
186        }
187    
188        void write(DataOutput out) throws IOException {
189            super.write(out);
190            switch (getOpcode()) {
191            case Constants.ISTORE:
192            case Constants.LSTORE:
193            case Constants.FSTORE:
194            case Constants.DSTORE:
195            case Constants.ASTORE:
196                out.writeByte(getLocal());
197            }
198        }
199    
200        void calculateOpcode() {
201            // taken care of when setting type
202            setType(getTypeName());
203        }
204    
205        void calculateLocal() {
206            switch (getOpcode()) {
207            case Constants.ISTORE0:
208            case Constants.LSTORE0:
209            case Constants.FSTORE0:
210            case Constants.DSTORE0:
211            case Constants.ASTORE0:
212                setLocal(0);
213                break;
214            case Constants.ISTORE1:
215            case Constants.LSTORE1:
216            case Constants.FSTORE1:
217            case Constants.DSTORE1:
218            case Constants.ASTORE1:
219                setLocal(1);
220                break;
221            case Constants.ISTORE2:
222            case Constants.LSTORE2:
223            case Constants.FSTORE2:
224            case Constants.DSTORE2:
225            case Constants.ASTORE2:
226                setLocal(2);
227                break;
228            case Constants.ISTORE3:
229            case Constants.LSTORE3:
230            case Constants.FSTORE3:
231            case Constants.DSTORE3:
232            case Constants.ASTORE3:
233                setLocal(3);
234                break;
235            }
236        }
237    }