001: // Copyright (c) 2003-2007, Jodd Team (jodd.sf.net). All Rights Reserved.
002:
003: package jodd.proxetta;
004:
005: import org.objectweb.asm.MethodVisitor;
006: import org.objectweb.asm.signature.SignatureReader;
007: import static org.objectweb.asm.Opcodes.*;
008:
009: /**
010: * Various ASM utilities used by {@link Proxetta}.
011: */
012: public class ProxettaAsmUtil {
013:
014: // ---------------------------------------------------------------- misc
015:
016: /**
017: * Pushs int value in an optimal way.
018: */
019: public static void pushInt(MethodVisitor mv, int value) {
020: if (value <= 5) {
021: mv.visitInsn(ICONST_0 + value);
022: } else if (value <= Byte.MAX_VALUE) {
023: mv.visitIntInsn(BIPUSH, value);
024: } else {
025: mv.visitIntInsn(SIPUSH, value);
026: }
027: }
028:
029: // ---------------------------------------------------------------- load
030:
031: public static void loadMethodArgumentClass(MethodVisitor mv,
032: MethodSignatureVisitor msign, int argIndex) {
033: int type = msign.getParamOpcodeType(argIndex);
034: switch (type) {
035: case 'V':
036: mv.visitFieldInsn(GETSTATIC, "java/lang/Void", "TYPE",
037: "Ljava/lang/Class;");
038: break;
039: case 'B':
040: mv.visitFieldInsn(GETSTATIC, "java/lang/Byte", "TYPE",
041: "Ljava/lang/Class;");
042: break;
043: case 'C':
044: mv.visitFieldInsn(GETSTATIC, "java/lang/Character", "TYPE",
045: "Ljava/lang/Class;");
046: break;
047: case 'S':
048: mv.visitFieldInsn(GETSTATIC, "java/lang/Short", "TYPE",
049: "Ljava/lang/Class;");
050: break;
051: case 'I':
052: mv.visitFieldInsn(GETSTATIC, "java/lang/Integer", "TYPE",
053: "Ljava/lang/Class;");
054: break;
055: case 'Z':
056: mv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "TYPE",
057: "Ljava/lang/Class;");
058: break;
059: case 'J':
060: mv.visitFieldInsn(GETSTATIC, "java/lang/Long", "TYPE",
061: "Ljava/lang/Class;");
062: break;
063: case 'F':
064: mv.visitFieldInsn(GETSTATIC, "java/lang/Float", "TYPE",
065: "Ljava/lang/Class;");
066: break;
067: case 'D':
068: mv.visitFieldInsn(GETSTATIC, "java/lang/Double", "TYPE",
069: "Ljava/lang/Class;");
070: break;
071: default:
072: loadMethodArgument(mv, msign, argIndex);
073: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object",
074: "getClass", "()Ljava/lang/Class;");
075: break;
076: }
077:
078: }
079:
080: /**
081: * Loads all method arguments before method call.
082: */
083: public static void loadMethodArguments(MethodVisitor mv,
084: MethodSignatureVisitor msign) {
085: mv.visitVarInsn(ALOAD, 0);
086: for (int i = 1; i <= msign.getParamCount(); i++) {
087: loadMethodArgument(mv, msign, i);
088: }
089: }
090:
091: /**
092: * Loads one argument. Index is 1-based. No conversion occurs.
093: */
094: public static void loadMethodArgument(MethodVisitor mv,
095: MethodSignatureVisitor msign, int index) {
096: int type = msign.getParamOpcodeType(index);
097: int offset = msign.getParamOffset(index);
098: switch (type) {
099: case 'V':
100: break;
101: case 'B':
102: case 'C':
103: case 'S':
104: case 'I':
105: case 'Z':
106: mv.visitVarInsn(ILOAD, offset);
107: break;
108: case 'J':
109: mv.visitVarInsn(LLOAD, offset);
110: break;
111: case 'F':
112: mv.visitVarInsn(FLOAD, offset);
113: break;
114: case 'D':
115: mv.visitVarInsn(DLOAD, offset);
116: break;
117: default:
118: mv.visitVarInsn(ALOAD, offset);
119: }
120: }
121:
122: public static void loadMethodArgumentAsObject(MethodVisitor mv,
123: MethodSignatureVisitor msign, int index) {
124: int type = msign.getParamOpcodeType(index);
125: int offset = msign.getParamOffset(index);
126: switch (type) {
127: case 'V':
128: break;
129: case 'B':
130: mv.visitTypeInsn(NEW, "java/lang/Byte");
131: mv.visitInsn(DUP);
132: mv.visitVarInsn(ILOAD, offset);
133: mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Byte",
134: "<init>", "(B)V");
135: break;
136: case 'C':
137: mv.visitTypeInsn(NEW, "java/lang/Character");
138: mv.visitInsn(DUP);
139: mv.visitVarInsn(ILOAD, offset);
140: mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Character",
141: "<init>", "(C)V");
142: break;
143: case 'S':
144: mv.visitTypeInsn(NEW, "java/lang/Short");
145: mv.visitInsn(DUP);
146: mv.visitVarInsn(ILOAD, offset);
147: mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Short",
148: "<init>", "(S)V");
149: break;
150: case 'I':
151: mv.visitTypeInsn(NEW, "java/lang/Integer");
152: mv.visitInsn(DUP);
153: mv.visitVarInsn(ILOAD, offset);
154: mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Integer",
155: "<init>", "(I)V");
156: break;
157: case 'Z':
158: mv.visitVarInsn(ILOAD, offset);
159: mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean",
160: "valueOf", "(Z)Ljava/lang/Boolean;");
161: break;
162: case 'J':
163: mv.visitTypeInsn(NEW, "java/lang/Long");
164: mv.visitInsn(DUP);
165: mv.visitVarInsn(LLOAD, offset);
166: mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Long",
167: "<init>", "(J)V");
168: break;
169: case 'F':
170: mv.visitTypeInsn(NEW, "java/lang/Float");
171: mv.visitInsn(DUP);
172: mv.visitVarInsn(FLOAD, offset);
173: mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Float",
174: "<init>", "(F)V");
175: break;
176: case 'D':
177: mv.visitTypeInsn(NEW, "java/lang/Double");
178: mv.visitInsn(DUP);
179: mv.visitVarInsn(DLOAD, offset);
180: mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Double",
181: "<init>", "(D)V");
182: break;
183: default:
184: mv.visitVarInsn(ALOAD, offset);
185: }
186: }
187:
188: // ---------------------------------------------------------------- store
189:
190: /**
191: * Stores one argument. Index is 1-based. No conversion occurs.
192: */
193: public static void storeMethodArgument(MethodVisitor mv,
194: MethodSignatureVisitor msign, int index) {
195: int type = msign.getParamOpcodeType(index);
196: int offset = msign.getParamOffset(index);
197: switch (type) {
198: case 'V':
199: break;
200: case 'B':
201: case 'C':
202: case 'S':
203: case 'I':
204: case 'Z':
205: mv.visitVarInsn(ISTORE, offset);
206: break;
207: case 'J':
208: mv.visitVarInsn(LSTORE, offset);
209: break;
210: case 'F':
211: mv.visitVarInsn(FSTORE, offset);
212: break;
213: case 'D':
214: mv.visitVarInsn(DSTORE, offset);
215: break;
216: default:
217: mv.visitVarInsn(ASTORE, offset);
218: }
219: }
220:
221: public static void storeMethodArgumentFromObject(MethodVisitor mv,
222: MethodSignatureVisitor msign, int index) {
223: int type = msign.getParamOpcodeType(index);
224: int offset = msign.getParamOffset(index);
225: storeValue(mv, offset, type);
226: }
227:
228: public static void storeValue(MethodVisitor mv, int offset, int type) {
229: switch (type) {
230: case 'V':
231: break;
232: case 'B':
233: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte",
234: "byteValue", "byteValue()B");
235: mv.visitVarInsn(ISTORE, offset);
236: break;
237: case 'C':
238: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character",
239: "charValue", "charValue()C");
240: mv.visitVarInsn(ISTORE, offset);
241: break;
242: case 'S':
243: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short",
244: "shortValue", "shortValue()S");
245: mv.visitVarInsn(ISTORE, offset);
246: break;
247: case 'I':
248: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer",
249: "intValue", "intValue()I");
250: mv.visitVarInsn(ISTORE, offset);
251: break;
252: case 'Z':
253: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean",
254: "booleanValue", "booleanValue()Z");
255: mv.visitVarInsn(ISTORE, offset);
256: break;
257: case 'J':
258: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long",
259: "longValue", "longValue()J");
260: mv.visitVarInsn(LSTORE, offset);
261: break;
262: case 'F':
263: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float",
264: "floatValue", "floatValue()F");
265: mv.visitVarInsn(FSTORE, offset);
266: break;
267: case 'D':
268: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double",
269: "doubleValue", "doubleValue()D");
270: mv.visitVarInsn(DSTORE, offset);
271: break;
272: default:
273: mv.visitVarInsn(ASTORE, offset);
274: }
275: }
276:
277: // ---------------------------------------------------------------- return
278:
279: public static void visitReturn(MethodVisitor mv,
280: MethodSignatureVisitor msign) {
281: int type = msign.getReturnOpcodeType();
282: switch (type) {
283: case 'V':
284: mv.visitInsn(RETURN);
285: break;
286: case 'B':
287: case 'C':
288: case 'S':
289: case 'I':
290: case 'Z':
291: mv.visitInsn(IRETURN);
292: break;
293: case 'J':
294: mv.visitInsn(LRETURN);
295: break;
296: case 'F':
297: mv.visitInsn(FRETURN);
298: break;
299: case 'D':
300: mv.visitInsn(DRETURN);
301: break;
302: default:
303: mv.visitInsn(ARETURN);
304: break;
305: }
306: }
307:
308: public static void visitReturn(MethodVisitor mv,
309: MethodSignatureVisitor msign, int returnValueOffset) {
310: int type = msign.getReturnOpcodeType();
311: switch (type) {
312: case 'V':
313: mv.visitInsn(RETURN);
314: break;
315: case 'B':
316: case 'C':
317: case 'S':
318: case 'I':
319: case 'Z':
320: if (returnValueOffset > 0) {
321: mv.visitVarInsn(ILOAD, returnValueOffset);
322: }
323: mv.visitInsn(IRETURN);
324: break;
325: case 'J':
326: if (returnValueOffset > 0) {
327: mv.visitVarInsn(LLOAD, returnValueOffset);
328: }
329: mv.visitInsn(LRETURN);
330: break;
331: case 'F':
332: if (returnValueOffset > 0) {
333: mv.visitVarInsn(FLOAD, returnValueOffset);
334: }
335: mv.visitInsn(FRETURN);
336: break;
337: case 'D':
338: if (returnValueOffset > 0) {
339: mv.visitVarInsn(DLOAD, returnValueOffset);
340: }
341: mv.visitInsn(DRETURN);
342: break;
343: default:
344: if (returnValueOffset > 0) {
345: mv.visitVarInsn(ALOAD, returnValueOffset);
346: }
347: mv.visitInsn(ARETURN);
348: break;
349: }
350: }
351:
352: // ---------------------------------------------------------------- method signature
353:
354: /**
355: * Creates method signature from method name.
356: */
357: public static MethodSignatureVisitor createMethodSignature(
358: int access, String methodName, String description,
359: String classname) {
360: MethodSignatureVisitor v = new MethodSignatureVisitor(
361: methodName, access, classname, description);
362: new SignatureReader(description).accept(v);
363: return v;
364: }
365: }
|