mirror of
https://github.com/corda/corda.git
synced 2025-03-15 00:36:49 +00:00
ensure that we can intercept static Java methods in bootimage build
Timezone code was broken in the Android class library bootimage build because the code we use to intercept loading the tzdata file wasn't working. The reason is have no way of intercepting static methods at runtime in the bootimage build without telling the bootimage-generator we're going to do it ahead of time. So now we do tell it so. This commit also removes the need to intercept Thread methods since we can update Thread.vmThread in VMThread.create instead.
This commit is contained in:
parent
3309a9f4ad
commit
c80ffa041d
@ -578,28 +578,33 @@ invoke(Thread* t, object method, object instance, object args)
|
||||
// running:
|
||||
void
|
||||
intercept(Thread* t, object c, const char* name, const char* spec,
|
||||
void* function)
|
||||
void* function, bool updateRuntimeData)
|
||||
{
|
||||
object m = findMethodOrNull(t, c, name, spec);
|
||||
if (m) {
|
||||
PROTECT(t, m);
|
||||
|
||||
object clone = methodClone(t, m);
|
||||
object clone;
|
||||
if (updateRuntimeData) {
|
||||
clone = methodClone(t, m);
|
||||
|
||||
// make clone private to prevent vtable updates at compilation
|
||||
// time. Otherwise, our interception might be bypassed by calls
|
||||
// through the vtable.
|
||||
methodFlags(t, clone) |= ACC_PRIVATE;
|
||||
// make clone private to prevent vtable updates at compilation
|
||||
// time. Otherwise, our interception might be bypassed by calls
|
||||
// through the vtable.
|
||||
methodFlags(t, clone) |= ACC_PRIVATE;
|
||||
}
|
||||
|
||||
methodFlags(t, m) |= ACC_NATIVE;
|
||||
|
||||
object native = makeNativeIntercept(t, function, true, clone);
|
||||
|
||||
PROTECT(t, native);
|
||||
|
||||
object runtimeData = getMethodRuntimeData(t, m);
|
||||
|
||||
set(t, runtimeData, MethodRuntimeDataNative, native);
|
||||
if (updateRuntimeData) {
|
||||
object native = makeNativeIntercept(t, function, true, clone);
|
||||
|
||||
PROTECT(t, native);
|
||||
|
||||
object runtimeData = getMethodRuntimeData(t, m);
|
||||
|
||||
set(t, runtimeData, MethodRuntimeDataNative, native);
|
||||
}
|
||||
} else {
|
||||
// If we can't find the method, just ignore it, since ProGuard may
|
||||
// have stripped it out as unused. Otherwise, the code below can
|
||||
|
@ -1564,6 +1564,9 @@ class Classpath {
|
||||
virtual void
|
||||
resolveNative(Thread* t, object method) = 0;
|
||||
|
||||
virtual void
|
||||
interceptMethods(Thread* t) = 0;
|
||||
|
||||
virtual void
|
||||
preBoot(Thread* t) = 0;
|
||||
|
||||
|
@ -152,28 +152,6 @@ initVmThread(Thread* t, object thread)
|
||||
}
|
||||
}
|
||||
|
||||
void JNICALL
|
||||
createThread(Thread* t, object method, uintptr_t* arguments)
|
||||
{
|
||||
object thread = reinterpret_cast<object>(arguments[0]);
|
||||
PROTECT(t, thread);
|
||||
|
||||
object group = reinterpret_cast<object>(arguments[1]);
|
||||
PROTECT(t, group);
|
||||
|
||||
object name = reinterpret_cast<object>(arguments[2]);
|
||||
PROTECT(t, name);
|
||||
|
||||
int64_t stackSize; memcpy(&stackSize, arguments + 3, 8);
|
||||
|
||||
initVmThread(t, thread);
|
||||
|
||||
t->m->processor->invoke
|
||||
(t, nativeInterceptOriginal
|
||||
(t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))),
|
||||
thread, group, name, stackSize);
|
||||
}
|
||||
|
||||
object
|
||||
translateStackTrace(Thread* t, object raw)
|
||||
{
|
||||
@ -359,17 +337,9 @@ class MyClasspath : public Classpath {
|
||||
vm::resolveNative(t, method);
|
||||
}
|
||||
|
||||
virtual void
|
||||
preBoot(Thread* t)
|
||||
void
|
||||
interceptMethods(Thread* t, bool updateRuntimeData)
|
||||
{
|
||||
// Android's System.initSystemProperties throws an NPE if
|
||||
// LD_LIBRARY_PATH is not set as of this writing:
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
_wputenv(L"LD_LIBRARY_PATH=dummy");
|
||||
#else
|
||||
setenv("LD_LIBRARY_PATH", "", false);
|
||||
#endif
|
||||
|
||||
{ object c = resolveClass
|
||||
(t, root(t, Machine::BootLoader), "java/lang/Runtime", false);
|
||||
|
||||
@ -378,7 +348,7 @@ class MyClasspath : public Classpath {
|
||||
|
||||
intercept(t, c, "loadLibrary",
|
||||
"(Ljava/lang/String;Ljava/lang/ClassLoader;)V",
|
||||
voidPointer(loadLibrary));
|
||||
voidPointer(loadLibrary), updateRuntimeData);
|
||||
}
|
||||
}
|
||||
|
||||
@ -389,7 +359,7 @@ class MyClasspath : public Classpath {
|
||||
PROTECT(t, c);
|
||||
|
||||
intercept(t, c, "createSystemClassLoader", "()Ljava/lang/ClassLoader;",
|
||||
voidPointer(appLoader));
|
||||
voidPointer(appLoader), updateRuntimeData);
|
||||
}
|
||||
}
|
||||
|
||||
@ -400,7 +370,7 @@ class MyClasspath : public Classpath {
|
||||
PROTECT(t, c);
|
||||
|
||||
intercept(t, c, "mapData", "()Llibcore/io/MemoryMappedFile;",
|
||||
voidPointer(mapData));
|
||||
voidPointer(mapData), updateRuntimeData);
|
||||
}
|
||||
}
|
||||
|
||||
@ -411,23 +381,31 @@ class MyClasspath : public Classpath {
|
||||
if (c) {
|
||||
PROTECT(t, c);
|
||||
|
||||
intercept(t, c, "close", "()V", voidPointer(closeMemoryMappedFile));
|
||||
intercept(t, c, "close", "()V", voidPointer(closeMemoryMappedFile),
|
||||
updateRuntimeData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{ object c = resolveClass
|
||||
(t, root(t, Machine::BootLoader), "java/lang/Thread", false);
|
||||
virtual void
|
||||
interceptMethods(Thread* t)
|
||||
{
|
||||
interceptMethods(t, false);
|
||||
}
|
||||
|
||||
if (c) {
|
||||
PROTECT(t, c);
|
||||
|
||||
intercept(t, c, "create",
|
||||
"(Ljava/lang/ThreadGroup;Ljava/lang/Runnable;"
|
||||
"Ljava/lang/String;J)V",
|
||||
voidPointer(createThread));
|
||||
}
|
||||
}
|
||||
virtual void
|
||||
preBoot(Thread* t)
|
||||
{
|
||||
// Android's System.initSystemProperties throws an NPE if
|
||||
// LD_LIBRARY_PATH is not set as of this writing:
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
_wputenv(L"LD_LIBRARY_PATH=(dummy)");
|
||||
#else
|
||||
setenv("LD_LIBRARY_PATH", "", false);
|
||||
#endif
|
||||
|
||||
interceptMethods(t, true);
|
||||
|
||||
JNI_OnLoad(reinterpret_cast< ::JavaVM*>(t->m), 0);
|
||||
}
|
||||
|
||||
@ -1101,7 +1079,11 @@ extern "C" JNIEXPORT void JNICALL
|
||||
Avian_java_lang_VMThread_create
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
startThread(t, reinterpret_cast<object>(arguments[0]));
|
||||
object thread = reinterpret_cast<object>(arguments[0]);
|
||||
PROTECT(t, thread);
|
||||
|
||||
local::initVmThread(t, thread);
|
||||
startThread(t, thread);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
@ -1195,6 +1177,35 @@ Avian_java_lang_Math_sin
|
||||
return doubleToBits(sin(bitsToDouble(v)));
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Math_sqrt
|
||||
(Thread*, object, uintptr_t* arguments)
|
||||
{
|
||||
int64_t v; memcpy(&v, arguments, 8);
|
||||
return doubleToBits(sqrt(bitsToDouble(v)));
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Math_abs__I
|
||||
(Thread*, object, uintptr_t* arguments)
|
||||
{
|
||||
return abs(static_cast<int32_t>(arguments[0]));
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Math_abs__J
|
||||
(Thread*, object, uintptr_t* arguments)
|
||||
{
|
||||
return llabs(arguments[0]);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Math_abs__F
|
||||
(Thread*, object, uintptr_t* arguments)
|
||||
{
|
||||
return floatToBits(abs(bitsToFloat(arguments[0])));
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Float_intBitsToFloat
|
||||
(Thread*, object, uintptr_t* arguments)
|
||||
|
@ -109,6 +109,12 @@ class MyClasspath : public Classpath {
|
||||
vm::resolveNative(t, method);
|
||||
}
|
||||
|
||||
virtual void
|
||||
interceptMethods(Thread*)
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
|
||||
virtual void
|
||||
preBoot(Thread*)
|
||||
{
|
||||
|
@ -352,7 +352,7 @@ object
|
||||
makeJfield(Thread* t, object vmField, int index = -1);
|
||||
|
||||
void
|
||||
interceptFileOperations(Thread*);
|
||||
interceptFileOperations(Thread*, bool);
|
||||
|
||||
void
|
||||
clearInterrupted(Thread*);
|
||||
@ -614,9 +614,16 @@ class MyClasspath : public Classpath {
|
||||
vm::notifyAll(t, t->javaThread);
|
||||
vm::release(t, t->javaThread);
|
||||
|
||||
object e = t->exception;
|
||||
PROTECT(t, e);
|
||||
|
||||
t->exception = 0;
|
||||
|
||||
t->m->processor->invoke
|
||||
(t, root(t, Machine::ThreadTerminated),
|
||||
threadGroup(t, t->javaThread), t->javaThread);
|
||||
|
||||
t->exception = e;
|
||||
});
|
||||
|
||||
object method = resolveMethod
|
||||
@ -643,6 +650,14 @@ class MyClasspath : public Classpath {
|
||||
vm::resolveNative(t, method);
|
||||
}
|
||||
|
||||
virtual void
|
||||
interceptMethods(Thread* t UNUSED)
|
||||
{
|
||||
#ifdef AVIAN_OPENJDK_SRC
|
||||
interceptFileOperations(t, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual void
|
||||
preBoot(Thread*)
|
||||
{
|
||||
@ -662,7 +677,7 @@ class MyClasspath : public Classpath {
|
||||
"threadTerminated", "(Ljava/lang/Thread;)V"));
|
||||
|
||||
#ifdef AVIAN_OPENJDK_SRC
|
||||
interceptFileOperations(t);
|
||||
interceptFileOperations(t, true);
|
||||
#else // not AVIAN_OPENJDK_SRC
|
||||
expect(t, loadLibrary(t, libraryPath, "verify", true, true));
|
||||
expect(t, loadLibrary(t, libraryPath, "java", true, true));
|
||||
@ -1957,7 +1972,7 @@ loadLibrary(Thread* t, object, uintptr_t* arguments)
|
||||
}
|
||||
|
||||
void
|
||||
interceptFileOperations(Thread* t)
|
||||
interceptFileOperations(Thread* t, bool updateRuntimeData)
|
||||
{
|
||||
MyClasspath* cp = static_cast<MyClasspath*>(t->m->classpath);
|
||||
|
||||
@ -2000,22 +2015,22 @@ interceptFileOperations(Thread* t)
|
||||
cp->fileInputStreamFdField = fieldOffset(t, fileInputStreamFdField);
|
||||
|
||||
intercept(t, fileInputStreamClass, "open", "(Ljava/lang/String;)V",
|
||||
voidPointer(openFile));
|
||||
voidPointer(openFile), updateRuntimeData);
|
||||
|
||||
intercept(t, fileInputStreamClass, "read", "()I",
|
||||
voidPointer(readByteFromFile));
|
||||
voidPointer(readByteFromFile), updateRuntimeData);
|
||||
|
||||
intercept(t, fileInputStreamClass, "readBytes", "([BII)I",
|
||||
voidPointer(readBytesFromFile));
|
||||
voidPointer(readBytesFromFile), updateRuntimeData);
|
||||
|
||||
intercept(t, fileInputStreamClass, "skip", "(J)J",
|
||||
voidPointer(skipBytesInFile));
|
||||
voidPointer(skipBytesInFile), updateRuntimeData);
|
||||
|
||||
intercept(t, fileInputStreamClass, "available", "()I",
|
||||
voidPointer(availableBytesInFile));
|
||||
voidPointer(availableBytesInFile), updateRuntimeData);
|
||||
|
||||
intercept(t, fileInputStreamClass, "close0", "()V",
|
||||
voidPointer(closeFile));
|
||||
voidPointer(closeFile), updateRuntimeData);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2033,40 +2048,42 @@ interceptFileOperations(Thread* t)
|
||||
cp->zipFileJzfileField = fieldOffset(t, zipFileJzfileField);
|
||||
|
||||
intercept(t, zipFileClass, "open", "(Ljava/lang/String;IJZ)J",
|
||||
voidPointer(openZipFile));
|
||||
voidPointer(openZipFile), updateRuntimeData);
|
||||
|
||||
intercept(t, zipFileClass, "getTotal", "(J)I",
|
||||
voidPointer(getZipFileEntryCount));
|
||||
voidPointer(getZipFileEntryCount), updateRuntimeData);
|
||||
|
||||
intercept(t, zipFileClass, "getEntry", "(J[BZ)J",
|
||||
voidPointer(getZipFileEntry));
|
||||
voidPointer(getZipFileEntry), updateRuntimeData);
|
||||
|
||||
intercept(t, zipFileClass, "getEntryBytes", "(JI)[B",
|
||||
voidPointer(getZipFileEntryBytes));
|
||||
voidPointer(getZipFileEntryBytes), updateRuntimeData);
|
||||
|
||||
intercept(t, zipFileClass, "getNextEntry", "(JI)J",
|
||||
voidPointer(getNextZipFileEntry));
|
||||
voidPointer(getNextZipFileEntry), updateRuntimeData);
|
||||
|
||||
intercept(t, zipFileClass, "getEntryMethod", "(J)I",
|
||||
voidPointer(getZipFileEntryMethod));
|
||||
voidPointer(getZipFileEntryMethod), updateRuntimeData);
|
||||
|
||||
intercept(t, zipFileClass, "freeEntry", "(JJ)V",
|
||||
voidPointer(freeZipFileEntry));
|
||||
voidPointer(freeZipFileEntry), updateRuntimeData);
|
||||
|
||||
intercept(t, zipFileClass, "read", "(JJJ[BII)I",
|
||||
voidPointer(readZipFileEntry));
|
||||
voidPointer(readZipFileEntry), updateRuntimeData);
|
||||
|
||||
intercept(t, zipFileClass, "getEntryCSize", "(J)J",
|
||||
voidPointer(getZipFileEntryCompressedSize));
|
||||
voidPointer(getZipFileEntryCompressedSize),
|
||||
updateRuntimeData);
|
||||
|
||||
intercept(t, zipFileClass, "getEntrySize", "(J)J",
|
||||
voidPointer(getZipFileEntryUncompressedSize));
|
||||
voidPointer(getZipFileEntryUncompressedSize),
|
||||
updateRuntimeData);
|
||||
|
||||
intercept(t, zipFileClass, "getZipMessage", "(J)Ljava/lang/String;",
|
||||
voidPointer(getZipMessage));
|
||||
voidPointer(getZipMessage), updateRuntimeData);
|
||||
|
||||
intercept(t, zipFileClass, "close", "(J)V",
|
||||
voidPointer(closeZipFile));
|
||||
voidPointer(closeZipFile), updateRuntimeData);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2077,7 +2094,7 @@ interceptFileOperations(Thread* t)
|
||||
if (jarFileClass) {
|
||||
intercept(t, jarFileClass, "getMetaInfEntryNames",
|
||||
"()[Ljava/lang/String;",
|
||||
voidPointer(getJarFileMetaInfEntryNames));
|
||||
voidPointer(getJarFileMetaInfEntryNames), updateRuntimeData);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2097,27 +2114,27 @@ interceptFileOperations(Thread* t)
|
||||
PROTECT(t, fsClass);
|
||||
|
||||
intercept(t, fsClass, gbaMethodName, "(Ljava/io/File;)I",
|
||||
voidPointer(getFileAttributes));
|
||||
voidPointer(getFileAttributes), updateRuntimeData);
|
||||
|
||||
intercept(t, fsClass, "checkAccess", "(Ljava/io/File;I)Z",
|
||||
voidPointer(checkFileAccess));
|
||||
voidPointer(checkFileAccess), updateRuntimeData);
|
||||
|
||||
intercept(t, fsClass, "getLength", "(Ljava/io/File;)J",
|
||||
voidPointer(getFileLength));
|
||||
voidPointer(getFileLength), updateRuntimeData);
|
||||
}
|
||||
}
|
||||
|
||||
intercept(t, type(t, Machine::ClassLoaderType), "loadLibrary",
|
||||
"(Ljava/lang/Class;Ljava/lang/String;Z)V",
|
||||
voidPointer(loadLibrary));
|
||||
voidPointer(loadLibrary), updateRuntimeData);
|
||||
|
||||
intercept(t, type(t, Machine::ClassLoaderType), "getBootstrapResource",
|
||||
"(Ljava/lang/String;)Ljava/net/URL;",
|
||||
voidPointer(getBootstrapResource));
|
||||
voidPointer(getBootstrapResource), updateRuntimeData);
|
||||
|
||||
intercept(t, type(t, Machine::ClassLoaderType), "getBootstrapResources",
|
||||
"(Ljava/lang/String;)Ljava/util/Enumeration;",
|
||||
voidPointer(getBootstrapResources));
|
||||
voidPointer(getBootstrapResources), updateRuntimeData);
|
||||
}
|
||||
|
||||
object
|
||||
|
@ -285,6 +285,8 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code,
|
||||
{
|
||||
PROTECT(t, typeMaps);
|
||||
|
||||
t->m->classpath->interceptMethods(t);
|
||||
|
||||
object constants = 0;
|
||||
PROTECT(t, constants);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user