View Javadoc

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      public Frame(int maxLocals, int maxStack){
59          locals = new LocalVariables(maxLocals);
60          stack = new OperandStack(maxStack);
61      }
62  
63      /**
64       *
65       */
66      public Frame(LocalVariables locals, OperandStack stack){
67          this.locals = locals;
68          this.stack = stack;
69      }
70  
71      /**
72       *
73       */
74      protected Object clone(){
75          Frame f = new Frame(locals.getClone(), stack.getClone());
76          return f;
77      }
78  
79      /**
80       *
81       */
82      public Frame getClone(){
83          return (Frame) clone();
84      }
85  
86      /**
87       *
88       */
89      public LocalVariables getLocals(){
90          return locals;
91      }
92  
93      /**
94       *
95       */
96      public OperandStack getStack(){
97          return stack;
98      }
99  
100     /**
101      *
102      */
103     public boolean equals(Object o){
104         if (!(o instanceof Frame)) return false; // implies "null" is non-equal.
105         Frame f = (Frame) o;
106         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         String s="Local Variables:\n";
114         s += locals;
115         s += "OperandStack:\n";
116         s += stack;
117         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             if ((!(lhs instanceof UninitializedObjectType)) && (rhs instanceof UninitializedObjectType)) {
134                 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             if ((!(lhs.equals(rhs))) && (lhs instanceof UninitializedObjectType) && (rhs instanceof UninitializedObjectType)) {
138                 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             if (lhs instanceof UninitializedObjectType) {
142                 if (! (rhs instanceof UninitializedObjectType)) {
143                     lhs = ((UninitializedObjectType) lhs).getInitialized();
144                 }
145             }
146             if ((lhs instanceof ReferenceType) && (rhs instanceof ReferenceType)) {
147                 if(lhs.equals(rhs)) {
148                     return lhs; // same type
149                 }
150 
151                 Type sup = ((ReferenceType) lhs).getFirstCommonSuperclass((ReferenceType) rhs);
152 
153                 if (sup != null) {
154                     return sup;
155                 } else {
156                     // We should have checked this in Pass2!
157                     throw new AssertionViolatedException("Could not load all the super classes of '" + lhs + "' and '" + rhs + "'.");
158                 }
159             }
160 
161             if ((lhs instanceof ReturnaddressType) && (rhs instanceof ReturnaddressType)) {
162                 // see 'FinallyFlow' test.
163                 return lhs;
164             }
165 
166             if (!lhs.equals(rhs)) {
167                 if(errorIfFailed) {
168                     throw new StructuralCodeConstraintException("Cannot merge different types:"+lhs+" and "+rhs);
169                 } else {
170                     return Type.UNKNOWN;
171                 }
172             }
173 
174             return lhs;
175         } catch (ClassNotFoundException e) {
176             // FIXME: maybe not the best way to handle this
177             throw new AssertionViolatedException("Missing class: " + e.toString());
178         }
179     }
180 }