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