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