mercredi 22 novembre 2017

reference to object created by the transformer

class Foo{
    private final Object obj0;
    private final Object obj1;
    private final Object def;

    Public Foo(obj0,obj1,def){
        this.obj0 = obj0;
        this.obj1 = obj1;
        this.def = def;
    }

    public int foo(long v){
        if      (v==0) return obj0;
        else if (v==1) return obj1;
        else return def;
    }
}

I now want to redefine method Foo.foo and add a case at runtime:

class Foo{
    private final Object obj0;
    private final Object obj1;
    private final Object def;

    Public Foo(obj0,obj1,def){
        this.obj0 = obj0;
        this.obj1 = obj1;
        this.def = def;
    }

    public int foo(long v){
        if      (v==0) return obj0;
        else if (v==1) return obj1;
        else if (v==2) return obj2_fixed_when_added;
        else return def;
    }
}

Now conceptually this sounds pretty easy. In pseudo code:

visit method Foo.foo{
    boolean transformed = false;
    for(stmt : Foo.foo.body){
        if (transformed || stmt is not if){
            emit unchanged
        }else if (stmt is IF){
            visit if-clause
            visit else-clause
            emit IF
        }else{
            emit new ELSIF for case v==2
            emit stmt unchanged
            transformed = true;
        }
    }
}

Problem then is that we're working with bytecode and the AST doesn't really deal with statements, let alone IF abstractions.

So what I can do in this case is use the fact that all the guards are mutually exclusive and each case returns on its own and just redefine the method like

    public int foo(long v){
        if      (v==2) return obj2_fixed_when_added;
        if      (v==0) return obj0;
        else if (v==1) return obj1;
        else return def;
    }

which is basically

visit method Foo.foo{
    emit new IF for v==2
    emit rest of method body unchanged
}

Crude, but does the job, I guess, and we can now reload the class to make the changes available.

The problem then becomes the

return obj2_fixed_when_added;

If I can just create a new Instance of whatever obj2_fixed_when_added is, I'd do so.

However, what do I do if I can not and want to set it to one specific Object the transformer generates as he inserts the new IF?

Aucun commentaire:

Enregistrer un commentaire