/* This file is part of JOP, the Java Optimized Processor see <http://www.jopdesign.com/> Copyright (C) 2007,2008, Martin Schoeberl (martin@jopdesign.com) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.jopdesign.build; import com.jopdesign.common.ClassInfo; import com.jopdesign.common.MethodCode; import com.jopdesign.common.MethodInfo; import com.jopdesign.common.graphutils.ClassVisitor; import com.jopdesign.common.misc.JavaClassFormatError; import org.apache.bcel.generic.ALOAD; import org.apache.bcel.generic.InstructionHandle; import org.apache.bcel.generic.InstructionList; import org.apache.bcel.generic.MONITORENTER; import org.apache.bcel.generic.MONITOREXIT; import org.apache.bcel.util.InstructionFinder; import java.util.Iterator; /** * Insert bytecodes for synchronizing methods. * * @author Martin Schoeberl, Wolfgang Puffitsch */ public class InsertSynchronized implements ClassVisitor { public InsertSynchronized() { } @Override public boolean visitClass(ClassInfo classInfo) { for (MethodInfo method : classInfo.getMethods()) { if (!(method.isAbstract() || method.isNative()) && method.isSynchronized()) { synchronize(method); // TODO prevent code inserted more than once if this is executed both in the optimizer and in JOPizer // method.setSynchronized(false); } } return true; } @Override public void finishClass(ClassInfo classInfo) { } private void synchronize(MethodInfo method) { MethodCode mc = method.getCode(); InstructionList il = mc.getInstructionList(); InstructionFinder f; // prepend monitorenter (reversed order of opcodes) il.insert(new MONITORENTER()); if (method.isStatic()) { // il.insert(new GET_CURRENT_CLASS()); throw new JavaClassFormatError("synchronized on static methods not yet supported"); } else { il.insert(new ALOAD(0)); } il.setPositions(); f = new InstructionFinder(il); // find return instructions and insert monitorexit String retInstr = "ReturnInstruction"; for (Iterator iterator = f.search(retInstr); iterator.hasNext();) { InstructionHandle[] match = (InstructionHandle[]) iterator.next(); InstructionHandle ih = match[0]; InstructionHandle newh; // handle for inserted sequence if (method.isStatic()) { // il.insert(ih, new GET_CURRENT_CLASS()); throw new JavaClassFormatError("synchronized on static methods not yet supported"); } else { // TODO this could become a bug if JCopter ever reassigns local variable slots, then // we could not be sure that slot 0 holds the this reference anymore.. To be on the safe side // we should check if there is an xSTORE_0 somewhere in the code newh = il.insert(ih, new ALOAD(0)); } il.insert(ih, new MONITOREXIT()); // correct jumps method.getCode().retarget(ih, newh); } il.setPositions(); method.compile(); } }