/* Soot - a J*va Optimization Framework * Copyright (C) 2005 Nomair A. Naeem * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ package soot.dava; import soot.Body; import soot.G; import soot.Modifier; import soot.Singletons; import soot.SootClass; import soot.SootMethod; import soot.dava.internal.AST.ASTMethodNode; import soot.dava.internal.AST.ASTNode; import soot.dava.internal.AST.ASTStatementSequenceNode; import soot.util.Chain; /* * Coded to remove the static "final" bug from Dava. Usually occurs in AspectJ code * **********The staticBlockInlining Method is invoked by PackManager************** * * In the bug this is what used to happen: * * public static final ClassName myField; * static{ CLASSNAME.postClinit(); } * postClinit(){ myField = new ClassName(); } * * Now this causes a problem since final fields can not be defined using a method call * So the solution was to inline just this method. to get something like * static{ myField = new ClassName(); } * At the same time the code in the method postClinit is removed and an exception is thrown if this method is invoked */ public class DavaStaticBlockCleaner { SootClass sootClass; public DavaStaticBlockCleaner(Singletons.Global g) { } public static DavaStaticBlockCleaner v() { return G.v().soot_dava_DavaStaticBlockCleaner(); } //invoked by the PackManager public void staticBlockInlining(SootClass sootClass){ this.sootClass=sootClass; //retrieve the clinit method if any for sootClass //the clinit method gets converted into the static block which could initialize the final variable if(!sootClass.declaresMethod("void <clinit>()")){ //System.out.println("no clinit"); return; } SootMethod clinit = sootClass.getMethod("void <clinit>()"); //System.out.println(clinit); //retireve the active body if (!clinit.hasActiveBody()) throw new RuntimeException("method "+ clinit.getName()+ " has no active body!"); Body clinitBody = clinit.getActiveBody(); Chain units = ((DavaBody) clinitBody).getUnits(); if (units.size() != 1) { throw new RuntimeException("DavaBody AST doesn't have single root."); } ASTNode AST = (ASTNode) units.getFirst(); if(! (AST instanceof ASTMethodNode)) throw new RuntimeException("Starting node of DavaBody AST is not an ASTMethodNode"); //running methodCallFinder on the Clinit method AST.apply(new MethodCallFinder(this)); } /* * Method called with a sootMethod to decide whether this method should be inlined or not * returns null if it shouldnt be inlined * * A method can be inlined if it belongs to the same class and also if its static....(why???) */ public ASTMethodNode inline(SootMethod maybeInline){ //check if this method should be inlined if(sootClass !=null){ //1, method should belong to the same class as the clinit method if(sootClass.declaresMethod(maybeInline.getSubSignature())){ //System.out.println("The method invoked is from the same class"); //2, method should be static if (Modifier.isStatic(maybeInline.getModifiers())){ //decided to inline //send the ASTMethod node of the TO BE INLINED METHOD //retireve the active body if (!maybeInline.hasActiveBody()) throw new RuntimeException("method "+ maybeInline.getName()+ " has no active body!"); Body bod = maybeInline.getActiveBody(); Chain units = ((DavaBody) bod).getUnits(); if (units.size() != 1) { throw new RuntimeException("DavaBody AST doesn't have single root."); } ASTNode ASTtemp = (ASTNode) units.getFirst(); if(! (ASTtemp instanceof ASTMethodNode)) throw new RuntimeException("Starting node of DavaBody AST is not an ASTMethodNode"); //restricting to methods which do not have any variables declared ASTMethodNode toReturn = (ASTMethodNode)ASTtemp; ASTStatementSequenceNode declarations = toReturn.getDeclarations(); if(declarations.getStatements().size() == 0){ //inline only if there are no declarations in the method inlined //System.out.println("No declarations in the method. we can inline this method"); return toReturn; } } } } return null;//meaning dont inline } }