1 cananian 1.1.2.1 // SyncTransformer.java, created Fri Oct 27 16:50:14 2000 by cananian 2 cananian 1.1.2.1 // Copyright (C) 2000 C. Scott Ananian <cananian@alumni.princeton.edu> 3 cananian 1.1.2.1 // Licensed under the terms of the GNU GPL; see COPYING for details. 4 cananian 1.1.2.1 package harpoon.Analysis.Transactions; 5 cananian 1.1.2.1 6 cananian 1.7 import harpoon.Analysis.AllocationInformationMap; 7 cananian 1.1.2.1 import harpoon.Analysis.ClassHierarchy; 8 cananian 1.7 import harpoon.Analysis.DefaultAllocationInformation; 9 cananian 1.1.2.1 import harpoon.Analysis.DomTree; 10 cananian 1.1.2.15 import harpoon.Analysis.Counters.CounterFactory; 11 cananian 1.7 import harpoon.Analysis.Maps.AllocationInformation; 12 cananian 1.6 import harpoon.Analysis.Maps.ExactTypeMap; 13 cananian 1.6 import harpoon.Analysis.Maps.ExactTypeMapProxy; 14 cananian 1.6 import harpoon.Analysis.Quads.TypeInfo; 15 cananian 1.1.2.21 import harpoon.Analysis.Transactions.BitFieldNumbering.BitFieldTuple; 16 cananian 1.1.2.2 import harpoon.Backend.Generic.Frame; 17 cananian 1.1.2.10 import harpoon.ClassFile.CachingCodeFactory; 18 cananian 1.1.2.1 import harpoon.ClassFile.HClass; 19 cananian 1.1.2.1 import harpoon.ClassFile.HClassMutator; 20 cananian 1.1.2.1 import harpoon.ClassFile.HCode; 21 cananian 1.1.2.1 import harpoon.ClassFile.HCodeAndMaps; 22 cananian 1.1.2.1 import harpoon.ClassFile.HCodeElement; 23 cananian 1.1.2.1 import harpoon.ClassFile.HCodeFactory; 24 cananian 1.6 import harpoon.ClassFile.HData; 25 cananian 1.1.2.1 import harpoon.ClassFile.HField; 26 cananian 1.1.2.1 import harpoon.ClassFile.HFieldMutator; 27 cananian 1.1.2.1 import harpoon.ClassFile.HMethod; 28 cananian 1.1.2.1 import harpoon.ClassFile.HMethodMutator; 29 cananian 1.1.2.1 import harpoon.ClassFile.Linker; 30 cananian 1.1.2.10 import harpoon.ClassFile.SerializableCodeFactory; 31 cananian 1.1.2.12 import harpoon.IR.Properties.CFGrapher; 32 cananian 1.1.2.5 import harpoon.IR.Properties.UseDefer; 33 cananian 1.1.2.1 import harpoon.IR.Quads.AGET; 34 cananian 1.1.2.18 import harpoon.IR.Quads.ANEW; 35 cananian 1.1.2.9 import harpoon.IR.Quads.ARRAYINIT; 36 cananian 1.1.2.1 import harpoon.IR.Quads.ASET; 37 cananian 1.1.2.1 import harpoon.IR.Quads.CALL; 38 cananian 1.1.2.1 import harpoon.IR.Quads.CJMP; 39 cananian 1.1.2.1 import harpoon.IR.Quads.CONST; 40 cananian 1.1.2.1 import harpoon.IR.Quads.Code; 41 cananian 1.1.2.1 import harpoon.IR.Quads.Edge; 42 cananian 1.1.2.1 import harpoon.IR.Quads.FOOTER; 43 cananian 1.1.2.1 import harpoon.IR.Quads.GET; 44 cananian 1.1.2.1 import harpoon.IR.Quads.HEADER; 45 cananian 1.1.2.1 import harpoon.IR.Quads.INSTANCEOF; 46 cananian 1.1.2.1 import harpoon.IR.Quads.METHOD; 47 cananian 1.1.2.1 import harpoon.IR.Quads.MONITORENTER; 48 cananian 1.1.2.1 import harpoon.IR.Quads.MONITOREXIT; 49 cananian 1.1.2.1 import harpoon.IR.Quads.MOVE; 50 cananian 1.1.2.18 import harpoon.IR.Quads.NEW; 51 cananian 1.1.2.1 import harpoon.IR.Quads.NOP; 52 cananian 1.1.2.1 import harpoon.IR.Quads.OPER; 53 cananian 1.1.2.1 import harpoon.IR.Quads.PHI; 54 cananian 1.1.2.1 import harpoon.IR.Quads.Qop; 55 cananian 1.1.2.1 import harpoon.IR.Quads.Quad; 56 cananian 1.1.2.1 import harpoon.IR.Quads.QuadFactory; 57 cananian 1.1.2.1 import harpoon.IR.Quads.QuadRSSx; 58 cananian 1.1.2.1 import harpoon.IR.Quads.QuadSSA; 59 cananian 1.1.2.10 import harpoon.IR.Quads.QuadSSI; 60 cananian 1.1.2.1 import harpoon.IR.Quads.QuadVisitor; 61 cananian 1.1.2.10 import harpoon.IR.Quads.RETURN; 62 cananian 1.1.2.1 import harpoon.IR.Quads.SET; 63 cananian 1.6 import harpoon.IR.Quads.SSIToSSA; 64 cananian 1.1.2.1 import harpoon.IR.Quads.THROW; 65 cananian 1.1.2.1 import harpoon.IR.Quads.TYPESWITCH; 66 cananian 1.1.2.1 import harpoon.Temp.Temp; 67 cananian 1.1.2.1 import harpoon.Temp.TempFactory; 68 cananian 1.6 import harpoon.Temp.TempMap; 69 cananian 1.1.2.1 import harpoon.Util.HClassUtil; 70 cananian 1.1.2.1 import harpoon.Util.ParseUtil; 71 cananian 1.1.2.1 import harpoon.Util.Util; 72 cananian 1.1.2.1 73 cananian 1.12 import net.cscott.jutil.Default; 74 cananian 1.12 import net.cscott.jutil.FilterIterator; 75 cananian 1.12 76 cananian 1.1.2.1 import java.lang.reflect.Modifier; 77 cananian 1.1.2.1 import java.util.ArrayList; 78 cananian 1.1.2.1 import java.util.Collections; 79 cananian 1.1.2.1 import java.util.HashMap; 80 cananian 1.1.2.1 import java.util.HashSet; 81 cananian 1.1.2.1 import java.util.Iterator; 82 cananian 1.1.2.1 import java.util.List; 83 cananian 1.1.2.1 import java.util.Map; 84 cananian 1.1.2.1 import java.util.Set; 85 cananian 1.1.2.1 /** 86 cananian 1.1.2.1 * <code>SyncTransformer</code> transforms synchronized code to 87 cananian 1.6 * atomic transactions. Works on <code>QuadSSI</code> form 88 cananian 1.6 * (via an internal conversion to SSA). Outputs <code>QuadRSSx</code>. 89 cananian 1.1.2.3 * Use the <code>SyncTransformer.treeCodeFactory()</code> to clean 90 cananian 1.1.2.3 * up the transformed code by doing low-level tree form optimizations. 91 cananian 1.1.2.1 * 92 cananian 1.1.2.1 * @author C. Scott Ananian <cananian@alumni.princeton.edu> 93 cananian 1.13 * @version $Id: SyncTransformer.java,v 1.13 2004/02/08 03:20:25 cananian Exp $ 94 cananian 1.1.2.1 */ 95 cananian 1.6 // we can apply sync-elimination analysis to remove unnecessary 96 cananian 1.6 // atomic operations. this may reduce the overall cost by a *lot*, 97 cananian 1.1.2.21 // but it would make it much harder to come up w/ realistic benchmarks. 98 cananian 1.6 // maybe barnes/water? (actually, only about 30% syncs are eliminated) 99 cananian 1.1.2.21 // ACTUALLY we should skip ALL transformation on objects which are 100 cananian 1.1.2.21 // marked as non-escaping. this too would be a big win. 101 cananian 1.6 // (not done yet) 102 cananian 1.6 103 cananian 1.6 // stages: 104 cananian 1.6 // X1) guts into C code. 105 cananian 1.6 // X2) code dup for sync check (actually, separate pass) 106 cananian 1.6 // 3) indirectize trans to support object.wait() 107 cananian 1.9 // (analyze possible calls to wait() and only indirectize the cases 108 cananian 1.9 // that need it. indirectize by reloading from a cell, or by 109 cananian 1.9 // returning the new transaction value or some such (maybe put 110 cananian 1.9 // it in thread-local memory) 111 cananian 1.6 // 4) separate out sync transform and implement general trans mech. 112 cananian 1.6 // 5) handle 'recovery' transaction? 113 cananian 1.6 // 6) separate pass to virtualize static fields? 114 cananian 1.6 // 7) strictness optimizations? 115 cananian 1.6 // 8) changes to caching read version over commit of subtransaction 116 cananian 1.6 // (possibly parallel commit?) 117 cananian 1.9 // 9) solution for static fields (virtualize static fields) 118 cananian 1.1.2.21 119 cananian 1.1.2.1 public class SyncTransformer 120 cananian 1.1.2.1 extends harpoon.Analysis.Transformation.MethodSplitter { 121 cananian 1.1.2.1 static final Token WITH_TRANSACTION = new Token("withtrans") { 122 cananian 1.1.2.1 public Object readResolve() { return WITH_TRANSACTION; } 123 cananian 1.1.2.1 }; 124 cananian 1.1.2.1 protected boolean isValidToken(Token which) { 125 cananian 1.1.2.1 return super.isValidToken(which) || which==WITH_TRANSACTION; 126 cananian 1.1.2.1 } 127 cananian 1.1.2.1 128 cananian 1.1.2.1 // for statistics: 129 cananian 1.1.2.9 private final boolean enabled = // turns off the transformation. 130 cananian 1.1.2.9 !Boolean.getBoolean("harpoon.synctrans.disabled"); 131 cananian 1.1.2.9 private final boolean noFieldModification = // only do monitorenter/exit 132 cananian 1.1.2.9 Boolean.getBoolean("harpoon.synctrans.nofieldmods"); 133 cananian 1.1.2.14 private final boolean noArrayModification = // only do regular objects 134 cananian 1.1.2.14 Boolean.getBoolean("harpoon.synctrans.noarraymods"); 135 cananian 1.8 private final boolean noNestedTransactions = // only top-level trans. 136 cananian 1.8 Boolean.getBoolean("harpoon.synctrans.nonestedtrans"); 137 cananian 1.1.2.9 private final boolean useSmartFieldOracle = // dumb down field oracle 138 cananian 1.1.2.9 !Boolean.getBoolean("harpoon.synctrans.nofieldoracle"); 139 cananian 1.1.2.9 private final boolean useSmartCheckOracle = // dumb down check oracle 140 cananian 1.6 // XXX this is currently broken. 141 cananian 1.6 Boolean.getBoolean("harpoon.synctrans.checkoracle"); 142 cananian 1.1.2.20 private final boolean useUniqueRWCounters = // high-overhead counters 143 cananian 1.1.2.20 Boolean.getBoolean("harpoon.synctrans.uniquerwcounters"); 144 cananian 1.9 private final boolean useHardwareTrans =// use hardware xaction mechanism 145 cananian 1.9 Boolean.getBoolean("harpoon.synctrans.hwtrans"); 146 cananian 1.9 private final boolean doMemoryTrace =// add hooks to generate memory traces 147 cananian 1.9 Boolean.getBoolean("harpoon.synctrans.memorytrace"); 148 cananian 1.11 private final boolean keepOldLocks =// keep old MONITORENTER/EXIT code. 149 cananian 1.11 Boolean.getBoolean("harpoon.synctrans.oldlocks"); 150 cananian 1.1.2.18 // this might have to be tweaked if we're using counters which are 151 cananian 1.1.2.18 // added *before* SyncTransformer gets the code. 152 cananian 1.1.2.18 private final boolean excludeCounters = true; 153 cananian 1.1.2.5 154 cananian 1.1.2.5 // FieldOracle to use. 155 cananian 1.1.2.5 final FieldOracle fieldOracle; 156 cananian 1.1.2.21 // BitFieldNumbering to use 157 cananian 1.1.2.21 final BitFieldNumbering bfn; 158 cananian 1.1.2.1 159 cananian 1.1.2.1 /** Cache the <code>java.lang.Class</code> <code>HClass</code>. */ 160 cananian 1.1.2.1 private final HClass HCclass; 161 cananian 1.1.2.1 /** Cache the <code>java.lang.reflect.Field</code> <code>HClass</code>. */ 162 cananian 1.1.2.1 private final HClass HCfield; 163 cananian 1.6 /** Cache the <code>java.lang.Object</code> <code>HClass</code>. */ 164 cananian 1.6 private final HClass HCobj; 165 cananian 1.6 /** Cache the <code>struct vinfo *</code> <code>HClass</code>. */ 166 cananian 1.6 private final HClass HCvinfo; 167 cananian 1.1.2.1 /** Cache the <code>CommitRecord</code> <code>HClass</code>. */ 168 cananian 1.1.2.1 private final HClass HCcommitrec; 169 cananian 1.1.2.1 private final HMethod HMcommitrec_new; 170 cananian 1.1.2.1 private final HMethod HMcommitrec_retry; 171 cananian 1.1.2.1 private final HMethod HMcommitrec_commit; 172 cananian 1.1.2.1 private final HField HFcommitrec_parent; 173 cananian 1.6 /** Cache the <code>AbortException</code> <code>HClass</code>. */ 174 cananian 1.1.2.1 private final HClass HCabortex; 175 cananian 1.1.2.1 private final HField HFabortex_upto; 176 cananian 1.6 private final HMethod HMabortex_cons; 177 cananian 1.6 /** Cache the <code>ImplHelper</code> <code>HClass</code>. */ 178 cananian 1.6 private final HClass HCimplHelper; 179 cananian 1.6 private final HMethod HMsetTrans; // setJNITransaction() 180 cananian 1.1.2.10 /** flag value */ 181 cananian 1.1.2.1 private final HField HFflagvalue; 182 cananian 1.1.2.20 /** last *reading* transaction */ 183 cananian 1.1.2.20 private final HField HFlastRTrans; 184 cananian 1.1.2.20 /** last *writing* transaction */ 185 cananian 1.1.2.20 private final HField HFlastWTrans; 186 cananian 1.6 /** additional method roots after transactions transformation */ 187 cananian 1.6 private final Set<HMethod> transRoots = new HashSet<HMethod>(); 188 cananian 1.1.2.10 /** Our version of the codefactory. */ 189 cananian 1.1.2.10 private final HCodeFactory hcf; 190 cananian 1.1.2.1 191 cananian 1.6 private final Linker linker; 192 cananian 1.6 private final MethodGenerator gen; 193 cananian 1.6 private final Set<HField> transFields = new HashSet<HField>(); 194 cananian 1.6 195 cananian 1.6 /** Creates a <code>SyncTransformer</code> with no transaction root 196 cananian 1.6 * methods. */ 197 cananian 1.1.2.5 public SyncTransformer(HCodeFactory hcf, ClassHierarchy ch, Linker l, 198 cananian 1.1.2.5 HMethod mainM, Set roots) { 199 cananian 1.12 this(hcf, ch, l, mainM, roots, Default.<HMethod>EMPTY_SET()); 200 cananian 1.1.2.1 } 201 cananian 1.6 /** Creates a <code>SyncTransformer</code> with a transaction root method 202 cananian 1.6 * set loaded from the specified resource name. */ 203 cananian 1.1.2.1 public SyncTransformer(HCodeFactory hcf, ClassHierarchy ch, Linker l, 204 cananian 1.1.2.5 HMethod mainM, Set roots, 205 cananian 1.1.2.1 String resourceName) { 206 cananian 1.1.2.5 this(hcf, ch, l, mainM, roots, parseResource(l, resourceName)); 207 cananian 1.1.2.1 } 208 cananian 1.6 /** Creates a <code>SyncTransformer</code> with the specified transaction 209 cananian 1.6 * root method set. */ 210 cananian 1.1.2.1 public SyncTransformer(HCodeFactory hcf, ClassHierarchy ch, Linker l, 211 cananian 1.1.2.5 HMethod mainM, Set roots, 212 cananian 1.6 Set<HMethod> transRoots) { 213 cananian 1.6 // our input is SSI. We'll convert it to SSA in the 'clone' method. 214 cananian 1.6 super(hcf, ch, false); 215 cananian 1.6 // and output is RSSx 216 cananian 1.3.2.1 assert hcf.getCodeName() 217 cananian 1.3.2.1 .equals(harpoon.IR.Quads.QuadSSI.codename); 218 cananian 1.3.2.1 assert super.codeFactory().getCodeName() 219 cananian 1.3.2.1 .equals(harpoon.IR.Quads.QuadRSSx.codename); 220 cananian 1.6 this.linker = l; 221 cananian 1.1.2.1 this.HCclass = l.forName("java.lang.Class"); 222 cananian 1.1.2.1 this.HCfield = l.forName("java.lang.reflect.Field"); 223 cananian 1.1.2.1 String pkg = "harpoon.Runtime.Transactions."; 224 cananian 1.1.2.1 this.HCcommitrec = l.forName(pkg+"CommitRecord"); 225 cananian 1.1.2.1 this.HMcommitrec_new = 226 cananian 1.1.2.1 HCcommitrec.getMethod("newTransaction", new HClass[]{HCcommitrec}); 227 cananian 1.1.2.1 this.HMcommitrec_retry = 228 cananian 1.1.2.1 HCcommitrec.getMethod("retryTransaction", new HClass[0]); 229 cananian 1.1.2.1 this.HMcommitrec_commit = 230 cananian 1.1.2.1 HCcommitrec.getMethod("commitTransaction", new HClass[0]); 231 cananian 1.1.2.1 this.HFcommitrec_parent = HCcommitrec.getField("parent"); 232 cananian 1.1.2.1 this.HCabortex = l.forName(pkg+"TransactionAbortException"); 233 cananian 1.1.2.1 this.HFabortex_upto = HCabortex.getField("abortUpTo"); 234 cananian 1.6 this.HMabortex_cons = 235 cananian 1.6 HCabortex.getConstructor(new HClass[] { HCcommitrec }); 236 cananian 1.1.2.1 // now create methods of java.lang.Object. 237 cananian 1.6 HCobj = l.forName("java.lang.Object"); 238 cananian 1.1.2.1 HClassMutator objM = HCobj.getMutator(); 239 cananian 1.1.2.21 int mod = Modifier.FINAL | Modifier.NATIVE; 240 cananian 1.1.2.20 // create a pair of instance fields in java.lang.Object for 241 cananian 1.1.2.20 // statistics gathering. 242 cananian 1.1.2.20 if (useUniqueRWCounters) { 243 cananian 1.1.2.20 this.HFlastRTrans=objM.addDeclaredField("lastRTrans", HCcommitrec); 244 cananian 1.1.2.20 this.HFlastWTrans=objM.addDeclaredField("lastWTrans", HCcommitrec); 245 cananian 1.1.2.20 } else { this.HFlastRTrans=this.HFlastWTrans=null; } 246 cananian 1.1.2.1 // create a static final field in java.lang.Object that will hold 247 cananian 1.1.2.1 // our 'unique' value. 248 cananian 1.1.2.1 this.HFflagvalue = objM.addDeclaredField("flagValue", HCobj); 249 cananian 1.1.2.1 HFflagvalue.getMutator().addModifiers(Modifier.FINAL|Modifier.STATIC); 250 cananian 1.1.2.5 251 cananian 1.6 // lookup the type of a 'struct vinfo *' 252 cananian 1.6 HCvinfo = HCobj; // hack. Also not strictly true. Maybe HClass.Int? 253 cananian 1.6 // create a method generator in the 'ImplHelper' class. 254 cananian 1.6 HCimplHelper = l.forName(pkg+"ImplHelper"); 255 cananian 1.6 gen = new MethodGenerator(HCimplHelper); 256 cananian 1.6 // cache ImplHelper.setJNITransaction(CommitRecord cr) 257 cananian 1.6 HMsetTrans = HCimplHelper.getMethod 258 cananian 1.6 ("setJNITransaction", new HClass[] { HCcommitrec }); 259 cananian 1.6 260 cananian 1.1.2.5 // set up our field oracle. 261 cananian 1.1.2.5 if (!useSmartFieldOracle) { 262 cananian 1.1.2.5 this.fieldOracle = new SimpleFieldOracle(); 263 cananian 1.1.2.5 } else { 264 cananian 1.1.2.5 // filter out HClasses from rootset 265 cananian 1.1.2.5 Set myroots = new HashSet(roots); 266 cananian 1.1.2.5 for (Iterator it=myroots.iterator(); it.hasNext(); ) 267 cananian 1.1.2.5 if (!(it.next() instanceof HMethod)) it.remove(); 268 cananian 1.1.2.5 // create fieldoracle 269 cananian 1.1.2.5 this.fieldOracle = new GlobalFieldOracle(ch, mainM, myroots, hcf); 270 cananian 1.1.2.5 } 271 cananian 1.1.2.21 // set up our BitFieldNumbering (and create array-check fields in 272 cananian 1.1.2.21 // all array classes) 273 cananian 1.9 if (noFieldModification) this.bfn = null; 274 cananian 1.9 else { 275 cananian 1.9 this.bfn = new BitFieldNumbering(l); 276 cananian 1.13 for (HClass hc : ch.classes()) { 277 cananian 1.1.2.21 if (hc.isArray()) bfn.arrayBitField(hc); 278 cananian 1.9 } 279 cananian 1.1.2.21 } 280 cananian 1.1.2.10 281 cananian 1.1.2.10 // fixup code factory for 'known safe' methods. 282 cananian 1.1.2.10 final HCodeFactory superfactory = super.codeFactory(); 283 cananian 1.3.2.1 assert superfactory.getCodeName().equals(QuadRSSx.codename); 284 cananian 1.1.2.10 this.hcf = new CachingCodeFactory(new SerializableCodeFactory() { 285 cananian 1.1.2.10 public String getCodeName() { return superfactory.getCodeName(); } 286 cananian 1.1.2.10 public void clear(HMethod m) { superfactory.clear(m); } 287 cananian 1.1.2.10 public HCode convert(HMethod m) { 288 cananian 1.1.2.10 if (Modifier.isNative(m.getModifiers()) && 289 cananian 1.1.2.10 select(select(m, ORIGINAL), WITH_TRANSACTION).equals(m)) 290 cananian 1.6 // call the original, 'safe' method, with trans in context 291 cananian 1.1.2.10 return redirectCode(m); 292 cananian 1.6 else if (gen.generatedMethodSet.contains(m)) 293 cananian 1.6 return emptyCode(m); 294 cananian 1.1.2.10 else return superfactory.convert(m); 295 cananian 1.1.2.10 } 296 cananian 1.1.2.10 }); 297 cananian 1.6 // lookup WITH_TRANSACTION version of the transaction root methods 298 cananian 1.13 for (HMethod hm : transRoots) { 299 cananian 1.6 this.transRoots.add(select(hm, WITH_TRANSACTION)); 300 cananian 1.6 } 301 cananian 1.1.2.1 } 302 cananian 1.1.2.10 // override parent's codefactory with ours! (which uses theirs) 303 cananian 1.1.2.10 public HCodeFactory codeFactory() { return hcf; } 304 cananian 1.6 /** Export additional method roots after transactions transformation. */ 305 cananian 1.6 public Set<HMethod> transRoots() { 306 cananian 1.6 return Collections.unmodifiableSet(transRoots); 307 cananian 1.6 } 308 cananian 1.1.2.10 309 cananian 1.1.2.1 protected String mutateDescriptor(HMethod hm, Token which) { 310 cananian 1.1.2.1 if (which==WITH_TRANSACTION) 311 cananian 1.1.2.1 // add CommitRecord as first arg. 312 cananian 1.1.2.1 return "(" + HCcommitrec.getDescriptor() + 313 cananian 1.1.2.1 hm.getDescriptor().substring(1); 314 cananian 1.1.2.1 else return super.mutateDescriptor(hm, which); 315 cananian 1.1.2.1 } 316 cananian 1.6 protected MyHCodeAndMaps cloneHCode(HCode hc, HMethod newmethod) { 317 cananian 1.6 // make SSI into RSSx. 318 cananian 1.6 assert hc.getName().equals(QuadSSI.codename); 319 cananian 1.1.2.1 return MyRSSx.cloneToRSSx((harpoon.IR.Quads.Code)hc, newmethod); 320 cananian 1.1.2.1 } 321 cananian 1.1.2.1 private static class MyRSSx extends QuadRSSx { 322 cananian 1.1.2.1 private MyRSSx(HMethod m) { super(m, null); } 323 cananian 1.6 public static MyHCodeAndMaps cloneToRSSx(harpoon.IR.Quads.Code c, 324 cananian 1.1.2.1 HMethod m) { 325 cananian 1.6 // c should be SSI. 326 cananian 1.6 assert c.getName().equals(QuadSSI.codename) : c.getName(); 327 cananian 1.6 // we first create a type info on the SSI form. 328 cananian 1.6 TypeInfo ti = new TypeInfo(c); 329 cananian 1.6 // now we convert to SSA 330 cananian 1.1.2.1 MyRSSx r = new MyRSSx(m); 331 cananian 1.6 SSIToSSA ssi2ssa = new SSIToSSA(c, r.qf); 332 cananian 1.6 r.quads = ssi2ssa.rootQuad; 333 cananian 1.6 r.setAllocationInformation(ssi2ssa.allocInfo); 334 cananian 1.6 // make the HCodeAndMaps 335 cananian 1.6 return new MyHCodeAndMaps 336 cananian 1.6 (r, ssi2ssa.quadMap, ssi2ssa.tempMap, 337 cananian 1.6 c, ssi2ssa.revQuadMap, ssi2ssa.revTempMap, 338 cananian 1.6 ti); 339 cananian 1.1.2.1 } 340 cananian 1.1.2.1 } 341 cananian 1.6 static class MyHCodeAndMaps extends HCodeAndMaps<Quad> { 342 cananian 1.6 final ExactTypeMap<Quad> ancestorTypeMap; 343 cananian 1.6 final ExactTypeMap<Quad> typeMap; 344 cananian 1.6 MyHCodeAndMaps(Code hc, Map<Quad,Quad> em, TempMap tm, 345 cananian 1.6 Code ahc, Map<Quad,Quad> aem, TempMap atm, 346 cananian 1.6 ExactTypeMap<Quad> ancestorTypeMap) { 347 cananian 1.6 super(hc, em, tm, ahc, aem, atm); 348 cananian 1.6 this.ancestorTypeMap = ancestorTypeMap; 349 cananian 1.6 this.typeMap = new ExactTypeMapProxy<Quad>(this, ancestorTypeMap); 350 cananian 1.6 } 351 cananian 1.6 } 352 cananian 1.6 353 cananian 1.1.2.1 protected String mutateCodeName(String codeName) { 354 cananian 1.6 assert codeName.equals(QuadSSI.codename); 355 cananian 1.1.2.1 return MyRSSx.codename; 356 cananian 1.1.2.1 } 357 cananian 1.1.2.1 protected HCode mutateHCode(HCodeAndMaps input, Token which) { 358 cananian 1.6 MyHCodeAndMaps hcam = (MyHCodeAndMaps) input; 359 cananian 1.7 MyRSSx hc = (MyRSSx) hcam.hcode(); 360 cananian 1.6 ExactTypeMap<Quad> etm = hcam.typeMap; 361 cananian 1.1.2.1 HEADER qH = (HEADER) hc.getRootElement(); 362 cananian 1.1.2.1 FOOTER qF = qH.footer(); 363 cananian 1.1.2.1 METHOD qM = qH.method(); 364 cananian 1.1.2.1 // recursively decend the dominator tree, rewriting as we go. 365 cananian 1.1.2.9 if (enabled && 366 cananian 1.6 // don't transform the transactions runtime support 367 cananian 1.1.2.18 (! "harpoon.Runtime.Transactions".equals 368 cananian 1.1.2.18 (hc.getMethod().getDeclaringClass().getPackage())) && 369 cananian 1.6 // don't transform static initialization code. 370 cananian 1.6 /* xxx runtime calls other startup code interspersed with static 371 cananian 1.6 * initialization; probably not safe to skip transform. 372 cananian 1.6 (! (hc.getMethod() instanceof HInitializer || 373 cananian 1.6 hc.getMethod().getName().endsWith("$$initcheck"))) && 374 cananian 1.6 */ 375 cananian 1.6 // don't transform the counter/statistic code. 376 cananian 1.1.2.18 (!excludeCounters || ! "harpoon.Runtime.Counters".equals 377 cananian 1.1.2.18 (hc.getMethod().getDeclaringClass().getName()))) { 378 cananian 1.1.2.14 CheckOracle co = new SimpleCheckOracle(noArrayModification); 379 cananian 1.1.2.8 if (useSmartCheckOracle) { 380 cananian 1.1.2.8 DomTree dt = new DomTree(hc, false); 381 cananian 1.6 // XXX don't allow hoisting past CALL or MONITOREXIT 382 cananian 1.1.2.8 co = new DominatingCheckOracle(dt, co); 383 cananian 1.1.2.12 co = new HoistingCheckOracle 384 cananian 1.1.2.12 (hc, CFGrapher.DEFAULT, UseDefer.DEFAULT, dt, co); 385 cananian 1.1.2.8 } 386 cananian 1.7 AllocationInformationMap aim = (AllocationInformationMap)//heh heh 387 cananian 1.7 hc.getAllocationInformation(); 388 cananian 1.7 Tweaker tw = new Tweaker(co, qF, (which==WITH_TRANSACTION), 389 cananian 1.7 etm, aim); 390 cananian 1.1.2.1 tweak(new DomTree(hc, false), qM, tw); 391 cananian 1.1.2.1 tw.fixup(); 392 cananian 1.1.2.1 } 393 cananian 1.1.2.1 // done! 394 cananian 1.1.2.1 return hc; 395 cananian 1.1.2.1 } 396 cananian 1.1.2.1 397 cananian 1.1.2.1 /** MONITORENTER must dominate all associated MONITOREXITs */ 398 cananian 1.1.2.1 private void tweak(DomTree dt, Quad q, Tweaker tw) { 399 cananian 1.1.2.1 HCodeElement[] nxt = dt.children(q); 400 cananian 1.1.2.1 // tweak q here, update currtrans, etc. 401 cananian 1.1.2.1 q.accept(tw); 402 cananian 1.1.2.1 // done, recurse. 403 cananian 1.1.2.1 ListList handlers = tw.handlers; // save this value. 404 cananian 1.10 int skipped_nested = tw.skipped_nested; 405 cananian 1.10 for (int i=0; i<nxt.length; // restore 406 cananian 1.10 i++, tw.handlers=handlers, tw.skipped_nested=skipped_nested) 407 cananian 1.1.2.1 tweak(dt, (Quad) nxt[i], tw); 408 cananian 1.1.2.1 } 409 cananian 1.5 static class ListList<T> { 410 cananian 1.5 public final List<T> head; 411 cananian 1.5 public final ListList<T> tail; 412 cananian 1.5 public ListList(List<T> head, ListList<T> tail) { 413 cananian 1.1.2.1 this.head = head; this.tail = tail; 414 cananian 1.1.2.1 } 415 cananian 1.1.2.1 } 416 cananian 1.1.2.1 class Tweaker extends QuadVisitor { 417 cananian 1.1.2.1 // immutable. 418 cananian 1.1.2.1 final QuadFactory qf; 419 cananian 1.1.2.1 final TempFactory tf; 420 cananian 1.1.2.1 final Temp retex; 421 cananian 1.1.2.1 final Temp currtrans; // current transaction. 422 cananian 1.5 private final Map<PHI,List<THROW>> fixupmap = 423 cananian 1.5 new HashMap<PHI,List<THROW>>(); 424 cananian 1.5 private final Set<NOP> typecheckset = new HashSet<NOP>(); 425 cananian 1.1.2.5 final CheckOracle co; 426 cananian 1.1.2.5 final FieldOracle fo; 427 cananian 1.1.2.1 final TempSplitter ts=new TempSplitter(); 428 cananian 1.6 final ExactTypeMap<Quad> etm; 429 cananian 1.7 final AllocationInformationMap aim; 430 cananian 1.1.2.1 // mutable. 431 cananian 1.1.2.1 FOOTER footer; // we attach new stuff to the footer. 432 cananian 1.5 ListList<THROW> handlers = null; // points to current abort handler 433 cananian 1.8 int skipped_nested=0; 434 cananian 1.6 Tweaker(CheckOracle co, FOOTER qF, boolean with_transaction, 435 cananian 1.7 ExactTypeMap<Quad> etm, AllocationInformationMap aim) { 436 cananian 1.1.2.5 this.co = co; 437 cananian 1.1.2.5 this.fo = fieldOracle; // cache in this object. 438 cananian 1.1.2.1 this.footer = qF; 439 cananian 1.1.2.5 this.qf = qF.getFactory(); 440 cananian 1.1.2.1 this.tf = this.qf.tempFactory(); 441 cananian 1.6 this.etm = etm; 442 cananian 1.7 this.aim = aim; 443 cananian 1.1.2.1 // indicate that we're inside transaction context, but 444 cananian 1.1.2.1 // that we need to rethrow TransactionAbortExceptions 445 cananian 1.1.2.1 if (with_transaction) 446 cananian 1.5 handlers = new ListList<THROW>(null, handlers); 447 cananian 1.1.2.1 this.currtrans = new Temp(tf, "transid"); 448 cananian 1.1.2.1 this.retex = new Temp(tf, "trabex"); // transaction abort exception 449 cananian 1.1.2.1 } 450 cananian 1.1.2.1 /** Insert abort exception check on the given edge. */ 451 cananian 1.1.2.1 private Edge checkForAbort(Edge e, HCodeElement src, Temp tex) { 452 cananian 1.1.2.1 if (handlers.head==null) return e; // rethrow directly. 453 cananian 1.1.2.1 Temp tst = new Temp(tf); 454 cananian 1.1.2.1 e = addAt(e, new INSTANCEOF(qf, src, tst, tex, HCabortex)); 455 cananian 1.1.2.1 e = addAt(e, new CJMP(qf, src, tst, new Temp[0])); 456 cananian 1.5 THROW q0 = new THROW(qf, src, tex); 457 cananian 1.5 Quad.addEdge(e.from(), 1, q0, 0); 458 cananian 1.1.2.1 handlers.head.add(q0); 459 cananian 1.1.2.15 CounterFactory.spliceIncrement(qf, q0.prevEdge(0), 460 cananian 1.1.2.15 "synctrans.aborts"); 461 cananian 1.1.2.1 return e; 462 cananian 1.1.2.1 } 463 cananian 1.6 private void throwAbort(Quad from, int which_succ, HCodeElement src) { 464 cananian 1.6 assert handlers!=null; 465 cananian 1.6 Quad q0 = new NEW(qf, src, retex, HCabortex); 466 cananian 1.6 Quad q1 = new CALL(qf, src, HMabortex_cons, 467 cananian 1.6 new Temp[] { retex, currtrans }, null, 468 cananian 1.6 retex, false, false, new Temp[0]); 469 cananian 1.6 THROW q2 = new THROW(qf, src, retex); 470 cananian 1.6 THROW q3 = new THROW(qf, src, retex); 471 cananian 1.6 Quad.addEdge(from, which_succ, q0, 0); 472 cananian 1.6 Quad.addEdge(q0, 0, q1, 0); 473 cananian 1.6 Quad.addEdge(q1, 0, q2, 0); 474 cananian 1.6 Quad.addEdge(q1, 1, q3, 0); 475 cananian 1.6 footer = footer.attach(q3, 0); // attach exc. throw to FOOTER. 476 cananian 1.6 if (handlers.head!=null) 477 cananian 1.6 handlers.head.add(q2); // "normal" throw is added to list. 478 cananian 1.6 else 479 cananian 1.6 footer = footer.attach(q2, 0); // really throw abort exception 480 cananian 1.6 CounterFactory.spliceIncrement(qf, q2.prevEdge(0), 481 cananian 1.6 "synctrans.aborts"); 482 cananian 1.7 // create appropriate allocation information for this NEW. 483 cananian 1.7 if (aim!=null) 484 cananian 1.7 aim.associate 485 cananian 1.7 (q0, DefaultAllocationInformation.SINGLETON.query(q0)); 486 cananian 1.6 // done! 487 cananian 1.6 } 488 cananian 1.1.2.1 /** Fix up PHIs leading to abort handler after we're all done. */ 489 cananian 1.1.2.1 void fixup() { 490 cananian 1.13 for(Map.Entry<PHI,List<THROW>> me : fixupmap.entrySet()) { 491 cananian 1.5 PHI phi = me.getKey(); 492 cananian 1.5 List<THROW> throwlist = me.getValue(); 493 cananian 1.1.2.1 PHI nphi = new PHI(qf, phi, new Temp[0], throwlist.size()); 494 cananian 1.1.2.1 Edge out = phi.nextEdge(0); 495 cananian 1.5 Quad.addEdge(nphi, 0, out.to(), out.which_pred()); 496 cananian 1.1.2.1 int n=0; 497 cananian 1.5 for (Iterator<THROW> it2 = throwlist.iterator(); 498 cananian 1.5 it2.hasNext(); n++) { 499 cananian 1.5 THROW thr = it2.next(); 500 cananian 1.1.2.1 Temp tex = thr.throwable(); 501 cananian 1.1.2.1 Edge in = thr.prevEdge(0); 502 cananian 1.1.2.1 if (tex!=retex) 503 cananian 1.1.2.1 in = addAt(in, new MOVE(qf, thr, retex, tex)); 504 cananian 1.5 Quad.addEdge(in.from(), in.which_succ(), nphi, n); 505 cananian 1.1.2.1 // NOTE THAT WE ARE NOT DELINKING THE THROW FROM THE 506 cananian 1.1.2.1 // FOOTER: this should be done before it is added to the 507 cananian 1.1.2.1 // list. 508 cananian 1.1.2.1 } 509 cananian 1.1.2.1 } 510 cananian 1.1.2.1 // fixup the dangling array type check edges 511 cananian 1.1.2.1 if (typecheckset.size()==0) return; 512 cananian 1.1.2.1 PHI phi = new PHI(qf, footer, new Temp[0], typecheckset.size()+1); 513 cananian 1.1.2.1 int i=0; 514 cananian 1.5 for (Iterator<NOP> it=typecheckset.iterator(); it.hasNext(); ) { 515 cananian 1.5 Edge in = it.next().prevEdge(0); 516 cananian 1.5 Quad.addEdge(in.from(), in.which_succ(), phi, i++); 517 cananian 1.1.2.1 } 518 cananian 1.1.2.1 // this is a hack: create an infinite loop. 519 cananian 1.1.2.1 // this path should never be executed. 520 cananian 1.1.2.1 Quad.addEdge(phi, 0, phi, i); 521 cananian 1.1.2.1 } 522 cananian 1.1.2.1 523 cananian 1.1.2.1 public void visit(Quad q) { addChecks(q); } 524 cananian 1.1.2.18 public void visit(ANEW q) { 525 cananian 1.1.2.18 CounterFactory.spliceIncrement 526 cananian 1.1.2.18 (qf, q.prevEdge(0), "synctrans.new_array"); 527 cananian 1.1.2.18 visit((Quad)q); 528 cananian 1.1.2.18 } 529 cananian 1.1.2.18 public void visit(NEW q) { 530 cananian 1.1.2.18 CounterFactory.spliceIncrement 531 cananian 1.1.2.18 (qf, q.prevEdge(0), "synctrans.new_object"); 532 cananian 1.1.2.18 visit((Quad)q); 533 cananian 1.1.2.18 } 534 cananian 1.1.2.1 535 cananian 1.1.2.1 public void visit(METHOD q) { 536 cananian 1.1.2.1 addChecks(q); 537 cananian 1.1.2.1 if (handlers==null) return; // don't rewrite if not in trans 538 cananian 1.1.2.1 Temp[] nparams = new Temp[q.paramsLength()+1]; 539 cananian 1.1.2.1 int i=0; 540 cananian 1.1.2.1 if (!q.isStatic()) 541 cananian 1.1.2.1 nparams[i++] = q.params(0); 542 cananian 1.1.2.1 nparams[i++] = currtrans; 543 cananian 1.1.2.1 for ( ; i<nparams.length; i++) 544 cananian 1.1.2.1 nparams[i] = q.params(i-1); 545 cananian 1.1.2.1 Quad.replace(q, new METHOD(qf, q, nparams, q.arity())); 546 cananian 1.1.2.1 } 547 cananian 1.1.2.1 548 cananian 1.1.2.1 public void visit(CALL q) { 549 cananian 1.1.2.1 addChecks(q); 550 cananian 1.1.2.1 // if in a transaction, call the transaction version & 551 cananian 1.1.2.1 // deal with possible abort. 552 cananian 1.1.2.1 if (handlers==null) return; 553 cananian 1.6 /* old optimization for calling known-safe methods: 554 cananian 1.1.2.11 if (safeMethods.contains(q.method()) && !q.isVirtual()) 555 cananian 1.1.2.11 return; // it's safe. (this is an optimization) 556 cananian 1.6 */ 557 cananian 1.1.2.1 Temp[] nparams = new Temp[q.paramsLength()+1]; 558 cananian 1.1.2.1 int i=0; 559 cananian 1.1.2.1 if (!q.isStatic()) 560 cananian 1.1.2.1 nparams[i++] = q.params(0); 561 cananian 1.1.2.1 nparams[i++] = currtrans; 562 cananian 1.1.2.1 for ( ; i<nparams.length; i++) 563 cananian 1.1.2.1 nparams[i] = q.params(i-1); 564 cananian 1.1.2.1 CALL ncall = new CALL(qf, q, select(q.method(), WITH_TRANSACTION), 565 cananian 1.1.2.1 nparams, q.retval(), q.retex(), 566 cananian 1.1.2.1 q.isVirtual(), q.isTailCall(), 567 cananian 1.1.2.1 q.dst(), q.src()); 568 cananian 1.1.2.1 Quad.replace(q, ncall); 569 cananian 1.1.2.1 // now check for abort case. 570 cananian 1.9 if (!useHardwareTrans) 571 cananian 1.9 checkForAbort(ncall.nextEdge(1), ncall, ncall.retex()); 572 cananian 1.1.2.1 // done. 573 cananian 1.1.2.1 } 574 cananian 1.1.2.1 public void visit(MONITORENTER q) { 575 cananian 1.1.2.1 addChecks(q); 576 cananian 1.1.2.1 Edge in = q.prevEdge(0), out = q.nextEdge(0); 577 cananian 1.8 if (handlers!=null && noNestedTransactions) { 578 cananian 1.8 // we've already got a top-level transaction; ignore this 579 cananian 1.8 // monitorenter 580 cananian 1.8 skipped_nested++; 581 cananian 1.8 Quad.addEdge(in.from(), in.which_succ(), 582 cananian 1.8 out.to(), out.which_pred()); 583 cananian 1.8 return; 584 cananian 1.8 } 585 cananian 1.1.2.1 if (handlers==null) 586 cananian 1.1.2.1 in = addAt(in, new CONST(qf, q, currtrans, null, HClass.Void)); 587 cananian 1.1.2.15 // counters! 588 cananian 1.1.2.15 in = CounterFactory.spliceIncrement 589 cananian 1.1.2.15 (qf, in, "synctrans.transactions"); 590 cananian 1.1.2.15 if (handlers!=null) 591 cananian 1.1.2.15 in = CounterFactory.spliceIncrement 592 cananian 1.1.2.15 (qf, in, "synctrans.nested_transactions"); 593 cananian 1.9 if (useHardwareTrans) { 594 cananian 1.9 // we use hardware state-restore/jump mechansism. So we 595 cananian 1.9 // just need a call to some inlined asm magic here, and 596 cananian 1.9 // we don't have to wrap the transaction in a loop. 597 cananian 1.9 // note that XACTION_BEGIN will never fail. 598 cananian 1.9 Temp tX = new Temp(tf, "retex"); 599 cananian 1.9 Quad qC = new CALL(qf, q, gen.lookupMethod 600 cananian 1.9 ("XACTION_BEGIN", new HClass[0], 601 cananian 1.9 HClass.Void), 602 cananian 1.9 new Temp[0], null, tX, false, false, 603 cananian 1.9 new Temp[0]); 604 cananian 1.9 Quad qP = new PHI(qf, q, new Temp[0], 2); 605 cananian 1.9 // set currtrans to null. (you got a better idea?) 606 cananian 1.9 Quad qT = new CONST(qf, q, currtrans, null, HClass.Void); 607 cananian 1.9 Quad.addEdge(in.from(), in.which_succ(), qC, 0); 608 cananian 1.9 Quad.addEdge(qC, 0, qP, 0); 609 cananian 1.9 Quad.addEdge(qC, 1, qP, 1); 610 cananian 1.9 Quad.addEdge(qP, 0, qT, 0); 611 cananian 1.11 Edge dest = keepOldLocks ? in : out; 612 cananian 1.11 Quad.addEdge(qT, 0, dest.to(), dest.which_pred()); 613 cananian 1.9 // tell everyone we're in transaction context. 614 cananian 1.9 handlers=new ListList<THROW>(new ArrayList<THROW>(), handlers); 615 cananian 1.9 // done. 616 cananian 1.9 return; 617 cananian 1.9 } 618 cananian 1.1.2.1 // loop looks like: 619 cananian 1.1.2.1 // c=newTransaction(c); 620 cananian 1.1.2.1 // L1: try { 621 cananian 1.1.2.1 // ... 622 cananian 1.1.2.1 // c.commitTransaction(); 623 cananian 1.1.2.1 // } catch (TransactionAbortException ex) { 624 cananian 1.1.2.1 // if (ex.which==c) { // allows us to abort up to a parent trans 625 cananian 1.1.2.1 // c = c.retryTransaction(); 626 cananian 1.1.2.1 // goto L1; 627 cananian 1.1.2.1 // } else throw ex; 628 cananian 1.1.2.1 // } 629 cananian 1.1.2.1 Quad q0 = new CALL(qf, q, HMcommitrec_new, 630 cananian 1.1.2.1 new Temp[] { currtrans }, currtrans, retex, 631 cananian 1.1.2.1 false, false, new Temp[0]); 632 cananian 1.1.2.1 Quad q1 = new PHI(qf, q, new Temp[0], 2); 633 cananian 1.1.2.1 Quad q2 = new CALL(qf, q, HMcommitrec_retry, 634 cananian 1.1.2.1 new Temp[] { currtrans }, currtrans, retex, 635 cananian 1.1.2.1 false, false, new Temp[0]); 636 cananian 1.1.2.1 Quad q3 = new PHI(qf, q, new Temp[0], 3); 637 cananian 1.1.2.1 Quad q4 = new THROW(qf, q, retex); 638 cananian 1.5 Quad.addEdge(in.from(), in.which_succ(), q0, 0); 639 cananian 1.1.2.1 Quad.addEdge(q0, 0, q1, 0); 640 cananian 1.1.2.1 Quad.addEdge(q0, 1, q3, 0); 641 cananian 1.5 Quad.addEdge(q1, 0, out.to(), out.which_pred());//delink q 642 cananian 1.1.2.1 Quad.addEdge(q2, 0, q1, 1); 643 cananian 1.1.2.1 Quad.addEdge(q2, 1, q3, 1); 644 cananian 1.1.2.1 Quad.addEdge(q3, 0, q4, 0); 645 cananian 1.1.2.1 footer = footer.attach(q4, 0); // attach throw to FOOTER. 646 cananian 1.1.2.1 // add test to TransactionAbortException; 647 cananian 1.5 PHI q5 = new PHI(qf, q, new Temp[0], 0); // stub 648 cananian 1.1.2.1 Temp tst = new Temp(tf), stop = new Temp(tf); 649 cananian 1.1.2.1 Quad q6 = new GET(qf, q, stop, HFabortex_upto, retex); 650 cananian 1.1.2.1 Quad q7 = new OPER(qf, q, Qop.ACMPEQ, tst, 651 cananian 1.1.2.1 new Temp[] { stop, currtrans }); 652 cananian 1.1.2.1 Quad q8= new CJMP(qf, q, tst, new Temp[0]); 653 cananian 1.1.2.1 Quad.addEdges(new Quad[] { q5, q6, q7, q8 }); 654 cananian 1.1.2.1 Quad.addEdge(q8, 0, q3, 2); // not equal: rethrow exception 655 cananian 1.1.2.1 Quad.addEdge(q8, 1, q2, 0); // else, retry. 656 cananian 1.1.2.1 // all transactionabortexceptions need to link to q5, 657 cananian 1.1.2.1 // with the exception in retex. 658 cananian 1.5 handlers = new ListList<THROW>(new ArrayList<THROW>(), handlers); 659 cananian 1.1.2.1 fixupmap.put(q5, handlers.head); 660 cananian 1.1.2.1 } 661 cananian 1.1.2.1 public void visit(MONITOREXIT q) { 662 cananian 1.3.2.1 assert handlers!=null : "MONITOREXIT not dominated by "+ 663 cananian 1.3.2.1 "MONITORENTER in "+q.getFactory().getParent(); 664 cananian 1.1.2.1 addChecks(q); 665 cananian 1.1.2.1 Edge in = q.prevEdge(0), out = q.nextEdge(0); 666 cananian 1.8 if (skipped_nested>0) { 667 cananian 1.8 skipped_nested--; 668 cananian 1.8 assert handlers!=null; 669 cananian 1.8 assert noNestedTransactions; 670 cananian 1.8 Quad.addEdge(in.from(), in.which_succ(), 671 cananian 1.8 out.to(), out.which_pred()); 672 cananian 1.8 return; 673 cananian 1.8 } 674 cananian 1.9 if (useHardwareTrans) { 675 cananian 1.9 // we use hardware state-restore/jump mechansism. So we 676 cananian 1.9 // just need a call to some inlined asm magic here, and 677 cananian 1.9 // we don't have to wrap the transaction in a loop. 678 cananian 1.9 // note that XACTION_END will never fail. 679 cananian 1.9 // (well, it might fail, but it's invisible to us) 680 cananian 1.9 Temp tX = new Temp(tf, "retex"); 681 cananian 1.9 Quad qC = new CALL(qf, q, gen.lookupMethod 682 cananian 1.9 ("XACTION_END", new HClass[0], 683 cananian 1.9 HClass.Void), 684 cananian 1.9 new Temp[0], null, tX, false, false, 685 cananian 1.9 new Temp[0]); 686 cananian 1.9 Quad qP = new PHI(qf, q, new Temp[0], 2); 687 cananian 1.9 Quad.addEdge(in.from(), in.which_succ(), qC, 0); 688 cananian 1.9 Quad.addEdge(qC, 0, qP, 0); 689 cananian 1.9 Quad.addEdge(qC, 1, qP, 1); 690 cananian 1.11 Edge dest = keepOldLocks ? in : out; 691 cananian 1.11 Quad.addEdge(qP, 0, dest.to(), dest.which_pred()); 692 cananian 1.9 // pop the transaction context. 693 cananian 1.9 handlers = handlers.tail; 694 cananian 1.9 // done. 695 cananian 1.9 return; 696 cananian 1.9 } 697 cananian 1.1.2.1 // call c.commitTransaction(), linking to abort code if fails. 698 cananian 1.1.2.1 Quad q0 = new CALL(qf, q, HMcommitrec_commit, 699 cananian 1.1.2.1 new Temp[] { currtrans }, null, retex, 700 cananian 1.1.2.1 false, false, new Temp[0]); 701 cananian 1.1.2.1 Quad q1 = new GET(qf, q, currtrans, HFcommitrec_parent, currtrans); 702 cananian 1.1.2.1 Quad q2 = new THROW(qf, q, retex); 703 cananian 1.5 Quad.addEdge(in.from(), in.which_succ(), q0, 0); 704 cananian 1.1.2.1 Quad.addEdge(q0, 0, q1, 0); 705 cananian 1.1.2.1 Quad.addEdge(q0, 1, q2, 0); 706 cananian 1.5 Quad.addEdge(q1, 0, out.to(), out.which_pred()); 707 cananian 1.1.2.1 footer = footer.attach(q2, 0); // add q2 to FOOTER. 708 cananian 1.1.2.1 checkForAbort(q0.nextEdge(1), q, retex); 709 cananian 1.1.2.1 handlers = handlers.tail; 710 cananian 1.1.2.1 if (handlers==null) q1.remove(); // unneccessary. 711 cananian 1.1.2.1 } 712 cananian 1.1.2.1 public void visit(AGET q) { 713 cananian 1.1.2.1 addChecks(q); 714 cananian 1.9 715 cananian 1.9 HClass compType = etm.typeMap(q, q.dst()); 716 cananian 1.9 // this is great for object arrays, but sub-integer components 717 cananian 1.9 // are all squashed into HClass.Int. So ask the quad in this case 718 cananian 1.9 if (compType.isPrimitive()) compType = q.type(); 719 cananian 1.9 HClass arrType = HClassUtil.arrayClass(linker, compType, 1); 720 cananian 1.9 721 cananian 1.9 if (doMemoryTrace) { 722 cananian 1.9 // log this read. 723 cananian 1.9 Edge in = q.prevEdge(0); 724 cananian 1.9 Temp tT = new Temp(tf, "is_trans"); 725 cananian 1.9 Temp tX = new Temp(tf, "retex"); 726 cananian 1.9 Quad qC, qP; 727 cananian 1.9 in = addAt(in, new CONST(qf, q, tT, 728 cananian 1.9 new Integer((handlers==null) ? 0 : 1), 729 cananian 1.9 HClass.Int)); 730 cananian 1.9 in = addAt(in, qC = 731 cananian 1.9 new CALL(qf, q, gen.lookupMethod 732 cananian 1.9 ("traceRead_Array", new HClass[] 733 cananian 1.9 { arrType, HClass.Int, HClass.Int }, 734 cananian 1.9 HClass.Void), 735 cananian 1.9 new Temp[]{ q.objectref(), q.index(), tT }, 736 cananian 1.9 null, tX, false, false, new Temp[0])); 737 cananian 1.9 in = addAt(in, qP = new PHI(qf, q, new Temp[0], 2)); 738 cananian 1.9 Quad.addEdge(qC, 1, qP, 1); 739 cananian 1.9 } 740 cananian 1.1.2.14 if (noFieldModification || noArrayModification) return; 741 cananian 1.1.2.20 addUniqueRWCounters(q.prevEdge(0), q, q.objectref(), true, true); 742 cananian 1.1.2.21 CounterFactory.spliceIncrement 743 cananian 1.1.2.21 (qf, q.prevEdge(0),(handlers==null) ? 744 cananian 1.1.2.21 "synctrans.read_nt_array" : "synctrans.read_t_array"); 745 cananian 1.6 746 cananian 1.6 Edge in = q.prevEdge(0), out = q.nextEdge(0); 747 cananian 1.6 Temp t1 = new Temp(tf, "retex"); 748 cananian 1.6 Quad q1; 749 cananian 1.6 if (handlers==null) { // non-transactional read 750 cananian 1.6 // VALUETYPE TA(EXACT_readNT)(struct oobj *obj, int offset, 751 cananian 1.6 // int flag_offset, int flag_bit) 752 cananian 1.6 Temp t2 = new Temp(tf, "flag_field"); 753 cananian 1.6 Temp t3 = new Temp(tf, "flag_bit"); 754 cananian 1.6 Temp t4 = new Temp(tf, "index_mod32"); 755 cananian 1.6 HField arrayCheckField = bfn.arrayBitField(arrType); 756 cananian 1.6 in = addAt(in, new CONST(qf, q, t2, arrayCheckField, HCfield)); 757 cananian 1.6 in = addAt(in, new CONST(qf, q, t4, new Integer(31), 758 cananian 1.6 HClass.Int)); 759 cananian 1.6 in = addAt(in, new OPER(qf, q, Qop.IAND, t4, 760 cananian 1.6 new Temp[] { q.index(), t4 })); 761 cananian 1.6 in = addAt(in, new CONST(qf, q, t3, new Integer(1), 762 cananian 1.6 HClass.Int)); 763 cananian 1.6 in = addAt(in, new OPER(qf, q, Qop.ISHL, t3, 764 cananian 1.6 new Temp[] { t3, t4 })); 765 cananian 1.6 q1 = new CALL(qf, q, gen.lookupMethod 766 cananian 1.6 ("readNT_Array", new HClass[] 767 cananian 1.6 { arrType, HClass.Int, HCfield, HClass.Int }, 768 cananian 1.6 compType), 769 cananian 1.6 new Temp[] { q.objectref(), q.index(), t2, t3 }, 770 cananian 1.6 q.dst(), t1, false, false, new Temp[0]); 771 cananian 1.6 } else { // transactional read 772 cananian 1.6 // VALUETYPE TA(EXACT_readT)(struct oobj *obj, int offset, 773 cananian 1.6 // struct vinfo *version, 774 cananian 1.6 // struct commitrec *cr) 775 cananian 1.6 q1 = new CALL(qf, q, gen.lookupMethod 776 cananian 1.6 ("readT_Array", new HClass[] 777 cananian 1.6 {arrType, HClass.Int, HCvinfo, HCcommitrec}, 778 cananian 1.6 compType), 779 cananian 1.6 new Temp[] { q.objectref(), q.index(), 780 cananian 1.6 ts.versioned(q.objectref()), 781 cananian 1.6 currtrans }, 782 cananian 1.6 q.dst(), t1, false, false, new Temp[0]); 783 cananian 1.6 } 784 cananian 1.6 Quad q2 = new THROW(qf, q, t1); 785 cananian 1.6 786 cananian 1.6 Quad.addEdge(in.from(), in.which_succ(), q1, 0); 787 cananian 1.6 Quad.addEdge(q1, 0, out.to(), out.which_pred()); 788 cananian 1.6 Quad.addEdge(q1, 1, q2, 0); 789 cananian 1.6 footer = footer.attach(q2, 0); // add q2 to FOOTER 790 cananian 1.6 /* // native call is not going to abort. 791 cananian 1.6 if (handlers!=null) // only trans can abort 792 cananian 1.6 checkForAbort(q1.nextEdge(1), q, t1); 793 cananian 1.6 */ 794 cananian 1.1.2.21 // done. 795 cananian 1.1.2.1 } 796 cananian 1.1.2.1 public void visit(GET q) { 797 cananian 1.1.2.1 addChecks(q); 798 cananian 1.9 if (doMemoryTrace && !q.isStatic()/*XXX*/) { 799 cananian 1.9 // log this read. 800 cananian 1.9 Edge in = q.prevEdge(0); 801 cananian 1.9 Temp tT = new Temp(tf, "is_trans"); 802 cananian 1.9 Temp tF = new Temp(tf, "field"); 803 cananian 1.9 Temp tX = new Temp(tf, "retex"); 804 cananian 1.9 Quad qC, qP; 805 cananian 1.9 in = addAt(in, new CONST(qf, q, tT, 806 cananian 1.9 new Integer((handlers==null) ? 0 : 1), 807 cananian 1.9 HClass.Int)); 808 cananian 1.9 in = addAt(in, new CONST(qf, q, tF, q.field(), HCfield)); 809 cananian 1.9 in = addAt(in, qC = 810 cananian 1.9 new CALL(qf, q, gen.lookupMethod 811 cananian 1.9 ("traceRead", new HClass[] 812 cananian 1.9 { HCobj, HCfield, HClass.Int }, 813 cananian 1.9 HClass.Void), 814 cananian 1.9 new Temp[]{ q.objectref(), tF, tT }, 815 cananian 1.9 null, tX, false, false, new Temp[0])); 816 cananian 1.9 in = addAt(in, qP = new PHI(qf, q, new Temp[0], 2)); 817 cananian 1.9 Quad.addEdge(qC, 1, qP, 1); 818 cananian 1.9 transFields.add(q.field()); 819 cananian 1.9 } 820 cananian 1.1.2.1 if (noFieldModification) return; 821 cananian 1.1.2.1 if (handlers==null && 822 cananian 1.1.2.15 !fo.isSyncRead(q.field()) && !fo.isSyncWrite(q.field())) { 823 cananian 1.1.2.15 // we can simply read/write fields with no sync access 824 cananian 1.1.2.15 CounterFactory.spliceIncrement 825 cananian 1.1.2.15 (qf, q.prevEdge(0), "synctrans.read_nt_skipped"); 826 cananian 1.1.2.15 return; 827 cananian 1.1.2.15 } 828 cananian 1.1.2.1 if (q.isStatic()) { 829 cananian 1.1.2.1 if (handlers==null) return; 830 cananian 1.1.2.1 System.err.println("WARNING: read of "+q.field()+" in "+ 831 cananian 1.1.2.1 qf.getMethod()); 832 cananian 1.1.2.1 return; 833 cananian 1.1.2.20 } else 834 cananian 1.1.2.20 addUniqueRWCounters(q.prevEdge(0), q, q.objectref(), true, false); 835 cananian 1.1.2.21 CounterFactory.spliceIncrement 836 cananian 1.1.2.21 (qf, q.prevEdge(0),(handlers==null) ? 837 cananian 1.1.2.21 "synctrans.read_nt_object" : "synctrans.read_t_object"); 838 cananian 1.6 839 cananian 1.6 transFields.add(q.field()); 840 cananian 1.6 Edge in = q.prevEdge(0), out = q.nextEdge(0); 841 cananian 1.6 Temp t0 = new Temp(tf, "read_field"); 842 cananian 1.6 Temp t1 = new Temp(tf, "retex"); 843 cananian 1.6 Quad q0 = new CONST(qf, q, t0, q.field(), HCfield); 844 cananian 1.6 Quad q1; 845 cananian 1.6 in = addAt(in, q0); 846 cananian 1.6 if (handlers==null) { // non-transactional read 847 cananian 1.6 // VALUETYPE TA(EXACT_readNT)(struct oobj *obj, int offset, 848 cananian 1.6 // int flag_offset, int flag_bit) 849 cananian 1.6 Temp t2 = new Temp(tf, "flag_field"); 850 cananian 1.6 Temp t3 = new Temp(tf, "flag_bit"); 851 cananian 1.6 BitFieldTuple bft = bfn.bfLoc(q.field()); 852 cananian 1.6 in = addAt(in, new CONST(qf, q, t2, bft.field, HCfield)); 853 cananian 1.6 in = addAt(in, new CONST(qf, q, t3, new Integer(1<<bft.bit), 854 cananian 1.6 HClass.Int)); 855 cananian 1.6 q1 = new CALL(qf, q, gen.lookupMethod 856 cananian 1.6 ("readNT", new HClass[] { HCobj, HCfield, 857 cananian 1.6 HCfield, HClass.Int }, 858 cananian 1.6 q.field().getType()), 859 cananian 1.6 new Temp[] { q.objectref(), t0, t2, t3 }, 860 cananian 1.6 q.dst(), t1, false, false, new Temp[0]); 861 cananian 1.6 } else { // transactional read 862 cananian 1.6 // VALUETYPE TA(EXACT_readT)(struct oobj *obj, int offset, 863 cananian 1.6 // struct vinfo *version, 864 cananian 1.6 // struct commitrec *cr) 865 cananian 1.6 q1 = new CALL(qf, q, gen.lookupMethod 866 cananian 1.6 ("readT", new HClass[] { HCobj, HCfield, 867 cananian 1.6 HCvinfo, HCcommitrec }, 868 cananian 1.6 q.field().getType()), 869 cananian 1.6 new Temp[] { q.objectref(), t0, 870 cananian 1.6 ts.versioned(q.objectref()), 871 cananian 1.6 currtrans }, 872 cananian 1.6 q.dst(), t1, false, false, new Temp[0]); 873 cananian 1.6 } 874 cananian 1.6 Quad q2 = new THROW(qf, q, t1); 875 cananian 1.6 876 cananian 1.6 Quad.addEdge(in.from(), in.which_succ(), q1, 0); 877 cananian 1.6 Quad.addEdge(q1, 0, out.to(), out.which_pred()); 878 cananian 1.6 Quad.addEdge(q1, 1, q2, 0); 879 cananian 1.6 footer = footer.attach(q2, 0); // add q2 to FOOTER 880 cananian 1.6 /* // native call is not going to abort. 881 cananian 1.6 if (handlers!=null) // only trans can abort 882 cananian 1.6 checkForAbort(q1.nextEdge(1), q, t1); 883 cananian 1.6 */ 884 cananian 1.1.2.21 // done. 885 cananian 1.1.2.1 } 886 cananian 1.6 887 cananian 1.1.2.1 public void visit(ASET q) { 888 cananian 1.1.2.1 addChecks(q); 889 cananian 1.9 890 cananian 1.9 HClass compType = q.type(); // don't need extra precision here. 891 cananian 1.9 HClass arrType = HClassUtil.arrayClass(linker, compType, 1); 892 cananian 1.9 893 cananian 1.9 if (doMemoryTrace) { 894 cananian 1.9 // log this write. 895 cananian 1.9 Edge in = q.prevEdge(0); 896 cananian 1.9 Temp tT = new Temp(tf, "is_trans"); 897 cananian 1.9 Temp tX = new Temp(tf, "retex"); 898 cananian 1.9 Quad qC, qP; 899 cananian 1.9 in = addAt(in, new CONST(qf, q, tT, 900 cananian 1.9 new Integer((handlers==null) ? 0 : 1), 901 cananian 1.9 HClass.Int)); 902 cananian 1.9 in = addAt(in, qC = 903 cananian 1.9 new CALL(qf, q, gen.lookupMethod 904 cananian 1.9 ("traceWrite_Array", new HClass[] 905 cananian 1.9 { arrType, HClass.Int, HClass.Int }, 906 cananian 1.9 HClass.Void), 907 cananian 1.9 new Temp[]{ q.objectref(), q.index(), tT }, 908 cananian 1.9 null, tX, false, false, new Temp[0])); 909 cananian 1.9 in = addAt(in, qP = new PHI(qf, q, new Temp[0], 2)); 910 cananian 1.9 Quad.addEdge(qC, 1, qP, 1); 911 cananian 1.9 } 912 cananian 1.1.2.14 if (noFieldModification || noArrayModification) return; 913 cananian 1.1.2.20 addUniqueRWCounters(q.prevEdge(0), q, q.objectref(), false, true); 914 cananian 1.1.2.21 CounterFactory.spliceIncrement 915 cananian 1.1.2.21 (qf, q.prevEdge(0),(handlers==null) ? 916 cananian 1.1.2.21 "synctrans.write_nt_array" : "synctrans.write_t_array"); 917 cananian 1.6 918 cananian 1.6 Edge in = q.prevEdge(0), out = q.nextEdge(0); 919 cananian 1.6 Temp t1 = new Temp(tf, "retex"); 920 cananian 1.6 Quad q1; 921 cananian 1.1.2.1 if (handlers==null) { // non-transactional write 922 cananian 1.6 // void TA(EXACT_writeNT)(struct oobj *obj, int offset, 923 cananian 1.6 // VALUETYPE value, 924 cananian 1.6 // int flag_offset, int flag_bit); 925 cananian 1.6 Temp t2 = new Temp(tf, "flag_field"); 926 cananian 1.6 Temp t3 = new Temp(tf, "flag_bit"); 927 cananian 1.6 Temp t4 = new Temp(tf, "index_mod32"); 928 cananian 1.6 HField arrayCheckField = bfn.arrayBitField(arrType); 929 cananian 1.6 in = addAt(in, new CONST(qf, q, t2, arrayCheckField, HCfield)); 930 cananian 1.6 in = addAt(in, new CONST(qf, q, t4, new Integer(31), 931 cananian 1.6 HClass.Int)); 932 cananian 1.6 in = addAt(in, new OPER(qf, q, Qop.IAND, t4, 933 cananian 1.6 new Temp[] { q.index(), t4 })); 934 cananian 1.6 in = addAt(in, new CONST(qf, q, t3, new Integer(1), 935 cananian 1.6 HClass.Int)); 936 cananian 1.6 in = addAt(in, new OPER(qf, q, Qop.ISHL, t3, 937 cananian 1.6 new Temp[] { t3, t4 })); 938 cananian 1.6 q1 = new CALL(qf, q, gen.lookupMethod 939 cananian 1.6 ("writeNT_Array", new HClass[] 940 cananian 1.6 { arrType, HClass.Int, compType, 941 cananian 1.6 HCfield, HClass.Int }, 942 cananian 1.6 HClass.Void), 943 cananian 1.6 new Temp[]{ q.objectref(), q.index(), q.src(), 944 cananian 1.6 t2, t3 }, 945 cananian 1.6 null, t1, false, false, new Temp[0]); 946 cananian 1.6 } else { // transactional write 947 cananian 1.6 // void TA(EXACT_writeT)(struct oobj *obj, int offset, 948 cananian 1.6 // VALUETYPE value, 949 cananian 1.6 // struct vinfo *version); 950 cananian 1.6 q1 = new CALL(qf, q, gen.lookupMethod 951 cananian 1.6 ("writeT_Array", new HClass[] 952 cananian 1.6 { arrType, HClass.Int, compType, HCvinfo }, 953 cananian 1.6 HClass.Void), 954 cananian 1.6 new Temp[] { q.objectref(), q.index(), q.src(), 955 cananian 1.6 ts.versioned(q.objectref()) }, 956 cananian 1.6 null, t1, false, false, new Temp[0]); 957 cananian 1.1.2.1 } 958 cananian 1.6 Quad q2 = new THROW(qf, q, t1); 959 cananian 1.6 960 cananian 1.6 Quad.addEdge(in.from(), in.which_succ(), q1, 0); 961 cananian 1.6 Quad.addEdge(q1, 0, out.to(), out.which_pred()); 962 cananian 1.6 Quad.addEdge(q1, 1, q2, 0); 963 cananian 1.6 footer = footer.attach(q2, 0); // add q2 to FOOTER 964 cananian 1.6 /* // native call is not going to abort. 965 cananian 1.6 if (handlers!=null) // only trans can abort 966 cananian 1.6 checkForAbort(q1.nextEdge(1), q, t1); 967 cananian 1.6 */ 968 cananian 1.6 // done. 969 cananian 1.1.2.1 } 970 cananian 1.1.2.1 public void visit(SET q) { 971 cananian 1.1.2.1 addChecks(q); 972 cananian 1.9 if (doMemoryTrace && !q.isStatic()/*XXX*/) { 973 cananian 1.9 // log this write. 974 cananian 1.9 Edge in = q.prevEdge(0); 975 cananian 1.9 Temp tT = new Temp(tf, "is_trans"); 976 cananian 1.9 Temp tF = new Temp(tf, "field"); 977 cananian 1.9 Temp tX = new Temp(tf, "retex"); 978 cananian 1.9 Quad qC, qP; 979 cananian 1.9 in = addAt(in, new CONST(qf, q, tT, 980 cananian 1.9 new Integer((handlers==null) ? 0 : 1), 981 cananian 1.9 HClass.Int)); 982 cananian 1.9 in = addAt(in, new CONST(qf, q, tF, q.field(), HCfield)); 983 cananian 1.9 in = addAt(in, qC = 984 cananian 1.9 new CALL(qf, q, gen.lookupMethod 985 cananian 1.9 ("traceWrite", new HClass[] 986 cananian 1.9 { HCobj, HCfield, HClass.Int }, 987 cananian 1.9 HClass.Void), 988 cananian 1.9 new Temp[]{ q.objectref(), tF, tT }, 989 cananian 1.9 null, tX, false, false, new Temp[0])); 990 cananian 1.9 in = addAt(in, qP = new PHI(qf, q, new Temp[0], 2)); 991 cananian 1.9 Quad.addEdge(qC, 1, qP, 1); 992 cananian 1.9 transFields.add(q.field()); 993 cananian 1.9 } 994 cananian 1.1.2.1 if (noFieldModification) return; 995 cananian 1.1.2.1 if (handlers==null && 996 cananian 1.1.2.15 !fo.isSyncRead(q.field()) && !fo.isSyncWrite(q.field())) { 997 cananian 1.1.2.15 // we can simply read/write fields with no sync access 998 cananian 1.1.2.15 CounterFactory.spliceIncrement 999 cananian 1.1.2.15 (qf, q.prevEdge(0), "synctrans.write_nt_skipped"); 1000 cananian 1.1.2.15 return; 1001 cananian 1.1.2.15 } 1002 cananian 1.1.2.1 if (q.isStatic()) { 1003 cananian 1.1.2.1 if (handlers==null) return; 1004 cananian 1.1.2.1 System.err.println("WARNING: write of "+q.field()+" in "+ 1005 cananian 1.1.2.1 qf.getMethod()); 1006 cananian 1.1.2.1 return; 1007 cananian 1.1.2.20 } else 1008 cananian 1.1.2.20 addUniqueRWCounters(q.prevEdge(0), q, q.objectref(), false, false); 1009 cananian 1.1.2.21 CounterFactory.spliceIncrement 1010 cananian 1.1.2.21 (qf, q.prevEdge(0),(handlers==null) ? 1011 cananian 1.1.2.21 "synctrans.write_nt_object" : "synctrans.write_t_object"); 1012 cananian 1.1.2.20 1013 cananian 1.6 transFields.add(q.field()); 1014 cananian 1.6 Edge in = q.prevEdge(0), out = q.nextEdge(0); 1015 cananian 1.6 Temp t0 = new Temp(tf, "write_field"); 1016 cananian 1.6 Temp t1 = new Temp(tf, "retex"); 1017 cananian 1.6 Quad q0 = new CONST(qf, q, t0, q.field(), HCfield); 1018 cananian 1.6 Quad q1; 1019 cananian 1.6 in = addAt(in, q0); 1020 cananian 1.6 if (handlers==null) { // non-transactional read 1021 cananian 1.6 // void TA(EXACT_writeNT)(struct oobj *obj, int offset, 1022 cananian 1.6 // VALUETYPE value, 1023 cananian 1.6 // int flag_offset, int flag_bit); 1024 cananian 1.6 Temp t2 = new Temp(tf, "flag_field"); 1025 cananian 1.6 Temp t3 = new Temp(tf, "flag_bit"); 1026 cananian 1.6 BitFieldTuple bft = bfn.bfLoc(q.field()); 1027 cananian 1.6 in = addAt(in, new CONST(qf, q, t2, bft.field, HCfield)); 1028 cananian 1.6 in = addAt(in, new CONST(qf, q, t3, new Integer(1<<bft.bit), 1029 cananian 1.6 HClass.Int)); 1030 cananian 1.6 q1 = new CALL(qf, q, gen.lookupMethod 1031 cananian 1.6 ("writeNT", new HClass[] { HCobj, HCfield, 1032 cananian 1.6 q.field().getType(), 1033 cananian 1.6 HCfield, HClass.Int }, 1034 cananian 1.6 HClass.Void), 1035 cananian 1.6 new Temp[]{ q.objectref(), t0, q.src(), t2, t3 }, 1036 cananian 1.6 null, t1, false, false, new Temp[0]); 1037 cananian 1.6 } else { // transactional read 1038 cananian 1.6 // void TA(EXACT_writeT)(struct oobj *obj, int offset, 1039 cananian 1.6 // VALUETYPE value, 1040 cananian 1.6 // struct vinfo *version); 1041 cananian 1.6 q1 = new CALL(qf, q, gen.lookupMethod 1042 cananian 1.6 ("writeT", new HClass[] { HCobj, HCfield, 1043 cananian 1.6 q.field().getType(), 1044 cananian 1.6 HCvinfo }, 1045 cananian 1.6 HClass.Void), 1046 cananian 1.6 new Temp[] { q.objectref(), t0, q.src(), 1047 cananian 1.6 ts.versioned(q.objectref()) }, 1048 cananian 1.6 null, t1, false, false, new Temp[0]); 1049 cananian 1.1.2.1 } 1050 cananian 1.6 Quad q2 = new THROW(qf, q, t1); 1051 cananian 1.6 1052 cananian 1.6 Quad.addEdge(in.from(), in.which_succ(), q1, 0); 1053 cananian 1.6 Quad.addEdge(q1, 0, out.to(), out.which_pred()); 1054 cananian 1.6 Quad.addEdge(q1, 1, q2, 0); 1055 cananian 1.6 footer = footer.attach(q2, 0); // add q2 to FOOTER 1056 cananian 1.6 /* // native call is not going to abort. 1057 cananian 1.6 if (handlers!=null) // only trans can abort 1058 cananian 1.6 checkForAbort(q1.nextEdge(1), q, t1); 1059 cananian 1.6 */ 1060 cananian 1.6 // done. 1061 cananian 1.1.2.9 } 1062 cananian 1.1.2.9 public void visit(ARRAYINIT q) { 1063 cananian 1.1.2.9 addChecks(q); 1064 cananian 1.1.2.14 if (noFieldModification || noArrayModification) return; 1065 cananian 1.1.2.9 // XXX: we don't handle ARRAYINIT yet. 1066 cananian 1.3.2.1 assert false : "ARRAYINIT transformation unimplemented."; 1067 cananian 1.1.2.1 } 1068 cananian 1.1.2.1 1069 cananian 1.1.2.1 void addChecks(Quad q) { 1070 cananian 1.1.2.1 // don't add checks if we're not currently in transaction context. 1071 cananian 1.1.2.1 if (handlers==null) return; 1072 cananian 1.1.2.1 // don't add checks if we're compiling monitorenter/exit stats. 1073 cananian 1.1.2.1 if (noFieldModification) return; 1074 cananian 1.1.2.1 // only deal with quads where "just before" makes sense. 1075 cananian 1.1.2.1 if (q.prevLength()!=1) { 1076 cananian 1.3.2.1 assert co.createReadVersions(q).size()==0; 1077 cananian 1.3.2.1 assert co.createWriteVersions(q).size()==0; 1078 cananian 1.3.2.1 assert co.checkFieldReads(q).size()==0; 1079 cananian 1.3.2.1 assert co.checkFieldWrites(q).size()==0; 1080 cananian 1.3.2.1 assert co.checkArrayElementReads(q).size()==0; 1081 cananian 1.3.2.1 assert co.checkArrayElementWrites(q).size()==0; 1082 cananian 1.1.2.1 return; 1083 cananian 1.1.2.1 } 1084 cananian 1.1.2.1 Edge in = q.prevEdge(0); 1085 cananian 1.1.2.1 // create read/write versions for objects that need it. 1086 cananian 1.1.2.1 Set rS = co.createReadVersions(q); 1087 cananian 1.1.2.1 Set wS = co.createWriteVersions(q); 1088 cananian 1.6 // note that reading is different from writing: if you want to 1089 cananian 1.6 // read *and* write, you must call ensureReader *and* ensureWriter 1090 cananian 1.1.2.1 for (int i=0; i<2; i++) { 1091 cananian 1.1.2.1 // iteration 0 for read; iteration 1 for write versions. 1092 cananian 1.5 Iterator<Temp> it = (i==0) ? rS.iterator() : wS.iterator(); 1093 cananian 1.6 // void EXACT_ensureReader(struct oobj *obj, 1094 cananian 1.6 // struct commitrec *cr); 1095 cananian 1.6 // struct vinfo *EXACT_ensureWriter(struct oobj *obj, 1096 cananian 1.6 // struct commitrec *cr); 1097 cananian 1.6 HMethod hm = 1098 cananian 1.6 gen.lookupMethod((i==0) ? "ensureReader" : "ensureWriter", 1099 cananian 1.6 new HClass[] { HCobj, HCcommitrec }, 1100 cananian 1.6 (i==0) ? HClass.Void : HCvinfo); 1101 cananian 1.1.2.1 while (it.hasNext()) { 1102 cananian 1.6 // for each temp, a call to 'ensureReader' or 1103 cananian 1.6 // 'ensureWriter'. 1104 cananian 1.5 Temp t = it.next(); 1105 cananian 1.1.2.1 CALL q0= new CALL(qf, q, hm, new Temp[] { t, currtrans }, 1106 cananian 1.6 (i==0) ? null : ts.versioned(t), retex, 1107 cananian 1.1.2.1 false/*final, not virtual*/, false, 1108 cananian 1.1.2.1 new Temp[0]); 1109 cananian 1.1.2.1 THROW q1= new THROW(qf, q, retex); 1110 cananian 1.1.2.1 in = addAt(in, q0); 1111 cananian 1.1.2.1 Quad.addEdge(q0, 1, q1, 0); 1112 cananian 1.1.2.1 footer = footer.attach(q1, 0); 1113 cananian 1.1.2.1 checkForAbort(q0.nextEdge(1), q, retex); 1114 cananian 1.6 if (i==0) { // start reader version at NULL. 1115 cananian 1.6 in = addAt(in, new CONST(qf, q, ts.versioned(t), 1116 cananian 1.6 null, HClass.Void)); 1117 cananian 1.6 } else { // check return value from writer 1118 cananian 1.6 // NULL version indicates suicide request. 1119 cananian 1.6 Quad q2; 1120 cananian 1.6 Temp tnull = new Temp(tf, "null"); 1121 cananian 1.6 Temp tcmp = new Temp(tf, "nullchk"); 1122 cananian 1.6 in = addAt(in, new CONST(qf, q, tnull, 1123 cananian 1.6 null, HClass.Void)); 1124 cananian 1.6 in = addAt(in, new OPER(qf, q, Qop.ACMPEQ, tcmp, 1125 cananian 1.6 new Temp[] { ts.versioned(t), 1126 cananian 1.6 tnull })); 1127 cananian 1.6 in = addAt(in, q2=new CJMP(qf, q, tcmp, new Temp[0])); 1128 cananian 1.6 throwAbort(q2, 1, q); 1129 cananian 1.6 } 1130 cananian 1.1.2.20 in = CounterFactory.spliceIncrement 1131 cananian 1.1.2.20 (qf, in, 1132 cananian 1.1.2.20 "synctrans."+((i==0)?"read":"write")+"_versions"); 1133 cananian 1.1.2.1 } 1134 cananian 1.1.2.1 } 1135 cananian 1.1.2.21 // do field-read checks... 1136 cananian 1.13 for (CheckOracle.RefAndField raf : co.checkFieldReads(q)) { 1137 cananian 1.1.2.1 // skip check for fields unaccessed outside a sync context. 1138 cananian 1.1.2.1 if (!fo.isUnsyncRead(raf.field) && 1139 cananian 1.1.2.15 !fo.isUnsyncWrite(raf.field)) { 1140 cananian 1.1.2.21 in = CounterFactory.spliceIncrement 1141 cananian 1.1.2.21 (qf, in, "synctrans.field_read_checks_skipped"); 1142 cananian 1.6 //continue; // XXX is this correct? 1143 cananian 1.1.2.21 } 1144 cananian 1.1.2.21 in = CounterFactory.spliceIncrement 1145 cananian 1.1.2.21 (qf, in, "synctrans.field_read_checks"); 1146 cananian 1.1.2.21 // create read check code (set read-bit to one). 1147 cananian 1.1.2.21 // (check that read-bit is set, else call fixup code, 1148 cananian 1.1.2.21 // which will do atomic-set of this bit.) 1149 cananian 1.6 transFields.add(raf.field); 1150 cananian 1.1.2.21 BitFieldTuple bft = bfn.bfLoc(raf.field); 1151 cananian 1.6 1152 cananian 1.6 // struct vinfo *TA(EXACT_setReadFlags) 1153 cananian 1.6 // (struct oobj *obj, int offset, 1154 cananian 1.6 // int flag_offset, int flag_bit, 1155 cananian 1.6 // struct vinfo *version, 1156 cananian 1.6 // struct commitrec*cr/*this trans*/); 1157 cananian 1.6 HMethod hm = gen.lookupMethod 1158 cananian 1.6 ("setReadFlags", new HClass[] 1159 cananian 1.6 { raf.field.getDeclaringClass(), HCfield, 1160 cananian 1.6 HCfield, HClass.Int, HCvinfo, HCcommitrec }, 1161 cananian 1.6 HCvinfo); 1162 cananian 1.6 1163 cananian 1.6 Temp t0 = new Temp(tf, "readcheck_field"); 1164 cananian 1.6 Temp t1 = new Temp(tf, "readcheck_flag_field"); 1165 cananian 1.6 Temp t2 = new Temp(tf, "readcheck_flag_bit"); 1166 cananian 1.6 in = addAt(in, new CONST(qf, q, t0, raf.field, HCfield)); 1167 cananian 1.6 in = addAt(in, new CONST(qf, q, t1, bft.field, HCfield)); 1168 cananian 1.6 in = addAt(in, new CONST(qf, q, t2, new Integer(1<<bft.bit), 1169 cananian 1.6 HClass.Int)); 1170 cananian 1.6 CALL q0= new CALL(qf, q, hm, 1171 cananian 1.6 new Temp[] { raf.objref, t0, t1, t2, 1172 cananian 1.6 ts.versioned(raf.objref), 1173 cananian 1.6 currtrans }, 1174 cananian 1.6 ts.versioned(raf.objref), retex, 1175 cananian 1.6 false, false, new Temp[0]); 1176 cananian 1.6 // never throws exception. 1177 cananian 1.6 Quad q1 = new THROW(qf, q, retex); 1178 cananian 1.1.2.21 in = addAt(in, q0); 1179 cananian 1.6 Quad.addEdge(q0, 1, q1, 0); 1180 cananian 1.6 footer = footer.attach(q1, 0); 1181 cananian 1.6 /* can't see the 'bad read check' case from here anymore. 1182 cananian 1.1.2.21 CounterFactory.spliceIncrement 1183 cananian 1.1.2.21 (qf, q6.prevEdge(0), "synctrans.field_read_checks_bad"); 1184 cananian 1.6 */ 1185 cananian 1.1.2.21 } 1186 cananian 1.1.2.21 // do field-write checks... 1187 cananian 1.13 for (CheckOracle.RefAndField raf : co.checkFieldWrites(q)) { 1188 cananian 1.1.2.21 // skip check for fields unaccessed outside a sync context. 1189 cananian 1.1.2.21 if (!fo.isUnsyncRead(raf.field) && 1190 cananian 1.1.2.21 !fo.isUnsyncWrite(raf.field)) { 1191 cananian 1.1.2.21 in = CounterFactory.spliceIncrement 1192 cananian 1.1.2.21 (qf, in, "synctrans.field_write_checks_skipped"); 1193 cananian 1.6 //continue; // XXX is this correct? 1194 cananian 1.1.2.21 } 1195 cananian 1.1.2.21 in = CounterFactory.spliceIncrement 1196 cananian 1.1.2.21 (qf, in, "synctrans.field_write_checks"); 1197 cananian 1.1.2.21 // create write check code (set field to FLAG). 1198 cananian 1.1.2.21 // (check that field==FLAG is set, else call fixup code) 1199 cananian 1.6 transFields.add(raf.field); 1200 cananian 1.6 BitFieldTuple bft = bfn.bfLoc(raf.field); 1201 cananian 1.6 1202 cananian 1.6 // void TA(EXACT_setWriteFlags)(struct oobj *obj, int offset, 1203 cananian 1.6 // int flag_offset, int flag_bit) 1204 cananian 1.6 HMethod hm = gen.lookupMethod 1205 cananian 1.6 ("setWriteFlags", new HClass[] 1206 cananian 1.6 { raf.field.getDeclaringClass(), HCfield, 1207 cananian 1.6 HCfield, HClass.Int }, HClass.Void); 1208 cananian 1.6 1209 cananian 1.6 Temp t0 = new Temp(tf, "writecheck_field"); 1210 cananian 1.6 Temp t1 = new Temp(tf, "writecheck_flag_field"); 1211 cananian 1.6 Temp t2 = new Temp(tf, "writecheck_flag_bit"); 1212 cananian 1.6 in = addAt(in, new CONST(qf, q, t0, raf.field, HCfield)); 1213 cananian 1.6 in = addAt(in, new CONST(qf, q, t1, bft.field, HCfield)); 1214 cananian 1.6 in = addAt(in, new CONST(qf, q, t2, new Integer(1<<bft.bit), 1215 cananian 1.6 HClass.Int)); 1216 cananian 1.6 CALL q0= new CALL(qf, q, hm, 1217 cananian 1.6 new Temp[] { raf.objref, t0, t1, t2 }, 1218 cananian 1.6 null, retex, false, false, new Temp[0]); 1219 cananian 1.6 // never throws exception. 1220 cananian 1.6 Quad q1 = new THROW(qf, q, retex); 1221 cananian 1.1.2.1 in = addAt(in, q0); 1222 cananian 1.6 Quad.addEdge(q0, 1, q1, 0); 1223 cananian 1.6 footer = footer.attach(q1, 0); 1224 cananian 1.6 // XXX maybe this method should check whether aborted? 1225 cananian 1.6 /* can't see the 'bad write check' case from here anymore. 1226 cananian 1.1.2.21 CounterFactory.spliceIncrement 1227 cananian 1.1.2.21 (qf, q5.prevEdge(0), "synctrans.field_write_checks_bad"); 1228 cananian 1.6 */ 1229 cananian 1.1.2.1 } 1230 cananian 1.1.2.21 // do array index read checks.... 1231 cananian 1.5 for (Iterator<CheckOracle.RefAndIndexAndType> it = 1232 cananian 1.5 co.checkArrayElementReads(q).iterator(); it.hasNext(); ) { 1233 cananian 1.1.2.21 // arrays have one check field (32 bits) which stand in 1234 cananian 1.1.2.21 // (modulo 32) for all the elements in the array. 1235 cananian 1.1.2.21 // we check that the appropriate read-bit is set, else 1236 cananian 1.1.2.21 // call the fixup code, which will do an atomic-set of 1237 cananian 1.1.2.21 // the bit. 1238 cananian 1.1.2.15 in = CounterFactory.spliceIncrement 1239 cananian 1.1.2.21 (qf, in, "synctrans.element_read_checks"); 1240 cananian 1.5 CheckOracle.RefAndIndexAndType rit = it.next(); 1241 cananian 1.6 HClass arrayClass = 1242 cananian 1.6 HClassUtil.arrayClass(qf.getLinker(), rit.type, 1); 1243 cananian 1.6 HField arrayCheckField = bfn.arrayBitField(arrayClass); 1244 cananian 1.6 // struct vinfo *TA(EXACT_setReadFlags) 1245 cananian 1.6 // (struct oobj *obj, int offset, 1246 cananian 1.6 // int flag_offset, int flag_bit, 1247 cananian 1.6 // struct vinfo *version, 1248 cananian 1.6 // struct commitrec*cr/*this trans*/); 1249 cananian 1.6 HMethod hm = gen.lookupMethod 1250 cananian 1.6 ("setReadFlags_Array", new HClass[] 1251 cananian 1.6 { arrayClass, HClass.Int, HCfield, HClass.Int, 1252 cananian 1.6 HCvinfo, HCcommitrec }, HCvinfo); 1253 cananian 1.6 1254 cananian 1.1.2.21 Temp t0 = new Temp(tf, "arrayreadcheck"); 1255 cananian 1.6 Temp t1 = new Temp(tf, "arrayreadcheck_flag_field"); 1256 cananian 1.6 Temp t2 = new Temp(tf, "arrayreadcheck_flag_bit"); 1257 cananian 1.6 in = addAt(in, new CONST(qf, q, t0, new Integer(31), 1258 cananian 1.6 HClass.Int)); 1259 cananian 1.6 in = addAt(in, new OPER(qf, q, Qop.IAND, t0, 1260 cananian 1.6 new Temp[]{ rit.index, t0 })); 1261 cananian 1.6 in = addAt(in, new CONST(qf, q, t2, new Integer(1), 1262 cananian 1.6 HClass.Int)); 1263 cananian 1.6 in = addAt(in, new OPER(qf, q, Qop.ISHL, t2, 1264 cananian 1.6 new Temp[]{t2, t0})); 1265 cananian 1.6 in = addAt(in, new CONST(qf, q, t1, arrayCheckField, HCfield)); 1266 cananian 1.6 CALL q0= new CALL(qf, q, hm, 1267 cananian 1.6 new Temp[] { rit.objref, rit.index, t1, t2, 1268 cananian 1.6 ts.versioned(rit.objref), 1269 cananian 1.6 currtrans }, 1270 cananian 1.6 ts.versioned(rit.objref), retex, 1271 cananian 1.6 false, false, new Temp[0]); 1272 cananian 1.6 // never throws exception. 1273 cananian 1.6 Quad q1 = new THROW(qf, q, retex); 1274 cananian 1.1.2.21 in = addAt(in, q0); 1275 cananian 1.6 Quad.addEdge(q0, 1, q1, 0); 1276 cananian 1.6 footer = footer.attach(q1, 0); 1277 cananian 1.6 /* can't see the 'bad read check' case from here anymore. 1278 cananian 1.1.2.21 CounterFactory.spliceIncrement 1279 cananian 1.1.2.21 (qf, q6.prevEdge(0), "synctrans.element_read_checks_bad"); 1280 cananian 1.6 */ 1281 cananian 1.1.2.21 } 1282 cananian 1.1.2.21 // do array index write checks. 1283 cananian 1.5 for (Iterator<CheckOracle.RefAndIndexAndType> it = 1284 cananian 1.5 co.checkArrayElementWrites(q).iterator(); it.hasNext(); ){ 1285 cananian 1.1.2.21 // (check that element==FLAG is set, else call fixup code) 1286 cananian 1.1.2.15 in = CounterFactory.spliceIncrement 1287 cananian 1.1.2.21 (qf, in, "synctrans.element_write_checks"); 1288 cananian 1.5 CheckOracle.RefAndIndexAndType rit = it.next(); 1289 cananian 1.6 HClass arrayClass = 1290 cananian 1.6 HClassUtil.arrayClass(qf.getLinker(), rit.type, 1); 1291 cananian 1.6 HField arrayCheckField = bfn.arrayBitField(arrayClass); 1292 cananian 1.6 // void TA(EXACT_setWriteFlags)(struct oobj *obj, int offset, 1293 cananian 1.6 // int flag_offset, int flag_bit) 1294 cananian 1.6 HMethod hm = gen.lookupMethod 1295 cananian 1.6 ("setWriteFlags_Array", new HClass[] 1296 cananian 1.6 { arrayClass, HClass.Int, HCfield, HClass.Int }, 1297 cananian 1.6 HClass.Void); 1298 cananian 1.6 1299 cananian 1.1.2.21 Temp t0 = new Temp(tf, "arraywritecheck"); 1300 cananian 1.6 Temp t1 = new Temp(tf, "arraywritecheck_flag_field"); 1301 cananian 1.6 Temp t2 = new Temp(tf, "arraywritecheck_flag_bit"); 1302 cananian 1.6 in = addAt(in, new CONST(qf, q, t0, new Integer(31), 1303 cananian 1.6 HClass.Int)); 1304 cananian 1.6 in = addAt(in, new OPER(qf, q, Qop.IAND, t0, 1305 cananian 1.6 new Temp[]{ rit.index, t0 })); 1306 cananian 1.6 in = addAt(in, new CONST(qf, q, t2, new Integer(1), 1307 cananian 1.6 HClass.Int)); 1308 cananian 1.6 in = addAt(in, new OPER(qf, q, Qop.ISHL, t2, 1309 cananian 1.6 new Temp[]{t2, t0})); 1310 cananian 1.6 in = addAt(in, new CONST(qf, q, t1, arrayCheckField, HCfield)); 1311 cananian 1.6 CALL q0= new CALL(qf, q, hm, 1312 cananian 1.6 new Temp[] { rit.objref, rit.index, t1, t2 }, 1313 cananian 1.6 null, retex, false, false, new Temp[0]); 1314 cananian 1.6 // never throws exception. 1315 cananian 1.6 Quad q1 = new THROW(qf, q, retex); 1316 cananian 1.1.2.1 in = addAt(in, q0); 1317 cananian 1.6 Quad.addEdge(q0, 1, q1, 0); 1318 cananian 1.6 footer = footer.attach(q1, 0); 1319 cananian 1.6 /* can't see the 'bad write check' case from here anymore. 1320 cananian 1.1.2.21 CounterFactory.spliceIncrement 1321 cananian 1.1.2.21 (qf, q6.prevEdge(0), "synctrans.element_write_checks_bad"); 1322 cananian 1.6 */ 1323 cananian 1.1.2.1 } 1324 cananian 1.1.2.20 } 1325 cananian 1.1.2.20 private Edge addUniqueRWCounters(Edge in, HCodeElement src, Temp Tobj, 1326 cananian 1.1.2.20 boolean isRead, boolean isArray) { 1327 cananian 1.1.2.20 if (!useUniqueRWCounters) return in; // disabled 1328 cananian 1.1.2.20 if (handlers==null) return in; // not a transaction. 1329 cananian 1.1.2.20 String suffix = isArray ? "_array" : "_object"; 1330 cananian 1.1.2.20 // check whether last read/written is the same as this transaction. 1331 cananian 1.1.2.20 Temp Ttmp0 = new Temp(tf); 1332 cananian 1.1.2.20 in = addAt(in, new GET(qf, src, Ttmp0, HFlastRTrans, Tobj)); 1333 cananian 1.1.2.20 Temp TsameR = new Temp(tf); 1334 cananian 1.1.2.20 in = addAt(in, new OPER(qf, src, Qop.ACMPEQ, TsameR, 1335 cananian 1.1.2.20 new Temp[] { Ttmp0, currtrans })); 1336 cananian 1.1.2.20 Temp Ttmp1 = new Temp(tf); 1337 cananian 1.1.2.20 in = addAt(in, new GET(qf, src, Ttmp1, HFlastWTrans, Tobj)); 1338 cananian 1.1.2.20 Temp TsameW = new Temp(tf); 1339 cananian 1.1.2.20 in = addAt(in, new OPER(qf, src, Qop.ACMPEQ, TsameW, 1340 cananian 1.1.2.20 new Temp[] { Ttmp1, currtrans })); 1341 cananian 1.1.2.20 // update last read/written according to whether we're r/writing. 1342 cananian 1.1.2.20 in = addAt(in, new SET(qf, src, isRead? HFlastRTrans: HFlastWTrans, 1343 cananian 1.1.2.20 Tobj, currtrans)); 1344 cananian 1.1.2.20 // test for counters 1345 cananian 1.1.2.20 Quad q0 = new CJMP(qf, src, isRead ? TsameR : TsameW, new Temp[0]); 1346 cananian 1.1.2.20 Quad q1 = new CJMP(qf, src, isRead ? TsameW : TsameR, new Temp[0]); 1347 cananian 1.1.2.20 Quad q2 = new PHI(qf, src, new Temp[0], 3); 1348 cananian 1.1.2.20 Quad.addEdge(q0, 0, q1, 0); 1349 cananian 1.1.2.20 Quad.addEdge(q0, 1, q2, 0); 1350 cananian 1.1.2.20 Quad.addEdge(q1, 0, q2, 1); 1351 cananian 1.1.2.20 Quad.addEdge(q1, 1, q2, 2); 1352 cananian 1.5 Quad.addEdge(in.from(), in.which_succ(), q0, 0); 1353 cananian 1.5 Quad.addEdge(q2, 0, in.to(), in.which_pred()); 1354 cananian 1.1.2.20 // increment counters 1355 cananian 1.1.2.20 CounterFactory.spliceIncrement 1356 cananian 1.1.2.20 (qf, q1.nextEdge(0), "synctrans." + 1357 cananian 1.1.2.20 (isRead ? "virgin_read" : "virgin_write") + suffix); 1358 cananian 1.1.2.20 CounterFactory.spliceIncrement 1359 cananian 1.1.2.20 (qf, q1.nextEdge(1), "synctrans." + 1360 cananian 1.1.2.20 (isRead ? "read_of_written" : "write_of_read") + suffix); 1361 cananian 1.1.2.20 // done. 1362 cananian 1.1.2.20 return q2.nextEdge(0); 1363 cananian 1.1.2.1 } 1364 cananian 1.1.2.1 // make a non-static equivalent field for static fields. 1365 cananian 1.1.2.21 // (IDEAS: new object type for static fields of each class. 1366 cananian 1.1.2.21 // then only one static field per class, which points to 1367 cananian 1.1.2.21 // the (singleton) object-of-fields. One dereference, but 1368 cananian 1.1.2.21 // from this point the fields behave 'normally'. Since the 1369 cananian 1.1.2.21 // single static field is now final, no transactions need 1370 cananian 1.1.2.21 // be done on it.) [maybe this is a separate pre-pass] 1371 cananian 1.1.2.1 private HField nonstatic(HField hf) { 1372 cananian 1.1.2.1 if (!hf.isStatic()) return hf; 1373 cananian 1.1.2.1 HClass hc = hf.getDeclaringClass(); 1374 cananian 1.1.2.1 // XXX: how exactly does this work? 1375 cananian 1.1.2.1 return null; 1376 cananian 1.1.2.1 } 1377 cananian 1.1.2.1 1378 cananian 1.1.2.1 private int cmpop(HClass type) { 1379 cananian 1.1.2.1 if (!type.isPrimitive()) return Qop.ACMPEQ; 1380 cananian 1.1.2.1 else if (type==HClass.Boolean || type==HClass.Byte || 1381 cananian 1.1.2.1 type==HClass.Char || type==HClass.Short || 1382 cananian 1.1.2.1 type==HClass.Int) return Qop.ICMPEQ; 1383 cananian 1.1.2.1 else if (type==HClass.Long) return Qop.LCMPEQ; 1384 cananian 1.1.2.1 else if (type==HClass.Float) return Qop.FCMPEQ; 1385 cananian 1.1.2.1 else if (type==HClass.Double) return Qop.DCMPEQ; 1386 cananian 1.1.2.1 else throw new Error("ACK: "+type); 1387 cananian 1.1.2.1 } 1388 cananian 1.1.2.1 } 1389 cananian 1.1.2.7 // flag values: repeating sequence of single bytes, must be valid double 1390 cananian 1.1.2.7 // and float (ie, not 00 or FF) 1391 cananian 1.1.2.7 private static final long FLAG_VALUE = 0xCACACACACACACACAL; 1392 cananian 1.1.2.1 private static final Integer booleanFlag=new Integer((byte)FLAG_VALUE); 1393 cananian 1.1.2.1 private static final Integer byteFlag = new Integer((byte)FLAG_VALUE); 1394 cananian 1.1.2.1 private static final Integer charFlag = new Integer((char)FLAG_VALUE); 1395 cananian 1.1.2.1 private static final Integer shortFlag= new Integer((short)FLAG_VALUE); 1396 cananian 1.1.2.1 private static final Integer intFlag = new Integer((int)FLAG_VALUE); 1397 cananian 1.1.2.1 private static final Long longFlag = new Long(FLAG_VALUE); 1398 cananian 1.1.2.1 private static final Float floatFlag = 1399 cananian 1.1.2.1 new Float(Float.intBitsToFloat(intFlag.intValue())); 1400 cananian 1.1.2.1 private static final Double doubleFlag = 1401 cananian 1.1.2.1 new Double(Double.longBitsToDouble(longFlag.longValue())); 1402 cananian 1.1.2.1 1403 cananian 1.1.2.1 private Quad makeFlagConst(QuadFactory qf, HCodeElement src, 1404 cananian 1.1.2.1 Temp dst, HClass type) { 1405 cananian 1.1.2.1 if (!type.isPrimitive()) 1406 cananian 1.1.2.2 /* value in FLAG_VALUE field is used as marker. */ 1407 cananian 1.1.2.2 /* (a post-pass converts this to a constant) */ 1408 cananian 1.1.2.1 return new GET(qf, src, dst, HFflagvalue, null); 1409 cananian 1.1.2.1 else if (type==HClass.Boolean) //XXX 1410 cananian 1.1.2.1 return new CONST(qf, src, dst, booleanFlag, HClass.Int); 1411 cananian 1.1.2.1 else if (type==HClass.Byte) 1412 cananian 1.1.2.1 return new CONST(qf, src, dst, byteFlag, HClass.Int); 1413 cananian 1.1.2.1 else if (type==HClass.Char) 1414 cananian 1.1.2.1 return new CONST(qf, src, dst, charFlag, HClass.Int); 1415 cananian 1.1.2.1 else if (type==HClass.Short) 1416 cananian 1.1.2.1 return new CONST(qf, src, dst, shortFlag, HClass.Int); 1417 cananian 1.1.2.1 else if (type==HClass.Int) 1418 cananian 1.1.2.1 return new CONST(qf, src, dst, intFlag, HClass.Int); 1419 cananian 1.1.2.1 else if (type==HClass.Long) 1420 cananian 1.1.2.1 return new CONST(qf, src, dst, longFlag, HClass.Long); 1421 cananian 1.1.2.1 else if (type==HClass.Float) 1422 cananian 1.1.2.1 return new CONST(qf, src, dst, floatFlag, HClass.Float); 1423 cananian 1.1.2.1 else if (type==HClass.Double) 1424 cananian 1.1.2.1 return new CONST(qf, src, dst, doubleFlag, HClass.Double); 1425 cananian 1.1.2.1 else throw new Error("ACK: "+type); 1426 cananian 1.1.2.2 } 1427 cananian 1.1.2.2 1428 cananian 1.1.2.2 /** Return an <code>HCodeFactory</code> that will clean up the 1429 cananian 1.1.2.2 * tree form of the transformed code by performing some optimizations 1430 cananian 1.1.2.2 * which can't be represented in quad form. */ 1431 cananian 1.1.2.2 public HCodeFactory treeCodeFactory(Frame f, HCodeFactory hcf) { 1432 cananian 1.6 Set<HField> allFields = new HashSet<HField>(transFields); 1433 cananian 1.9 if (bfn!=null) allFields.addAll(bfn.bitfields); 1434 cananian 1.6 return new TreePostPass(f, FLAG_VALUE, HFflagvalue, gen, allFields) 1435 cananian 1.6 .codeFactory(hcf); 1436 cananian 1.6 } 1437 cananian 1.6 1438 cananian 1.6 /** Munge <code>HData</code>s to insert bit-field numbering information. */ 1439 cananian 1.6 public Iterator<HData> filterData(Frame f, Iterator<HData> it) { 1440 cananian 1.9 if (bfn==null) return it; 1441 cananian 1.6 if (tdf==null) tdf = new TreeDataFilter(f, bfn, transFields); 1442 cananian 1.6 return new FilterIterator<HData,HData>(it, tdf); 1443 cananian 1.1.2.10 } 1444 cananian 1.6 TreeDataFilter tdf=null; 1445 cananian 1.6 1446 cananian 1.6 /** Create a redirection method for native methods in a transactions 1447 cananian 1.6 * context which sets/restores the JNI transaction state appropriately. 1448 cananian 1.6 */ 1449 cananian 1.1.2.10 // parts borrowed from InitializerTransform.java 1450 cananian 1.1.2.10 private QuadRSSx redirectCode(final HMethod hm) { 1451 cananian 1.1.2.10 final HMethod orig = select(hm, ORIGINAL); 1452 cananian 1.1.2.10 // make the Code for this method (note how we work around the 1453 cananian 1.1.2.10 // protected fields). 1454 cananian 1.1.2.10 return new QuadRSSx(hm, null) { /* constructor */ { 1455 cananian 1.6 harpoon.IR.Quads.Edge e; // wants to use Graph.Edge instead =( 1456 cananian 1.1.2.10 // figure out how many temps we need, then make them. 1457 cananian 1.1.2.10 int nargs = hm.getParameterTypes().length + (hm.isStatic()? 0: 1); 1458 cananian 1.1.2.10 Temp[] params = new Temp[nargs]; 1459 cananian 1.1.2.10 for (int i=0; i<params.length; i++) 1460 cananian 1.1.2.10 params[i] = new Temp(qf.tempFactory(), "param"+i); 1461 cananian 1.1.2.10 Temp[] nparams = new Temp[nargs-1]; 1462 cananian 1.1.2.10 int i=0; 1463 cananian 1.1.2.10 if (!hm.isStatic()) 1464 cananian 1.6 nparams[0] = params[i++]; 1465 cananian 1.6 Temp currTrans = params[i++]; 1466 cananian 1.6 for ( ; i<params.length; i++) 1467 cananian 1.1.2.10 nparams[i-1] = params[i]; 1468 cananian 1.1.2.10 Temp retex = new Temp(qf.tempFactory(), "retex"); 1469 cananian 1.1.2.10 Temp retval = (hm.getReturnType()==HClass.Void) ? null : 1470 cananian 1.1.2.10 new Temp(qf.tempFactory(), "retval"); 1471 cananian 1.1.2.10 // okay, make the dispatch core. 1472 cananian 1.1.2.10 Quad q0 = new HEADER(qf, null); 1473 cananian 1.1.2.10 Quad q1 = new METHOD(qf, null, params, 1); 1474 cananian 1.6 // save the transaction state. 1475 cananian 1.6 Quad q1a= new CALL(qf, null, HMsetTrans, new Temp[] { currTrans }, 1476 cananian 1.6 currTrans, retex, false, false, new Temp[0]); 1477 cananian 1.6 // do the dispatch to JNI 1478 cananian 1.1.2.10 Quad q2 = new CALL(qf, null, orig, nparams, 1479 cananian 1.6 retval, retex, false, false, new Temp[0]); 1480 cananian 1.6 // restore the transaction state (on both normal and exc. edges) 1481 cananian 1.6 Quad q2a= new CALL(qf, null, HMsetTrans, new Temp[] { currTrans }, 1482 cananian 1.6 currTrans, retex, false, false, new Temp[0]); 1483 cananian 1.6 Quad q2b= new CALL(qf, null, HMsetTrans, new Temp[] { currTrans }, 1484 cananian 1.6 currTrans, retex, false, false, new Temp[0]); 1485 cananian 1.6 // finish up. 1486 cananian 1.1.2.10 Quad q3 = new RETURN(qf, null, retval); 1487 cananian 1.6 Quad q3a= new PHI(qf, null, new Temp[0], 4); 1488 cananian 1.1.2.10 Quad q4 = new THROW(qf, null, retex); 1489 cananian 1.1.2.10 Quad q5 = new FOOTER(qf, null, 3); 1490 cananian 1.1.2.10 Quad.addEdge(q0, 0, q5, 0); 1491 cananian 1.1.2.10 Quad.addEdge(q0, 1, q1, 0); 1492 cananian 1.6 e = Quad.addEdge(q1, 0, q3, 0); 1493 cananian 1.6 Quad.addEdge(q3, 0, q5, 1); 1494 cananian 1.6 e = addAt(e, q1a); 1495 cananian 1.6 e = addAt(e, q2); 1496 cananian 1.6 e = addAt(e, q2a); 1497 cananian 1.6 Quad.addEdge(q1a,1, q3a,0); 1498 cananian 1.6 Quad.addEdge(q2, 1, q2b,0); 1499 cananian 1.6 Quad.addEdge(q2b,0, q3a,1); 1500 cananian 1.6 Quad.addEdge(q2b,1, q3a,2); 1501 cananian 1.6 Quad.addEdge(q2a,1, q3a,3); 1502 cananian 1.6 Quad.addEdge(q3a,0, q4, 0); 1503 cananian 1.6 Quad.addEdge(q4, 0, q5, 2); 1504 cananian 1.6 this.quads = q0; 1505 cananian 1.6 // done! 1506 cananian 1.6 } }; 1507 cananian 1.6 } 1508 cananian 1.6 /** Create an empty stub for generated placeholder methods. */ 1509 cananian 1.6 private QuadRSSx emptyCode(final HMethod hm) { 1510 cananian 1.6 // make the Code for this method (note how we work around the 1511 cananian 1.6 // protected fields). 1512 cananian 1.6 return new QuadRSSx(hm, null) { /* constructor */ { 1513 cananian 1.6 // figure out how many temps we need, then make them. 1514 cananian 1.6 int nargs = hm.getParameterTypes().length + (hm.isStatic()? 0: 1); 1515 cananian 1.6 Temp[] params = new Temp[nargs]; 1516 cananian 1.6 for (int i=0; i<params.length; i++) 1517 cananian 1.6 params[i] = new Temp(qf.tempFactory(), "param"+i); 1518 cananian 1.6 1519 cananian 1.6 HClass type = hm.getReturnType(); 1520 cananian 1.6 Temp retval = new Temp(qf.tempFactory(), "retval"); 1521 cananian 1.6 1522 cananian 1.6 Quad q0 = new HEADER(qf, null); 1523 cananian 1.6 Quad q1 = new METHOD(qf, null, params, 1); 1524 cananian 1.6 Quad q2=null; 1525 cananian 1.6 if (type==HClass.Void || !type.isPrimitive()) 1526 cananian 1.6 q2 = new CONST(qf, null, retval, null, HClass.Void); 1527 cananian 1.6 else if (type==HClass.Boolean || 1528 cananian 1.6 type==HClass.Byte || 1529 cananian 1.6 type==HClass.Char || 1530 cananian 1.6 type==HClass.Short || 1531 cananian 1.6 type==HClass.Int) 1532 cananian 1.6 q2 = new CONST(qf, null, retval, new Integer(0), HClass.Int); 1533 cananian 1.6 else if (type==HClass.Long) 1534 cananian 1.6 q2 = new CONST(qf, null, retval, new Long(0), HClass.Long); 1535 cananian 1.6 else if (type==HClass.Float) 1536 cananian 1.6 q2 = new CONST(qf, null, retval, new Float(0), HClass.Float); 1537 cananian 1.6 else if (type==HClass.Double) 1538 cananian 1.6 q2 = new CONST(qf, null, retval, new Double(0), HClass.Double); 1539 cananian 1.6 else assert false; 1540 cananian 1.6 Quad q3 = new RETURN(qf, null, (type==HClass.Void)? null : retval); 1541 cananian 1.6 Quad q4 = new FOOTER(qf, null, 2); 1542 cananian 1.6 Quad.addEdge(q0, 0, q4, 0); 1543 cananian 1.6 Quad.addEdge(q0, 1, q1, 0); 1544 cananian 1.1.2.10 Quad.addEdge(q1, 0, q2, 0); 1545 cananian 1.1.2.10 Quad.addEdge(q2, 0, q3, 0); 1546 cananian 1.6 Quad.addEdge(q3, 0, q4, 1); 1547 cananian 1.1.2.10 this.quads = q0; 1548 cananian 1.1.2.10 // done! 1549 cananian 1.1.2.10 } }; 1550 cananian 1.1.2.1 } 1551 cananian 1.1.2.1 1552 cananian 1.6 /** helper routine to add a quad on an edge. */ 1553 cananian 1.6 private static Edge addAt(Edge e, Quad q) { return addAt(e, 0, q, 0); } 1554 cananian 1.6 /** helper routine to add a quad on an edge. */ 1555 cananian 1.6 private static Edge addAt(Edge e, int which_pred, Quad q, int which_succ) { 1556 cananian 1.6 Quad frm = e.from(); int frm_succ = e.which_succ(); 1557 cananian 1.6 Quad to = e.to(); int to_pred = e.which_pred(); 1558 cananian 1.6 Quad.addEdge(frm, frm_succ, q, which_pred); 1559 cananian 1.6 Quad.addEdge(q, which_succ, to, to_pred); 1560 cananian 1.6 return to.prevEdge(to_pred); 1561 cananian 1.6 } 1562 cananian 1.6 1563 cananian 1.1.2.1 private class TempSplitter { 1564 cananian 1.5 private final Map<Temp,Temp> m = new HashMap<Temp,Temp>(); 1565 cananian 1.1.2.1 public Temp versioned(Temp t) { 1566 cananian 1.1.2.1 if (!m.containsKey(t)) 1567 cananian 1.1.2.1 m.put(t, new Temp(t)); 1568 cananian 1.5 return m.get(t); 1569 cananian 1.1.2.1 } 1570 cananian 1.1.2.1 } 1571 cananian 1.1.2.1 1572 cananian 1.5 private static Set<HMethod> parseResource(final Linker l, 1573 cananian 1.5 String resourceName) { 1574 cananian 1.5 final Set<HMethod> result = new HashSet<HMethod>(); 1575 cananian 1.1.2.1 try { 1576 cananian 1.1.2.1 ParseUtil.readResource(resourceName, new ParseUtil.StringParser() { 1577 cananian 1.1.2.1 public void parseString(String s) 1578 cananian 1.1.2.1 throws ParseUtil.BadLineException { 1579 cananian 1.1.2.1 result.add(ParseUtil.parseMethod(l, s)); 1580 cananian 1.1.2.1 } 1581 cananian 1.1.2.1 }); 1582 cananian 1.1.2.1 } catch (java.io.IOException ex) { 1583 cananian 1.6 System.err.println("ERROR READING TRANSACTIONS ROOT SET, "+ 1584 cananian 1.6 "SKIPPING REST."); 1585 cananian 1.1.2.1 System.err.println(ex.toString()); 1586 cananian 1.1.2.1 } 1587 cananian 1.1.2.1 // done. 1588 cananian 1.1.2.1 return result; 1589 cananian 1.1.2.1 } 1590 cananian 1.2 }