Scope.java 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. // Copyright (c) 1997, 2004 Per M.A. Bothner.
  2. // This is free software; for terms and warranty disclaimer see ./COPYING.
  3. package gnu.bytecode;
  4. import java.util.HashMap;
  5. public class Scope
  6. {
  7. /** The enclosing scope. */
  8. Scope parent;
  9. Scope nextSibling;
  10. Scope firstChild, lastChild;
  11. /** If true, don't call freeLocal on our variables (yet). */
  12. boolean preserved;
  13. boolean autoPop;
  14. Label start;
  15. Label end;
  16. private Variable vars;
  17. Variable last_var;
  18. public Scope()
  19. {
  20. }
  21. public Scope (Label start, Label end)
  22. {
  23. this.start = start;
  24. this.end = end;
  25. }
  26. // Variable lookup (String name);
  27. public final Variable firstVar () { return vars; }
  28. public VarEnumerator allVars () { return new VarEnumerator (this); }
  29. public Label getStartLabel() { return start; }
  30. public Label getEndLabel() { return end; }
  31. /** Link this scope as the next child of its parent scope. */
  32. public void linkChild (Scope parent)
  33. {
  34. this.parent = parent;
  35. if (parent == null)
  36. return;
  37. if (parent.lastChild == null)
  38. parent.firstChild = this;
  39. else
  40. parent.lastChild.nextSibling = this;
  41. parent.lastChild = this;
  42. }
  43. public Variable addVariable (CodeAttr code, Type type, String name)
  44. {
  45. Variable var = new Variable(name, type);
  46. addVariable (code, var);
  47. return var;
  48. }
  49. public void addVariable (Variable var)
  50. {
  51. if (last_var == null)
  52. vars = var;
  53. else
  54. last_var.next = var;
  55. last_var = var;
  56. var.setScope(this);
  57. }
  58. /* Add a new Variable, linking it in after a given Variable, */
  59. public void addVariableAfter (Variable prev, Variable var)
  60. {
  61. if (prev == null)
  62. { // Put first
  63. var.next = vars;
  64. vars = var;
  65. }
  66. else
  67. {
  68. var.next = prev.next;
  69. prev.next = var;
  70. }
  71. if (last_var == prev)
  72. last_var = var;
  73. if (var.next == var)
  74. throw new Error("cycle");
  75. var.setScope(this);
  76. }
  77. public void addVariable (CodeAttr code, Variable var)
  78. {
  79. addVariable (var);
  80. if (var.isSimple() && code != null)
  81. var.allocateLocal(code);
  82. }
  83. /**
  84. * Return a variable the scope, by numerical index.
  85. * @param index the number of the variable
  86. */
  87. public Variable getVariable(int index) {
  88. Variable var = vars;
  89. while (--index >= 0)
  90. var = var.next;
  91. return var;
  92. }
  93. /** Fix duplicate names.
  94. * This is needed for Android, since otherwise dex complains.
  95. */
  96. public void fixParamNames(HashMap<String,Variable> map) {
  97. for (Variable var = firstVar(); var != null;
  98. var = var.nextVar()) {
  99. String name = var.getName();
  100. if (name != null) {
  101. String xname = name;
  102. Variable old;
  103. for (int i = 0; (old = map.get(xname)) != null; i++)
  104. xname = name + '$' + i;
  105. if (name != xname)
  106. var.setName(xname);
  107. map.put(xname, var);
  108. }
  109. }
  110. }
  111. static boolean equals (byte[] name1, byte[] name2) {
  112. if (name1.length != name2.length)
  113. return false;
  114. if (name1 == name2)
  115. return true;
  116. for (int i = name1.length; --i >= 0; )
  117. if (name1[i] != name2[i])
  118. return false;
  119. return true;
  120. }
  121. public void setStartPC(CodeAttr code)
  122. {
  123. if (start == null)
  124. start = new Label();
  125. boolean reachable = code.reachableHere();
  126. start.define(code);
  127. code.setReachable(reachable);
  128. }
  129. /** Should be called at the start of a logical function - inlined or not. */
  130. public void noteStartFunction(CodeAttr code)
  131. {
  132. setStartPC(code);
  133. }
  134. /**
  135. * Search by name for a Variable in this Scope (only).
  136. * @param name name to search for
  137. * @return the Variable, or null if not found (in this scope).
  138. */
  139. public Variable lookup (String name) {
  140. for (Variable var = vars; var != null; var = var.next) {
  141. if (name.equals(var.name))
  142. return var;
  143. }
  144. return null;
  145. }
  146. /** Make local variable slots of this scope available for re-use.
  147. * However, if the 'preserved' flag is set, defer doing so until
  148. * we exit a non-preserved Scope. */
  149. void freeLocals (CodeAttr code)
  150. {
  151. if (preserved)
  152. return;
  153. for (Variable var = vars; var != null; var = var.next)
  154. {
  155. if (var.isSimple () && ! var.dead ())
  156. var.freeLocal(code);
  157. }
  158. for (Scope child = firstChild; child != null; child = child.nextSibling)
  159. {
  160. if (child.preserved)
  161. {
  162. child.preserved = false;
  163. child.freeLocals(code);
  164. }
  165. }
  166. }
  167. /* DEBUG
  168. static int counter; int id=++counter;
  169. public String toString() { return "Scope#"+id; }
  170. */
  171. }