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 */
013package org.jikesrvm.compilers.opt.escape;
014
015import org.jikesrvm.VM;
016import org.jikesrvm.classloader.NormalMethod;
017import org.jikesrvm.compilers.opt.DefUse;
018import org.jikesrvm.compilers.opt.OptOptions;
019import org.jikesrvm.compilers.opt.ir.Call;
020import org.jikesrvm.compilers.opt.ir.Empty;
021import org.jikesrvm.compilers.opt.ir.New;
022import org.jikesrvm.compilers.opt.ir.IR;
023import org.jikesrvm.compilers.opt.ir.Instruction;
024import static org.jikesrvm.compilers.opt.ir.Operators.CALL_opcode;
025import static org.jikesrvm.compilers.opt.ir.Operators.MONITORENTER_opcode;
026import static org.jikesrvm.compilers.opt.ir.Operators.MONITOREXIT_opcode;
027import static org.jikesrvm.compilers.opt.ir.Operators.READ_CEILING;
028import static org.jikesrvm.compilers.opt.ir.Operators.SYSCALL_opcode;
029import static org.jikesrvm.compilers.opt.ir.Operators.WRITE_FLOOR;
030import org.jikesrvm.compilers.opt.ir.Register;
031import org.jikesrvm.compilers.opt.ir.operand.MethodOperand;
032import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
033import org.jikesrvm.compilers.opt.specialization.InvokeeThreadLocalContext;
034
035/**
036 * Replace calls to synchronized methods to calls specialized to be
037 * unsynchronized.
038 */
039final 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}