001    /*
002      Copyright (C) 2002-2003 Laurent Martelli <laurent@aopsys.com>
003    
004      This program is free software; you can redistribute it and/or modify
005      it under the terms of the GNU Lesser General Public License as
006      published by the Free Software Foundation; either version 2 of the
007      License, or (at your option) any later version.
008    
009      This program is distributed in the hope that it will be useful, but
010      WITHOUT ANY WARRANTY; without even the implied warranty of
011      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
012      Lesser General Public License for more details.
013    
014      You should have received a copy of the GNU Lesser General Public
015      License along with this program; if not, write to the Free Software
016      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
017      USA */
018    
019    package org.objectweb.jac.core.translators;
020    
021    import java.io.Serializable;
022    import java.util.Arrays;
023    import java.util.HashSet;
024    import java.util.Set;
025    import java.util.Vector;
026    import org.apache.bcel.classfile.*;
027    import org.apache.bcel.generic.*;
028    import org.apache.log4j.Logger;
029    import org.objectweb.jac.util.Stack;
030    
031    /**
032     * Represents the VM stack
033     */
034    public class VMStack extends Stack {
035        static Logger logger = Logger.getLogger("translator.bytecode");
036    
037        public static final ThisPointer thisPointer = new ThisPointer();
038        public static final DontCare dontCare = new DontCare();
039    
040        static final int UNPREDICTABLE = -1;
041        static final int UNDEFINED = -2;
042    
043        Vector locals = new Vector(); // Local variables
044    
045        ConstantPoolGen cp;
046        int[] exceptionHandlers;
047        int currentHandler = 0;
048        int nbArgs;
049        int localsOffest;
050        boolean isStatic;
051        public VMStack(ConstantPoolGen cp, Code code, int nbArgs, boolean isStatic) {
052            this.cp = cp;
053            this.nbArgs = nbArgs;
054            this.isStatic = isStatic;
055            this.localsOffest = nbArgs+(isStatic?1:0);
056            if (code!=null) {
057                CodeException[] exceptions = code.getExceptionTable();
058                exceptionHandlers = new int[exceptions.length];
059                for (int i=0; i<exceptions.length; i++) {
060                    exceptionHandlers[i] = exceptions[i].getHandlerPC();
061                    logger.debug("Exception handler at "+exceptionHandlers[i]);
062                }
063                Arrays.sort(exceptionHandlers);
064            }
065        }
066    
067        public void preExecute(InstructionHandle ih) {
068            if (currentHandler<exceptionHandlers.length)
069                logger.debug("position="+ih.getPosition()+", nextHandler="+exceptionHandlers[currentHandler]);
070            if ( currentHandler<exceptionHandlers.length &&
071                 ih.getPosition()==exceptionHandlers[currentHandler] ) {
072                logger.debug("entering exception handler");
073                currentHandler++;
074                push(dontCare);
075            }
076        }
077    
078        static Set primitiveWrapperTypes = new HashSet();
079        static {
080            primitiveWrapperTypes.add("java.lang.Float");
081            primitiveWrapperTypes.add("java.lang.Double");
082            primitiveWrapperTypes.add("java.lang.Integer");
083            primitiveWrapperTypes.add("java.lang.Long");
084            primitiveWrapperTypes.add("java.lang.Boolean");
085            primitiveWrapperTypes.add("java.lang.Character");
086            primitiveWrapperTypes.add("java.lang.Byte");
087        }
088    
089        public void execute(Instruction i, InstructionHandle ih) {
090            logger.debug("execute "+i.toString(cp.getConstantPool()));
091    
092            if (i instanceof SWAP) {
093                swap();
094            } else if (i instanceof DUP || i instanceof DUP2) {
095                push(peek());
096            } else if (i instanceof DUP_X1 || i instanceof DUP2_X2 || 
097                       i instanceof DUP2_X1 || i instanceof DUP_X2) {
098                swap();
099                push(peek(1));
100            } else if (i instanceof ALOAD && ((ALOAD)i).getIndex() == 0
101                       && !isStatic) {
102                push(thisPointer);
103            } else if (i instanceof NEW) {         
104                if (primitiveWrapperTypes.contains(
105                    ((NEW)i).getLoadClassType(cp).getClassName())) {
106                    push(new PrimitiveValue(((NEW)i).getLoadClassType(cp).getClassName()));
107                } else {
108                    push(new Instance(
109                        ((NEW)i).getLoadClassType(cp).getClassName(),ih));
110                }
111            } else if (i instanceof LoadInstruction) {
112                LoadInstruction load = (LoadInstruction)i;
113                if (load.getIndex()<=nbArgs) {
114                    push(new Argument(load.getIndex()));
115                } else {
116                    int index = load.getIndex()-nbArgs;
117                    // We must ensure the size of locals is correct
118                    // because a LOAD may occur before a STORE in the
119                    // bytecode (because of a JMP)
120                    if (locals.size()<index+1)
121                        locals.setSize(index+1);
122                    push(locals.get(index));
123                }
124            } else if (i instanceof StoreInstruction) {
125                StoreInstruction store = (StoreInstruction)i;
126                if (store.getIndex()<=nbArgs) {
127                } else {
128                    int index = store.getIndex()-nbArgs;
129                    if (locals.size()<store.getIndex()+1)
130                        locals.setSize(store.getIndex()+1);
131                    locals.set(store.getIndex(),peek());
132                }
133                consume(i);
134            } else if (i instanceof GETFIELD) {
135                Object substance = peek();
136                consume(i);
137                push(new FieldValue(substance,
138                                    ((GETFIELD)i).getIndex(),
139                                    ((GETFIELD)i).getFieldName(cp)));
140            } else if (i instanceof GETSTATIC) {
141                consume(i);
142                push(new FieldValue(null,
143                                    ((GETSTATIC)i).getIndex(),
144                                    ((GETSTATIC)i).getFieldName(cp)));
145            } else if (i instanceof INVOKESPECIAL && 
146                       ((INVOKESPECIAL)i).getMethodName(cp).equals("<init>")) {
147                Object invoked = invokedObject((INVOKESPECIAL)i);
148                if (invoked instanceof PrimitiveValue) 
149                    ((PrimitiveValue)invoked).wrappedValue = peek();
150                consume(i);
151                produce(i);
152                /*
153            } else if (i instanceof InvokeInstruction) {
154                InvokeInstruction invoke = (InvokeInstruction)i;
155                if (invoke.getMethodName(cp).equals("iterator")) {
156                    consume(i);
157                    push(new IteratorValue(peek()));
158                } else if (invoke.getMethodName(cp).equals("next") &&
159                           peek() instanceof IteratorValue) {
160                    consume(i);
161                    push(new CollectionValue(((IteratorValue)peek()).collection));
162                } else {
163                    consume(i);
164                    produce(i);
165                }
166                */
167            } else if (i instanceof CHECKCAST || i instanceof ATHROW) {
168                // nothing
169            } else if (i instanceof ANEWARRAY) {
170                // BCEL bug workaround (ANEWARRAY is a StackProducer but not
171                // a StackConsumer)
172                pop(1);
173                push(dontCare);
174            } else {
175                consume(i);
176                produce(i);
177            }
178            logger.debug("stack: "+this);
179        }
180    
181        /**
182         * Returns the stack element corresponding to the object on which
183         * the InvokeInstruction is applied.
184         */
185        public Object invokedObject(InvokeInstruction i) {
186            return peek(i.getArgumentTypes(cp).length);
187        }
188    
189        /**
190         * Consume values from the stack for the given instruction
191         */
192        public void consume(Instruction i) {
193            if (i instanceof StackConsumer)
194                pop(getConsumed(i,cp));
195        }
196        public void produce(Instruction i) {
197            if (i instanceof StackProducer) {
198                for(int j=0; j<getProduced(i,cp); j++)
199                    push(dontCare);
200            }
201        }
202        /**
203         * Returns the number of elements from the stack consumed by an
204         * instruction 
205         */
206        public static int getConsumed(Instruction i, ConstantPoolGen cp) {
207            if (i instanceof INVOKESTATIC) 
208                return ((InvokeInstruction)i).getArgumentTypes(cp).length;
209            else if (i instanceof InvokeInstruction) 
210                return ((InvokeInstruction)i).getArgumentTypes(cp).length+1;
211            else if (i instanceof MULTIANEWARRAY) 
212                return ((MULTIANEWARRAY)i).getDimensions();
213            else
214                return CONSUME_STACK[i.getOpcode()];
215        }
216    
217        /**
218         * Returns the number of elements produced on the stack by an instruction 
219         */
220        public static int getProduced(Instruction i, ConstantPoolGen cp) {
221            if (i instanceof InvokeInstruction) {
222                return ((InvokeInstruction)i).getReturnType(cp)==Type.VOID ? 0 : 1;
223            } else {
224                return PRODUCE_STACK[i.getOpcode()];
225            }
226        }
227    
228        /**
229         * Gets the value on which a method is invoked
230         * @param invoke the invoke instruction
231         */
232        public Object getSubstance(InvokeInstruction invoke) {
233            return peek(invoke.getArgumentTypes(cp).length);
234        }
235    
236        static final int[] CONSUME_STACK = {
237            0/*nop*/, 0/*aconst_null*/, 0/*iconst_m1*/, 0/*iconst_0*/, 0/*iconst_1*/,
238            0/*iconst_2*/, 0/*iconst_3*/, 0/*iconst_4*/, 0/*iconst_5*/, 0/*lconst_0*/,
239            0/*lconst_1*/, 0/*fconst_0*/, 0/*fconst_1*/, 0/*fconst_2*/, 0/*dconst_0*/,
240            0/*dconst_1*/, 0/*bipush*/, 0/*sipush*/, 0/*ldc*/, 0/*ldc_w*/, 0/*ldc2_w*/, 0/*iload*/,
241            0/*lload*/, 0/*fload*/, 0/*dload*/, 0/*aload*/, 0/*iload_0*/, 0/*iload_1*/, 0/*iload_2*/,
242            0/*iload_3*/, 0/*lload_0*/, 0/*lload_1*/, 0/*lload_2*/, 0/*lload_3*/, 0/*fload_0*/,
243            0/*fload_1*/, 0/*fload_2*/, 0/*fload_3*/, 0/*dload_0*/, 0/*dload_1*/, 0/*dload_2*/,
244            0/*dload_3*/, 0/*aload_0*/, 0/*aload_1*/, 0/*aload_2*/, 0/*aload_3*/, 2/*iaload*/,
245            2/*laload*/, 2/*faload*/, 2/*daload*/, 2/*aaload*/, 2/*baload*/, 2/*caload*/, 2/*saload*/,
246            1/*istore*/, 1/*lstore*/, 1/*fstore*/, 1/*dstore*/, 1/*astore*/, 1/*istore_0*/,
247            1/*istore_1*/, 1/*istore_2*/, 1/*istore_3*/, 1/*lstore_0*/, 1/*lstore_1*/,
248            1/*lstore_2*/, 1/*lstore_3*/, 1/*fstore_0*/, 1/*fstore_1*/, 1/*fstore_2*/,
249            1/*fstore_3*/, 1/*dstore_0*/, 1/*dstore_1*/, 1/*dstore_2*/, 1/*dstore_3*/,
250            1/*astore_0*/, 1/*astore_1*/, 1/*astore_2*/, 1/*astore_3*/, 3/*iastore*/, 3/*lastore*/,
251            3/*fastore*/, 3/*dastore*/, 3/*aastore*/, 3/*bastore*/, 3/*castore*/, 3/*sastore*/,
252            1/*pop*/, 1/*pop2*/, 1/*dup*/, 2/*dup_x1*/, 3/*dup_x2*/, 1/*dup2*/, 3/*dup2_x1*/,
253            4/*dup2_x2*/, 2/*swap*/, 2/*iadd*/, 2/*ladd*/, 2/*fadd*/, 2/*dadd*/, 2/*isub*/, 2/*lsub*/,
254            2/*fsub*/, 2/*dsub*/, 2/*imul*/, 2/*lmul*/, 2/*fmul*/, 2/*dmul*/, 2/*idiv*/, 2/*ldiv*/,
255            2/*fdiv*/, 2/*ddiv*/, 2/*irem*/, 2/*lrem*/, 2/*frem*/, 2/*drem*/, 1/*ineg*/, 1/*lneg*/,
256            1/*fneg*/, 1/*dneg*/, 2/*ishl*/, 2/*lshl*/, 2/*ishr*/, 2/*lshr*/, 2/*iushr*/, 2/*lushr*/,
257            2/*iand*/, 2/*land*/, 2/*ior*/, 2/*lor*/, 2/*ixor*/, 2/*lxor*/, 0/*iinc*/,
258            1/*i2l*/, 1/*i2f*/, 1/*i2d*/, 1/*l2i*/, 1/*l2f*/, 1/*l2d*/, 1/*f2i*/, 1/*f2l*/,
259            1/*f2d*/, 1/*d2i*/, 1/*d2l*/, 1/*d2f*/, 1/*i2b*/, 1/*i2c*/, 1/*i2s*/, 
260            2/*lcmp*/, 2/*fcmpl*/, 2/*fcmpg*/, 2/*dcmpl*/, 2/*dcmpg*/, 1/*ifeq*/, 1/*ifne*/,
261            1/*iflt*/, 1/*ifge*/, 1/*ifgt*/, 1/*ifle*/, 2/*if_icmpeq*/, 2/*if_icmpne*/, 2/*if_icmplt*/,
262            2 /*if_icmpge*/, 2/*if_icmpgt*/, 2/*if_icmple*/, 2/*if_acmpeq*/, 2/*if_acmpne*/,
263            0/*goto*/, 0/*jsr*/, 0/*ret*/, 1/*tableswitch*/, 1/*lookupswitch*/, 1/*ireturn*/,
264            1/*lreturn*/, 1/*freturn*/, 1/*dreturn*/, 1/*areturn*/, 0/*return*/, 0/*getstatic*/,
265            1,/*putstatic*/ 1/*getfield*/, 2/*putfield*/,
266            UNPREDICTABLE/*invokevirtual*/, UNPREDICTABLE/*invokespecial*/,
267            UNPREDICTABLE/*invokestatic*/,
268            UNPREDICTABLE/*invokeinterface*/, UNDEFINED, 0/*new*/, 1/*newarray*/, 1/*anewarray*/,
269            1/*arraylength*/, 1/*athrow*/, 1/*checkcast*/, 1/*instanceof*/, 1/*monitorenter*/,
270            1/*monitorexit*/, 0/*wide*/, UNPREDICTABLE/*multianewarray*/, 1/*ifnull*/, 1/*ifnonnull*/,
271            0/*goto_w*/, 0/*jsr_w*/, 0/*breakpoint*/, UNDEFINED, UNDEFINED,
272            UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
273            UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
274            UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
275            UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
276            UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
277            UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
278            UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
279            UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
280            UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
281            UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
282            UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
283            UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
284            UNDEFINED, UNPREDICTABLE/*impdep1*/, UNPREDICTABLE/*impdep2*/
285        };
286    
287        public static final int[] PRODUCE_STACK = {
288            0/*nop*/, 1/*aconst_null*/, 1/*iconst_m1*/, 1/*iconst_0*/, 1/*iconst_1*/,
289            1/*iconst_2*/, 1/*iconst_3*/, 1/*iconst_4*/, 1/*iconst_5*/, 1/*lconst_0*/,
290            1/*lconst_1*/, 1/*fconst_0*/, 1/*fconst_1*/, 1/*fconst_2*/, 1/*dconst_0*/,
291            1/*dconst_1*/, 1/*bipush*/, 1/*sipush*/, 1/*ldc*/, 1/*ldc_w*/, 1/*ldc2_w*/, 1/*iload*/,
292            1/*lload*/, 1/*fload*/, 1/*dload*/, 1/*aload*/, 1/*iload_0*/, 1/*iload_1*/, 1/*iload_2*/,
293            1/*iload_3*/, 1/*lload_0*/, 1/*lload_1*/, 1/*lload_2*/, 1/*lload_3*/, 1/*fload_0*/,
294            1/*fload_1*/, 1/*fload_2*/, 1/*fload_3*/, 1/*dload_0*/, 1/*dload_1*/, 1/*dload_2*/,
295            1/*dload_3*/, 1/*aload_0*/, 1/*aload_1*/, 1/*aload_2*/, 1/*aload_3*/, 1/*iaload*/,
296            1/*laload*/, 1/*faload*/, 1/*daload*/, 1/*aaload*/, 1/*baload*/, 1/*caload*/, 1/*saload*/,
297            0/*istore*/, 0/*lstore*/, 0/*fstore*/, 0/*dstore*/, 0/*astore*/, 0/*istore_0*/,
298            0/*istore_1*/, 0/*istore_2*/, 0/*istore_3*/, 0/*lstore_0*/, 0/*lstore_1*/,
299            0/*lstore_2*/, 0/*lstore_3*/, 0/*fstore_0*/, 0/*fstore_1*/, 0/*fstore_2*/,
300            0/*fstore_3*/, 0/*dstore_0*/, 0/*dstore_1*/, 0/*dstore_2*/, 0/*dstore_3*/,
301            0/*astore_0*/, 0/*astore_1*/, 0/*astore_2*/, 0/*astore_3*/, 0/*iastore*/, 0/*lastore*/,
302            0/*fastore*/, 0/*dastore*/, 0/*aastore*/, 0/*bastore*/, 0/*castore*/, 0/*sastore*/,
303            0/*pop*/, 0/*pop2*/, 2/*dup*/, 3/*dup_x1*/, 4/*dup_x2*/, 4/*dup2*/, 5/*dup2_x1*/,
304            6/*dup2_x2*/, 2/*swap*/, 1/*iadd*/, 1/*ladd*/, 1/*fadd*/, 1/*dadd*/, 1/*isub*/, 1/*lsub*/,
305            1/*fsub*/, 1/*dsub*/, 1/*imul*/, 1/*lmul*/, 1/*fmul*/, 1/*dmul*/, 1/*idiv*/, 1/*ldiv*/,
306            1/*fdiv*/, 1/*ddiv*/, 1/*irem*/, 1/*lrem*/, 1/*frem*/, 1/*drem*/, 1/*ineg*/, 1/*lneg*/,
307            1/*fneg*/, 1/*dneg*/, 1/*ishl*/, 1/*lshl*/, 1/*ishr*/, 1/*lshr*/, 1/*iushr*/, 1/*lushr*/,
308            1/*iand*/, 1/*land*/, 1/*ior*/, 1/*lor*/, 1/*ixor*/, 1/*lxor*/,
309            0/*iinc*/, 1/*i2l*/, 1/*i2f*/, 1/*i2d*/, 1/*l2i*/, 1/*l2f*/, 1/*l2d*/, 1/*f2i*/,
310            1/*f2l*/, 1/*f2d*/, 1/*d2i*/, 1/*d2l*/, 1/*d2f*/,
311            1/*i2b*/, 1/*i2c*/, 1/*i2s*/, 1/*lcmp*/, 1/*fcmpl*/, 1/*fcmpg*/,
312            1/*dcmpl*/, 1/*dcmpg*/, 0/*ifeq*/, 0/*ifne*/, 0/*iflt*/, 0/*ifge*/, 0/*ifgt*/, 0/*ifle*/,
313            0/*if_icmpeq*/, 0/*if_icmpne*/, 0/*if_icmplt*/, 0/*if_icmpge*/, 0/*if_icmpgt*/,
314            0/*if_icmple*/, 0/*if_acmpeq*/, 0/*if_acmpne*/, 0/*goto*/, 1/*jsr*/, 0/*ret*/,
315            0/*tableswitch*/, 0/*lookupswitch*/, 0/*ireturn*/, 0/*lreturn*/, 0/*freturn*/,
316            0/*dreturn*/, 0/*areturn*/, 0/*return*/, 1/*getstatic*/, 0/*putstatic*/,
317            1/*getfield*/, 0/*putfield*/, UNPREDICTABLE/*invokevirtual*/,
318            UNPREDICTABLE/*invokespecial*/, UNPREDICTABLE/*invokestatic*/,
319            UNPREDICTABLE/*invokeinterface*/, UNDEFINED, 1/*new*/, 1/*newarray*/, 1/*anewarray*/,
320            1/*arraylength*/, 1/*athrow*/, 1/*checkcast*/, 1/*instanceof*/, 0/*monitorenter*/,
321            0/*monitorexit*/, 0/*wide*/, 1/*multianewarray*/, 0/*ifnull*/, 0/*ifnonnull*/,
322            0/*goto_w*/, 1/*jsr_w*/, 0/*breakpoint*/, UNDEFINED, UNDEFINED,
323            UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
324            UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
325            UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
326            UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
327            UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
328            UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
329            UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
330            UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
331            UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
332            UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
333            UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
334            UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
335            UNDEFINED, UNPREDICTABLE/*impdep1*/, UNPREDICTABLE/*impdep2*/
336        };
337    
338        // various classes to represent values on the stack
339        public static class ThisPointer implements Serializable { 
340            public String toString() { return "This"; } 
341        }
342    
343        /** Unknown value */
344        public static class DontCare implements Serializable { 
345            public String toString() { return "???"; } 
346        }
347    
348        /** Instance of a class */
349        public static class Instance implements Serializable { 
350            public String type;
351            /** the InstructionHandle who created this instance */
352            public transient InstructionHandle newHandle;
353            public transient InstructionHandle initHandle;
354            public Instance(String type, InstructionHandle newHandle) { 
355                this.type = type; 
356                this.newHandle = newHandle;
357            }
358            public String toString() { return type; }
359        }
360    
361        /** An argument */
362        public static class Argument implements Serializable {
363            public int n;
364            public Argument(int n) { this.n = n; }
365            public String toString() { return "arg["+n+"]"; }
366        }
367    
368        /** The value of a field */
369        public static class FieldValue implements Serializable {
370            int index; // const pool FieldRef index
371            String field; // name of field
372            Object substance; // owner of the field
373            public FieldValue(Object substance, int index, String field) { 
374                this.field = field; 
375                this.index = index;
376                this.substance = substance; 
377            }
378            public String toString() { return substance+"."+field; }
379        }
380    
381        /** A primitive value */
382        public static class PrimitiveValue implements Serializable {
383            public Object wrappedValue;
384            public String type;
385            public PrimitiveValue(String type) {
386                this.type = type;
387                this.wrappedValue = null;
388            }
389            public String toString() {
390                return type+"("+wrappedValue+")";
391            }
392        }
393    
394        /** An iterator on a collection */
395        public static class IteratorValue {
396            public Object collection;
397            public IteratorValue(Object collection) {
398                this.collection = collection;
399            }
400            public String toString() {
401                return "iterator("+collection.toString()+")";
402            }
403        }
404    
405        /** An item of a collection */
406        public static class CollectionValue {
407            public Object collection;
408            public CollectionValue(Object collection) {
409                this.collection = collection;
410            }
411            public String toString() {
412                return "iterator("+collection.toString()+")";
413            }
414        }
415    }
416