001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005: package com.tc.object.bytecode;
006:
007: import com.tc.asm.ClassAdapter;
008: import com.tc.asm.ClassVisitor;
009: import com.tc.asm.MethodVisitor;
010: import com.tc.asm.Opcodes;
011: import com.tc.asm.Type;
012:
013: import java.util.HashMap;
014: import java.util.Map;
015:
016: /**
017: * This class will change the class name in methodInsn.
018: */
019: public abstract class ChangeClassNameHierarchyAdapter extends
020: ClassAdapter implements Opcodes {
021: public final static char DOT_DELIMITER = '.';
022: public final static char SLASH_DELIMITER = '/';
023: public final static char INNER_CLASS_DELIMITER = '$';
024: final static String CLASS_DELIMITER = ";";
025: final static String CLASS_START_CHAR = "L";
026: final static String CLASS_START_DESC_CHAR = "(L";
027: final static String CLASS_RETURN_DESC_CHAR = ")L";
028: final static String CLASS_ARRAY_DESC_CHAR = "[L";
029:
030: ChangeContext addNewContextIfNotExist(String fullClassNameSlashes,
031: String convertedFullClassNameSlashes,
032: Map instrumentedContext) {
033: ChangeContext changeContext = (ChangeContext) instrumentedContext
034: .get(fullClassNameSlashes);
035: if (changeContext == null) {
036: changeContext = new ChangeContext(fullClassNameSlashes,
037: convertedFullClassNameSlashes);
038: instrumentedContext
039: .put(fullClassNameSlashes, changeContext);
040: } else if (!convertedFullClassNameSlashes
041: .equals(fullClassNameSlashes)
042: && !convertedFullClassNameSlashes
043: .equals(changeContext.convertedClassNameSlashes)) {
044: changeContext.convertedClassNameSlashes = convertedFullClassNameSlashes;
045: }
046: return changeContext;
047: }
048:
049: ChangeContext addNewContext(String fullClassNameSlashes,
050: String convertedFullClassNameSlashes,
051: Map instrumentedContext) {
052: ChangeContext changeContext = new ChangeContext(
053: fullClassNameSlashes, convertedFullClassNameSlashes);
054: instrumentedContext.put(fullClassNameSlashes, changeContext);
055:
056: return changeContext;
057: }
058:
059: ModifiedMethodInfo getModifiedMethodInfo(
060: ChangeContext changeContext, String methodName, String desc) {
061: if (changeContext == null) {
062: return null;
063: }
064:
065: ModifiedMethodInfo methodInfo = (ModifiedMethodInfo) changeContext.modifiedMethodInfo
066: .get(methodName + desc);
067: if (methodInfo != null
068: && methodName.equals(methodInfo.methodName)
069: && desc.equals(methodInfo.originalMethodDesc)) {
070: return methodInfo;
071: }
072: return null;
073: }
074:
075: String getConvertedMethodDesc(Map instrumentedContext,
076: String fullClassNameSlashes, String methodName,
077: String methodDesc) {
078: ChangeContext context = (ChangeContext) instrumentedContext
079: .get(fullClassNameSlashes);
080: while (context != null) {
081: ModifiedMethodInfo methodInfo = getModifiedMethodInfo(
082: context, methodName, methodDesc);
083: if (methodInfo != null) {
084: return methodInfo.convertedMethodDesc;
085: }
086: String super ClassName = context.originalSuperClassNameSlashes;
087: if (super ClassName != null) {
088: context = (ChangeContext) instrumentedContext
089: .get(super ClassName);
090: } else {
091: context = null;
092: }
093: }
094: return null;
095: }
096:
097: static class ChangeContext {
098: final String originalClassNameSlashes;
099: String convertedClassNameSlashes;
100: String originalSuperClassNameSlashes;
101:
102: final Map modifiedMethodInfo = new HashMap();
103: final Map modifiedFieldInfo = new HashMap();
104:
105: public ChangeContext(String originalClassNameSlashes,
106: String convertedClassNameSlashes) {
107: this .originalClassNameSlashes = originalClassNameSlashes;
108: this .convertedClassNameSlashes = convertedClassNameSlashes;
109: }
110:
111: public void setOriginalSuperClass(String super ClassNameSlashes) {
112: this .originalSuperClassNameSlashes = super ClassNameSlashes;
113: }
114:
115: void addModifiedMethodInfo(String name, String originalDesc,
116: String convertedDesc, String signature,
117: String convertedSignature) {
118: ModifiedMethodInfo methodInfo = (ModifiedMethodInfo) modifiedMethodInfo
119: .get(name + originalDesc);
120: if (methodInfo == null) {
121: modifiedMethodInfo.put(name + originalDesc,
122: new ModifiedMethodInfo(name, originalDesc,
123: convertedDesc, signature,
124: convertedSignature));
125: } else {
126: if (!convertedDesc
127: .equals(methodInfo.convertedMethodDesc)) {
128: methodInfo.convertedMethodDesc = convertedDesc;
129: }
130: if (signature != null
131: && !signature
132: .equals(methodInfo.originalSignature)) {
133: methodInfo.originalSignature = signature;
134: }
135: if (convertedSignature != null
136: && !convertedSignature
137: .equals(methodInfo.convertedSignature)) {
138: methodInfo.convertedSignature = signature;
139: }
140: }
141: }
142:
143: void addModifiedFieldInfo(String name, String originalDesc,
144: String convertedDesc, String signature,
145: String convertedSignature) {
146: modifiedFieldInfo.put(name + originalDesc,
147: new ModifiedFieldInfo(name, originalDesc,
148: convertedDesc, signature,
149: convertedSignature));
150: }
151:
152: public String toString() {
153: StringBuffer buf = new StringBuffer();
154: buf.append(super .toString());
155: buf.append(" ChangeContext :- ");
156: buf.append("originalClassNameSlashes: ");
157: buf.append(originalClassNameSlashes);
158: buf.append(", convertedClassNameSlashes: ");
159: buf.append(convertedClassNameSlashes);
160: buf.append(", modifiedMethodInfo size: ");
161: buf.append(modifiedMethodInfo.size());
162: buf.append(modifiedMethodInfo);
163: return buf.toString();
164: }
165: }
166:
167: static class ModifiedFieldInfo {
168: final String fieldName;
169: final String originalFieldDesc;
170: String convertedFieldDesc;
171: String originalSignature;
172: String convertedSignature;
173:
174: ModifiedFieldInfo(String name, String originalDesc,
175: String convertedDesc, String signature,
176: String convertedSignature) {
177: this .fieldName = name;
178: this .originalFieldDesc = originalDesc;
179: this .convertedFieldDesc = convertedDesc;
180: this .originalSignature = signature;
181: this .convertedSignature = convertedSignature;
182: }
183:
184: public boolean equals(Object obj) {
185: ModifiedFieldInfo fieldInfo = (ModifiedFieldInfo) obj;
186: boolean match = this .fieldName != null
187: && this .fieldName.equals(fieldInfo.fieldName);
188: match = match
189: && this .originalFieldDesc != null
190: && this .originalFieldDesc
191: .equals(fieldInfo.originalFieldDesc);
192: match = match
193: && this .convertedFieldDesc != null
194: && this .convertedFieldDesc
195: .equals(fieldInfo.convertedFieldDesc);
196: match = match
197: && ((this .originalSignature == null && fieldInfo.originalSignature == null) || (this .originalSignature != null && this .originalSignature
198: .equals(fieldInfo.originalSignature)));
199: match = match
200: && ((this .convertedSignature == null && fieldInfo.convertedSignature == null) || (this .convertedSignature != null && this .convertedSignature
201: .equals(fieldInfo.convertedSignature)));
202: return match;
203: }
204:
205: public String toString() {
206: return super .toString() + ", name: " + fieldName
207: + ", desc: " + originalFieldDesc
208: + ", convertedDesc: " + convertedFieldDesc;
209: }
210: }
211:
212: static class ModifiedMethodInfo {
213: final String methodName;
214: final String originalMethodDesc;
215: String convertedMethodDesc;
216: String originalSignature;
217: String convertedSignature;
218:
219: ModifiedMethodInfo(String name, String originalDesc,
220: String convertedDesc, String signature,
221: String convertedSignature) {
222: this .methodName = name;
223: this .originalMethodDesc = originalDesc;
224: this .convertedMethodDesc = convertedDesc;
225: this .originalSignature = signature;
226: this .convertedSignature = convertedSignature;
227: }
228:
229: public boolean equals(Object obj) {
230: ModifiedMethodInfo methodInfo = (ModifiedMethodInfo) obj;
231: boolean match = this .methodName != null
232: && this .methodName.equals(methodInfo.methodName);
233: match = match
234: && this .originalMethodDesc != null
235: && this .originalMethodDesc
236: .equals(methodInfo.originalMethodDesc);
237: match = match
238: && this .convertedMethodDesc != null
239: && this .convertedMethodDesc
240: .equals(methodInfo.convertedMethodDesc);
241: match = match
242: && ((this .originalSignature == null && methodInfo.originalSignature == null) || (this .originalSignature != null && this .originalSignature
243: .equals(methodInfo.originalSignature)));
244: match = match
245: && ((this .convertedSignature == null && methodInfo.convertedSignature == null) || (this .convertedSignature != null && this .convertedSignature
246: .equals(methodInfo.convertedSignature)));
247: return match;
248: }
249:
250: public String toString() {
251: return super .toString() + ", name: " + methodName
252: + ", desc: " + originalMethodDesc
253: + ", convertedDesc: " + convertedMethodDesc;
254: }
255: }
256:
257: public ChangeClassNameHierarchyAdapter(ClassVisitor cv) {
258: super (cv);
259: }
260:
261: public MethodVisitor invokeSuperVisitMethod(int access,
262: String name, String desc, String signature,
263: String[] exceptions, Map instrumentedContext,
264: String fullClassSlashes) {
265: ChangeContext context = (ChangeContext) instrumentedContext
266: .get(fullClassSlashes);
267: String origSuperClassName = context.originalSuperClassNameSlashes;
268: // -- need this when superClassNameAdapter and RootAdapter are merged context =
269: // (ChangeContext)instrumentedContext.get(origSuperClassName);
270: // String convertedSuperClassName = context.convertedClassNameSlashes;
271:
272: Type returnType = Type.getReturnType(desc);
273: MethodVisitor mv = cv.visitMethod(access, name, desc,
274: signature, exceptions);
275: mv.visitCode();
276: mv.visitVarInsn(ALOAD, 0);
277: ByteCodeUtil.pushMethodArguments(access, desc, mv);
278: mv.visitMethodInsn(INVOKESPECIAL, origSuperClassName, name,
279: desc);
280: mv.visitInsn(returnType.getOpcode(IRETURN));
281: mv.visitMaxs(0, 0);
282: mv.visitEnd();
283: return mv;
284: }
285:
286: }
|