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