001    /*
002     *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003     *
004     *  This file is licensed to You under the Eclipse Public License (EPL);
005     *  You may not use this file except in compliance with the License. You
006     *  may obtain a copy of the License at
007     *
008     *      http://www.opensource.org/licenses/eclipse-1.0.php
009     *
010     *  See the COPYRIGHT.txt file distributed with this work for information
011     *  regarding copyright ownership.
012     */
013    package org.jikesrvm.compilers.opt.escape;
014    
015    import org.jikesrvm.VM;
016    import org.jikesrvm.classloader.NormalMethod;
017    import org.jikesrvm.compilers.opt.DefUse;
018    import org.jikesrvm.compilers.opt.OptOptions;
019    import org.jikesrvm.compilers.opt.ir.Call;
020    import org.jikesrvm.compilers.opt.ir.Empty;
021    import org.jikesrvm.compilers.opt.ir.New;
022    import org.jikesrvm.compilers.opt.ir.IR;
023    import org.jikesrvm.compilers.opt.ir.Instruction;
024    import static org.jikesrvm.compilers.opt.ir.Operators.CALL_opcode;
025    import static org.jikesrvm.compilers.opt.ir.Operators.MONITORENTER_opcode;
026    import static org.jikesrvm.compilers.opt.ir.Operators.MONITOREXIT_opcode;
027    import static org.jikesrvm.compilers.opt.ir.Operators.READ_CEILING;
028    import static org.jikesrvm.compilers.opt.ir.Operators.SYSCALL_opcode;
029    import static org.jikesrvm.compilers.opt.ir.Operators.WRITE_FLOOR;
030    import org.jikesrvm.compilers.opt.ir.Register;
031    import org.jikesrvm.compilers.opt.ir.operand.MethodOperand;
032    import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
033    import org.jikesrvm.compilers.opt.specialization.InvokeeThreadLocalContext;
034    
035    /**
036     * Replace calls to synchronized methods to calls specialized to be
037     * unsynchronized.
038     */
039    final class UnsyncReplacer {
040      /**
041       * The register to replace
042       */
043      private final Register reg;
044      /**
045       * Controlling compiler options
046       */
047      private final OptOptions options;
048      /**
049       * Singleton: a single context representing "specialize this method when
050       * the invokee of this method is thread-local"
051       */
052      private static final InvokeeThreadLocalContext context = new InvokeeThreadLocalContext();
053    
054      /**
055       * @param r the register operand target of the allocation
056       * @param options controlling compiler options
057       */
058      private UnsyncReplacer(Register r, OptOptions options) {
059        reg = r;
060        this.options = options;
061      }
062    
063      /**
064       * Generate an instance of this class for a particular
065       * instantiation site.
066       *
067       * @param inst the allocation site
068       * @param ir governing ir
069       * @return the object, or null if illegal
070       */
071      public static UnsyncReplacer getReplacer(Instruction inst, IR ir) {
072        Register r = New.getResult(inst).getRegister();
073        return new UnsyncReplacer(r, ir.options);
074      }
075    
076      /**
077       * Perform the transformation
078       */
079      public void transform() {
080        synchronized (context) {
081          // first change the defs
082          for (RegisterOperand def = reg.defList; def != null; def = def.getNext()) {
083            transform(def);
084          }
085          // now fix the uses
086          for (RegisterOperand use = reg.useList; use != null; use = use.getNext()) {
087            transform(use);
088          }
089        }
090      }
091    
092      /**
093       * Perform the transformation for a given register appearance
094       *
095       * @param rop  The def or use to check
096       */
097      private void transform(RegisterOperand rop) {
098        final boolean DEBUG = false;
099        Instruction inst = rop.instruction;
100        switch (inst.getOpcode()) {
101          case SYSCALL_opcode:
102          case CALL_opcode:
103            RegisterOperand invokee = Call.getParam(inst, 0).asRegister();
104            if (invokee == rop) {
105              // replace with equivalent call on the synthetic
106              // unsynchronized type
107              MethodOperand mop = Call.getMethod(inst);
108              if (mop.getTarget().isSynchronized()) {
109                mop.spMethod = context.findOrCreateSpecializedVersion((NormalMethod) mop.getTarget());
110                if (DEBUG) {
111                  VM.sysWrite("Identified call " + inst + " for unsynchronization\n");
112                }
113              }
114            }
115            break;
116          case MONITORENTER_opcode:
117            if (DEBUG) {
118              VM.sysWrite("Removing " + inst);
119            }
120            inst.insertBefore(Empty.create(READ_CEILING));
121            DefUse.removeInstructionAndUpdateDU(inst);
122            break;
123          case MONITOREXIT_opcode:
124            if (DEBUG) {
125              VM.sysWrite("Removing " + inst);
126            }
127            inst.insertAfter(Empty.create(WRITE_FLOOR));
128            DefUse.removeInstructionAndUpdateDU(inst);
129            break;
130          default:
131            // no action necessary
132            break;
133        }
134      }
135    }