From d5504d8f58a40800059f7f5edefe5de84356960e Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 14 Mar 2013 15:33:05 -0600 Subject: [PATCH] first step towards supporting Android class library on Windows A majority of the tests are passing, but more work is needed to get them all to pass. --- makefile | 63 ++++++++---- src/android/icu.cpp | 12 --- src/classpath-android.cpp | 208 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 243 insertions(+), 40 deletions(-) delete mode 100644 src/android/icu.cpp diff --git a/makefile b/makefile index 22e79f76f0..7a618ca3e5 100755 --- a/makefile +++ b/makefile @@ -165,21 +165,47 @@ ifneq ($(android),) -I$(build)/android-src/external/fdlibm \ -I$(build)/android-src \ -fno-exceptions \ - -DHAVE_SYS_UIO_H \ -D_FILE_OFFSET_BITS=64 \ -g3 \ - -Werror \ - -fPIC + -Werror + + luni-cpps := $(shell find $(luni-native) -name '*.cpp') + + ifeq ($(platform),windows) + android-cflags += -D__STDC_CONSTANT_MACROS + ifneq ($(arch),i386) + android-cflags += -fPIC + endif + blacklist = $(luni-native)/java_io_Console.cpp \ + $(luni-native)/java_lang_ProcessManager.cpp \ + $(luni-native)/libcore_io_OsConstants.cpp \ + $(luni-native)/libcore_io_Posix.cpp \ + $(luni-native)/libcore_io_AsynchronousCloseMonitor.cpp \ + $(luni-native)/libcore_net_RawSocket.cpp \ + $(luni-native)/org_apache_harmony_xnet_provider_jsse_NativeCrypto.cpp \ + $(luni-native)/AsynchronousSocketCloseMonitor.cpp \ + $(luni-native)/NetworkUtilities.cpp + luni-cpps := $(filter-out $(blacklist),$(luni-cpps)) + icu-libs := $(android)/icu4c/lib/sicuin.a \ + $(android)/icu4c/lib/sicuuc.a \ + $(android)/icu4c/lib/sicudt.a + platform-lflags := -lgdi32 + else + android-cflags += -fPIC -DHAVE_SYS_UIO_H + icu-libs := $(android)/icu4c/lib/icui18n.a \ + $(android)/icu4c/lib/libicuuc.a \ + $(android)/icu4c/lib/libicudat.a + endif + classpath-lflags := \ - $(android)/icu4c/lib/libicui18n.a \ - $(android)/icu4c/lib/libicuuc.a \ - $(android)/icu4c/lib/libicudata.a \ + $(icu-libs) \ $(android)/fdlibm/libfdm.a \ $(android)/expat/.libs/libexpat.a \ $(android)/openssl-upstream/libssl.a \ $(android)/openssl-upstream/libcrypto.a \ + $(platform-lflags) \ -lstdc++ - luni-cpps := $(shell find $(luni-native) -name '*.cpp') + classpath-objects = \ $(call cpp-objects,$(luni-cpps),$(luni-native),$(build)) luni-java = $(android)/libcore/luni/src/main/java @@ -198,6 +224,8 @@ ifneq ($(android),) javahome-object = $(build)/javahome-jar.o boot-javahome-object = $(build)/boot-javahome.o build-javahome = $(android)/bionic/libc/zoneinfo + stub-sources = $(src)/android/stubs.cpp + stub-objects = $(call cpp-objects,$(stub-sources),$(src),$(build)) endif ifeq ($(classpath),avian) @@ -1017,7 +1045,7 @@ target-asm = $(asm) build-embed = $(build)/embed build-embed-loader = $(build)/embed-loader -embed-loader-sources = $(src)/embedded-loader.cpp +embed-loader-sources = $(src)/embedded-loader.cpp $(stub-sources) embed-loader-objects = $(call cpp-objects,$(embed-loader-sources),$(src),$(build-embed-loader)) embed-sources = $(src)/embed.cpp @@ -1091,14 +1119,12 @@ ifeq ($(continuations),true) asmflags += -DAVIAN_CONTINUATIONS endif -bootimage-generator-sources = $(src)/tools/bootimage-generator/main.cpp $(src)/util/arg-parser.cpp +bootimage-generator-sources = $(src)/tools/bootimage-generator/main.cpp $(src)/util/arg-parser.cpp $(stub-sources) ifneq ($(lzma),) bootimage-generator-sources += $(src)/lzma-encode.cpp endif -ifneq ($(android),) - bootimage-generator-sources += $(src)/android/stubs.cpp -endif + bootimage-generator-objects = \ $(call cpp-objects,$(bootimage-generator-sources),$(src),$(build)) bootimage-generator = $(build)/bootimage-generator @@ -1438,10 +1464,7 @@ $(classpath-dep): $(classpath-sources) $(classpath-jar-dep) @touch $(@) $(build)/android-src/%.cpp: $(luni-native)/%.cpp - if [ "$(luni-native)/libcore_icu_ICU.cpp" = "$(<)" ]; then \ - sed 's/register_libcore_icu_ICU/hide_register_libcore_icu_ICU/' \ - < $(<) > $(@).tmp && cat $(@).tmp $(src)/android/icu.cpp > $(@); else \ - cp $(<) $(@); fi + cp $(<) $(@) $(build)/%.o: $(build)/android-src/%.cpp $(build)/android.dep @echo "compiling $(@)" @@ -1562,8 +1585,8 @@ $(embed-loader-o): $(embed-loader) $(converter) $(converter) $(<) $(@) _binary_loader_start \ _binary_loader_end $(target-format) $(arch) -$(embed-loader): $(embed-loader-objects) $(vm-objects) $(classpath-objects) $(vm-heapwalk-objects) \ - $(javahome-object) $(boot-javahome-object) $(lzma-decode-objects) +$(embed-loader): $(embed-loader-objects) $(vm-objects) $(classpath-object) \ + $(heapwalk-objects) $(lzma-decode-objects) ifdef ms_cl_compiler $(ld) $(lflags) $(^) -out:$(@) \ -debug -PDB:$(subst $(exe-suffix),.pdb,$(@)) $(manifest-flags) @@ -1701,7 +1724,7 @@ executable-objects = $(vm-objects) $(classpath-objects) $(driver-object) \ $(javahome-object) $(boot-javahome-object) $(lzma-decode-objects) unittest-executable-objects = $(unittest-objects) $(vm-objects) \ - $(build)/util/arg-parser.o + $(build)/util/arg-parser.o $(stub-objects) ifeq ($(process),interpret) unittest-executable-objects += $(all-codegen-target-objects) @@ -1742,7 +1765,7 @@ define link-executable @echo linking $(@) $(dlltool) -z $(@).def $(^) $(dlltool) -d $(@).def -e $(@).exp - $(ld) $(@).exp $(^) $(lflags) -o $(@) + $(ld) $(@).exp $(^) $(lflags) $(classpath-lflags) -o $(@) endef endif endif diff --git a/src/android/icu.cpp b/src/android/icu.cpp deleted file mode 100644 index 15b661e4c7..0000000000 --- a/src/android/icu.cpp +++ /dev/null @@ -1,12 +0,0 @@ -void -register_libcore_icu_ICU(JNIEnv* e) -{ - UErrorCode status = U_ZERO_ERROR; - udata_setFileAccess(UDATA_NO_FILES, &status); - if (status != U_ZERO_ERROR) abort(); - - u_init(&status); - if (status != U_ZERO_ERROR) abort(); - - jniRegisterNativeMethods(e, "libcore/icu/ICU", gMethods, NELEM(gMethods)); -} diff --git a/src/classpath-android.cpp b/src/classpath-android.cpp index b2a2a174b3..93af185a92 100644 --- a/src/classpath-android.cpp +++ b/src/classpath-android.cpp @@ -24,6 +24,18 @@ namespace { namespace local { +void* +getDirectBufferAddress(Thread* t, object b) +{ + PROTECT(t, b); + + object field = resolveField + (t, objectClass(t, b), "effectiveDirectAddress", "J"); + + return reinterpret_cast + (fieldAtOffset(b, fieldOffset(t, field))); +} + void JNICALL loadLibrary(Thread* t, object, uintptr_t* arguments) { @@ -140,6 +152,28 @@ initVmThread(Thread* t, object thread) } } +void JNICALL +createThread(Thread* t, object method, uintptr_t* arguments) +{ + object thread = reinterpret_cast(arguments[0]); + PROTECT(t, thread); + + object group = reinterpret_cast(arguments[1]); + PROTECT(t, group); + + object name = reinterpret_cast(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) { @@ -163,7 +197,8 @@ translateStackTrace(Thread* t, object raw) class MyClasspath : public Classpath { public: MyClasspath(Allocator* allocator): - allocator(allocator) + allocator(allocator), + tzdata(0) { } virtual object @@ -329,7 +364,11 @@ class MyClasspath : public Classpath { { // 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); @@ -375,6 +414,19 @@ class MyClasspath : public Classpath { intercept(t, c, "close", "()V", voidPointer(closeMemoryMappedFile)); } } + + { object c = resolveClass + (t, root(t, Machine::BootLoader), "java/lang/Thread", false); + + if (c) { + PROTECT(t, c); + + intercept(t, c, "create", + "(Ljava/lang/ThreadGroup;Ljava/lang/Runnable;" + "Ljava/lang/String;J)V", + voidPointer(createThread)); + } + } JNI_OnLoad(reinterpret_cast< ::JavaVM*>(t->m), 0); } @@ -419,13 +471,7 @@ class MyClasspath : public Classpath { virtual void* getDirectBufferAddress(Thread* t, object b) { - PROTECT(t, b); - - object field = resolveField - (t, objectClass(t, b), "effectiveDirectAddress", "J"); - - return reinterpret_cast - (fieldAtOffset(b, fieldOffset(t, field))); + return local::getDirectBufferAddress(t, b); } virtual int64_t @@ -599,11 +645,21 @@ jniThrowIOException(JNIEnv* e, const char* message) extern "C" const char* jniStrError(int error, char* buffer, size_t length) { +#ifdef PLATFORM_WINDOWS + const char* s = strerror(error); + if (strlen(s) < length) { + strncpy(buffer, s, length); + return buffer; + } else { + return 0; + } +#else if (static_cast(strerror_r(error, buffer, length)) == 0) { return buffer; } else { return 0; } +#endif } extern "C" int @@ -1676,3 +1732,139 @@ Avian_java_lang_System_mapLibraryName RUNTIME_ARRAY_BODY(originalChars), t->m->system->librarySuffix())); } + +#ifdef PLATFORM_WINDOWS + +# include + +void register_java_io_Console(_JNIEnv*) { } +void register_java_lang_ProcessManager(_JNIEnv*) { } +void register_libcore_io_OsConstants(_JNIEnv*) { } +void register_libcore_io_AsynchronousCloseMonitor(_JNIEnv*) { } +void register_libcore_io_Posix(_JNIEnv*) { } +void register_libcore_net_RawSocket(_JNIEnv*) { } +void register_org_apache_harmony_xnet_provider_jsse_NativeCrypto(_JNIEnv*) { } + +extern "C" JNIEXPORT void JNICALL +Avian_libcore_io_OsConstants_initConstants +(Thread* t, object method, uintptr_t*) +{ + object c = methodClass(t, method); + PROTECT(t, c); + + object table = classStaticTable(t, c); + PROTECT(t, table); + + object field = resolveField(t, c, "STDIN_FILENO", "I"); + fieldAtOffset(table, fieldOffset(t, field)) = 0; + + field = resolveField(t, c, "STDOUT_FILENO", "I"); + fieldAtOffset(table, fieldOffset(t, field)) = 1; + + field = resolveField(t, c, "STDERR_FILENO", "I"); + fieldAtOffset(table, fieldOffset(t, field)) = 2; +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_libcore_io_Posix_getenv(Thread* t, object, uintptr_t* arguments) +{ + object name = reinterpret_cast(arguments[1]); + + THREAD_RUNTIME_ARRAY(t, uint16_t, chars, stringLength(t, name) + 1); + stringChars(t, name, RUNTIME_ARRAY_BODY(chars)); + + wchar_t* value = _wgetenv + (reinterpret_cast(RUNTIME_ARRAY_BODY(chars))); + + if (value) { + unsigned size = wcslen(value); + + object a = makeCharArray(t, size); + if (size) { + memcpy(&charArrayBody(t, a, 0), value, size * sizeof(jchar)); + } + + return reinterpret_cast + (t->m->classpath->makeString(t, a, 0, size)); + } else { + return 0; + } +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_libcore_io_Posix_uname(Thread* t, object, uintptr_t*) +{ + object c = resolveClass + (t, root(t, Machine::BootLoader), "libcore/io/StructUtsname"); + PROTECT(t, c); + + object instance = makeNew(t, c); + PROTECT(t, instance); + +#ifdef ARCH_x86_32 + object arch = makeString(t, "x86"); +#elif defined ARCH_x86_64 + object arch = makeString(t, "x86_64"); +#elif defined ARCH_powerpc + object arch = makeString(t, "ppc"); +#elif defined ARCH_arm + object arch = makeString(t, "arm"); +#else + object arch = makeString(t, "unknown"); +#endif + + set(t, instance, fieldOffset + (t, resolveField(t, c, "machine", "Ljava/lang/String;")), arch); + + object platform = makeString(t, "Windows"); + + set(t, instance, fieldOffset + (t, resolveField(t, c, "sysname", "Ljava/lang/String;")), platform); + + object version = makeString(t, "unknown"); + + set(t, instance, fieldOffset + (t, resolveField(t, c, "release", "Ljava/lang/String;")), version); + + return reinterpret_cast(instance); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_libcore_io_Posix_writeBytes(Thread* t, object, uintptr_t* arguments) +{ + object fd = reinterpret_cast(arguments[1]); + PROTECT(t, fd); + + object buffer = reinterpret_cast(arguments[2]); + PROTECT(t, buffer); + + int offset = arguments[3]; + int count = arguments[4]; + + int d = jniGetFDFromFileDescriptor(t, &fd); + + int r; + if (objectClass(t, buffer) == type(t, Machine::ByteArrayType)) { + void* tmp = t->m->heap->allocate(count); + memcpy(tmp, &byteArrayBody(t, buffer, offset), count); + { ENTER(t, Thread::IdleState); + r = _write(d, tmp, count); + } + t->m->heap->free(tmp, count); + } else { + void* p = local::getDirectBufferAddress(t, buffer); + { ENTER(t, Thread::IdleState); + r = _write(d, p, count); + } + } + + if (r < 0) { + THREAD_RUNTIME_ARRAY(t, char, message, 256); + throwNew(t, Machine::RuntimeExceptionType, "writeBytes %d: %s", d, + jniStrError(errno, RUNTIME_ARRAY_BODY(message), 0)); + } else { + return r; + } +} + +#endif