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 }