/* This file is part of the db4o object database http://www.db4o.com
Copyright (C) 2004 - 2011 Versant Corporation http://www.versant.com
db4o is free software; you can redistribute it and/or modify it under
the terms of version 3 of the GNU General Public License as published
by the Free Software Foundation.
db4o 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.db4o.ta.instrumentation;
import java.util.*;
import EDU.purdue.cs.bloat.editor.*;
import com.db4o.instrumentation.core.*;
public class ReplaceClassOnInstantiationEdit implements BloatClassEdit {
final Map _replacements;
public ReplaceClassOnInstantiationEdit(Class origClass, Class replacementClass) {
this(new ClassReplacementSpec[] {
new ClassReplacementSpec(origClass, replacementClass)
});
}
public ReplaceClassOnInstantiationEdit(ClassReplacementSpec[] replacementSpecs) {
_replacements = new HashMap();
for (int specIdx = 0; specIdx < replacementSpecs.length; specIdx++) {
ClassReplacementSpec spec = replacementSpecs[specIdx];
// TODO get type from runtime bloat environment and pass qualified names instead?
Type origType = Type.getType(spec._origClass);
Type replacementType = Type.getType(spec._replacementClass);
_replacements.put(origType, replacementType);
}
}
public InstrumentationStatus enhance(ClassEditor ce, ClassLoader origLoader, BloatLoaderContext loaderContext) {
ArrayListInstantiationMethodVisitor methodVisitor = new ArrayListInstantiationMethodVisitor();
try {
ce.visit(methodVisitor);
} catch(Exception exc) {
exc.printStackTrace();
return InstrumentationStatus.FAILED;
}
if (methodVisitor.instrumented()) {
ce.commit();
return InstrumentationStatus.INSTRUMENTED;
}
return InstrumentationStatus.NOT_INSTRUMENTED;
}
private final class ArrayListInstantiationMethodVisitor implements EditorVisitor {
private boolean _instrumented;
public void visitClassEditor(ClassEditor editor) {
Type replacementType = (Type) _replacements.get(editor.superclass());
if (replacementType == null) {
return;
}
editor.setSuperclass(replacementType);
_instrumented = true;
}
public void visitFieldEditor(FieldEditor editor) {
}
public void visitMethodEditor(MethodEditor editor) {
boolean instrumented = false;
final Iterator codeIterator = editor.code().iterator();
while (codeIterator.hasNext()) {
final Object instructionOrLabel = codeIterator.next();
if(instructionOrLabel instanceof Label) {
continue;
}
if(!(instructionOrLabel instanceof Instruction)) {
throw new IllegalStateException();
}
final Instruction instruction = (Instruction)instructionOrLabel;
switch(instruction.origOpcode()) {
case Instruction.opc_new:
Type newReplacementType = (Type) _replacements.get(instruction.operand());
if(newReplacementType == null) {
break;
}
instruction.setOperand(newReplacementType);
break;
// invokespecial covers instance initializer, super class method and private method invocations
case Instruction.opc_invokespecial:
MemberRef methodRef = (MemberRef) instruction.operand();
Type invokeReplacementType = (Type) _replacements.get(methodRef.declaringClass());
if(invokeReplacementType == null) {
break;
}
instruction.setOperand(new MemberRef(invokeReplacementType, methodRef.nameAndType()));
instrumented = true;
break;
default:
// do nothing
}
}
if(instrumented) {
_instrumented = true;
editor.commit();
}
}
public boolean instrumented() {
return _instrumented;
}
}
}