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}