/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Common Public License (CPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/cpl1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.compilers.opt; import org.jikesrvm.VM; import org.jikesrvm.classloader.VM_NormalMethod; import org.jikesrvm.compilers.opt.ir.Call; import org.jikesrvm.compilers.opt.ir.Empty; import org.jikesrvm.compilers.opt.ir.New; import org.jikesrvm.compilers.opt.ir.OPT_IR; import org.jikesrvm.compilers.opt.ir.OPT_Instruction; import org.jikesrvm.compilers.opt.ir.OPT_MethodOperand; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.CALL_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.MONITORENTER_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.MONITOREXIT_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.READ_CEILING; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.SYSCALL_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.WRITE_FLOOR; import org.jikesrvm.compilers.opt.ir.OPT_Register; import org.jikesrvm.compilers.opt.ir.OPT_RegisterOperand; /** * Replace calls to synchronized methods to calls specialized to be * unsynchronized. */ public final class OPT_UnsyncReplacer { private static final boolean DEBUG = false; /** * Generate an instance of this class for a particular * instantiation site. * * @param inst the allocation site * @param ir governing ir * @return the object, or null if illegal */ public static OPT_UnsyncReplacer getReplacer(OPT_Instruction inst, OPT_IR ir) { OPT_Register r = New.getResult(inst).getRegister(); return new OPT_UnsyncReplacer(r, ir.options); } /** * Perform the transformation */ public void transform() { synchronized (context) { // first change the defs for (OPT_RegisterOperand def = reg.defList; def != null; def = def.getNext()) { transform(def); } // now fix the uses for (OPT_RegisterOperand use = reg.useList; use != null; use = use.getNext()) { transform(use); } } } /** * @param r the register operand target of the allocation * @param options controlling compiler options */ private OPT_UnsyncReplacer(OPT_Register r, OPT_Options options) { reg = r; this.options = options; } /** * Perform the transformation for a given register appearance * * @param rop The def or use to check */ private void transform(OPT_RegisterOperand rop) { OPT_Instruction inst = rop.instruction; switch (inst.getOpcode()) { case SYSCALL_opcode: case CALL_opcode: OPT_RegisterOperand invokee = Call.getParam(inst, 0).asRegister(); if (invokee == rop) { // replace with equivalent call on the synthetic // unsynchronized type OPT_MethodOperand mop = Call.getMethod(inst); if (mop.getTarget().isSynchronized()) { mop.spMethod = context.findOrCreateSpecializedVersion((VM_NormalMethod) mop.getTarget()); if (DEBUG) { VM.sysWrite("Identified call " + inst + " for unsynchronization\n"); } } } break; case MONITORENTER_opcode: if (DEBUG) { VM.sysWrite("Removing " + inst); } if (!options.NO_CACHE_FLUSH) { inst.insertBefore(Empty.create(READ_CEILING)); } OPT_DefUse.removeInstructionAndUpdateDU(inst); break; case MONITOREXIT_opcode: if (DEBUG) { VM.sysWrite("Removing " + inst); } if (!options.NO_CACHE_FLUSH) { inst.insertAfter(Empty.create(WRITE_FLOOR)); } OPT_DefUse.removeInstructionAndUpdateDU(inst); break; default: // no action necessary break; } } /** * The register to replace */ private OPT_Register reg; /** * Controlling compiler options */ private OPT_Options options; /** * Singleton: a single context representing "specialize this method when * the invokee of this method is thread-local" */ private static final OPT_InvokeeThreadLocalContext context = new OPT_InvokeeThreadLocalContext(); }