raphw / byte-buddy

Runtime code generation for the Java virtual machine.
https://bytebuddy.net
Apache License 2.0
6.29k stars 807 forks source link

[Question] Why would a new field var2 be added after replace field access with method? #1697

Closed lucas-myx closed 1 month ago

lucas-myx commented 3 months ago

@raphw First of all, thank you for your previous response. The issue has been resolved. Thank you!

I found use MemberSubstitution to replace field A.foo access with B.bar() , will add a new field var2 in the decompiled bytecode file, as follows:

public class A {
    public String foo;
    public String foo() {
        return foo; // 'return B.bar()' after replaced
    }
}
public class B {
    public Object bar(@CustomFiled String foo, @CustomRetunType Class<?> returnType) {
       if (String.class.isAssignableFrom(returnType)) {
            return "bar";
        }
        return null;
    }
}

MemberSubstitution usage:

new ByteBuddy().redefine(Foo.class)
                    .visit(MemberSubstitution.relaxed()
                    .field(named("foo"))
                    .onRead()
                    .replaceWithChain(
                            MemberSubstitution.Substitution.Chain.Step.ForDelegation.withCustomMapping()
                                    .bind(CustomFiled.class, fooFieldDescription)
                                    .bind(CustomRetunType.class, fieldDescription.getType().asErasure())
                                    .to(B.class.getDeclaredMethod("bar"),
                            MemberSubstitution.Substitution.Chain.Step.ForAssignment.castToSubstitutionResult())
                    .on(any()))).make().saveIn(file);

open the decompiled A.class bytecode file, as follows:

public String foo() {
    Object var2 = null; // new add field
     return (String)B.bar(this.foo, String.class);
}

I don't understand why we need to add a new field var2 and what its purpose is? (I'm worried that the extra fields may have other additional impacts)

I guess it might be due to my incorrect usage, please correct me. Thank you very much!

raphw commented 3 months ago

If a chain is used, all arguments are temporarily stored as local variable. This is expected and will likely be ignored by the JIT, nothing to worry about.

If you want to write custom byte code, you can avoid it by implementing your own handler and avoid the chain. There's also some ready made ones.

lucas-myx commented 3 months ago

Thank you for your reply! one more question, Is there such an example: implementing your own handler and avoid the chain? Thank you!

raphw commented 3 months ago

Yes, any other method implements such a handler, the chain method also offers a handler implementation itself. If you look at the source, you will be able to see how this looks like.