0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */
0017:
0018: package org.apache.harmony.luni.internal.reflect;
0019:
0020: import java.io.PrintStream;
0021: import java.lang.reflect.Constructor;
0022: import java.lang.reflect.Field;
0023: import java.lang.reflect.InvocationHandler;
0024: import java.lang.reflect.Method;
0025: import java.lang.reflect.Proxy;
0026: import java.lang.reflect.UndeclaredThrowableException;
0027: import java.util.ArrayList;
0028: import java.util.HashSet;
0029:
0030: public final class ProxyClassFile implements ProxyConstants {
0031:
0032: private static final int INITIAL_CONTENTS_SIZE = 1000;
0033:
0034: private static final int INITIAL_HEADER_SIZE = 500;
0035:
0036: private static final int INCREMENT_SIZE = 250;
0037:
0038: private static Method ObjectEqualsMethod;
0039:
0040: private static Method ObjectHashCodeMethod;
0041:
0042: private static Method ObjectToStringMethod;
0043:
0044: private static Method ClassGetMethod;
0045:
0046: private static Method HandlerInvokeMethod;
0047:
0048: private static Constructor<?> ProxyConstructor;
0049:
0050: private static Constructor<?> UndeclaredThrowableExceptionConstructor;
0051:
0052: private static Field ProxyHandlerField;
0053:
0054: public static byte[] generateBytes(String typeName,
0055: Class[] interfaces) {
0056: ProxyClassFile classFile = new ProxyClassFile(typeName,
0057: interfaces);
0058: classFile.findMethods(interfaces);
0059: classFile.addFields();
0060: classFile.addMethods();
0061: classFile.addAttributes();
0062: return classFile.getBytes();
0063: }
0064:
0065: static char[] getConstantPoolName(Class<?> c) {
0066: if (c.isArray()) {
0067: // Array classes are named/ with their signature
0068: return c.getName().replace('.', '/').toCharArray();
0069: }
0070:
0071: if (c.isPrimitive()) {
0072: // Special cases for each base type.
0073: if (c == void.class) {
0074: return new char[] { 'V' };
0075: }
0076: if (c == int.class) {
0077: return new char[] { 'I' };
0078: }
0079: if (c == boolean.class) {
0080: return new char[] { 'Z' };
0081: }
0082: if (c == byte.class) {
0083: return new char[] { 'B' };
0084: }
0085: if (c == char.class) {
0086: return new char[] { 'C' };
0087: }
0088: if (c == short.class) {
0089: return new char[] { 'S' };
0090: }
0091: if (c == long.class) {
0092: return new char[] { 'J' };
0093: }
0094: if (c == float.class) {
0095: return new char[] { 'F' };
0096: }
0097: if (c == double.class) {
0098: return new char[] { 'D' };
0099: }
0100: }
0101: return ("L" + c.getName().replace('.', '/') + ";")
0102: .toCharArray();
0103: }
0104:
0105: static char[] getConstantPoolName(Constructor<?> method) /* (ILjava/lang/Thread;)V */{
0106: Class[] parameters = method.getParameterTypes();
0107: StringBuffer buffer = new StringBuffer(
0108: parameters.length + 1 * 20);
0109: buffer.append('(');
0110: for (Class<?> element : parameters) {
0111: buffer.append(getConstantPoolName(element));
0112: }
0113: buffer.append(')');
0114: buffer.append(getConstantPoolName(void.class));
0115: return buffer.toString().toCharArray();
0116: }
0117:
0118: static char[] getConstantPoolName(Method method) /* (ILjava/lang/Thread;)Ljava/lang/Object; */{
0119: Class[] parameters = method.getParameterTypes();
0120: StringBuffer buffer = new StringBuffer(
0121: parameters.length + 1 * 20);
0122: buffer.append('(');
0123: for (Class<?> element : parameters) {
0124: buffer.append(getConstantPoolName(element));
0125: }
0126: buffer.append(')');
0127: buffer.append(getConstantPoolName(method.getReturnType()));
0128: return buffer.toString().toCharArray();
0129: }
0130:
0131: private ProxyConstantPool constantPool;
0132:
0133: // the header contains all the bytes till the end of the constant pool
0134: byte[] header;
0135:
0136: int headerOffset;
0137:
0138: // that collection contains all the remaining bytes of the .class file
0139: private byte[] contents;
0140:
0141: private int contentsOffset;
0142:
0143: private int constantPoolOffset;
0144:
0145: private ProxyMethod[] proxyMethods;
0146:
0147: private String typeName;
0148:
0149: ProxyClassFile(String typeName, Class[] interfaces) {
0150: super ();
0151: this .typeName = typeName;
0152: header = new byte[INITIAL_HEADER_SIZE];
0153: // generate the magic numbers inside the header
0154: header[headerOffset++] = (byte) (0xCAFEBABEL >> 24);
0155: header[headerOffset++] = (byte) (0xCAFEBABEL >> 16);
0156: header[headerOffset++] = (byte) (0xCAFEBABEL >> 8);
0157: header[headerOffset++] = (byte) (0xCAFEBABEL >> 0);
0158: // Compatible with JDK 1.2
0159: header[headerOffset++] = 0;
0160: header[headerOffset++] = 0;
0161: header[headerOffset++] = 0;
0162: header[headerOffset++] = 49;
0163: constantPoolOffset = headerOffset;
0164: headerOffset += 2;
0165: constantPool = new ProxyConstantPool(this );
0166: contents = new byte[INITIAL_CONTENTS_SIZE];
0167: // now we continue to generate the bytes inside the contents array
0168: int accessFlags = AccPublic | AccFinal | AccSuper;
0169: contents[contentsOffset++] = (byte) (accessFlags >> 8);
0170: contents[contentsOffset++] = (byte) accessFlags;
0171: int classNameIndex = constantPool.typeIndex(typeName);
0172: contents[contentsOffset++] = (byte) (classNameIndex >> 8);
0173: contents[contentsOffset++] = (byte) classNameIndex;
0174: int super classNameIndex = constantPool
0175: .typeIndex("java/lang/reflect/Proxy");
0176: contents[contentsOffset++] = (byte) (super classNameIndex >> 8);
0177: contents[contentsOffset++] = (byte) super classNameIndex;
0178: int interfacesCount = interfaces.length;
0179: contents[contentsOffset++] = (byte) (interfacesCount >> 8);
0180: contents[contentsOffset++] = (byte) interfacesCount;
0181: for (int i = 0; i < interfacesCount; i++) {
0182: int interfaceIndex = constantPool.typeIndex(interfaces[i]
0183: .getName());
0184: contents[contentsOffset++] = (byte) (interfaceIndex >> 8);
0185: contents[contentsOffset++] = (byte) interfaceIndex;
0186: }
0187: }
0188:
0189: private void addAttributes() {
0190: writeUnsignedShort(0); // classFile does not have attributes of its own
0191:
0192: // resynchronize all offsets of the classfile
0193: header = constantPool.poolContent;
0194: headerOffset = constantPool.currentOffset;
0195: int constantPoolCount = constantPool.currentIndex;
0196: header[constantPoolOffset++] = (byte) (constantPoolCount >> 8);
0197: header[constantPoolOffset] = (byte) constantPoolCount;
0198: }
0199:
0200: private void writeStaticInitializer() {
0201: writeUnsignedShort(AccStatic);
0202: writeUnsignedShort(constantPool.literalIndex(new char[] { '<',
0203: 'c', 'l', 'i', 'n', 'i', 't', '>' }));
0204: writeUnsignedShort(constantPool.literalIndex(new char[] { '(',
0205: ')', 'V' }));
0206: writeUnsignedShort(1); //todo add Exceptions
0207: generateCodeAttribute3();
0208: }
0209:
0210: private void completeCodeDescription(int codeLength, int offset,
0211: int maxLocals) {
0212: writeUnsignedWord(codeLength + 8, offset);
0213: writeUnsignedShort(maxLocals + 10, offset + 4);
0214: writeUnsignedShort(maxLocals, offset + 6);
0215: writeUnsignedWord(codeLength - 12, offset + 8);
0216: }
0217:
0218: private void initializeField(ProxyMethod m, int index) {
0219: String methodName = m.method.getName();
0220: Class[] params = m.method.getParameterTypes();
0221: int paramLengths = params.length;
0222: writeLdcWithClass(m.getDeclaringClass().getName());
0223: writeLdc(methodName);
0224: writeIntConstant(paramLengths);
0225: writeUnsignedByte(OPC_anewarray);
0226: writeUnsignedShort(constantPool.typeIndex("java/lang/Class"));
0227: for (int i = 0; i < paramLengths; i++) {
0228: writeUnsignedByte(OPC_dup);
0229: writeIntConstant(i);
0230: if (params[i].isPrimitive()) {
0231: writeUnsignedByte(OPC_getstatic);
0232: writeUnsignedShort(constantPool
0233: .literalIndex(typeWrapperName(params[i]),
0234: "TYPE", Class.class));
0235:
0236: } else {
0237: writeLdcWithClass(params[i].getName());
0238: }
0239: writeUnsignedByte(OPC_aastore);
0240: }
0241:
0242: if (ClassGetMethod == null) {
0243: try {
0244: ClassGetMethod = Class.class.getMethod("getMethod",
0245: new Class[] { String.class, Class[].class });
0246: } catch (NoSuchMethodException e) {
0247: throw new InternalError();
0248: }
0249: }
0250: writeUnsignedByte(OPC_invokevirtual);
0251: writeUnsignedShort(constantPool.literalIndex(ClassGetMethod));
0252: writeUnsignedByte(OPC_putstatic);
0253: writeUnsignedShort(constantPool.literalIndex(typeName,
0254: getFieldNamebyMethodName(methodName, index),
0255: Method.class));
0256: }
0257:
0258: private void generateCodeAttribute3() {
0259: writeUnsignedShort(constantPool.literalIndex(CodeName));
0260: int codeStart = contentsOffset;
0261: writeUnsignedWord(0); //skip these fields so far
0262: writeUnsignedWord(0);
0263: writeUnsignedWord(0);
0264: for (int i = 0; i < proxyMethods.length; i++) {
0265: initializeField(proxyMethods[i], i);
0266: }
0267: int gotoTarget = contentsOffset;
0268: writeUnsignedByte(OPC_goto);
0269: int targetForGotoOffset = contentsOffset;
0270: writeUnsignedShort(4); //to be updated
0271: int handlerStart = contentsOffset - codeStart - 12;
0272: generateExceptionHandler();
0273: gotoTarget = contentsOffset - gotoTarget;
0274: writeUnsignedByte(OPC_return);
0275: writeUnsignedShort(gotoTarget, targetForGotoOffset);
0276: completeCodeDescription(contentsOffset - codeStart, codeStart,
0277: 1);
0278: writeUnsignedShort(1);
0279: writeUnsignedShort(0);
0280: writeUnsignedShort(handlerStart);
0281: writeUnsignedShort(handlerStart);
0282: writeUnsignedShort(constantPool
0283: .typeIndex("java/lang/Exception"));
0284: writeUnsignedShort(0); // there are no attributes for the code
0285: }
0286:
0287: //return handlerStart
0288: private void generateExceptionHandler() {
0289: //writeUnsignedByte(OPC_astore_0);
0290: writeUnsignedByte(OPC_astore_0);
0291: writeUnsignedByte(OPC_aload_0);
0292:
0293: writeUnsignedByte(OPC_getstatic);
0294: writeUnsignedShort(constantPool.literalIndex(
0295: "java/lang/System", "err", PrintStream.class));
0296: Method m = null;
0297: try {
0298: m = Exception.class.getMethod("printStackTrace",
0299: new Class[] { PrintStream.class });
0300: } catch (Exception e) {
0301: e.printStackTrace(System.err);
0302: }
0303:
0304: writeUnsignedByte(OPC_invokevirtual);
0305: writeUnsignedShort(constantPool.literalIndex(m));
0306: }
0307:
0308: private String getFieldNamebyMethodName(String methodName, int index) {
0309: return methodName + "Method" + index;
0310: }
0311:
0312: private void addMethods() {
0313: int methodCount = proxyMethods.length;
0314: writeUnsignedShort(methodCount + 2);
0315:
0316: // save constructor
0317: writeUnsignedShort(AccPublic);
0318: writeUnsignedShort(constantPool.literalIndex(Init));
0319: if (ProxyConstructor == null) {
0320: try {
0321: ProxyConstructor = Proxy.class
0322: .getDeclaredConstructor(new Class[] { InvocationHandler.class });
0323: } catch (NoSuchMethodException e) {
0324: throw new InternalError();
0325: }
0326: }
0327: writeUnsignedShort(constantPool
0328: .literalIndex(getConstantPoolName(ProxyConstructor)));
0329: writeUnsignedShort(1); // store just the code attribute
0330: writeUnsignedShort(constantPool.literalIndex(CodeName));
0331: // save attribute_length(4), max_stack(2), max_locals(2), code_length(4)
0332: int codeLength = 6;
0333: writeUnsignedWord(12 + codeLength); // max_stack(2), max_locals(2),
0334: // code_length(4), 2 zero shorts
0335: writeUnsignedShort(2);
0336: writeUnsignedShort(2);
0337: writeUnsignedWord(codeLength);
0338: writeUnsignedByte(OPC_aload_0);
0339: writeUnsignedByte(OPC_aload_1);
0340: writeUnsignedByte(OPC_invokespecial);
0341: writeUnsignedShort(constantPool.literalIndex(ProxyConstructor));
0342: writeUnsignedByte(OPC_return);
0343: writeUnsignedShort(0); // no exceptions table
0344: writeUnsignedShort(0); // there are no attributes for the code
0345: // attribute
0346:
0347: for (int i = 0; i < methodCount; i++) {
0348: ProxyMethod pMethod = proxyMethods[i];
0349: Method method = pMethod.method;
0350: writeUnsignedShort(AccPublic | AccFinal);
0351: writeUnsignedShort(constantPool.literalIndex(method
0352: .getName().toCharArray()));
0353: writeUnsignedShort(constantPool
0354: .literalIndex(getConstantPoolName(method)));
0355:
0356: Class[] thrownsExceptions = pMethod.commonExceptions;
0357: int eLength = thrownsExceptions.length;
0358: if (eLength > 0) {
0359: writeUnsignedShort(2); // store the exception & code attributes
0360: // The method has a throw clause. So we need to add an exception
0361: // attribute
0362: writeUnsignedShort(constantPool
0363: .literalIndex(ExceptionsName));
0364: // The attribute length = length * 2 + 2 in case of a exception
0365: // attribute
0366: writeUnsignedWord(eLength * 2 + 2);
0367: writeUnsignedShort(eLength);
0368: for (int e = 0; e < eLength; e++) {
0369: writeUnsignedShort(constantPool
0370: .typeIndex(thrownsExceptions[e].getName()));
0371: }
0372: } else {
0373: writeUnsignedShort(1); // store just the code attribute
0374: }
0375: generateCodeAttribute(pMethod, i);
0376: }
0377:
0378: writeStaticInitializer();
0379: }
0380:
0381: private void findMethods(Class[] interfaces) {
0382: /*
0383: * find all methods defined by the interfaces (including inherited
0384: * interfaces) plus hashCode, equals & toString from Object build an
0385: * array with the methods... no duplicates - check up to the array size
0386: * when the interface's first method was added
0387: */
0388: if (ObjectEqualsMethod == null) {
0389: try {
0390: ObjectEqualsMethod = Object.class.getMethod("equals",
0391: new Class[] { Object.class });
0392: ObjectHashCodeMethod = Object.class.getMethod(
0393: "hashCode", new Class[0]);
0394: ObjectToStringMethod = Object.class.getMethod(
0395: "toString", new Class[0]);
0396: } catch (NoSuchMethodException ex) {
0397: throw new InternalError();
0398: }
0399: }
0400:
0401: ArrayList<ProxyMethod> allMethods = new ArrayList<ProxyMethod>(
0402: 25);
0403: allMethods
0404: .add(new ProxyMethod(Object.class, ObjectEqualsMethod));
0405: allMethods.add(new ProxyMethod(Object.class,
0406: ObjectHashCodeMethod));
0407: allMethods.add(new ProxyMethod(Object.class,
0408: ObjectToStringMethod));
0409:
0410: HashSet<Class<?>> interfacesSeen = new HashSet<Class<?>>();
0411: for (Class<?> element : interfaces) {
0412: findMethods(element, allMethods, interfacesSeen);
0413: }
0414:
0415: proxyMethods = new ProxyMethod[allMethods.size()];
0416: allMethods.toArray(proxyMethods);
0417: }
0418:
0419: private void addFields() {
0420: //writeUnsignedShort(0); // we have no fields
0421: int methodCount = proxyMethods.length;
0422: writeUnsignedShort(methodCount);
0423: for (int i = 0; i < methodCount; i++) {
0424: writeUnsignedShort(AccPublic | AccStatic);
0425: String methodName = getFieldNamebyMethodName(
0426: proxyMethods[i].method.getName(), i);
0427: writeUnsignedShort(constantPool.literalIndex(methodName
0428: .toCharArray()));
0429: writeUnsignedShort(constantPool
0430: .literalIndex("Ljava/lang/reflect/Method;"
0431: .toCharArray()));
0432: writeUnsignedShort(0);
0433: }
0434: }
0435:
0436: private void findMethods(Class<?> nextInterface,
0437: ArrayList<ProxyMethod> allMethods,
0438: HashSet<Class<?>> interfacesSeen) {
0439: /*
0440: * add the nextInterface's methods to allMethods if an equivalent method
0441: * already exists then return types must be identical... don't replace
0442: * it
0443: */
0444: if (interfacesSeen.contains(nextInterface)) {
0445: return; // already walked it
0446: }
0447: interfacesSeen.add(nextInterface);
0448:
0449: int existingMethodCount = allMethods.size();
0450: Method[] methods = nextInterface.getMethods();
0451: nextMethod: for (Method method : methods) {
0452: for (int j = 0; j < existingMethodCount; j++) {
0453: if (allMethods.get(j).matchMethod(method)) {
0454: continue nextMethod;
0455: }
0456: }
0457: allMethods.add(new ProxyMethod(nextInterface, method));
0458: }
0459:
0460: Class<?>[] super Interfaces = nextInterface.getInterfaces();
0461: for (Class<?> element : super Interfaces) {
0462: // recursion should be minimal
0463: findMethods(element, allMethods, interfacesSeen);
0464: }
0465: }
0466:
0467: private void generateCodeAttribute(ProxyMethod pMethod, int index) {
0468: int codeAttributeOffset = contentsOffset;
0469: int contentsLength = contents.length;
0470: if (contentsOffset + 20 + 100 >= contentsLength) {
0471: System.arraycopy(contents, 0,
0472: (contents = new byte[contentsLength
0473: + INCREMENT_SIZE]), 0, contentsLength);
0474: }
0475: writeUnsignedShort(constantPool.literalIndex(CodeName));
0476: // leave space for attribute_length(4), max_stack(2), max_locals(2),
0477: // code_length(4)
0478: contentsOffset += 12;
0479:
0480: /*
0481: * to push the args for the call to invoke push the receiver field h 0
0482: * aload0 1 getfield 33 java.lang.reflect.Proxy.h
0483: * Ljava.lang.reflect.InvocationHandler; push the receiver as the first
0484: * arg 4 aload0 push the method push the array of args call invoke 89
0485: * invokeinterface 67
0486: * java.lang.reflect.InvocationHandler.invoke(Ljava.lang.Object;Ljava.lang.reflect.Method;[Ljava.lang.Object;)Ljava.lang.Object;
0487: * cast return result catch & convert exceptions if necessary
0488: */
0489:
0490: int codeStartOffset = contentsOffset;
0491: writeUnsignedByte(OPC_aload_0);
0492: writeUnsignedByte(OPC_getfield);
0493: if (ProxyHandlerField == null) {
0494: try {
0495: ProxyHandlerField = Proxy.class.getDeclaredField("h");
0496: } catch (NoSuchFieldException e) {
0497: throw new InternalError();
0498: }
0499: }
0500: writeUnsignedShort(constantPool.literalIndex(ProxyHandlerField));
0501: writeUnsignedByte(OPC_aload_0);
0502: Method method = pMethod.method;
0503: Class[] argTypes = method.getParameterTypes();
0504: writeUnsignedByte(OPC_getstatic);
0505: writeUnsignedShort(constantPool.literalIndex(typeName,
0506: getFieldNamebyMethodName(pMethod.method.getName(),
0507: index), Method.class));
0508: int maxLocals = genInvokeArgs(argTypes);
0509: writeUnsignedByte(OPC_invokeinterface);
0510: if (HandlerInvokeMethod == null) {
0511: try {
0512: HandlerInvokeMethod = InvocationHandler.class
0513: .getMethod("invoke", new Class[] {
0514: Object.class, Method.class,
0515: Object[].class });
0516: } catch (NoSuchMethodException e) {
0517: throw new InternalError();
0518: }
0519: }
0520: writeUnsignedShort(constantPool
0521: .literalIndex(HandlerInvokeMethod));
0522: writeUnsignedByte(4); // invoke has 3 args
0523: writeUnsignedByte(0); // 4th operand must be 0
0524: genCastReturnType(method.getReturnType());
0525: int codeLength = contentsOffset - codeStartOffset;
0526:
0527: Class[] checkedExceptions = pMethod.getCheckedExceptions();
0528: int checkedLength = checkedExceptions.length;
0529: if (checkedLength > 0) {
0530: int codeEndIndex = contentsOffset - codeStartOffset;
0531: writeUnsignedByte(OPC_athrow); // re-throw the caught exception
0532:
0533: genStoreArg(maxLocals);
0534: writeUnsignedByte(OPC_new);
0535: writeUnsignedShort(constantPool
0536: .typeIndex("java/lang/reflect/UndeclaredThrowableException"));
0537: writeUnsignedByte(OPC_dup);
0538: genLoadArg(maxLocals);
0539: maxLocals++; // now expecting the exception
0540: writeUnsignedByte(OPC_invokespecial);
0541: if (UndeclaredThrowableExceptionConstructor == null) {
0542: try {
0543: UndeclaredThrowableExceptionConstructor = UndeclaredThrowableException.class
0544: .getConstructor(new Class[] { Throwable.class });
0545: } catch (NoSuchMethodException e) {
0546: throw new InternalError();
0547: }
0548: }
0549: writeUnsignedShort(constantPool
0550: .literalIndex(UndeclaredThrowableExceptionConstructor));
0551: writeUnsignedByte(OPC_athrow);
0552:
0553: codeLength = contentsOffset - codeStartOffset;
0554:
0555: // write the exception table
0556: writeUnsignedShort(checkedLength + 1);
0557: for (int i = 0; i < checkedLength; i++) {
0558: writeUnsignedShort(0);
0559: writeUnsignedShort(codeEndIndex);
0560: writeUnsignedShort(codeEndIndex);
0561: writeUnsignedShort(constantPool
0562: .typeIndex(checkedExceptions[i].getName()));
0563: }
0564: writeUnsignedShort(0);
0565: writeUnsignedShort(codeEndIndex);
0566: writeUnsignedShort(codeEndIndex + 1); // starts after the first
0567: // throw
0568: writeUnsignedShort(constantPool
0569: .typeIndex("java/lang/Throwable"));
0570: } else {
0571: writeUnsignedShort(0); // no exceptions table
0572: }
0573: // there are no attributes for the code attribute
0574: writeUnsignedShort(0);
0575:
0576: /*
0577: * Complete the creation of the code attribute by setting the
0578: * attribute_length, max_stack max_locals, code_length & exception table
0579: * codeAttributeOffset is the position inside contents byte array before
0580: * we started to write That means that to write the attribute_length you
0581: * need to offset by 2 the value of codeAttributeOffset to get the right
0582: * position, 6 for the max_stack etc...
0583: */
0584: int codeAttributeLength = contentsOffset
0585: - (codeAttributeOffset + 6);
0586: contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
0587: contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
0588: contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
0589: contents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
0590:
0591: int maxStack = maxLocals + 10; // larger than the exact amount
0592: contents[codeAttributeOffset + 6] = (byte) (maxStack >> 8);
0593: contents[codeAttributeOffset + 7] = (byte) maxStack;
0594: contents[codeAttributeOffset + 8] = (byte) (maxLocals >> 8);
0595: contents[codeAttributeOffset + 9] = (byte) maxLocals;
0596: contents[codeAttributeOffset + 10] = (byte) (codeLength >> 24);
0597: contents[codeAttributeOffset + 11] = (byte) (codeLength >> 16);
0598: contents[codeAttributeOffset + 12] = (byte) (codeLength >> 8);
0599: contents[codeAttributeOffset + 13] = (byte) codeLength;
0600: }
0601:
0602: /**
0603: * Add argument array for call to InvocationHandler.invoke
0604: *
0605: * 46 aconstnull or 81 iconst1 82 anewarray 61 java.lang.Object 85 dup 86
0606: * iconst0 87 aload1 88 aastore or 58 iconst2 59 anewarray 61
0607: * java.lang.Object 62 dup 63 iconst0 64 new 84 java.lang.Integer 67 dup 68
0608: * iload1 69 invokespecial 107 java.lang.Integer.<init>(I)V 72 aastore 73
0609: * dup 74 iconst1 75 new 69 java.lang.Boolean 78 dup 79 iload2 80
0610: * invokespecial 110 java.lang.Boolean.<init>(Z)V 83 aastore
0611: */
0612: private int genInvokeArgs(Class[] argTypes) {
0613: int argByteOffset = 1; // remember h is at position 0
0614: int length = argTypes.length;
0615: if (length == 0) {
0616: writeUnsignedByte(OPC_aconst_null);
0617: } else {
0618: writeIntConstant(length);
0619: writeUnsignedByte(OPC_anewarray);
0620: writeUnsignedShort(constantPool
0621: .typeIndex("java/lang/Object"));
0622: for (int i = 0; i < length; i++) {
0623: writeUnsignedByte(OPC_dup);
0624: writeIntConstant(i);
0625: argByteOffset = genInvokeArg(argTypes[i], argByteOffset);
0626: writeUnsignedByte(OPC_aastore);
0627: }
0628: }
0629: return argByteOffset;
0630: }
0631:
0632: private int genInvokeArg(Class<?> type, int argByteOffset) {
0633: // offset represents maxLocals in bytes
0634: if (type.isPrimitive()) {
0635: writeUnsignedByte(OPC_new);
0636: writeUnsignedShort(constantPool
0637: .typeIndex(typeWrapperName(type)));
0638: writeUnsignedByte(OPC_dup);
0639: if (argByteOffset > 255) {
0640: writeUnsignedByte(OPC_wide);
0641: }
0642: if (type == long.class) {
0643: switch (argByteOffset) {
0644: case 0:
0645: writeUnsignedByte(OPC_lload_0);
0646: break;
0647: case 1:
0648: writeUnsignedByte(OPC_lload_1);
0649: break;
0650: case 2:
0651: writeUnsignedByte(OPC_lload_2);
0652: break;
0653: case 3:
0654: writeUnsignedByte(OPC_lload_3);
0655: break;
0656: default:
0657: writeUnsignedByte(OPC_lload);
0658: if (argByteOffset > 255) {
0659: writeUnsignedShort(argByteOffset);
0660: } else {
0661: writeUnsignedByte(argByteOffset);
0662: }
0663: }
0664: argByteOffset += 2;
0665: } else if (type == float.class) {
0666: switch (argByteOffset) {
0667: case 0:
0668: writeUnsignedByte(OPC_fload_0);
0669: break;
0670: case 1:
0671: writeUnsignedByte(OPC_fload_1);
0672: break;
0673: case 2:
0674: writeUnsignedByte(OPC_fload_2);
0675: break;
0676: case 3:
0677: writeUnsignedByte(OPC_fload_3);
0678: break;
0679: default:
0680: writeUnsignedByte(OPC_fload);
0681: if (argByteOffset > 255) {
0682: writeUnsignedShort(argByteOffset);
0683: } else {
0684: writeUnsignedByte(argByteOffset);
0685: }
0686: }
0687: argByteOffset++;
0688: } else if (type == double.class) {
0689: switch (argByteOffset) {
0690: case 0:
0691: writeUnsignedByte(OPC_dload_0);
0692: break;
0693: case 1:
0694: writeUnsignedByte(OPC_dload_1);
0695: break;
0696: case 2:
0697: writeUnsignedByte(OPC_dload_2);
0698: break;
0699: case 3:
0700: writeUnsignedByte(OPC_dload_3);
0701: break;
0702: default:
0703: writeUnsignedByte(OPC_dload);
0704: if (argByteOffset > 255) {
0705: writeUnsignedShort(argByteOffset);
0706: } else {
0707: writeUnsignedByte(argByteOffset);
0708: }
0709: }
0710: argByteOffset += 2;
0711: } else { // handles int, short, byte, boolean & char
0712: switch (argByteOffset) {
0713: case 0:
0714: writeUnsignedByte(OPC_iload_0);
0715: break;
0716: case 1:
0717: writeUnsignedByte(OPC_iload_1);
0718: break;
0719: case 2:
0720: writeUnsignedByte(OPC_iload_2);
0721: break;
0722: case 3:
0723: writeUnsignedByte(OPC_iload_3);
0724: break;
0725: default:
0726: writeUnsignedByte(OPC_iload);
0727: if (argByteOffset > 255) {
0728: writeUnsignedShort(argByteOffset);
0729: } else {
0730: writeUnsignedByte(argByteOffset);
0731: }
0732: }
0733: argByteOffset++;
0734: }
0735: writeUnsignedByte(OPC_invokespecial);
0736: writeUnsignedShort(constantPool
0737: .literalIndex(typeInitMethod(type)));
0738: } else {
0739: genLoadArg(argByteOffset);
0740: argByteOffset++;
0741: }
0742: return argByteOffset;
0743: }
0744:
0745: /**
0746: * 94 checkcast 69 java.lang.Boolean 97 invokevirtual 73
0747: * java.lang.Boolean.booleanValue()Z 100 ireturn or 52 checkcast 91
0748: * java.lang.String 55 areturn
0749: */
0750: private void genCastReturnType(Class<?> type) {
0751: if (type.isPrimitive()) {
0752: if (type == void.class) {
0753: writeUnsignedByte(OPC_pop);
0754: writeUnsignedByte(OPC_return);
0755: } else {
0756: writeUnsignedByte(OPC_checkcast);
0757: writeUnsignedShort(constantPool
0758: .typeIndex(typeWrapperName(type)));
0759: writeUnsignedByte(OPC_invokevirtual);
0760: writeUnsignedShort(constantPool
0761: .literalIndex(typeAccessMethod(type)));
0762: if (type == long.class) {
0763: writeUnsignedByte(OPC_lreturn);
0764: } else if (type == float.class) {
0765: writeUnsignedByte(OPC_freturn);
0766: } else if (type == double.class) {
0767: writeUnsignedByte(OPC_dreturn);
0768: } else { // handles int, short, byte, boolean & char
0769: writeUnsignedByte(OPC_ireturn);
0770: }
0771: }
0772: } else {
0773: writeUnsignedByte(OPC_checkcast);
0774: writeUnsignedShort(constantPool.typeIndex(type.getName()));
0775: writeUnsignedByte(OPC_areturn);
0776: }
0777: }
0778:
0779: private void genLoadArg(int argByteOffset) {
0780: if (argByteOffset > 255) {
0781: writeUnsignedByte(OPC_wide);
0782: writeUnsignedByte(OPC_aload);
0783: writeUnsignedShort(argByteOffset);
0784: } else {
0785: switch (argByteOffset) {
0786: case 0:
0787: writeUnsignedByte(OPC_aload_0);
0788: break;
0789: case 1:
0790: writeUnsignedByte(OPC_aload_1);
0791: break;
0792: case 2:
0793: writeUnsignedByte(OPC_aload_2);
0794: break;
0795: case 3:
0796: writeUnsignedByte(OPC_aload_3);
0797: break;
0798: default:
0799: writeUnsignedByte(OPC_aload);
0800: writeUnsignedByte(argByteOffset);
0801: }
0802: }
0803: }
0804:
0805: private void genStoreArg(int argByteOffset) {
0806: if (argByteOffset > 255) {
0807: writeUnsignedByte(OPC_wide);
0808: writeUnsignedByte(OPC_astore);
0809: writeUnsignedShort(argByteOffset);
0810: } else {
0811: switch (argByteOffset) {
0812: case 0:
0813: writeUnsignedByte(OPC_astore_0);
0814: break;
0815: case 1:
0816: writeUnsignedByte(OPC_astore_1);
0817: break;
0818: case 2:
0819: writeUnsignedByte(OPC_astore_2);
0820: break;
0821: case 3:
0822: writeUnsignedByte(OPC_astore_3);
0823: break;
0824: default:
0825: writeUnsignedByte(OPC_astore);
0826: writeUnsignedByte(argByteOffset);
0827: }
0828: }
0829: }
0830:
0831: private byte[] getBytes() {
0832: byte[] fullContents = new byte[headerOffset + contentsOffset];
0833: System.arraycopy(header, 0, fullContents, 0, headerOffset);
0834: System.arraycopy(contents, 0, fullContents, headerOffset,
0835: contentsOffset);
0836: return fullContents;
0837: }
0838:
0839: private Method typeAccessMethod(Class<?> baseType) {
0840: try {
0841: if (baseType == int.class) {
0842: return Integer.class.getMethod("intValue",
0843: (Class[]) null);
0844: }
0845: if (baseType == short.class) {
0846: return Short.class.getMethod("shortValue",
0847: (Class[]) null);
0848: }
0849: if (baseType == byte.class) {
0850: return Byte.class
0851: .getMethod("byteValue", (Class[]) null);
0852: }
0853: if (baseType == boolean.class) {
0854: return Boolean.class.getMethod("booleanValue",
0855: (Class[]) null);
0856: }
0857: if (baseType == char.class) {
0858: return Character.class.getMethod("charValue",
0859: (Class[]) null);
0860: }
0861: if (baseType == long.class) {
0862: return Long.class
0863: .getMethod("longValue", (Class[]) null);
0864: }
0865: if (baseType == float.class) {
0866: return Float.class.getMethod("floatValue",
0867: (Class[]) null);
0868: }
0869: if (baseType == double.class) {
0870: return Double.class.getMethod("doubleValue",
0871: (Class[]) null);
0872: }
0873: } catch (NoSuchMethodException e) {
0874: throw new InternalError();
0875: }
0876: return null;
0877: }
0878:
0879: private Field typeField(Class<?> baseType) {
0880: try {
0881: if (baseType == int.class) {
0882: return Integer.class.getField("TYPE");
0883: }
0884: if (baseType == short.class) {
0885: return Short.class.getField("TYPE");
0886: }
0887: if (baseType == byte.class) {
0888: return Byte.class.getField("TYPE");
0889: }
0890: if (baseType == boolean.class) {
0891: return Boolean.class.getField("TYPE");
0892: }
0893: if (baseType == char.class) {
0894: return Character.class.getField("TYPE");
0895: }
0896: if (baseType == long.class) {
0897: return Long.class.getField("TYPE");
0898: }
0899: if (baseType == float.class) {
0900: return Float.class.getField("TYPE");
0901: }
0902: if (baseType == double.class) {
0903: return Double.class.getField("TYPE");
0904: }
0905: } catch (NoSuchFieldException e) {
0906: throw new InternalError();
0907: }
0908: return null;
0909: }
0910:
0911: private Constructor<?> typeInitMethod(Class<?> baseType) {
0912: try {
0913: if (baseType == int.class) {
0914: return Integer.class
0915: .getConstructor(new Class[] { int.class });
0916: }
0917: if (baseType == short.class) {
0918: return Short.class
0919: .getConstructor(new Class[] { short.class });
0920: }
0921: if (baseType == byte.class) {
0922: return Byte.class
0923: .getConstructor(new Class[] { byte.class });
0924: }
0925: if (baseType == boolean.class) {
0926: return Boolean.class
0927: .getConstructor(new Class[] { boolean.class });
0928: }
0929: if (baseType == char.class) {
0930: return Character.class
0931: .getConstructor(new Class[] { char.class });
0932: }
0933: if (baseType == long.class) {
0934: return Long.class
0935: .getConstructor(new Class[] { long.class });
0936: }
0937: if (baseType == float.class) {
0938: return Float.class
0939: .getConstructor(new Class[] { float.class });
0940: }
0941: if (baseType == double.class) {
0942: return Double.class
0943: .getConstructor(new Class[] { double.class });
0944: }
0945: } catch (NoSuchMethodException e) {
0946: throw new InternalError();
0947: }
0948: return null;
0949: }
0950:
0951: private String typeWrapperName(Class<?> baseType) {
0952: if (baseType == int.class) {
0953: return "java/lang/Integer";
0954: }
0955: if (baseType == short.class) {
0956: return "java/lang/Short";
0957: }
0958: if (baseType == byte.class) {
0959: return "java/lang/Byte";
0960: }
0961: if (baseType == boolean.class) {
0962: return "java/lang/Boolean";
0963: }
0964: if (baseType == char.class) {
0965: return "java/lang/Character";
0966: }
0967: if (baseType == long.class) {
0968: return "java/lang/Long";
0969: }
0970: if (baseType == float.class) {
0971: return "java/lang/Float";
0972: }
0973: if (baseType == double.class) {
0974: return "java/lang/Double";
0975: }
0976: return null;
0977: }
0978:
0979: private void writeIntConstant(int b) {
0980: switch (b) {
0981: case 0:
0982: writeUnsignedByte(OPC_iconst_0);
0983: break;
0984: case 1:
0985: writeUnsignedByte(OPC_iconst_1);
0986: break;
0987: case 2:
0988: writeUnsignedByte(OPC_iconst_2);
0989: break;
0990: case 3:
0991: writeUnsignedByte(OPC_iconst_3);
0992: break;
0993: case 4:
0994: writeUnsignedByte(OPC_iconst_4);
0995: break;
0996: case 5:
0997: writeUnsignedByte(OPC_iconst_5);
0998: break;
0999: default:
1000: writeUnsignedByte(OPC_bipush);
1001: writeUnsignedByte(b);
1002: }
1003: }
1004:
1005: private void writeLdc(String constant) {
1006: int index = constantPool.literalIndexForLdc(constant
1007: .toCharArray());
1008: if (index <= 0) {
1009: throw new InternalError();
1010: }
1011: if (index > 255) {
1012: writeUnsignedByte(OPC_ldc_w);
1013: writeUnsignedShort(index);
1014: } else {
1015: writeUnsignedByte(OPC_ldc);
1016: writeUnsignedByte(index);
1017: }
1018: }
1019:
1020: private void writeLdcWithClass(String name) {
1021: int index = constantPool.typeIndex(name);
1022: if (index <= 0) {
1023: throw new InternalError();
1024: }
1025: if (index > 255) {
1026: writeUnsignedByte(OPC_ldc_w);
1027: writeUnsignedShort(index);
1028: } else {
1029: writeUnsignedByte(OPC_ldc);
1030: writeUnsignedByte(index);
1031: }
1032: }
1033:
1034: private void writeUnsignedByte(int b) {
1035: try {
1036: contents[contentsOffset++] = (byte) b;
1037: } catch (IndexOutOfBoundsException e) {
1038: int actualLength = contents.length;
1039: System
1040: .arraycopy(contents, 0,
1041: (contents = new byte[actualLength
1042: + INCREMENT_SIZE]), 0, actualLength);
1043: contents[contentsOffset - 1] = (byte) b;
1044: }
1045: }
1046:
1047: private void writeUnsignedShort(int b) {
1048: writeUnsignedByte(b >>> 8);
1049: writeUnsignedByte(b);
1050: }
1051:
1052: private void writeUnsignedWord(int b) {
1053: writeUnsignedByte(b >>> 24);
1054: writeUnsignedByte(b >>> 16);
1055: writeUnsignedByte(b >>> 8);
1056: writeUnsignedByte(b);
1057: }
1058:
1059: private void writeUnsignedByte(int b, int offset) {
1060: try {
1061: contents[offset] = (byte) b;
1062: } catch (IndexOutOfBoundsException e) {
1063: int actualLength = contents.length;
1064: System
1065: .arraycopy(contents, 0,
1066: (contents = new byte[actualLength
1067: + INCREMENT_SIZE]), 0, actualLength);
1068: contents[offset - 1] = (byte) b;
1069: }
1070: }
1071:
1072: private void writeUnsignedShort(int b, int offset) {
1073: writeUnsignedByte(b >>> 8, offset);
1074: writeUnsignedByte(b, offset + 1);
1075: }
1076:
1077: private void writeUnsignedWord(int b, int offset) {
1078: writeUnsignedByte(b >>> 24, offset);
1079: writeUnsignedByte(b >>> 16, offset + 1);
1080: writeUnsignedByte(b >>> 8, offset + 2);
1081: writeUnsignedByte(b, offset + 3);
1082: }
1083:
1084: }
|