linkedin / dexmaker

A utility for doing compile or runtime code generation targeting Android's Dalvik VM
Apache License 2.0
1.86k stars 248 forks source link

Why Code#compare parameter order is reversed after generated dex? #180

Open wuyr opened 2 years ago

wuyr commented 2 years ago

I have the following code:

Local local1 = methodCodeBlock.newLocal(TypeId.INT);
Local parameter = methodCodeBlock.getParameter(0, TypeId.INT);

...

methodCodeBlock.compare(Comparison.LT, label, local1, parameter);

The expected result should be:

if(local1 >= parameter)
...

But when I invoke the DexMaker#generate, the result I see is:

if(parameter >= local1)
...

Is this a bug? Or am I using it incorrectly? If I use it incorrectly, can someone tell me how to use it correctly? Thank a lot! Is this project still alive? The last update I saw was last May

wuyr commented 2 years ago

I got it, when local1 value = 0, the result order is always reversed. how can i fix this?

kkoser commented 2 years ago

Hey @wuyr sorry I'm getting back so late - I think this is working as expected. writing a comparison of compare(LT, local1, param) is the java equivalent of

if (local1 < param) which could also be rewritten as

if (param >= local1)

I tried writing a test case for this with the local having a value of 0, and it seems to work correctly - lmk if you're seeing different, or if I'm misunderstanding your use case. Thanks!


    @Test
    public void testIntCompare() throws Exception {
        /*
         * public static bool call(int b) {
         *   return 0 < b
         * }
         */
        MethodId<?, Boolean> methodId = GENERATED.getMethod(
                TypeId.BOOLEAN, "call", TypeId.INT);
        Code code = dexMaker.declare(methodId, PUBLIC | STATIC);
        Local<Integer> localA = code.newLocal(TypeId.INT);
        Local<Integer> localB = code.getParameter(0, TypeId.INT);
        Local<Boolean> result = code.newLocal(TypeId.get(boolean.class));
        Label afterIf = new Label();
        Label ifBody = new Label();
        code.loadConstant(localA, 0);
        code.compare(Comparison.LT, ifBody, localA, localB);
        code.jump(afterIf);

        code.mark(ifBody);
        code.loadConstant(result, true);
        code.returnValue(result);

        code.mark(afterIf);
        code.loadConstant(result, false);
        code.returnValue(result);
        Method method = getMethod();

        assertEquals(true, method.invoke(null, 5));
        assertEquals(false, method.invoke(null, -5));
        assertEquals(false, method.invoke(null, 0));
    }```