PageRenderTime 67ms CodeModel.GetById 13ms app.highlight 49ms RepoModel.GetById 1ms app.codeStats 0ms

/src/kilim/analysis/Frame.java

http://github.com/kilim/kilim
Java | 299 lines | 244 code | 30 blank | 25 comment | 63 complexity | 1db7162cca8db82a2794ecf6296db862 MD5 | raw file
  1/* Copyright (c) 2006, Sriram Srinivasan
  2 *
  3 * You may distribute this software under the terms of the license 
  4 * specified in the file "License"
  5 */
  6
  7package kilim.analysis;
  8import static kilim.Constants.D_DOUBLE;
  9import static kilim.Constants.D_FLOAT;
 10import static kilim.Constants.D_LONG;
 11import static kilim.Constants.D_OBJECT;
 12import kilim.mirrors.Detector;
 13import static org.objectweb.asm.Opcodes.ACC_STATIC;
 14import static org.objectweb.asm.Opcodes.ACC_SYNCHRONIZED;
 15import static org.objectweb.asm.Opcodes.ALOAD;
 16import static org.objectweb.asm.Opcodes.DLOAD;
 17import static org.objectweb.asm.Opcodes.FLOAD;
 18import static org.objectweb.asm.Opcodes.ILOAD;
 19import static org.objectweb.asm.Opcodes.LLOAD;
 20
 21import org.objectweb.asm.tree.MethodNode;
 22
 23
 24/**
 25 * An activation frame.
 26
 27 *
 28 */
 29public class Frame {
 30    Value[] locals;
 31    Value[] stack;
 32    int numMonitorsActive = 0;
 33    int stacklen = 0;
 34    
 35    private Frame(int nLocals, int nStack, boolean init) {
 36        this.locals = new Value[nLocals];
 37        if (init) {
 38            for (int i = 0; i < nLocals; i++) {
 39                locals[i] = Value.V_UNDEFINED;
 40            }
 41        }
 42        this.stack = new Value[nStack];
 43    }
 44    
 45    public Frame(int nLocals, int nStack) {
 46        this(nLocals, nStack, true);
 47    }
 48    
 49    /**
 50     * Merge the local variables and stack from the incoming frame 
 51     * into the current frame. 
 52     * @param inframe -- incoming frame
 53     * @param localsOnly -- true for exception handlers, because the
 54     *      stack is cleared.
 55     * @param usage -- Only those locals are merged that are deemed
 56     *        live (@see Usage#isLiveIn(int)) 
 57     * @return this, if the merge didn't change anything
 58     *      or a new Frame if the operation changed a slot on the stack
 59     *      or a local variable
 60     */
 61    public Frame merge(Detector det,Frame inframe, boolean localsOnly, Usage usage) {
 62        int slen = stacklen;
 63
 64        Value[] nst = null; // new stack. allocated if needed
 65        
 66        if (!localsOnly) {
 67            Value[] st = stack;
 68            Value[] ist = inframe.stack;
 69            for (int i = 0; i < slen; i++) {
 70                Value va = st[i];
 71                Value vb = ist[i];
 72                if (va == vb || va.equals(vb)) continue;
 73                Value newval = va.merge(det,vb);
 74                if (newval != va) {
 75                    if (nst == null) nst = dupArray(st);
 76                    nst[i] = newval;
 77                }
 78            }
 79        }
 80        
 81        Value[] lo = locals;
 82        Value[] ilo = inframe.locals; 
 83        Value[] nlo = null; // new locals array. allocated if needed
 84        for (int i = 0; i < lo.length; i++) {
 85            if (!usage.isLiveIn(i)) continue;
 86            Value va = lo[i];
 87            Value vb = ilo[i];
 88            if (va == vb || va.equals(vb)) continue;
 89            Value newval = va.merge(det,vb);
 90            if (newval != va) {
 91                if (nlo == null) nlo = dupArray(lo);
 92                nlo[i] = newval;
 93            }
 94        }
 95        if (nst == null && nlo == null) {
 96            return this;
 97        } else {
 98            // One or both of locals and stacks have new values
 99            if (nst == null) nst = dupArray(stack);
100            if (nlo == null) nlo = dupArray(locals);
101            return new Frame(nlo, nst, slen, numMonitorsActive);
102        }
103    }
104    
105    public static Value[] dupArray(Value[] a) {
106        Value[] ret = new Value[a.length];
107        System.arraycopy(a, 0, ret, 0, a.length);
108        return ret;
109    }
110    
111    private Frame(Value[] alocals, Value[] astack, int astacklen, int aNumMonitorsActive) {
112        this.locals = alocals;
113        this.stack = astack;
114        this.stacklen = astacklen;
115        this.numMonitorsActive = aNumMonitorsActive;
116    }
117    
118    public Frame dup() {
119        return new Frame(dupArray(locals), dupArray(stack), stacklen, numMonitorsActive); 
120    }
121    
122    public Frame(String classDesc, MethodNode method) {
123        this(method.maxLocals, method.maxStack, false);
124        String[] argTypeDescs = TypeDesc.getArgumentTypes(method.desc);
125        for (int i = 0; i < method.maxLocals; i++) {
126            setLocal(i, Value.V_UNDEFINED);
127        }
128        int local = 0;
129        int fakeParamPos = 100000;
130        if ((method.access & ACC_STATIC) == 0) {
131            // 0th local is "this"
132            setLocal(local++, Value.make(fakeParamPos++,classDesc));
133        }
134        for (int i = 0; i < argTypeDescs.length; i++) {
135            local += setLocal(local, Value.make(fakeParamPos++, argTypeDescs[i]));
136        }
137        if ((method.access & ACC_SYNCHRONIZED) != 0) {
138            numMonitorsActive = 1;
139        }
140    }
141    
142    private boolean checkType(String desc) {
143        if (desc.equals("Ljava/lang/Object;") && desc != D_OBJECT) return false;
144        switch(desc.charAt(0)) {
145            case 'L': case 'B': case 'C': case 'D': case 'F': case 'I':
146            case 'J': case 'S': case 'Z': case 'N': case '[': case 'A': 
147            case 'U':
148                return true;
149            default: 
150                return false;
151        }
152    }
153    
154    public int setLocal(int local, Value v) {
155        assert checkType(v.getTypeDesc()) : "Invalid type: " + v.getTypeDesc();
156        locals[local] = v;
157        if (v.isCategory2()) {
158            locals[local+1] = v;
159            return 2;
160        }
161        return 1;
162    }
163    
164    public Value getLocal(int local, int opcode) {
165        Value v = locals[local];
166        String desc = v.getTypeDesc();
167        String expected = null;
168        switch(opcode) {
169            case ILOAD: {
170                if (TypeDesc.isIntType(desc)) {
171                    return v;
172                } else {
173                    expected = "int";
174                }
175                break;
176            }
177            case LLOAD: {
178                if (desc == D_LONG) {
179                    return v; 
180                } else {
181                    expected = "long";
182                }
183                break;
184            }
185            case DLOAD: {
186                if (desc == D_DOUBLE) {
187                    return v;
188                } else {
189                    expected = "double";
190                }
191                break;
192            }
193            case FLOAD: {
194                if (desc == D_FLOAT) {
195                    return v;
196                } else {
197                    expected = "float";
198                }
199                break;
200            }
201            case ALOAD: {
202                if (TypeDesc.isRefType(desc)) { 
203                    return v;
204                } else {
205                    expected = "ref";
206                }
207            }
208        }
209        throw new AssertionError("Expected " + expected + " in local# " + local + ", got " + desc);
210    }
211    
212    public Value getLocal(int local) {
213        return locals[local];
214    }
215    
216    public Value getStack(int pos) {
217        // for testing
218        return stack[pos];
219    }
220    
221    public Value push(Value v) {
222        assert (v != Value.V_UNDEFINED) : "UNDEFINED type pushed";
223        assert checkType(v.getTypeDesc()) : "Invalid type: " + v.getTypeDesc();
224        stack[stacklen++] = v;
225        return v;
226    }
227    
228    public Value pop() {
229        try {
230            return stack[--stacklen];
231        } catch (ArrayIndexOutOfBoundsException e) {
232            throw new RuntimeException("Verify error. Expected word in stack, but stack is empty");
233        }
234    }
235    
236    public Value popWord() {
237        Value v = pop();
238        assert v.isCategory1() : "double word present where single expected";
239        return v;
240    }
241    
242    public void popn(int n) {
243        stacklen -= n;
244    }
245    
246    void clearStack() {
247        stacklen = 0;
248    }
249    
250    @Override
251    public boolean equals(Object other) {
252        Frame that = (Frame)other;
253        for (int i = 0; i < locals.length; i++) {
254            if (!locals[i].equals(that.locals[i])) return false;
255        }
256        for (int i = 0; i < stacklen; i++) {
257            if (!stack[i].equals(that.stack[i])) return false;
258        }
259        return true;
260    }
261    
262    @Override
263    public int hashCode() {
264        int hash = 0;
265        for (int i = 0; i < this.locals.length;i++) hash ^= this.locals[i].hashCode();
266        for (int i = 0; i < this.stacklen;i++) hash ^= this.locals[i].hashCode();
267        return hash;
268    }
269    
270    @Override
271    public String toString() {
272        StringBuffer sb = new StringBuffer(100);
273        int numDefined = 0;
274        sb.append("): ");
275        for (int i = 0; i < this.locals.length;i++) {
276            Value v = locals[i];
277            if (v != Value.V_UNDEFINED) {
278                numDefined++;
279                sb.append(i).append(':').append(this.locals[i]).append(" ");
280            }
281        }
282        sb.insert(0, numDefined);
283        sb.insert(0, "Locals(");
284        sb.append("\n").append("Stack(").append(stacklen).append("): ");
285        for (int i = 0; i < this.stacklen;i++) {
286            sb.append(this.stack[i]).append(" ");
287        }
288        return sb.toString();
289    }
290
291    public int getMaxLocals() {
292        return locals.length;
293    }
294    
295    public int getStackLen() {
296        return stacklen;
297    }
298    
299}