No filters applied - covering 100% of reports

Java tests

Note: iOS does not allow to load bytecode in runtime, both ReflectASM and ByteBuddy do not work there

Note: ByteBuddy and ReflectASM fieldAccess tests passed on all of the Android and Desktop devices, except one - so, technically, it has 100% support on these platforms

Note: ReflectASM methodAccess tests failed for some Android devices with exception: java.lang.ClassNotFoundException: com.prineside.tdi2.utils.PerformanceSurvey$TestClassMethodAccess (MethodAccess is a suffix added to an existing class name by ReflectASM)

Test Passed Support percentage
ByteBuddy 123,853
90.81%
ReflectASM fieldAccess 123,853
90.81%
ReflectASM methodAccess 123,742
90.73%
Unsafe allocateMemory 122,499
89.82%
Unsafe allocateInstance 136,351
99.98%

Source code of tests

// Inner class (PerformanceSurvey$TestFieldAccess)
public static class TestClass {
    public int intVal;
    private int otherVal;

    public TestFieldAccessClass() {
        otherVal = 5;
    }

    public TestClass() {
    }

    public int getIntValPlus(int v) {
        return intVal + v;
    }

    public int getMethodConstant() {
        return 200;
    }
}

// Static instance of Unsafe
public static final Unsafe unsafe;
static {
    // This code worked on every platform and device
    try {
        Constructor unsafeConstructor = Unsafe.class.getDeclaredConstructor();
        unsafeConstructor.setAccessible(true);
        unsafe = unsafeConstructor.newInstance();
    } catch (Exception e) {
        try {
            Field f = Unsafe.class.getDeclaredField("theUnsafe");
            f.setAccessible(true);
            unsafe = (Unsafe)f.get((Object) null);
        } catch (Exception ignored) {}
    }
}

ByteBuddy

// Subclass, override a method and test its intercepted return value
DynamicType.Unloaded unloaded = new ByteBuddy().subclass(TestClass.class)
    .method(ElementMatchers.named("getMethodConstant"))
    .intercept(FixedValue.value(301))
    .make();

Class runtimeClass;
if (Gdx.app.getType() == ApplicationType.Android) {
    ClassLoadingStrategy strategy = new AndroidClassLoadingStrategy.Wrapping(AndroidLauncher.this.getContext().getDir("generated", Context.MODE_PRIVATE));
    unloaded.load(PerformanceSurvey.class.getClassLoader(), strategy).getLoaded();
} else {
    runtimeClass = unloaded.load(PerformanceSurvey.class.getClassLoader()).getLoaded();
}

TestClass testObj = (TestClass) runtimeClass.getConstructor().newInstance();
assert testObj.getMethodConstant() == 301;

ReflectASM fieldAccess

TestClass asmTestObject = new TestClass();
asmTestObject.intVal = 9001;

FieldAccess intValFA = FieldAccess.get(TestClass.class);
intValFA.setInt(asmTestObject, intValFA.getIndex("intVal"), 12701);
assert intValFA.getInt(asmTestObject, intValFA.getIndex("intVal")) == 12701;

ReflectASM methodAccess

TestClass asmTestObject = new TestClass();
asmTestObject.intVal = 9001;

MethodAccess ma = MethodAccess.get(TestClass.class);
int mIdx = ma.getIndex("getIntValPlus", int.class);
assert (int) ma.invoke(asmTestObject, mIdx, 500) == 9001 + 500;

Unsafe allocateMemory

long addr = unsafe.allocateMemory(64);
unsafe.putByte(addr + 7, 121);
assert unsafe.getByte(addr + 7) == 121;
unsafe.freeMemory(addr);

Unsafe allocateInstance

TestClass testObj = (TestClass) unsafe.allocateInstance(TestClass.class);
assert testObj.otherVal == 0;