Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/401.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在运行时使用Byte Buddy动态生成表示二进制表达式树的单个函数(无子函数) 介绍_Java_Binary Tree_Bytecode Manipulation_Byte Buddy - Fatal编程技术网

Java 在运行时使用Byte Buddy动态生成表示二进制表达式树的单个函数(无子函数) 介绍

Java 在运行时使用Byte Buddy动态生成表示二进制表达式树的单个函数(无子函数) 介绍,java,binary-tree,bytecode-manipulation,byte-buddy,Java,Binary Tree,Bytecode Manipulation,Byte Buddy,我想比较一些在运行时生成代码的库。此时,我接触了Javassist和Byte Buddy的表面 作为概念证明,我试图解决一个小问题,这是一个更复杂问题的起点。 基本上,我有一个我想转换成一行代码并加载到java运行时的。为了简单起见,到目前为止,我只添加了节点和常量作为leaf Javassist引用 我已经在Javassist中找到了实现这一点的方法(它至少适用于具有两个leaf的单个节点)。代码如下所示: public class JavassistNodeFactory{ publ

我想比较一些在运行时生成代码的库。此时,我接触了Javassist和Byte Buddy的表面

作为概念证明,我试图解决一个小问题,这是一个更复杂问题的起点。
基本上,我有一个我想转换成一行代码并加载到java运行时的。为了简单起见,到目前为止,我只添加了节点和常量作为leaf

Javassist引用 我已经在Javassist中找到了实现这一点的方法(它至少适用于具有两个leaf的单个节点)。代码如下所示:

public class JavassistNodeFactory{
    public DynamicNode generateDynamicNode(INode root){
        DynamicNode dynamicNode = null;
        try {
            CtClass cc = createClass();
            interceptMethod(root, cc);
            compileClass(cc);
            dynamicNode = instantiate(cc);
        }catch (Exception e){
            System.out.println("Error compiling class with javassist: "+ e.getMessage());
            e.printStackTrace();
        }
        return dynamicNode;
    }

    private DynamicNode instantiate(CtClass cc) throws CannotCompileException, IllegalAccessException, InstantiationException {
        Class<?> clazz = cc.toClass();
        return (DynamicNode) clazz.newInstance();
    }

    private void compileClass(CtClass cc) throws NotFoundException, IOException, CannotCompileException {
        cc.writeFile();
    }

    private void interceptMethod(INode root, CtClass cc) throws NotFoundException, CannotCompileException {
        CtMethod calculateMethod = cc.getSuperclass().getDeclaredMethod("calculateValue",null);
        calculateMethod.setBody("return "+ nodeToString(root)+ ";");
    }

    private CtClass createClass() throws CannotCompileException, NotFoundException {
        ClassPool pool = ClassPool.getDefault();
        CtClass cc = pool.makeClass(
                "DN"+ UUID.randomUUID().toString().replace("-","")
        );
        cc.setSuperclass(pool.get("org.jamesii.mlrules.util.runtimeCompiling.DynamicNode"));
        return cc;
    }

    private static String nodeToString(INode node){
        if (node.getName().equals("")){
            return ((ValueNode)node).getValue().toString();
        }else{
            List<? extends INode> children = node.getChildren();
            assert(children.size()==2);
            return ("("+nodeToString(children.get(0))+node.getName()+nodeToString(children.get(1))+")");
        }
    }
}
public class DynamicNode implements INode   {
    @Override
    public <N extends INode> N calc() {
        Double value = calculateValue();
        return (N) new ValueNode<Double>(value);
    }

    @Override
    public List<? extends INode> getChildren() {
        return null;
    }

    @Override
    public String getName() {
        return null;
    }

    private Double calculateValue() {
        return null;
    }
}
public class ByteBuddyNodeFactory{
    @Override
    public DynamicNode generateDynamicNode(INode root) {
        DynamicNode dynamicNode = null;
        try {
            Class<?> dynamicType = new ByteBuddy()
                    .subclass(DynamicNode.class)
                    .name("DN"+ UUID.randomUUID().toString().replace("-",""))
    //this is the point where I have problems
    //I don't know how to generate the Implementation for the intercept() function
    //An attempt is in the nodeToImplementation() function
                    .method(ElementMatchers.named("calculateValue")).intercept(nodeToImplementation(root))
                    .make()
                    .load(Object.class.getClassLoader())
                    .getLoaded();
            dynamicNode = (DynamicNode) dynamicType.newInstance();
        } catch (Exception e) {
            System.out.println("Error compiling testclass with bytebuddy: " + e.getMessage());
            e.printStackTrace();
        }
        return dynamicNode;
    }

    private Implementation.Composable nodeToImplementation(INode node){
        if (node.getName().equals("")){
            return (Implementation.Composable)FixedValue.value(((ValueNode)node).getValue());
        }else{
            List<? extends INode> children = node.getChildren();
            assert(children.size()==2);
            switch (node.getName()){
                case ("+"):
                    //This is the point where I am completely lost
                    //This return is just the last thing I tried and may be not even correct Java code
                    // But hopefully at least my intention gets clearer
                    return (MethodCall.invoke((Method sdjk)-> {
                        return (nodeToImplementation(children.get(0)).andThen(node.getName().andThen(nodeToImplementation(children.get(1)))));
                    }));
                
                default:
                    throw new NotImplementedException();
            }
        }
    }
}
重要的部分是
nodeToString()
函数,在该函数中,我从给定的根节点生成一个由返回字符串表示的算术公式。
ValueNode
是具有常量值的树的叶子,该值将作为字符串返回。
其他节点(只为我的情况添加节点)将递归地为每个子函数调用函数和打印括号,同时在两个孩子的中间打印操作符(由<代码> GETNAME()/代码>函数)(简称:“代码>”(LeftCudi+ RealCHIAD)<< /> >)。 Javassist将在
interceptMethod()
函数中更改
calculateValue()
函数的主体,以返回生成公式的结果

字节伙伴尝试 我和Byte Buddy一起玩过,以获得类似的解决方案。但随着我对概念和文档的深入了解,我越来越觉得Buddy的设计目的不是为了解决这个问题。大多数示例和问题似乎都集中在对其他函数的函数委托上(这些函数实际上已经在编译时存在,并且只在运行时连接到)。在我的例子中,这并不方便,因为我无法知道在编译时要转换的实际树。可能可以使用底层ASM库,但我希望避免自己(以及可能的继任者)处理字节码

我有一个基本的实现(显然不工作),但我必须为Byte Buddy库的
intercept()
函数提供
实现。我的上一个状态如下所示:

public class JavassistNodeFactory{
    public DynamicNode generateDynamicNode(INode root){
        DynamicNode dynamicNode = null;
        try {
            CtClass cc = createClass();
            interceptMethod(root, cc);
            compileClass(cc);
            dynamicNode = instantiate(cc);
        }catch (Exception e){
            System.out.println("Error compiling class with javassist: "+ e.getMessage());
            e.printStackTrace();
        }
        return dynamicNode;
    }

    private DynamicNode instantiate(CtClass cc) throws CannotCompileException, IllegalAccessException, InstantiationException {
        Class<?> clazz = cc.toClass();
        return (DynamicNode) clazz.newInstance();
    }

    private void compileClass(CtClass cc) throws NotFoundException, IOException, CannotCompileException {
        cc.writeFile();
    }

    private void interceptMethod(INode root, CtClass cc) throws NotFoundException, CannotCompileException {
        CtMethod calculateMethod = cc.getSuperclass().getDeclaredMethod("calculateValue",null);
        calculateMethod.setBody("return "+ nodeToString(root)+ ";");
    }

    private CtClass createClass() throws CannotCompileException, NotFoundException {
        ClassPool pool = ClassPool.getDefault();
        CtClass cc = pool.makeClass(
                "DN"+ UUID.randomUUID().toString().replace("-","")
        );
        cc.setSuperclass(pool.get("org.jamesii.mlrules.util.runtimeCompiling.DynamicNode"));
        return cc;
    }

    private static String nodeToString(INode node){
        if (node.getName().equals("")){
            return ((ValueNode)node).getValue().toString();
        }else{
            List<? extends INode> children = node.getChildren();
            assert(children.size()==2);
            return ("("+nodeToString(children.get(0))+node.getName()+nodeToString(children.get(1))+")");
        }
    }
}
public class DynamicNode implements INode   {
    @Override
    public <N extends INode> N calc() {
        Double value = calculateValue();
        return (N) new ValueNode<Double>(value);
    }

    @Override
    public List<? extends INode> getChildren() {
        return null;
    }

    @Override
    public String getName() {
        return null;
    }

    private Double calculateValue() {
        return null;
    }
}
public class ByteBuddyNodeFactory{
    @Override
    public DynamicNode generateDynamicNode(INode root) {
        DynamicNode dynamicNode = null;
        try {
            Class<?> dynamicType = new ByteBuddy()
                    .subclass(DynamicNode.class)
                    .name("DN"+ UUID.randomUUID().toString().replace("-",""))
    //this is the point where I have problems
    //I don't know how to generate the Implementation for the intercept() function
    //An attempt is in the nodeToImplementation() function
                    .method(ElementMatchers.named("calculateValue")).intercept(nodeToImplementation(root))
                    .make()
                    .load(Object.class.getClassLoader())
                    .getLoaded();
            dynamicNode = (DynamicNode) dynamicType.newInstance();
        } catch (Exception e) {
            System.out.println("Error compiling testclass with bytebuddy: " + e.getMessage());
            e.printStackTrace();
        }
        return dynamicNode;
    }

    private Implementation.Composable nodeToImplementation(INode node){
        if (node.getName().equals("")){
            return (Implementation.Composable)FixedValue.value(((ValueNode)node).getValue());
        }else{
            List<? extends INode> children = node.getChildren();
            assert(children.size()==2);
            switch (node.getName()){
                case ("+"):
                    //This is the point where I am completely lost
                    //This return is just the last thing I tried and may be not even correct Java code
                    // But hopefully at least my intention gets clearer
                    return (MethodCall.invoke((Method sdjk)-> {
                        return (nodeToImplementation(children.get(0)).andThen(node.getName().andThen(nodeToImplementation(children.get(1)))));
                    }));
                
                default:
                    throw new NotImplementedException();
            }
        }
    }
}
公共类ByteBuddyNodeFactory{
@凌驾
公共动态节点GeneratedDynamicNode(索引节点根){
DynamicNode DynamicNode=null;
试一试{
类dynamicType=newbytebuddy()
.subclass(DynamicNode.class)
.name(“DN”+UUID.randomUUID().toString().replace(“-”,”))
//这就是我的问题所在
//我不知道如何生成intercept()函数的实现
//在nodeToImplementation()函数中进行了尝试
.method(ElementMatchers.named(“calculateValue”).intercept(nodeToImplementation(root))
.make()
.load(Object.class.getClassLoader())
.getLoaded();
dynamicNode=(dynamicNode)dynamicType.newInstance();
}捕获(例外e){
System.out.println(“使用bytebuddy编译testclass时出错:+e.getMessage());
e、 printStackTrace();
}
返回动态节点;
}
私有实现。可组合节点实现(INode节点){
if(node.getName().equals(“”){
return(Implementation.Composable)FixedValue.value(((ValueNode)node.getValue());
}否则{

列表使用Byte Buddy的高级API不容易实现您要做的事情。相反,如果您想使用Byte Buddy,您应该使用
StackManipulation
s组装一个方法。堆栈操作仍然包含Java字节码,但这些字节码应该非常简单,易于实现


Byte Buddy不针对此场景的原因是,通常情况下,您可以为代码找到比汇编代码片段更好的抽象。为什么节点不能实现实际实现,然后从插入指令的方法调用该实现?JIT编译器通常会优化此代码,以获得与ma相同的结果每年一次的内联代码。此外,您可以保留可调试性并降低代码的复杂性。

事实上,节点已经完成了计算。它们是模拟框架的一部分。但是我们发现遍历树并计算值(这是经常做的)速度相当慢。因此,这基本上只是一个性能问题,我们尝试用这种方法解决。实际上,节点的类型甚至比算术类型更多,允许递归和其他混乱的东西。我们希望重要节点的自定义公式将提供显著的加速。