001: /* Copyright (C) 2004 - 2007 db4objects Inc. http://www.db4o.com
002:
003: This file is part of the db4o open source object database.
004:
005: db4o is free software; you can redistribute it and/or modify it under
006: the terms of version 2 of the GNU General Public License as published
007: by the Free Software Foundation and as clarified by db4objects' GPL
008: interpretation policy, available at
009: http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
010: Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
011: Suite 350, San Mateo, CA 94403, USA.
012:
013: db4o is distributed in the hope that it will be useful, but WITHOUT ANY
014: WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: for more details.
017:
018: You should have received a copy of the GNU General Public License along
019: with this program; if not, write to the Free Software Foundation, Inc.,
020: 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
021: package com.db4o.ta.instrumentation;
022:
023: import java.util.Comparator;
024: import java.util.Iterator;
025: import java.util.TreeMap;
026:
027: import EDU.purdue.cs.bloat.editor.ClassEditor;
028: import EDU.purdue.cs.bloat.editor.EditorVisitor;
029: import EDU.purdue.cs.bloat.editor.FieldEditor;
030: import EDU.purdue.cs.bloat.editor.Instruction;
031: import EDU.purdue.cs.bloat.editor.MemberRef;
032: import EDU.purdue.cs.bloat.editor.MethodEditor;
033: import EDU.purdue.cs.bloat.editor.NameAndType;
034: import EDU.purdue.cs.bloat.editor.Opcode;
035: import EDU.purdue.cs.bloat.editor.Type;
036:
037: import com.db4o.activation.Activator;
038: import com.db4o.foundation.*;
039: import com.db4o.instrumentation.core.*;
040: import com.db4o.instrumentation.util.*;
041:
042: public class InstrumentFieldAccessEdit implements BloatClassEdit {
043:
044: private ClassFilter _filter;
045:
046: public InstrumentFieldAccessEdit(ClassFilter filter) {
047: _filter = filter;
048: }
049:
050: public InstrumentationStatus enhance(ClassEditor ce,
051: ClassLoader origLoader, BloatLoaderContext loaderContext) {
052: return instrumentAllMethods(ce, origLoader);
053: }
054:
055: private InstrumentationStatus instrumentAllMethods(
056: final ClassEditor ce, final ClassLoader origLoader) {
057: final MemberRef activateMethod = createMethodReference(
058: ce.type(),
059: TransparentActivationInstrumentationConstants.ACTIVATE_METHOD_NAME,
060: new Type[] {}, Type.VOID);
061: final MemberRef bindMethod = createMethodReference(
062: ce.type(),
063: TransparentActivationInstrumentationConstants.BIND_METHOD_NAME,
064: new Type[] { Type.getType(Activator.class) }, Type.VOID);
065: final ObjectByRef instrumented = new ObjectByRef(
066: InstrumentationStatus.NOT_INSTRUMENTED);
067: ce.visit(new EditorVisitor() {
068:
069: public void visitClassEditor(ClassEditor editor) {
070: }
071:
072: public void visitFieldEditor(FieldEditor editor) {
073: }
074:
075: public void visitMethodEditor(MethodEditor editor) {
076: if (editor.isConstructor() || editor.isAbstract()
077: || editor.isStatic()) {
078: return;
079: }
080: MemberRef methodRef = editor.memberRef();
081: if (methodRef.equals(activateMethod)
082: || methodRef.equals(bindMethod)) {
083: return;
084: }
085:
086: TreeMap fieldAccessIndexes = new TreeMap(
087: new Comparator() {
088: public int compare(Object o1, Object o2) {
089: return -((Comparable) o1).compareTo(o2);
090: }
091: });
092: for (int codeIdx = 0; codeIdx < editor.codeLength(); codeIdx++) {
093: Object curCode = editor.codeElementAt(codeIdx);
094: MemberRef fieldRef = fieldRef(curCode);
095: if (fieldRef != null && accept(fieldRef)) {
096: fieldAccessIndexes.put(new Integer(codeIdx),
097: fieldRef);
098: }
099: }
100: if (fieldAccessIndexes.isEmpty()) {
101: return;
102: }
103: for (Iterator idxIter = fieldAccessIndexes.keySet()
104: .iterator(); idxIter.hasNext();) {
105: Integer idx = ((Integer) idxIter.next());
106: MemberRef fieldRef = (MemberRef) fieldAccessIndexes
107: .get(idx);
108: MemberRef targetActivateMethod = createMethodReference(
109: fieldRef.declaringClass(),
110: TransparentActivationInstrumentationConstants.ACTIVATE_METHOD_NAME,
111: new Type[] {}, Type.VOID);
112: if (targetActivateMethod == null) {
113: continue;
114: }
115: editor.insertCodeAt(
116: new Instruction(Opcode.opc_dup), idx
117: .intValue());
118: editor.insertCodeAt(new Instruction(
119: Opcode.opc_invokevirtual,
120: targetActivateMethod), idx.intValue() + 1);
121: }
122: editor.commit();
123: instrumented.value = InstrumentationStatus.INSTRUMENTED;
124: }
125:
126: private boolean accept(MemberRef fieldRef) {
127: String className = fieldRef.declaringClass()
128: .className();
129: String normalizedClassName = BloatUtil
130: .normalizeClassName(className);
131: try {
132: return _filter.accept(origLoader
133: .loadClass(normalizedClassName));
134: } catch (ClassNotFoundException e) {
135: // TODO: sensible error notification.
136: e.printStackTrace();
137: return false;
138: }
139: }
140:
141: private MemberRef fieldRef(Object code) {
142: if (!(code instanceof Instruction)) {
143: return null;
144: }
145: Instruction curInstr = (Instruction) code;
146: if (curInstr.origOpcode() == Opcode.opc_getfield) {
147: return (MemberRef) curInstr.operand();
148: }
149: return null;
150: }
151:
152: });
153: if (((InstrumentationStatus) instrumented.value)
154: .isInstrumented()) {
155: ce.commit();
156: }
157: return (InstrumentationStatus) instrumented.value;
158: }
159:
160: private MemberRef createMethodReference(Type parent, String name,
161: Type[] args, Type ret) {
162: NameAndType nameAndType = new NameAndType(name, Type.getType(
163: args, ret));
164: return new MemberRef(parent, nameAndType);
165: }
166: }
|