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:
Joel Dice 2013-03-15 13:28:01 -06:00
parent 3309a9f4ad
commit c80ffa041d
6 changed files with 133 additions and 89 deletions

View File

@ -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

View File

@ -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;

View File

@ -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)

View File

@ -109,6 +109,12 @@ class MyClasspath : public Classpath {
vm::resolveNative(t, method);
}
virtual void
interceptMethods(Thread*)
{
// ignore
}
virtual void
preBoot(Thread*)
{

View File

@ -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

View File

@ -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);