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      }