1. package com.sun.org.apache.bcel.internal.verifier.structurals;
  2. /* ====================================================================
  3. * The Apache Software License, Version 1.1
  4. *
  5. * Copyright (c) 2001 The Apache Software Foundation. All rights
  6. * reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in
  17. * the documentation and/or other materials provided with the
  18. * distribution.
  19. *
  20. * 3. The end-user documentation included with the redistribution,
  21. * if any, must include the following acknowledgment:
  22. * "This product includes software developed by the
  23. * Apache Software Foundation (http://www.apache.org/)."
  24. * Alternately, this acknowledgment may appear in the software itself,
  25. * if and wherever such third-party acknowledgments normally appear.
  26. *
  27. * 4. The names "Apache" and "Apache Software Foundation" and
  28. * "Apache BCEL" must not be used to endorse or promote products
  29. * derived from this software without prior written permission. For
  30. * written permission, please contact apache@apache.org.
  31. *
  32. * 5. Products derived from this software may not be called "Apache",
  33. * "Apache BCEL", nor may "Apache" appear in their name, without
  34. * prior written permission of the Apache Software Foundation.
  35. *
  36. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  37. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  38. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  39. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  40. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  41. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  42. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  43. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  44. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  45. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  46. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  47. * SUCH DAMAGE.
  48. * ====================================================================
  49. *
  50. * This software consists of voluntary contributions made by many
  51. * individuals on behalf of the Apache Software Foundation. For more
  52. * information on the Apache Software Foundation, please see
  53. * <http://www.apache.org/>.
  54. */
  55. import com.sun.org.apache.bcel.internal.generic.*;
  56. import com.sun.org.apache.bcel.internal.verifier.exc.*;
  57. import java.util.*;
  58. /**
  59. * This class implements a stack used for symbolic JVM stack simulation.
  60. * [It's used an an operand stack substitute.]
  61. * Elements of this stack are com.sun.org.apache.bcel.internal.generic.Type objects.
  62. *
  63. * @version $Id: OperandStack.java,v 1.1.1.1 2001/10/29 20:00:41 jvanzyl Exp $
  64. * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
  65. */
  66. public class OperandStack{
  67. /** We hold the stack information here. */
  68. private ArrayList stack = new ArrayList();
  69. /** The maximum number of stack slots this OperandStack instance may hold. */
  70. private int maxStack;
  71. /**
  72. * Creates an empty stack with a maximum of maxStack slots.
  73. */
  74. public OperandStack(int maxStack){
  75. this.maxStack = maxStack;
  76. }
  77. /**
  78. * Creates an otherwise empty stack with a maximum of maxStack slots and
  79. * the ObjectType 'obj' at the top.
  80. */
  81. public OperandStack(int maxStack, ObjectType obj){
  82. this.maxStack = maxStack;
  83. this.push(obj);
  84. }
  85. /**
  86. * Returns a deep copy of this object; that means, the clone operates
  87. * on a new stack. However, the Type objects on the stack are
  88. * shared.
  89. */
  90. protected Object clone(){
  91. OperandStack newstack = new OperandStack(this.maxStack);
  92. newstack.stack = (ArrayList) this.stack.clone();
  93. return newstack;
  94. }
  95. /**
  96. * Clears the stack.
  97. */
  98. public void clear(){
  99. stack = new ArrayList();
  100. }
  101. /**
  102. * Returns true if and only if this OperandStack
  103. * equals another, meaning equal lengths and equal
  104. * objects on the stacks.
  105. */
  106. public boolean equals(Object o){
  107. if (!(o instanceof OperandStack)) return false;
  108. OperandStack s = (OperandStack) o;
  109. return this.stack.equals(s.stack);
  110. }
  111. /**
  112. * Returns a (typed!) clone of this.
  113. *
  114. * @see #clone()
  115. */
  116. public OperandStack getClone(){
  117. return (OperandStack) this.clone();
  118. }
  119. /**
  120. * Returns true IFF this OperandStack is empty.
  121. */
  122. public boolean isEmpty(){
  123. return stack.isEmpty();
  124. }
  125. /**
  126. * Returns the number of stack slots this stack can hold.
  127. */
  128. public int maxStack(){
  129. return this.maxStack;
  130. }
  131. /**
  132. * Returns the element on top of the stack. The element is not popped off the stack!
  133. */
  134. public Type peek(){
  135. return peek(0);
  136. }
  137. /**
  138. * Returns the element that's i elements below the top element; that means,
  139. * iff i==0 the top element is returned. The element is not popped off the stack!
  140. */
  141. public Type peek(int i){
  142. return (Type) stack.get(size()-i-1);
  143. }
  144. /**
  145. * Returns the element on top of the stack. The element is popped off the stack.
  146. */
  147. public Type pop(){
  148. Type e = (Type) stack.remove(size()-1);
  149. return e;
  150. }
  151. /**
  152. * Pops i elements off the stack. ALWAYS RETURNS "null"!!!
  153. */
  154. public Type pop(int i){
  155. for (int j=0; j<i; j++){
  156. pop();
  157. }
  158. return null;
  159. }
  160. /**
  161. * Pushes a Type object onto the stack.
  162. */
  163. public void push(Type type){
  164. if (type == null) throw new AssertionViolatedException("Cannot push NULL onto OperandStack.");
  165. if (type == Type.BOOLEAN || type == Type.CHAR || type == Type.BYTE || type == Type.SHORT){
  166. throw new AssertionViolatedException("The OperandStack does not know about '"+type+"'; use Type.INT instead.");
  167. }
  168. if (slotsUsed() >= maxStack){
  169. throw new AssertionViolatedException("OperandStack too small, should have thrown proper Exception elsewhere. Stack: "+this);
  170. }
  171. stack.add(type);
  172. }
  173. /**
  174. * Returns the size of this OperandStack; that means, how many Type objects there are.
  175. */
  176. int size(){
  177. return stack.size();
  178. }
  179. /**
  180. * Returns the number of stack slots used.
  181. * @see #maxStack()
  182. */
  183. public int slotsUsed(){
  184. /* XXX change this to a better implementation using a variable
  185. that keeps track of the actual slotsUsed()-value monitoring
  186. all push()es and pop()s.
  187. */
  188. int slots = 0;
  189. for (int i=0; i<stack.size(); i++){
  190. slots += peek(i).getSize();
  191. }
  192. return slots;
  193. }
  194. /**
  195. * Returns a String representation of this OperandStack instance.
  196. */
  197. public String toString(){
  198. String s = "Slots used: "+slotsUsed()+" MaxStack: "+maxStack+".\n";
  199. for (int i=0; i<size(); i++){
  200. s+=peek(i)+" (Size: "+peek(i).getSize()+")\n";
  201. }
  202. return s;
  203. }
  204. /**
  205. * Merges another stack state into this instance's stack state.
  206. * See the Java Virtual Machine Specification, Second Edition, page 146: 4.9.2
  207. * for details.
  208. */
  209. public void merge(OperandStack s){
  210. if ( (slotsUsed() != s.slotsUsed()) || (size() != s.size()) )
  211. throw new StructuralCodeConstraintException("Cannot merge stacks of different size:\nOperandStack A:\n"+this+"\nOperandStack B:\n"+s);
  212. for (int i=0; i<size(); i++){
  213. // If the object _was_ initialized and we're supposed to merge
  214. // in some uninitialized object, we reject the code (see vmspec2, 4.9.4, last paragraph).
  215. if ( (! (stack.get(i) instanceof UninitializedObjectType)) && (s.stack.get(i) instanceof UninitializedObjectType) ){
  216. throw new StructuralCodeConstraintException("Backwards branch with an uninitialized object on the stack detected.");
  217. }
  218. // Even harder, we're not initialized but are supposed to broaden
  219. // the known object type
  220. if ( (!(stack.get(i).equals(s.stack.get(i)))) && (stack.get(i) instanceof UninitializedObjectType) && (!(s.stack.get(i) instanceof UninitializedObjectType))){
  221. throw new StructuralCodeConstraintException("Backwards branch with an uninitialized object on the stack detected.");
  222. }
  223. // on the other hand...
  224. if (stack.get(i) instanceof UninitializedObjectType){ //if we have an uninitialized object here
  225. if (! (s.stack.get(i) instanceof UninitializedObjectType)){ //that has been initialized by now
  226. stack.set(i, ((UninitializedObjectType) (stack.get(i))).getInitialized() ); //note that.
  227. }
  228. }
  229. if (! stack.get(i).equals(s.stack.get(i))){
  230. if ( (stack.get(i) instanceof ReferenceType) &&
  231. (s.stack.get(i) instanceof ReferenceType) ){
  232. stack.set(i, ((ReferenceType) stack.get(i)).firstCommonSuperclass((ReferenceType) (s.stack.get(i))));
  233. }
  234. else{
  235. throw new StructuralCodeConstraintException("Cannot merge stacks of different types:\nStack A:\n"+this+"\nStack B:\n"+s);
  236. }
  237. }
  238. }
  239. }
  240. /**
  241. * Replaces all occurences of u in this OperandStack instance
  242. * with an "initialized" ObjectType.
  243. */
  244. public void initializeObject(UninitializedObjectType u){
  245. for (int i=0; i<stack.size(); i++){
  246. if (stack.get(i) == u){
  247. stack.set(i, u.getInitialized());
  248. }
  249. }
  250. }
  251. }