Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
Frame |
|
| 3.5555555555555554;3.556 |
1 | /* | |
2 | * Licensed to the Apache Software Foundation (ASF) under one or more | |
3 | * contributor license agreements. See the NOTICE file distributed with | |
4 | * this work for additional information regarding copyright ownership. | |
5 | * The ASF licenses this file to You under the Apache License, Version 2.0 | |
6 | * (the "License"); you may not use this file except in compliance with | |
7 | * the License. You may obtain a copy of the License at | |
8 | * | |
9 | * http://www.apache.org/licenses/LICENSE-2.0 | |
10 | * | |
11 | * Unless required by applicable law or agreed to in writing, software | |
12 | * distributed under the License is distributed on an "AS IS" BASIS, | |
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | * See the License for the specific language governing permissions and | |
15 | * limitations under the License. | |
16 | */ | |
17 | package org.apache.commons.javaflow.bytecode.transformation.bcel.analyser; | |
18 | ||
19 | import org.apache.bcel.generic.Type; | |
20 | import org.apache.bcel.generic.ReferenceType; | |
21 | import org.apache.bcel.generic.ReturnaddressType; | |
22 | import org.apache.bcel.verifier.exc.StructuralCodeConstraintException; | |
23 | import org.apache.bcel.verifier.exc.AssertionViolatedException; | |
24 | ||
25 | /** | |
26 | * This class represents a JVM execution frame; that means, | |
27 | * a local variable array and an operand stack. | |
28 | * | |
29 | * WARNING! These classes are a fork of the bcel verifier. | |
30 | * | |
31 | * @version $Id: Frame.java 480487 2006-11-29 08:54:42Z bayard $ | |
32 | * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A> | |
33 | */ | |
34 | ||
35 | public class Frame{ | |
36 | ||
37 | /** | |
38 | * For instance initialization methods, it is important to remember | |
39 | * which instance it is that is not initialized yet. It will be | |
40 | * initialized invoking another constructor later. | |
41 | * NULL means the instance already *is* initialized. | |
42 | */ | |
43 | public static UninitializedObjectType _this; | |
44 | ||
45 | /** | |
46 | * | |
47 | */ | |
48 | private LocalVariables locals; | |
49 | ||
50 | /** | |
51 | * | |
52 | */ | |
53 | private OperandStack stack; | |
54 | ||
55 | /** | |
56 | * | |
57 | */ | |
58 | 0 | public Frame(int maxLocals, int maxStack){ |
59 | 0 | locals = new LocalVariables(maxLocals); |
60 | 0 | stack = new OperandStack(maxStack); |
61 | 0 | } |
62 | ||
63 | /** | |
64 | * | |
65 | */ | |
66 | 0 | public Frame(LocalVariables locals, OperandStack stack){ |
67 | 0 | this.locals = locals; |
68 | 0 | this.stack = stack; |
69 | 0 | } |
70 | ||
71 | /** | |
72 | * | |
73 | */ | |
74 | protected Object clone(){ | |
75 | 0 | Frame f = new Frame(locals.getClone(), stack.getClone()); |
76 | 0 | return f; |
77 | } | |
78 | ||
79 | /** | |
80 | * | |
81 | */ | |
82 | public Frame getClone(){ | |
83 | 0 | return (Frame) clone(); |
84 | } | |
85 | ||
86 | /** | |
87 | * | |
88 | */ | |
89 | public LocalVariables getLocals(){ | |
90 | 0 | return locals; |
91 | } | |
92 | ||
93 | /** | |
94 | * | |
95 | */ | |
96 | public OperandStack getStack(){ | |
97 | 0 | return stack; |
98 | } | |
99 | ||
100 | /** | |
101 | * | |
102 | */ | |
103 | public boolean equals(Object o){ | |
104 | 0 | if (!(o instanceof Frame)) return false; // implies "null" is non-equal. |
105 | 0 | Frame f = (Frame) o; |
106 | 0 | return this.stack.equals(f.stack) && this.locals.equals(f.locals); |
107 | } | |
108 | ||
109 | /** | |
110 | * Returns a String representation of the Frame instance. | |
111 | */ | |
112 | public String toString(){ | |
113 | 0 | String s="Local Variables:\n"; |
114 | 0 | s += locals; |
115 | 0 | s += "OperandStack:\n"; |
116 | 0 | s += stack; |
117 | 0 | return s; |
118 | } | |
119 | ||
120 | ||
121 | /** | |
122 | * Merges two {@link Type}s into one. | |
123 | * | |
124 | * @param errorIfFailed | |
125 | * if true, attempting to merge two types that are incompatible causes an error. | |
126 | * if false, it yields {@link Type#UNKNOWN} value, indicating that value is unusable. | |
127 | */ | |
128 | /*package*/ static Type merge(Type lhs, Type rhs, boolean errorIfFailed) { | |
129 | try { | |
130 | ||
131 | // We won't accept an unitialized object if we know it was initialized; | |
132 | // compare vmspec2, 4.9.4, last paragraph. | |
133 | 0 | if ((!(lhs instanceof UninitializedObjectType)) && (rhs instanceof UninitializedObjectType)) { |
134 | 0 | throw new StructuralCodeConstraintException("Backwards branch with an uninitialized object in the local variables detected."); |
135 | } | |
136 | // Even harder, what about _different_ uninitialized object types?! | |
137 | 0 | if ((!(lhs.equals(rhs))) && (lhs instanceof UninitializedObjectType) && (rhs instanceof UninitializedObjectType)) { |
138 | 0 | throw new StructuralCodeConstraintException("Backwards branch with an uninitialized object in the local variables detected."); |
139 | } | |
140 | // If we just didn't know that it was initialized, we have now learned. | |
141 | 0 | if (lhs instanceof UninitializedObjectType) { |
142 | 0 | if (! (rhs instanceof UninitializedObjectType)) { |
143 | 0 | lhs = ((UninitializedObjectType) lhs).getInitialized(); |
144 | } | |
145 | } | |
146 | 0 | if ((lhs instanceof ReferenceType) && (rhs instanceof ReferenceType)) { |
147 | 0 | if(lhs.equals(rhs)) { |
148 | 0 | return lhs; // same type |
149 | } | |
150 | ||
151 | 0 | Type sup = ((ReferenceType) lhs).getFirstCommonSuperclass((ReferenceType) rhs); |
152 | ||
153 | 0 | if (sup != null) { |
154 | 0 | return sup; |
155 | } else { | |
156 | // We should have checked this in Pass2! | |
157 | 0 | throw new AssertionViolatedException("Could not load all the super classes of '" + lhs + "' and '" + rhs + "'."); |
158 | } | |
159 | } | |
160 | ||
161 | 0 | if ((lhs instanceof ReturnaddressType) && (rhs instanceof ReturnaddressType)) { |
162 | // see 'FinallyFlow' test. | |
163 | 0 | return lhs; |
164 | } | |
165 | ||
166 | 0 | if (!lhs.equals(rhs)) { |
167 | 0 | if(errorIfFailed) { |
168 | 0 | throw new StructuralCodeConstraintException("Cannot merge different types:"+lhs+" and "+rhs); |
169 | } else { | |
170 | 0 | return Type.UNKNOWN; |
171 | } | |
172 | } | |
173 | ||
174 | 0 | return lhs; |
175 | 0 | } catch (ClassNotFoundException e) { |
176 | // FIXME: maybe not the best way to handle this | |
177 | 0 | throw new AssertionViolatedException("Missing class: " + e.toString()); |
178 | } | |
179 | } | |
180 | } |