WEB开发网
开发学院软件开发Java Java 编程的动态性,第 7 部分: 用 BCEL 设计字节... 阅读

Java 编程的动态性,第 7 部分: 用 BCEL 设计字节码

 2010-03-18 00:00:00 来源:WEB开发网   
核心提示: 生成了计时消息代码后,留给清单 7 的就是保存包装的方法的调用结果值(如果有的话),Java 编程的动态性,第 7 部分: 用 BCEL 设计字节码(9),然后结束构建的包装器方法,最后这部分涉及几个步骤,就可以实际生成方法的最终版本,并将它加入到类中,调用 stripAttributes(tr

生成了计时消息代码后,留给清单 7 的就是保存包装的方法的调用结果值(如果有的话),然后结束构建的包装器方法。最后这部分涉及几个步骤。调用 stripAttributes(true) 只是告诉 BCEL 不对构建的方法生成调试信息,而 setMaxStack() 和 setMaxLocals() 调用计算并设置方法的堆栈使用信息。完成了这一步后,就可以实际生成方法的最终版本,并将它加入到类中。

清单 7. 完成包装器

// return result from wrapped method call 
if (result != Type.VOID) { 
  ilist.append(InstructionFactory.createLoad(result, slot+2)); 
} 
ilist.append(InstructionFactory.createReturn(result)); 
   
// finalize the constructed method 
wrapgen.stripAttributes(true); 
wrapgen.setMaxStack(); 
wrapgen.setMaxLocals(); 
cgen.addMethod(wrapgen.getMethod()); 
ilist.dispose(); 

完整的代码

清单 8 显示了完整的代码(稍微改变了一下格式以适合显示宽度),包括以类文件的名字为参数的 main() 方法和要转换的方法:

清单 8. 完整的转换代码

public class BCELTiming 
{ 
  private static void addWrapper(ClassGen cgen, Method method) { 
     
    // set up the construction tools 
    InstructionFactory ifact = new InstructionFactory(cgen); 
    InstructionList ilist = new InstructionList(); 
    ConstantPoolGen pgen = cgen.getConstantPool(); 
    String cname = cgen.getClassName(); 
    MethodGen wrapgen = new MethodGen(method, cname, pgen); 
    wrapgen.setInstructionList(ilist); 
     
    // rename a copy of the original method 
    MethodGen methgen = new MethodGen(method, cname, pgen); 
    cgen.removeMethod(method); 
    String iname = methgen.getName() + "$impl"; 
    methgen.setName(iname); 
    cgen.addMethod(methgen.getMethod()); 
    Type result = methgen.getReturnType(); 
     
    // compute the size of the calling parameters 
    Type[] types = methgen.getArgumentTypes(); 
    int slot = methgen.isStatic() ? 0 : 1; 
    for (int i = 0; i < types.length; i++) { 
      slot += types[i].getSize(); 
    } 
     
    // save time prior to invocation 
    ilist.append(ifact.createInvoke("java.lang.System", 
      "currentTimeMillis", Type.LONG, Type.NO_ARGS, 
      Constants.INVOKESTATIC)); 
    ilist.append(InstructionFactory. 
      createStore(Type.LONG, slot)); 
     
    // call the wrapped method 
    int offset = 0; 
    short invoke = Constants.INVOKESTATIC; 
    if (!methgen.isStatic()) { 
      ilist.append(InstructionFactory. 
        createLoad(Type.OBJECT, 0)); 
      offset = 1; 
      invoke = Constants.INVOKEVIRTUAL; 
    } 
    for (int i = 0; i < types.length; i++) { 
      Type type = types[i]; 
      ilist.append(InstructionFactory. 
        createLoad(type, offset)); 
      offset += type.getSize(); 
    } 
    ilist.append(ifact.createInvoke(cname, 
      iname, result, types, invoke)); 
     
    // store result for return later 
    if (result != Type.VOID) { 
      ilist.append(InstructionFactory. 
        createStore(result, slot+2)); 
    } 
     
    // print time required for method call 
    ilist.append(ifact.createFieldAccess("java.lang.System", 
      "out", new ObjectType("java.io.PrintStream"), 
      Constants.GETSTATIC)); 
    ilist.append(InstructionConstants.DUP); 
    ilist.append(InstructionConstants.DUP); 
    String text = "Call to method " + methgen.getName() + 
      " took "; 
    ilist.append(new PUSH(pgen, text)); 
    ilist.append(ifact.createInvoke("java.io.PrintStream", 
      "print", Type.VOID, new Type[] { Type.STRING }, 
      Constants.INVOKEVIRTUAL)); 
    ilist.append(ifact.createInvoke("java.lang.System", 
      "currentTimeMillis", Type.LONG, Type.NO_ARGS, 
      Constants.INVOKESTATIC)); 
    ilist.append(InstructionFactory. 
      createLoad(Type.LONG, slot)); 
    ilist.append(InstructionConstants.LSUB); 
    ilist.append(ifact.createInvoke("java.io.PrintStream", 
      "print", Type.VOID, new Type[] { Type.LONG }, 
      Constants.INVOKEVIRTUAL)); 
    ilist.append(new PUSH(pgen, " ms.")); 
    ilist.append(ifact.createInvoke("java.io.PrintStream", 
      "println", Type.VOID, new Type[] { Type.STRING }, 
      Constants.INVOKEVIRTUAL)); 
       
    // return result from wrapped method call 
    if (result != Type.VOID) { 
      ilist.append(InstructionFactory. 
        createLoad(result, slot+2)); 
    } 
    ilist.append(InstructionFactory.createReturn(result)); 
     
    // finalize the constructed method 
    wrapgen.stripAttributes(true); 
    wrapgen.setMaxStack(); 
    wrapgen.setMaxLocals(); 
    cgen.addMethod(wrapgen.getMethod()); 
    ilist.dispose(); 
  } 
   
  public static void main(String[] argv) { 
    if (argv.length == 2 && argv[0].endsWith(".class")) { 
      try { 
       
        JavaClass jclas = new ClassParser(argv[0]).parse(); 
        ClassGen cgen = new ClassGen(jclas); 
        Method[] methods = jclas.getMethods(); 
        int index; 
        for (index = 0; index < methods.length; index++) { 
          if (methods[index].getName().equals(argv[1])) { 
            break; 
          } 
        } 
        if (index < methods.length) { 
          addWrapper(cgen, methods[index]); 
          FileOutputStream fos = 
            new FileOutputStream(argv[0]); 
          cgen.getJavaClass().dump(fos); 
          fos.close(); 
        } else { 
          System.err.println("Method " + argv[1] + 
            " not found in " + argv[0]); 
        } 
      } catch (IOException ex) { 
        ex.printStackTrace(System.err); 
      } 
       
    } else { 
      System.out.println 
        ("Usage: BCELTiming class-file method-name"); 
    } 
  } 
} 

上一页  4 5 6 7 8 9 10  下一页

Tags:Java 编程 动态性

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接