1 kkz      1.1.2.1 // WriteBarrierQuadPass.java, created Tue Aug 21 19:42:49 2001 by kkz
  2 kkz      1.1.2.1 // Copyright (C) 2000 Karen Zee <kkz@tmi.lcs.mit.edu>
  3 kkz      1.1.2.1 // Licensed under the terms of the GNU GPL; see COPYING for details.
  4 kkz      1.1.2.1 package harpoon.Analysis.PreciseGC;
  5 kkz      1.1.2.1 
  6 kkz      1.1.2.1 import harpoon.Analysis.ClassHierarchy;
  7 kkz      1.1.2.1 import harpoon.Backend.Generic.Frame;
  8 kkz      1.1.2.1 import harpoon.Backend.Runtime1.Data;
  9 kkz      1.1.2.1 import harpoon.ClassFile.HClass;
 10 kkz      1.1.2.1 import harpoon.ClassFile.HCode;
 11 kkz      1.1.2.1 import harpoon.ClassFile.HCodeAndMaps;
 12 kkz      1.1.2.1 import harpoon.ClassFile.HCodeFactory;
 13 kkz      1.1.2.1 import harpoon.ClassFile.HMethod;
 14 kkz      1.1.2.1 import harpoon.ClassFile.Linker;
 15 kkz      1.1.2.3 import harpoon.IR.Quads.ASET;
 16 kkz      1.1.2.1 import harpoon.IR.Quads.CALL;
 17 kkz      1.1.2.1 import harpoon.IR.Quads.Code;
 18 kkz      1.1.2.1 import harpoon.IR.Quads.CONST;
 19 kkz      1.1.2.1 import harpoon.IR.Quads.Code;
 20 kkz      1.1.2.1 import harpoon.IR.Quads.Edge;
 21 kkz      1.1.2.1 import harpoon.IR.Quads.FOOTER;
 22 kkz      1.1.2.1 import harpoon.IR.Quads.GET;
 23 kkz      1.1.2.1 import harpoon.IR.Quads.HEADER;
 24 kkz      1.1.2.1 import harpoon.IR.Quads.Quad;
 25 kkz      1.1.2.1 import harpoon.IR.Quads.QuadFactory;
 26 kkz      1.1.2.3 import harpoon.IR.Quads.QuadKind;
 27 kkz      1.1.2.1 import harpoon.IR.Quads.QuadVisitor;
 28 kkz      1.1.2.1 import harpoon.IR.Quads.SET;
 29 kkz      1.1.2.1 import harpoon.IR.Quads.THROW;
 30 kkz      1.1.2.1 import harpoon.IR.Quads.Code;
 31 kkz      1.1.2.1 import harpoon.Temp.Temp;
 32 kkz      1.1.2.1 import harpoon.Temp.TempFactory;
 33 kkz      1.1.2.6 import harpoon.Util.Tuple;
 34 kkz      1.1.2.1 import harpoon.Util.Util;
 35 kkz      1.1.2.1 
 36 kkz      1.1.2.2 import java.io.PrintStream;
 37 kkz      1.1.2.4 import java.util.Collections;
 38 kkz      1.1.2.3 import java.util.HashSet;
 39 kkz      1.1.2.3 import java.util.Iterator;
 40 kkz      1.1.2.6 import java.util.Map;
 41 kkz      1.1.2.3 import java.util.Set;
 42 kkz      1.1.2.2 
 43 kkz      1.4     import java.util.HashMap;
 44 cananian 1.8     import net.cscott.jutil.WorkSet;
 45 kkz      1.4     import harpoon.IR.Quads.RETURN;
 46 kkz      1.4     import harpoon.IR.Quads.AGET;
 47 kkz      1.4     import harpoon.IR.Quads.ANEW;
 48 kkz      1.4     import harpoon.IR.Quads.NEW;
 49 kkz      1.4     
 50 kkz      1.4     
 51 kkz      1.1.2.1 /**
 52 kkz      1.1.2.1  * <code>WriteBarrierQuadPass</code> takes code in Quad form and
 53 kkz      1.1.2.1  * inserts a fake call to a write barrier that is later replaced with
 54 kkz      1.1.2.1  * a real implementation in <code>WriteBarrierTreePass</code>.
 55 kkz      1.1.2.1  *
 56 kkz      1.1.2.1  * When used without <code>WriteBarrierTreePass</code> and in 
 57 kkz      1.1.2.1  * combination with the mark-and-sweep collector, reports statistics 
 58 kkz      1.1.2.1  * about the number of times the write-barrier is called.
 59 kkz      1.1.2.1  * 
 60 kkz      1.1.2.1  * @author  Karen Zee <kkz@tmi.lcs.mit.edu>
 61 cananian 1.8      * @version $Id: WriteBarrierQuadPass.java,v 1.8 2004/02/08 01:53:11 cananian Exp $
 62 kkz      1.1.2.1  */
 63 kkz      1.1.2.1 public class WriteBarrierQuadPass extends 
 64 kkz      1.1.2.1     harpoon.Analysis.Transformation.MethodMutator {
 65 kkz      1.1.2.4 
 66 kkz      1.1.2.5     private final ClassHierarchy ch;
 67 kkz      1.1.2.4     private final boolean optimize;
 68 kkz      1.1.2.4     private final MRAFactory mraf;
 69 kkz      1.1.2.4     private final HMethod arraySC;
 70 kkz      1.1.2.4     private final HMethod fieldSC;
 71 kkz      1.1.2.4     private final HClass JLT;
 72 kkz      1.1.2.4     private final HClass JLRF;
 73 kkz      1.1.2.1     private WriteBarrierStats wbs;
 74 kkz      1.1.2.1 
 75 kkz      1.1.2.4     /** Creates a <code>WriteBarrierQuadPass</code>. 
 76 kkz      1.1.2.4      *  Write barrier removal performed if optimize is true.
 77 kkz      1.1.2.4      */
 78 kkz      1.1.2.4     public WriteBarrierQuadPass(ClassHierarchy ch, 
 79 kkz      1.1.2.4                                 HCodeFactory parent, 
 80 kkz      1.1.2.4                                 Linker linker,
 81 kkz      1.1.2.5                                 String resourceName,
 82 kkz      1.1.2.7                                 int optLevel) {
 83 kkz      1.1.2.1         super(parent);
 84 kkz      1.1.2.5         this.ch = ch;
 85 kkz      1.1.2.1         this.JLT = linker.forName("java.lang.Throwable");
 86 kkz      1.1.2.1         HClass WB = linker.forName("harpoon.Runtime.PreciseGC.WriteBarrier");
 87 kkz      1.1.2.1         HClass JLO = linker.forName("java.lang.Object");
 88 kkz      1.1.2.1         this.JLRF = linker.forName("java.lang.reflect.Field");
 89 kkz      1.1.2.1         this.arraySC = WB.getMethod("asc", new HClass[] 
 90 kkz      1.1.2.1                                     { JLO, HClass.Int, JLO, HClass.Int });
 91 kkz      1.1.2.1         this.fieldSC = WB.getMethod("fsc", new HClass[] 
 92 kkz      1.1.2.1                                     { JLO, JLRF, JLO, HClass.Int });
 93 kkz      1.1.2.7         this.optimize = (optLevel != 0);
 94 kkz      1.1.2.7         System.out.print("MRA analysis time = ");
 95 kkz      1.7             // for timing reasons, first force passes to run
 96 kkz      1.7             for(Iterator it = ch.callableMethods().iterator(); it.hasNext(); )
 97 kkz      1.7                 parent.convert((HMethod)it.next());
 98 kkz      1.1.2.6         long start_time = System.currentTimeMillis();
 99 kkz      1.1.2.7         this.mraf = optimize ?
100 kkz      1.1.2.7             new MRAFactory(ch, parent, linker, resourceName, optLevel): null;
101 kkz      1.1.2.7         System.out.println(System.currentTimeMillis()-start_time);
102 kkz      1.1.2.1     }
103 kkz      1.1.2.1     
104 kkz      1.1.2.1     protected HCode mutateHCode(HCodeAndMaps input) {
105 kkz      1.1.2.1         Code hc = (Code)input.hcode();
106 kkz      1.1.2.5         String cls_str = hc.getMethod().getDeclaringClass().getName();
107 kkz      1.1.2.1         // we should not have to update derivation information
108 cananian 1.3.2.1         assert hc.getDerivation() == null;
109 kkz      1.1.2.3         // create a set of SETs and ASETs that can be ignored
110 kkz      1.1.2.3         Set ignore = new HashSet();
111 kkz      1.1.2.4         if (optimize) {
112 kkz      1.1.2.4             // first, run the MRA an the code
113 kkz      1.1.2.4             MRA mra = mraf.mra(hc);
114 kkz      1.1.2.4             // MRA mra = new MRA(hc, safeSet);
115 kkz      1.1.2.4             for (Iterator it = hc.getElementsI(); it.hasNext(); ) {
116 kkz      1.1.2.4                 Quad q = (Quad)it.next();
117 kkz      1.1.2.6                 Tuple mra_before = mra.mra_before(q);
118 kkz      1.1.2.4                 if (q.kind() == QuadKind.ASET) {
119 kkz      1.1.2.5                     // ASETs only know whether the component type is
120 kkz      1.1.2.5                     // an object, and not the specific type of the
121 kkz      1.1.2.5                     // array, so we can only do an ignore if the
122 kkz      1.1.2.5                     // exception set is empty, unless we want to do
123 kkz      1.1.2.5                     // more analysis to determine the type of the array.
124 kkz      1.1.2.6                     Map m = (Map) mra_before.proj(0);
125 kkz      1.1.2.6                     Set s = (Set) mra_before.proj(1);
126 kkz      1.1.2.6                     if (m.containsKey(((ASET)q).objectref()) && s.isEmpty()) {
127 kkz      1.1.2.4                         ignore.add(q);
128 kkz      1.1.2.5                     }
129 kkz      1.1.2.4                 } else if (q.kind() == QuadKind.SET) {
130 kkz      1.1.2.6                     Map m = (Map) mra_before.proj(0);
131 kkz      1.1.2.6                     Set s = (Set) mra_before.proj(1);
132 kkz      1.1.2.6                     if (m.containsKey(((SET)q).objectref())) {
133 kkz      1.1.2.5                         // add first, remove later if problems
134 kkz      1.1.2.4                         ignore.add(q);
135 kkz      1.1.2.5                         HClass type = ((SET)q).field().getType();
136 kkz      1.1.2.6                         for (Iterator cls = s.iterator(); cls.hasNext(); ) {
137 kkz      1.1.2.5                             if (ch.parents((HClass)cls.next()).
138 kkz      1.1.2.5                                 contains(type)) {
139 kkz      1.4                                     ignore.remove(q);
140 kkz      1.1.2.5                                 break;
141 kkz      1.1.2.5                             }
142 kkz      1.1.2.5                         }
143 kkz      1.1.2.5                     }
144 kkz      1.1.2.4                 }
145 kkz      1.1.2.3             }
146 kkz      1.1.2.3         }
147 kkz      1.1.2.4         // freeze our results
148 kkz      1.1.2.4         ignore = Collections.unmodifiableSet(ignore);
149 kkz      1.1.2.1         //hc.print(new java.io.PrintWriter(System.out), null);
150 kkz      1.1.2.1         HEADER header = (HEADER) hc.getRootElement();
151 kkz      1.1.2.1         FOOTER footer = (FOOTER) header.footer();
152 kkz      1.4             // BIT EXPERIMENT
153 kkz      1.4             // QuadVisitor qv = new WriteBarrierVisitor(footer, Collections.EMPTY_SET);
154 kkz      1.1.2.3         QuadVisitor qv = new WriteBarrierVisitor(footer, ignore);
155 kkz      1.1.2.1         // we put all elements in array to avoid screwing up the
156 kkz      1.1.2.1         // iterator as we mutate the quad graph in-place.
157 kkz      1.1.2.1         Quad[] allquads = (Quad[]) hc.getElements();
158 kkz      1.1.2.1         for (int i=0; i<allquads.length; i++)
159 kkz      1.1.2.1             allquads[i].accept(qv);
160 kkz      1.1.2.1         // yay, done!
161 kkz      1.4     
162 kkz      1.4             // BIT EXPERIMENT BEGIN
163 kkz      1.7             // MartinVisitor mv = new MartinVisitor(ignore);
164 kkz      1.7             // mv.doAnalysis((Quad)hc.getRootElement());
165 kkz      1.4             // BIT EXPERIMENT END
166 kkz      1.1.2.1         return hc;
167 kkz      1.1.2.1     }
168 kkz      1.1.2.1 
169 kkz      1.1.2.1     /** Code factory for post pass. Emits data needed for gathering
170 kkz      1.1.2.1      *  write barrier statistics. This pass needs to be run before
171 kkz      1.1.2.1      *  the pass returned by <code>treeCodeFactory</code> to have
172 kkz      1.1.2.1      *  any effect.
173 kkz      1.1.2.1      */
174 kkz      1.7         /*
175 kkz      1.1.2.1     public HCodeFactory statsCodeFactory(Frame f, HCodeFactory hcf,
176 kkz      1.1.2.2                                          ClassHierarchy ch,
177 kkz      1.1.2.2                                          PrintStream out) {
178 kkz      1.1.2.2         this.wbs = new WriteBarrierStats(f, hcf, ch, arraySC, fieldSC, out);
179 kkz      1.1.2.1         return wbs.codeFactory();
180 kkz      1.1.2.1     }
181 kkz      1.7         */
182 kkz      1.1.2.1     /** <code>Data</code> for gathering statistics on write barriers.
183 kkz      1.1.2.1      *  Needs the results of the pass returned by
184 kkz      1.1.2.1      *  <code>statsCodeFactory</code>.
185 kkz      1.1.2.1      */
186 kkz      1.7         /*
187 kkz      1.1.2.1     public Data getData(HClass hc, Frame f) {
188 kkz      1.1.2.1         // must have run statsCodeFactory first
189 cananian 1.3.2.1         assert wbs != null;
190 kkz      1.1.2.1         return new WriteBarrierData(hc, f, wbs.getCount());
191 kkz      1.1.2.1     }
192 kkz      1.7         */
193 kkz      1.4     
194 kkz      1.4         // BIT EXPERIMENT
195 kkz      1.4         private class MartinVisitor {
196 kkz      1.4             private final Set ignore;
197 kkz      1.4             private HashMap map;
198 kkz      1.4     
199 kkz      1.4             MartinVisitor(Set ignore) {
200 kkz      1.4                 this.ignore=ignore;
201 kkz      1.4                 this.map=new HashMap();
202 kkz      1.4             }
203 kkz      1.4             
204 kkz      1.4             public void doAnalysis(Quad header) {
205 kkz      1.4                 WorkSet quadstolookat=new WorkSet();
206 kkz      1.4                 WorkSet newstatements=new WorkSet();
207 kkz      1.4                 quadstolookat.add(header);
208 kkz      1.4                 while(!quadstolookat.isEmpty()) {
209 cananian 1.8                     Quad q=(Quad)quadstolookat.removeLast();
210 kkz      1.4                     if (isremovedSet(q)) {
211 kkz      1.4                         if (!map.containsKey(q)) {
212 kkz      1.4                             WorkSet ws=new WorkSet();
213 kkz      1.4                             ws.add(q);
214 kkz      1.4                             map.put(q,ws);
215 kkz      1.4                             for(int i=0;i<q.nextLength();i++)
216 kkz      1.4                                 quadstolookat.add(q.next(i));
217 kkz      1.4                         }
218 kkz      1.4                     } else if (mightCauseNewObject(q)) {
219 kkz      1.4                         if (!map.containsKey(q)) {
220 kkz      1.4                             WorkSet ws=new WorkSet();
221 kkz      1.4                             map.put(q,ws);
222 kkz      1.4                             for(int i=0;i<q.nextLength();i++)
223 kkz      1.4                                 quadstolookat.add(q.next(i));
224 kkz      1.4                             newstatements.add(q);
225 kkz      1.4                         }
226 kkz      1.4                     } else {
227 kkz      1.4                         if (!map.containsKey(q)) {
228 kkz      1.4                             WorkSet ws=new WorkSet();
229 kkz      1.4                             for(int i=0;i<q.prevLength();i++)
230 kkz      1.4                                 if (map.containsKey(q.prev(i))) {
231 kkz      1.4                                     WorkSet prevset=(WorkSet)map.get(q.prev(i));
232 kkz      1.4                                     ws.addAll(prevset);
233 kkz      1.4                                 }
234 kkz      1.4                             map.put(q,ws);
235 kkz      1.4                             for(int i=0;i<q.nextLength();i++)
236 kkz      1.4                                 quadstolookat.add(q.next(i));
237 kkz      1.4                         } else {
238 kkz      1.4                             WorkSet ws=new WorkSet();
239 kkz      1.4                             for(int i=0;i<q.prevLength();i++)
240 kkz      1.4                                 if (map.containsKey(q.prev(i))) {
241 kkz      1.4                                     WorkSet prevset=(WorkSet)map.get(q.prev(i));
242 kkz      1.4                                     ws.addAll(prevset);
243 kkz      1.4                                 }
244 kkz      1.4                             WorkSet oldset=(WorkSet) map.get(q);
245 kkz      1.4                             if (ws.size()>oldset.size()) {
246 kkz      1.4                                 map.put(q,ws);
247 kkz      1.4                                 for(int i=0;i<q.nextLength();i++)
248 kkz      1.4                                     quadstolookat.add(q.next(i));
249 kkz      1.4                             }
250 kkz      1.4                         }
251 kkz      1.4                     }
252 kkz      1.4                 }
253 kkz      1.4                 //cycle through each newstatements
254 kkz      1.4                 WorkSet assigns=new WorkSet();
255 kkz      1.4                 while(!newstatements.isEmpty()) {
256 kkz      1.4                     Quad q=(Quad)newstatements.pop();
257 kkz      1.4                     for(int i=0;i<q.prevLength();i++)
258 kkz      1.4                         if (map.containsKey(q.prev(i))) {
259 kkz      1.4                             WorkSet prevset=(WorkSet)map.get(q.prev(i));
260 kkz      1.4                             assigns.addAll(prevset);
261 kkz      1.4                         } else System.out.println("ERROR: "+q+" "+i+" "+q.prev(i)+ " in hacked analysis");
262 kkz      1.4                 }
263 kkz      1.4                 while(!assigns.isEmpty()) {
264 kkz      1.4                     Quad q=(Quad)assigns.pop();
265 kkz      1.4                     System.out.println("Adding overhead to: "+q);
266 kkz      1.4                     if (q instanceof SET) {
267 kkz      1.4                         SET s=(SET)q;
268 kkz      1.4                         Temp t=new Temp(q.getFactory().tempFactory());
269 kkz      1.4                         GET g=new GET(q.getFactory(), q, t, s.field(), s.objectref());
270 kkz      1.4                         SET ns=new SET(q.getFactory(), q, s.field(), s.objectref(),t);
271 kkz      1.4                         Quad.addEdge(ns,0,s.next(0),s.nextEdge(0).which_pred());
272 kkz      1.4                         Quad.addEdge(g,0,ns,0);
273 kkz      1.4                         Quad.addEdge(s,0,g,0);
274 kkz      1.4                     } else if (q instanceof ASET) {
275 kkz      1.4                         ASET s=(ASET)q;
276 kkz      1.4                         Temp t=new Temp(q.getFactory().tempFactory());
277 kkz      1.4                         AGET ag=new AGET(q.getFactory(), q, t, s.objectref(),s.index(),s.type());
278 kkz      1.4                         ASET ans=new ASET(q.getFactory(), q, s.objectref(), s.index(), t, s.type());
279 kkz      1.4     
280 kkz      1.4                         Quad.addEdge(ans,0,s.next(0),s.nextEdge(0).which_pred());
281 kkz      1.4                         Quad.addEdge(ag,0,ans,0);
282 kkz      1.4                         Quad.addEdge(s,0,ag,0);
283 kkz      1.4                     } else {
284 kkz      1.4                         System.out.println("ERROR: "+q+" in hacked analysis");
285 kkz      1.4                     }
286 kkz      1.4                 }
287 kkz      1.4             }
288 kkz      1.4     
289 kkz      1.4             public boolean isremovedSet(Quad q) {
290 kkz      1.4                 if (q instanceof ASET) {
291 kkz      1.4                     ASET as = (ASET)q;
292 kkz      1.4                     return (!as.type().isPrimitive() && ignore.contains(as));
293 kkz      1.4                 } else if (q instanceof SET) {
294 kkz      1.4                     SET s = (SET)q;
295 kkz      1.4                     return (!s.isStatic() && !s.field().getType().isPrimitive() &&
296 kkz      1.4                             ignore.contains(s));
297 kkz      1.4                 } else return false;
298 kkz      1.4             }
299 kkz      1.4             public boolean mightCauseNewObject(Quad q) {
300 kkz      1.4                 return ((q instanceof NEW)||
301 kkz      1.4                     (q instanceof THROW)||
302 kkz      1.4                     (q instanceof ANEW)||
303 kkz      1.4                     (q instanceof RETURN));
304 kkz      1.4             }
305 kkz      1.4     
306 kkz      1.4         }
307 kkz      1.4     
308 kkz      1.1.2.1 
309 kkz      1.1.2.3     private class WriteBarrierVisitor extends QuadVisitor {
310 kkz      1.1.2.3         private FOOTER footer;
311 kkz      1.1.2.3         private final Set ignore;
312 kkz      1.1.2.3 
313 kkz      1.1.2.3         /** Creates a <code>WriteBarrierVisitor</code>. */
314 kkz      1.1.2.3         WriteBarrierVisitor(FOOTER footer, Set ignore) {
315 kkz      1.1.2.1             this.footer = footer;
316 kkz      1.1.2.3             this.ignore = ignore;
317 kkz      1.1.2.1         }
318 kkz      1.1.2.3 
319 kkz      1.1.2.1         public void visit(Quad q) { /* do nothing */ }
320 kkz      1.1.2.1         public void visit(ASET q) {
321 kkz      1.1.2.3             // we are interested only in arrays containing pointers
322 kkz      1.1.2.3             // we can ignore ASETs where the array is the mra object
323 kkz      1.1.2.3             if (!q.type().isPrimitive() && !ignore.contains(q)) {
324 kkz      1.1.2.1                 QuadFactory qf = (QuadFactory)q.getFactory();
325 kkz      1.1.2.1                 TempFactory tf = qf.tempFactory();
326 kkz      1.1.2.1                 // create Temps
327 kkz      1.1.2.1                 Temp retex = new Temp(tf, "wbex");
328 kkz      1.1.2.1                 Temp id = new Temp(tf, "wbid");
329 kkz      1.1.2.1                 // create needed Quads
330 kkz      1.1.2.1                 CONST idc = new CONST(qf, q, id, new Integer(0), HClass.Int);
331 kkz      1.1.2.1                 CALL call = new CALL(qf, q, arraySC,
332 kkz      1.1.2.1                                      new Temp[] { q.objectref(), q.index(), 
333 kkz      1.1.2.1                                                   q.src(), id }, 
334 kkz      1.1.2.1                                      null, retex, false, false, new Temp[0]);
335 kkz      1.1.2.1                 THROW thr = new THROW(qf, q, retex);
336 kkz      1.1.2.1                 // add CONST and CALL before ASET
337 kkz      1.1.2.1                 splice(idc, q.prevEdge(0));
338 kkz      1.1.2.1                 splice(call, q.prevEdge(0));
339 kkz      1.1.2.1                 // add THROW after CALL
340 kkz      1.1.2.1                 Quad.addEdge(call, 1, thr, 0);
341 kkz      1.1.2.1                 footer = footer.attach(thr, 0);
342 kkz      1.1.2.1             }
343 kkz      1.1.2.1         }
344 kkz      1.1.2.1         public void visit(SET q) {
345 kkz      1.1.2.1             // we are interested only in non-static fields containing pointers
346 kkz      1.1.2.3             // we can ignore SETs where the object is the mra object
347 kkz      1.1.2.3             if (!q.isStatic() && !q.field().getType().isPrimitive() &&
348 kkz      1.1.2.3                 !ignore.contains(q)) {
349 kkz      1.1.2.1                 QuadFactory qf = (QuadFactory)q.getFactory();
350 kkz      1.1.2.1                 TempFactory tf = qf.tempFactory();
351 kkz      1.1.2.1                 // create needed Temps
352 kkz      1.1.2.1                 Temp field = new Temp(tf, "wbfield");
353 kkz      1.1.2.1                 Temp retex = new Temp(tf, "wbex");
354 kkz      1.1.2.1                 Temp id = new Temp(tf, "wbid");
355 kkz      1.1.2.1                 // create needed Quads
356 kkz      1.1.2.1                 CONST idc = new CONST(qf, q, id, new Integer(0), HClass.Int);
357 kkz      1.1.2.1                 CONST fieldc = new CONST(qf, q, field, q.field(), JLRF); 
358 kkz      1.1.2.1                 CALL call = new CALL(qf, q, fieldSC,
359 kkz      1.1.2.1                                      new Temp[] { q.objectref(), field, 
360 kkz      1.1.2.1                                                   q.src(), id }, 
361 kkz      1.1.2.1                                      null, retex, false, false, new Temp[0]);
362 kkz      1.1.2.1                 THROW thr = new THROW(qf, q, retex);
363 kkz      1.1.2.1                 // add CONSTs and CALL before SET
364 kkz      1.1.2.1                 splice(idc, q.prevEdge(0));
365 kkz      1.1.2.1                 splice(fieldc, q.prevEdge(0));
366 kkz      1.1.2.1                 splice(call, q.prevEdge(0));
367 kkz      1.1.2.1                 // add THROW after CALL
368 kkz      1.1.2.1                 Quad.addEdge(call, 1, thr, 0);
369 kkz      1.1.2.1                 footer = footer.attach(thr, 0);
370 kkz      1.1.2.1             }
371 kkz      1.1.2.1         }
372 kkz      1.1.2.1         /** inserts the given Quad on the given Edge */
373 kkz      1.1.2.1         private void splice(Quad q, Edge e) {
374 kkz      1.1.2.1             Quad.addEdge((Quad)e.from(), e.which_succ(), q, 0);
375 kkz      1.1.2.1             Quad.addEdge(q, 0, (Quad)e.to(), e.which_pred());
376 kkz      1.1.2.1         }
377 kkz      1.1.2.1     }
378 cananian 1.2     }