2009 lines · 77.6 KB · Java
RawDownload
         * invocation handler's "invoke" method.  The code is written         * to the supplied stream.         */        private void codeWrapArgument(Class type, int slot,                                      DataOutputStream out)            throws IOException        {            if (type.isPrimitive()) {                PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(type);                 if (type == int.class ||                    type == boolean.class ||                    type == byte.class ||                    type == char.class ||                    type == short.class)                {                    code_iload(slot, out);                } else if (type == long.class) {                    code_lload(slot, out);                } else if (type == float.class) {                    code_fload(slot, out);                } else if (type == double.class) {                    code_dload(slot, out);                } else {                    throw new AssertionError();                }                 out.writeByte(opc_invokestatic);                out.writeShort(cp.getMethodRef(                    prim.wrapperClassName,                    "valueOf", prim.wrapperValueOfDesc));             } else {                 code_aload(slot, out);            }        }         /**         * Generate code for unwrapping a return value of the given         * type from the invocation handler's "invoke" method (as type         * Object) to its correct type.  The code is written to the         * supplied stream.         */        private void codeUnwrapReturnValue(Class type, DataOutputStream out)            throws IOException        {            if (type.isPrimitive()) {                PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(type);                 out.writeByte(opc_checkcast);                out.writeShort(cp.getClass(prim.wrapperClassName));                 out.writeByte(opc_invokevirtual);                out.writeShort(cp.getMethodRef(                    prim.wrapperClassName,                    prim.unwrapMethodName, prim.unwrapMethodDesc));                 if (type == int.class ||                    type == boolean.class ||                    type == byte.class ||                    type == char.class ||                    type == short.class)                {                    out.writeByte(opc_ireturn);                } else if (type == long.class) {                    out.writeByte(opc_lreturn);                } else if (type == float.class) {                    out.writeByte(opc_freturn);                } else if (type == double.class) {                    out.writeByte(opc_dreturn);                } else {                    throw new AssertionError();                }             } else {                 out.writeByte(opc_checkcast);                out.writeShort(cp.getClass(dotToSlash(type.getName())));                 out.writeByte(opc_areturn);            }        }         /**         * Generate code for initializing the static field that stores         * the Method object for this proxy method.  The code is written         * to the supplied stream.         */        private void codeFieldInitialization(DataOutputStream out)            throws IOException        {            codeClassForName(fromClass, out);             code_ldc(cp.getString(methodName), out);             code_ipush(parameterTypes.length, out);             out.writeByte(opc_anewarray);            out.writeShort(cp.getClass("java/lang/Class"));             for (int i = 0; i < parameterTypes.length; i++) {                 out.writeByte(opc_dup);                 code_ipush(i, out);                 if (parameterTypes[i].isPrimitive()) {                    PrimitiveTypeInfo prim =                        PrimitiveTypeInfo.get(parameterTypes[i]);                     out.writeByte(opc_getstatic);                    out.writeShort(cp.getFieldRef(                        prim.wrapperClassName, "TYPE", "Ljava/lang/Class;"));                 } else {                    codeClassForName(parameterTypes[i], out);                }                 out.writeByte(opc_aastore);            }             out.writeByte(opc_invokevirtual);            out.writeShort(cp.getMethodRef(                "java/lang/Class",                "getMethod",                "(Ljava/lang/String;[Ljava/lang/Class;)" +                "Ljava/lang/reflect/Method;"));             out.writeByte(opc_putstatic);            out.writeShort(cp.getFieldRef(                dotToSlash(className),                methodFieldName, "Ljava/lang/reflect/Method;"));        }    }     /**     * Generate the constructor method for the proxy class.     */    private MethodInfo generateConstructor() throws IOException {        MethodInfo minfo = new MethodInfo(            "<init>", "(Ljava/lang/reflect/InvocationHandler;)V",            ACC_PUBLIC);         DataOutputStream out = new DataOutputStream(minfo.code);         code_aload(0, out);         code_aload(1, out);         out.writeByte(opc_invokespecial);        out.writeShort(cp.getMethodRef(            superclassName,            "<init>", "(Ljava/lang/reflect/InvocationHandler;)V"));         out.writeByte(opc_return);         minfo.maxStack = 10;        minfo.maxLocals = 2;        minfo.declaredExceptions = new short[0];         return minfo;    }     /**     * Generate the static initializer method for the proxy class.     */    private MethodInfo generateStaticInitializer() throws IOException {        MethodInfo minfo = new MethodInfo(            "<clinit>", "()V", ACC_STATIC);         int localSlot0 = 1;        short pc, tryBegin = 0, tryEnd;         DataOutputStream out = new DataOutputStream(minfo.code);         for (List<ProxyMethod> sigmethods : proxyMethods.values()) {            for (ProxyMethod pm : sigmethods) {                pm.codeFieldInitialization(out);            }        }         out.writeByte(opc_return);         tryEnd = pc = (short) minfo.code.size();         minfo.exceptionTable.add(new ExceptionTableEntry(            tryBegin, tryEnd, pc,            cp.getClass("java/lang/NoSuchMethodException")));         code_astore(localSlot0, out);         out.writeByte(opc_new);        out.writeShort(cp.getClass("java/lang/NoSuchMethodError"));         out.writeByte(opc_dup);         code_aload(localSlot0, out);         out.writeByte(opc_invokevirtual);        out.writeShort(cp.getMethodRef(            "java/lang/Throwable", "getMessage", "()Ljava/lang/String;"));         out.writeByte(opc_invokespecial);        out.writeShort(cp.getMethodRef(            "java/lang/NoSuchMethodError", "<init>", "(Ljava/lang/String;)V"));         out.writeByte(opc_athrow);         pc = (short) minfo.code.size();         minfo.exceptionTable.add(new ExceptionTableEntry(            tryBegin, tryEnd, pc,            cp.getClass("java/lang/ClassNotFoundException")));         code_astore(localSlot0, out);         out.writeByte(opc_new);        out.writeShort(cp.getClass("java/lang/NoClassDefFoundError"));         out.writeByte(opc_dup);         code_aload(localSlot0, out);         out.writeByte(opc_invokevirtual);        out.writeShort(cp.getMethodRef(            "java/lang/Throwable", "getMessage", "()Ljava/lang/String;"));         out.writeByte(opc_invokespecial);        out.writeShort(cp.getMethodRef(            "java/lang/NoClassDefFoundError",            "<init>", "(Ljava/lang/String;)V"));         out.writeByte(opc_athrow);         if (minfo.code.size() > 65535) {            throw new IllegalArgumentException("code size limit exceeded");        }         minfo.maxStack = 10;        minfo.maxLocals = (short) (localSlot0 + 1);        minfo.declaredExceptions = new short[0];         return minfo;    }      /*     * =============== Code Generation Utility Methods ===============     */     /*     * The following methods generate code for the load or store operation     * indicated by their name for the given local variable.  The code is     * written to the supplied stream.     */     private void code_iload(int lvar, DataOutputStream out)        throws IOException    {        codeLocalLoadStore(lvar, opc_iload, opc_iload_0, out);    }     private void code_lload(int lvar, DataOutputStream out)        throws IOException    {        codeLocalLoadStore(lvar, opc_lload, opc_lload_0, out);    }     private void code_fload(int lvar, DataOutputStream out)        throws IOException    {        codeLocalLoadStore(lvar, opc_fload, opc_fload_0, out);    }     private void code_dload(int lvar, DataOutputStream out)        throws IOException    {        codeLocalLoadStore(lvar, opc_dload, opc_dload_0, out);    }     private void code_aload(int lvar, DataOutputStream out)        throws IOException    {        codeLocalLoadStore(lvar, opc_aload, opc_aload_0, out);    } //  private void code_istore(int lvar, DataOutputStream out)//      throws IOException//  {//      codeLocalLoadStore(lvar, opc_istore, opc_istore_0, out);//  } //  private void code_lstore(int lvar, DataOutputStream out)//      throws IOException//  {//      codeLocalLoadStore(lvar, opc_lstore, opc_lstore_0, out);//  } //  private void code_fstore(int lvar, DataOutputStream out)//      throws IOException//  {//      codeLocalLoadStore(lvar, opc_fstore, opc_fstore_0, out);//  } //  private void code_dstore(int lvar, DataOutputStream out)//      throws IOException//  {//      codeLocalLoadStore(lvar, opc_dstore, opc_dstore_0, out);//  }     private void code_astore(int lvar, DataOutputStream out)        throws IOException    {        codeLocalLoadStore(lvar, opc_astore, opc_astore_0, out);    }     /**     * Generate code for a load or store instruction for the given local     * variable.  The code is written to the supplied stream.     *     * "opcode" indicates the opcode form of the desired load or store     * instruction that takes an explicit local variable index, and     * "opcode_0" indicates the corresponding form of the instruction     * with the implicit index 0.     */    private void codeLocalLoadStore(int lvar, int opcode, int opcode_0,                                    DataOutputStream out)        throws IOException    {        assert lvar >= 0 && lvar <= 0xFFFF;        if (lvar <= 3) {            out.writeByte(opcode_0 + lvar);        } else if (lvar <= 0xFF) {            out.writeByte(opcode);            out.writeByte(lvar & 0xFF);        } else {            /*             * Use the "wide" instruction modifier for local variable             * indexes that do not fit into an unsigned byte.             */            out.writeByte(opc_wide);            out.writeByte(opcode);            out.writeShort(lvar & 0xFFFF);        }    }     /**     * Generate code for an "ldc" instruction for the given constant pool     * index (the "ldc_w" instruction is used if the index does not fit     * into an unsigned byte).  The code is written to the supplied stream.     */    private void code_ldc(int index, DataOutputStream out)        throws IOException    {        assert index >= 0 && index <= 0xFFFF;        if (index <= 0xFF) {            out.writeByte(opc_ldc);            out.writeByte(index & 0xFF);        } else {            out.writeByte(opc_ldc_w);            out.writeShort(index & 0xFFFF);        }    }     /**     * Generate code to push a constant integer value on to the operand     * stack, using the "iconst_<i>", "bipush", or "sipush" instructions     * depending on the size of the value.  The code is written to the     * supplied stream.     */    private void code_ipush(int value, DataOutputStream out)        throws IOException    {        if (value >= -1 && value <= 5) {            out.writeByte(opc_iconst_0 + value);        } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {            out.writeByte(opc_bipush);            out.writeByte(value & 0xFF);        } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {            out.writeByte(opc_sipush);            out.writeShort(value & 0xFFFF);        } else {            throw new AssertionError();        }    }     /**     * Generate code to invoke the Class.forName with the name of the given     * class to get its Class object at runtime.  The code is written to     * the supplied stream.  Note that the code generated by this method     * may caused the checked ClassNotFoundException to be thrown.     */    private void codeClassForName(Class cl, DataOutputStream out)        throws IOException    {        code_ldc(cp.getString(cl.getName()), out);         out.writeByte(opc_invokestatic);        out.writeShort(cp.getMethodRef(            "java/lang/Class",            "forName", "(Ljava/lang/String;)Ljava/lang/Class;"));    }      /*     * ==================== General Utility Methods ====================     */     /**     * Convert a fully qualified class name that uses '.' as the package     * separator, the external representation used by the Java language     * and APIs, to a fully qualified class name that uses '/' as the     * package separator, the representation used in the class file     * format (see JVMS section 4.2).     */    private static String dotToSlash(String name) {        return name.replace('.', '/');    }     /**     * Return the "method descriptor" string for a method with the given     * parameter types and return type.  See JVMS section 4.3.3.     */    private static String getMethodDescriptor(Class[] parameterTypes,                                              Class returnType)    {        return getParameterDescriptors(parameterTypes) +            ((returnType == void.class) ? "V" : getFieldType(returnType));    }     /**     * Return the list of "parameter descriptor" strings enclosed in     * parentheses corresponding to the given parameter types (in other     * words, a method descriptor without a return descriptor).  This     * string is useful for constructing string keys for methods without     * regard to their return type.     */    private static String getParameterDescriptors(Class[] parameterTypes) {        StringBuilder desc = new StringBuilder("(");        for (int i = 0; i < parameterTypes.length; i++) {            desc.append(getFieldType(parameterTypes[i]));        }        desc.append(')');        return desc.toString();    }     /**     * Return the "field type" string for the given type, appropriate for     * a field descriptor, a parameter descriptor, or a return descriptor     * other than "void".  See JVMS section 4.3.2.     */    private static String getFieldType(Class type) {        if (type.isPrimitive()) {            return PrimitiveTypeInfo.get(type).baseTypeString;        } else if (type.isArray()) {            /*             * According to JLS 20.3.2, the getName() method on Class does             * return the VM type descriptor format for array classes (only);             * using that should be quicker than the otherwise obvious code:             *             *     return "[" + getTypeDescriptor(type.getComponentType());             */            return type.getName().replace('.', '/');        } else {            return "L" + dotToSlash(type.getName()) + ";";        }    }     /**     * Returns a human-readable string representing the signature of a     * method with the given name and parameter types.     */    private static String getFriendlyMethodSignature(String name,                                                     Class[] parameterTypes)    {        StringBuilder sig = new StringBuilder(name);        sig.append('(');        for (int i = 0; i < parameterTypes.length; i++) {            if (i > 0) {                sig.append(',');            }            Class parameterType = parameterTypes[i];            int dimensions = 0;            while (parameterType.isArray()) {                parameterType = parameterType.getComponentType();                dimensions++;            }            sig.append(parameterType.getName());            while (dimensions-- > 0) {                sig.append("[]");            }        }        sig.append(')');        return sig.toString();    }     /**     * Return the number of abstract "words", or consecutive local variable     * indexes, required to contain a value of the given type.  See JVMS

Lines 1001–1500 of 2009. Previous lines