diff --git a/.gitignore b/.gitignore index 201518bb12..588446f90d 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ build bin /lib /distrib +*.pdb diff --git a/README.md b/README.md index c09ec39db6..1e35318627 100644 --- a/README.md +++ b/README.md @@ -249,12 +249,11 @@ where OpenJDK is installed, e.g.: This will build Avian as a conventional JVM (e.g. libjvm.so) which loads its boot class library and native libraries (e.g. libjava.so) -from _/usr/lib/jvm/java-7-openjdk/jre_ at runtime. To run an -application in this configuration, you'll need to make sure the VM is -in your library search path. For example: +from _/usr/lib/jvm/java-7-openjdk/jre_ at runtime. In this configuration, +OpenJDK needs to remain installed for Avian to work, and you can run +applications like this: - $ LD_LIBRARY_PATH=build/linux-x86_64-openjdk \ - build/linux-x86_64-openjdk/avian-dynamic -cp /path/to/my/application \ + $ build/linux-x86_64-openjdk/avian-dynamic -cp /path/to/my/application \ com.example.MyApplication Alternatively, you can enable a stand-alone build using OpenJDK by diff --git a/classpath/java-io.cpp b/classpath/java-io.cpp index 86020f57c8..f2e9fd3c18 100644 --- a/classpath/java-io.cpp +++ b/classpath/java-io.cpp @@ -55,6 +55,15 @@ typedef wchar_t char_t; +#if defined(WINAPI_FAMILY) +#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + +#include "avian-interop.h" +#define SKIP_OPERATOR_NEW + +#endif +#endif + #else // not PLATFORM_WINDOWS # include @@ -83,7 +92,19 @@ typedef char char_t; #endif // not PLATFORM_WINDOWS +#ifndef WINAPI_FAMILY +# ifndef WINAPI_PARTITION_DESKTOP +# define WINAPI_PARTITION_DESKTOP 1 +# endif + +# ifndef WINAPI_FAMILY_PARTITION +# define WINAPI_FAMILY_PARTITION(x) (x) +# endif +#endif // WINAPI_FAMILY + +#if !defined(SKIP_OPERATOR_NEW) inline void* operator new(size_t, void* p) throw() { return p; } +#endif typedef const char_t* string_t; @@ -155,69 +176,9 @@ doWrite(JNIEnv* e, jint fd, const jbyte* data, jint length) } } + #ifdef PLATFORM_WINDOWS -class Mapping { - public: - Mapping(uint8_t* start, size_t length, HANDLE mapping, HANDLE file): - start(start), - length(length), - mapping(mapping), - file(file) - { } - - uint8_t* start; - size_t length; - HANDLE mapping; - HANDLE file; -}; - -inline Mapping* -map(JNIEnv* e, string_t path) -{ - Mapping* result = 0; - HANDLE file = CreateFileW(path, FILE_READ_DATA, - FILE_SHARE_READ | FILE_SHARE_WRITE, 0, - OPEN_EXISTING, 0, 0); - if (file != INVALID_HANDLE_VALUE) { - unsigned size = GetFileSize(file, 0); - if (size != INVALID_FILE_SIZE) { - HANDLE mapping = CreateFileMapping(file, 0, PAGE_READONLY, 0, size, 0); - if (mapping) { - void* data = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0); - if (data) { - void* p = allocate(e, sizeof(Mapping)); - if (not e->ExceptionCheck()) { - result = new (p) - Mapping(static_cast(data), size, file, mapping); - } - } - - if (result == 0) { - CloseHandle(mapping); - } - } - } - - if (result == 0) { - CloseHandle(file); - } - } - if (result == 0 and not e->ExceptionCheck()) { - throwNew(e, "java/io/IOException", "%d", GetLastError()); - } - return result; -} - -inline void -unmap(JNIEnv*, Mapping* mapping) -{ - UnmapViewOfFile(mapping->start); - CloseHandle(mapping->mapping); - CloseHandle(mapping->file); - free(mapping); -} - class Directory { public: Directory(): handle(0), findNext(false) { } @@ -250,51 +211,9 @@ class Directory { #else // not PLATFORM_WINDOWS -class Mapping { - public: - Mapping(uint8_t* start, size_t length): - start(start), - length(length) - { } - - uint8_t* start; - size_t length; -}; - -inline Mapping* -map(JNIEnv* e, string_t path) -{ - Mapping* result = 0; - int fd = open(path, O_RDONLY); - if (fd != -1) { - struct stat s; - int r = fstat(fd, &s); - if (r != -1) { - void* data = mmap(0, s.st_size, PROT_READ, MAP_PRIVATE, fd, 0); - if (data) { - void* p = allocate(e, sizeof(Mapping)); - if (not e->ExceptionCheck()) { - result = new (p) Mapping(static_cast(data), s.st_size); - } - } - } - close(fd); - } - if (result == 0 and not e->ExceptionCheck()) { - throwNewErrno(e, "java/io/IOException"); - } - return result; -} - -inline void -unmap(JNIEnv*, Mapping* mapping) -{ - munmap(mapping->start, mapping->length); - free(mapping); -} - #endif // not PLATFORM_WINDOWS + } // namespace inline string_t getChars(JNIEnv* e, jstring path) { @@ -316,6 +235,7 @@ extern "C" JNIEXPORT jstring JNICALL Java_java_io_File_toAbsolutePath(JNIEnv* e UNUSED, jclass, jstring path) { #ifdef PLATFORM_WINDOWS +# if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) string_t chars = getChars(e, path); if (chars) { const unsigned BufferSize = MAX_PATH; @@ -330,6 +250,19 @@ Java_java_io_File_toAbsolutePath(JNIEnv* e UNUSED, jclass, jstring path) } return path; +# else + string_t chars = getChars(e, path); + if(chars) { + std::wstring partialPath = chars; + releaseChars(e, path, chars); + + std::wstring fullPath = AvianInterop::GetFullPath(partialPath); + + return e->NewString + (reinterpret_cast(fullPath.c_str()), fullPath.length()); + } + return path; +# endif #else jstring result = path; string_t chars = getChars(e, path); @@ -353,20 +286,41 @@ Java_java_io_File_toAbsolutePath(JNIEnv* e UNUSED, jclass, jstring path) extern "C" JNIEXPORT jlong JNICALL Java_java_io_File_length(JNIEnv* e, jclass, jstring path) { - #ifdef PLATFORM_WINDOWS - - LARGE_INTEGER fileSize; + // Option: without opening file + // http://msdn.microsoft.com/en-us/library/windows/desktop/aa364946(v=vs.85).aspx string_t chars = getChars(e, path); - HANDLE file = CreateFileW - (chars, FILE_READ_DATA, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); - releaseChars(e, path, chars); - if (file != INVALID_HANDLE_VALUE) - GetFileSizeEx(file, &fileSize); - else return 0; - CloseHandle(file); - return static_cast(fileSize.QuadPart); + if(chars) { + LARGE_INTEGER fileSize; + #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + HANDLE file = CreateFileW + (chars, FILE_READ_DATA, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); + #else + HANDLE file = CreateFile2 + (chars, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr); + #endif + releaseChars(e, path, chars); + if (file == INVALID_HANDLE_VALUE) + return 0; + #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + if(!GetFileSizeEx(file, &fileSize)) + { + CloseHandle(file); + return 0; + } + #else + FILE_STANDARD_INFO info; + if(!GetFileInformationByHandleEx(file, FileStandardInfo, &info, sizeof(info))) + { + CloseHandle(file); + return 0; + } + fileSize = info.EndOfFile; + #endif + CloseHandle(file); + return static_cast(fileSize.QuadPart); + } #else string_t chars = getChars(e, path); @@ -598,7 +552,11 @@ Java_java_io_File_openDir(JNIEnv* e, jclass, jstring path) releaseChars(e, path, chars); Directory* d = new (malloc(sizeof(Directory))) Directory; + #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) d->handle = FindFirstFileW(RUNTIME_ARRAY_BODY(buffer), &(d->data)); + #else + d->handle = FindFirstFileExW(RUNTIME_ARRAY_BODY(buffer), FindExInfoStandard, &(d->data), FindExSearchNameMatch, NULL, 0); + #endif if (d->handle == INVALID_HANDLE_VALUE) { d->dispose(); d = 0; @@ -610,6 +568,62 @@ Java_java_io_File_openDir(JNIEnv* e, jclass, jstring path) } } +extern "C" JNIEXPORT jlong JNICALL +Java_java_io_File_lastModified(JNIEnv* e, jclass, jstring path) +{ + string_t chars = getChars(e, path); + if (chars) { + #ifdef PLATFORM_WINDOWS + // Option: without opening file + // http://msdn.microsoft.com/en-us/library/windows/desktop/aa364946(v=vs.85).aspx + #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + HANDLE hFile = CreateFileW + (chars, FILE_READ_DATA, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); + #else + HANDLE hFile = CreateFile2 + (chars, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr); + #endif + releaseChars(e, path, chars); + if (hFile == INVALID_HANDLE_VALUE) + return 0; + LARGE_INTEGER fileDate, filetimeToUnixEpochAdjustment; + filetimeToUnixEpochAdjustment.QuadPart = 11644473600000L * 10000L; + #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + FILETIME fileLastWriteTime; + if (!GetFileTime(hFile, 0, 0, &fileLastWriteTime)) + { + CloseHandle(hFile); + return 0; + } + fileDate.HighPart = fileLastWriteTime.dwHighDateTime; + fileDate.LowPart = fileLastWriteTime.dwLowDateTime; + #else + FILE_BASIC_INFO fileInfo; + if (!GetFileInformationByHandleEx(hFile, FileBasicInfo, &fileInfo, sizeof(fileInfo))) + { + CloseHandle(hFile); + return 0; + } + fileDate = fileInfo.ChangeTime; + #endif + CloseHandle(hFile); + fileDate.QuadPart -= filetimeToUnixEpochAdjustment.QuadPart; + return fileDate.QuadPart / 10000000L; + #else + struct stat fileStat; + if (stat(chars, &fileStat) == -1) { + releaseChars(e, path, chars); + return 0; + } + + return (static_cast(st.st_mtim.tv_sec) * 1000) + + (static_cast(st.st_mtim.tv_nsec) / (1000*1000)); + #endif + } + + return 0; +} + extern "C" JNIEXPORT jstring JNICALL Java_java_io_File_readDir(JNIEnv* e, jclass, jlong handle) { @@ -759,13 +773,13 @@ Java_java_io_FileOutputStream_write__I_3BII (JNIEnv* e, jclass, jint fd, jbyteArray b, jint offset, jint length) { jbyte* data = static_cast(malloc(length)); + if (data == 0) { throwNew(e, "java/lang/OutOfMemoryError", 0); return; } e->GetByteArrayRegion(b, offset, length, data); - if (not e->ExceptionCheck()) { doWrite(e, fd, data, length); } @@ -785,35 +799,104 @@ Java_java_io_RandomAccessFile_open(JNIEnv* e, jclass, jstring path, { string_t chars = getChars(e, path); if (chars) { - Mapping* mapping = map(e, chars); + jlong peer = 0; + jlong length = 0; + #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + #if defined(PLATFORM_WINDOWS) + int fd = ::_wopen(chars, O_RDONLY | OPEN_MASK); + #else + int fd = ::open((const char*)chars, O_RDONLY | OPEN_MASK); + #endif + releaseChars(e, path, chars); + if (fd == -1) { + throwNewErrno(e, "java/io/IOException"); + return; + } + struct ::stat fileStats; + if(::fstat(fd, &fileStats) == -1) { + ::close(fd); + throwNewErrno(e, "java/io/IOException"); + return; + } + peer = fd; + length = fileStats.st_size; + #else + HANDLE hFile = CreateFile2 + (chars, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr); + if (hFile == INVALID_HANDLE_VALUE) { + throwNewErrno(e, "java/io/IOException"); + return; + } + + FILE_STANDARD_INFO info; + if(!GetFileInformationByHandleEx(hFile, FileStandardInfo, &info, sizeof(info))) { + CloseHandle(hFile); + throwNewErrno(e, "java/io/IOException"); + return; + } + + peer = (jlong)hFile; + length = info.EndOfFile.QuadPart; + #endif - jlong peer = reinterpret_cast(mapping); e->SetLongArrayRegion(result, 0, 1, &peer); - - jlong length = (mapping ? mapping->length : 0); e->SetLongArrayRegion(result, 1, 1, &length); - - releaseChars(e, path, chars); } } -extern "C" JNIEXPORT void JNICALL -Java_java_io_RandomAccessFile_copy(JNIEnv* e, jclass, jlong peer, +extern "C" JNIEXPORT jint JNICALL +Java_java_io_RandomAccessFile_readBytes(JNIEnv* e, jclass, jlong peer, jlong position, jbyteArray buffer, int offset, int length) { +#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + int fd = (int)peer; + if(::lseek(fd, position, SEEK_SET) == -1) { + throwNewErrno(e, "java/io/IOException"); + return -1; + } + uint8_t* dst = reinterpret_cast (e->GetPrimitiveArrayCritical(buffer, 0)); - memcpy(dst + offset, - reinterpret_cast(peer)->start + position, - length); - + ssize_t bytesRead = ::read(fd, dst + offset, length); e->ReleasePrimitiveArrayCritical(buffer, dst, 0); + + if(bytesRead == -1) { + throwNewErrno(e, "java/io/IOException"); + return -1; + } +#else + HANDLE hFile = (HANDLE)peer; + LARGE_INTEGER lPos; + lPos.QuadPart = position; + if(!SetFilePointerEx(hFile, lPos, nullptr, FILE_BEGIN)) { + throwNewErrno(e, "java/io/IOException"); + return -1; + } + + uint8_t* dst = reinterpret_cast + (e->GetPrimitiveArrayCritical(buffer, 0)); + + DWORD bytesRead = 0; + if(!ReadFile(hFile, dst + offset, length, &bytesRead, nullptr)) { + throwNewErrno(e, "java/io/IOException"); + return -1; + } + e->ReleasePrimitiveArrayCritical(buffer, dst, 0); +#endif + + return (jint)bytesRead; } extern "C" JNIEXPORT void JNICALL -Java_java_io_RandomAccessFile_close(JNIEnv* e, jclass, jlong peer) +Java_java_io_RandomAccessFile_close(JNIEnv* /* e*/, jclass, jlong peer) { - unmap(e, reinterpret_cast(peer)); +#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + int fd = (int)peer; + ::close(fd); +#else + HANDLE hFile = (HANDLE)peer; + CloseHandle(hFile); +#endif } diff --git a/classpath/java-lang.cpp b/classpath/java-lang.cpp index 865f3c3fb4..88a4cf5ef6 100644 --- a/classpath/java-lang.cpp +++ b/classpath/java-lang.cpp @@ -54,33 +54,64 @@ # include "signal.h" # include "sys/time.h" # include "sys/types.h" +# ifndef __ANDROID__ # include "sys/sysctl.h" +# endif # include "sys/utsname.h" # include "sys/wait.h" #endif // not PLATFORM_WINDOWS +#ifndef WINAPI_FAMILY +# ifndef WINAPI_PARTITION_DESKTOP +# define WINAPI_PARTITION_DESKTOP 1 +# endif + +# ifndef WINAPI_FAMILY_PARTITION +# define WINAPI_FAMILY_PARTITION(x) (x) +# endif +#else +# if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + +# include "avian-interop.h" + +# endif +#endif // WINAPI_FAMILY + namespace { #ifdef PLATFORM_WINDOWS - char* getErrorStr(DWORD err){ - // The poor man's error string, just print the error code - char * errStr = (char*) malloc(9 * sizeof(char)); - snprintf(errStr, 9, "%d", (int) err); - return errStr; - - // The better way to do this, if I could figure out how to convert LPTSTR to char* - //char* errStr; - //LPTSTR s; - //if(FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | - // FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, 0, &s, 0, NULL) == 0) - //{ - // errStr.Format("Unknown error occurred (%08x)", err); - //} else { - // errStr = s; - //} - //return errStr; - } +#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + char* getErrorStr(DWORD err) { + LPSTR errorStr = 0; + if(!FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, err, LANG_SYSTEM_DEFAULT, (LPSTR)&errorStr, 0, 0)) + { + char* errStr = (char*) malloc(9 * sizeof(char)); + snprintf(errStr, 9, "%d", (int) err); + return errStr; + } + char* errStr = strdup(errorStr); + LocalFree(errorStr); + return errStr; + } +#else + char* getErrorStr(DWORD err) { + LPSTR errorStr = (LPSTR)malloc(4096); //NOTE: something constant + if(!FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, err, LANG_SYSTEM_DEFAULT, errorStr, 0, 0)) + { + free(errorStr); + + char* errStr = (char*) malloc(9 * sizeof(char)); + snprintf(errStr, 9, "%d", (int) err); + return errStr; + } + char* errStr = strdup(errorStr); + free(errorStr); + return errStr; + } +#endif + +#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) void makePipe(JNIEnv* e, HANDLE p[2]) { SECURITY_ATTRIBUTES sa; @@ -93,6 +124,7 @@ namespace { throwNew(e, "java/io/IOException", getErrorStr(GetLastError())); } } +#endif int descriptor(JNIEnv* e, HANDLE h) { @@ -194,7 +226,7 @@ extern "C" JNIEXPORT void JNICALL Java_java_lang_Runtime_exec(JNIEnv* e, jclass, jobjectArray command, jlongArray process) { - +#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) int size = 0; for (int i = 0; i < e->GetArrayLength(command); ++i){ jstring element = (jstring) e->GetObjectArrayElement(command, i); @@ -265,11 +297,15 @@ Java_java_lang_Runtime_exec(JNIEnv* e, jclass, e->SetLongArrayRegion(process, 0, 1, &pid); jlong tid = reinterpret_cast(pi.hThread); e->SetLongArrayRegion(process, 1, 1, &tid); +#else + throwNew(e, "java/io/Exception", strdup("Not supported on WinRT/WinPhone8")); +#endif } extern "C" JNIEXPORT jint JNICALL Java_java_lang_Runtime_waitFor(JNIEnv* e, jclass, jlong pid, jlong tid) { +#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) DWORD exitCode; WaitForSingleObject(reinterpret_cast(pid), INFINITE); BOOL success = GetExitCodeProcess(reinterpret_cast(pid), &exitCode); @@ -281,14 +317,23 @@ Java_java_lang_Runtime_waitFor(JNIEnv* e, jclass, jlong pid, jlong tid) CloseHandle(reinterpret_cast(tid)); return exitCode; +#else + throwNew(e, "java/io/Exception", strdup("Not supported on WinRT/WinPhone8")); + return -1; +#endif } extern "C" JNIEXPORT void JNICALL -Java_java_lang_Runtime_kill(JNIEnv*, jclass, jlong pid) { +Java_java_lang_Runtime_kill(JNIEnv* e UNUSED, jclass, jlong pid) { +#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) TerminateProcess(reinterpret_cast(pid), 1); +#else + throwNew(e, "java/io/Exception", strdup("Not supported on WinRT/WinPhone8")); +#endif } Locale getLocale() { +#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) const char* lang = ""; const char* reg = ""; unsigned langid = GetUserDefaultUILanguage(); @@ -360,8 +405,23 @@ Locale getLocale() { default: lang = "en"; } + return Locale(lang, reg); +#else + std::wstring culture = AvianInterop::GetCurrentUICulture(); + char* cultureName = strdup(std::string(culture.begin(), culture.end()).c_str()); + char* delimiter = strchr(cultureName, '-'); + if(!delimiter) + { + free(cultureName); + return Locale("en", "US"); + } + const char* lang = cultureName; + const char* reg = delimiter + 1; + *delimiter = 0; Locale locale(lang, reg); + free(cultureName); return locale; +#endif } #else extern "C" JNIEXPORT void JNICALL @@ -529,8 +589,15 @@ Java_java_lang_System_getProperty(JNIEnv* e, jclass, jstring name, } else if (strcmp(chars, "file.separator") == 0) { r = e->NewStringUTF("\\"); } else if (strcmp(chars, "os.name") == 0) { +# if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) r = e->NewStringUTF("Windows"); +# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE) + r = e->NewStringUTF("Windows Phone"); +# else + r = e->NewStringUTF("Windows RT"); +# endif } else if (strcmp(chars, "os.version") == 0) { +# if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) unsigned size = 32; RUNTIME_ARRAY(char, buffer, size); OSVERSIONINFO OSversion; @@ -538,6 +605,10 @@ Java_java_lang_System_getProperty(JNIEnv* e, jclass, jstring name, ::GetVersionEx(&OSversion); snprintf(RUNTIME_ARRAY_BODY(buffer), size, "%i.%i", (int)OSversion.dwMajorVersion, (int)OSversion.dwMinorVersion); r = e->NewStringUTF(RUNTIME_ARRAY_BODY(buffer)); +# else + // Currently there is no alternative on WinRT/WP8 + r = e->NewStringUTF("8.0"); +# endif } else if (strcmp(chars, "os.arch") == 0) { #ifdef ARCH_x86_32 r = e->NewStringUTF("x86"); @@ -549,15 +620,26 @@ Java_java_lang_System_getProperty(JNIEnv* e, jclass, jstring name, r = e->NewStringUTF("arm"); #endif } else if (strcmp(chars, "java.io.tmpdir") == 0) { +# if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) TCHAR buffer[MAX_PATH]; GetTempPath(MAX_PATH, buffer); r = e->NewStringUTF(buffer); +# else + std::wstring tmpDir = AvianInterop::GetTemporaryFolder(); + r = e->NewString((const jchar*)tmpDir.c_str(), tmpDir.length()); +# endif } else if (strcmp(chars, "user.dir") == 0) { +# if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) TCHAR buffer[MAX_PATH]; GetCurrentDirectory(MAX_PATH, buffer); r = e->NewStringUTF(buffer); +# else + std::wstring userDir = AvianInterop::GetInstalledLocation(); + r = e->NewString((const jchar*)userDir.c_str(), userDir.length()); +# endif } else if (strcmp(chars, "user.home") == 0) { # ifdef _MSC_VER +# if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) WCHAR buffer[MAX_PATH]; size_t needed; if (_wgetenv_s(&needed, buffer, MAX_PATH, L"USERPROFILE") == 0) { @@ -565,6 +647,10 @@ Java_java_lang_System_getProperty(JNIEnv* e, jclass, jstring name, } else { r = 0; } +# else + std::wstring userHome = AvianInterop::GetDocumentsLibraryLocation(); + r = e->NewString((const jchar*)userHome.c_str(), userHome.length()); +# endif # else LPWSTR home = _wgetenv(L"USERPROFILE"); r = e->NewString(reinterpret_cast(home), lstrlenW(home)); @@ -652,6 +738,9 @@ namespace { #elif defined __APPLE__ # include # define environ (*_NSGetEnviron()) +#elif defined(WINAPI_FAMILY) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +// WinRT/WP8 does not provide alternative for environment variables +char* environ[] = { 0 }; #else extern char** environ; #endif @@ -785,6 +874,54 @@ Java_java_lang_Math_cos(JNIEnv*, jclass, jdouble val) return cos(val); } +extern "C" JNIEXPORT jdouble JNICALL +Java_java_lang_Math_tan(JNIEnv*, jclass, jdouble val) +{ + return tan(val); +} + +extern "C" JNIEXPORT jdouble JNICALL +Java_java_lang_Math_asin(JNIEnv*, jclass, jdouble val) +{ + return asin(val); +} + +extern "C" JNIEXPORT jdouble JNICALL +Java_java_lang_Math_acos(JNIEnv*, jclass, jdouble val) +{ + return acos(val); +} + +extern "C" JNIEXPORT jdouble JNICALL +Java_java_lang_Math_atan(JNIEnv*, jclass, jdouble val) +{ + return atan(val); +} + +extern "C" JNIEXPORT jdouble JNICALL +Java_java_lang_Math_atan2(JNIEnv*, jclass, jdouble y, jdouble x) +{ + return atan2(y, x); +} + +extern "C" JNIEXPORT jdouble JNICALL +Java_java_lang_Math_sinh(JNIEnv*, jclass, jdouble val) +{ + return sinh(val); +} + +extern "C" JNIEXPORT jdouble JNICALL +Java_java_lang_Math_cosh(JNIEnv*, jclass, jdouble val) +{ + return cosh(val); +} + +extern "C" JNIEXPORT jdouble JNICALL +Java_java_lang_Math_tanh(JNIEnv*, jclass, jdouble val) +{ + return tanh(val); +} + extern "C" JNIEXPORT jdouble JNICALL Java_java_lang_Math_sqrt(JNIEnv*, jclass, jdouble val) { @@ -797,6 +934,12 @@ Java_java_lang_Math_pow(JNIEnv*, jclass, jdouble val, jdouble exp) return pow(val, exp); } +extern "C" JNIEXPORT jdouble JNICALL +Java_java_lang_Math_log(JNIEnv*, jclass, jdouble val) +{ + return log(val); +} + extern "C" JNIEXPORT jdouble JNICALL Java_java_lang_Math_floor(JNIEnv*, jclass, jdouble val) { diff --git a/classpath/java/io/File.java b/classpath/java/io/File.java index b66aa03ff9..8eceed4b71 100644 --- a/classpath/java/io/File.java +++ b/classpath/java/io/File.java @@ -294,12 +294,19 @@ public class File implements Serializable { } } + public long lastModified() { + return lastModified(path); + } private static native long openDir(String path); + private static native long lastModified(String path); + private static native String readDir(long handle); private static native long closeDir(long handle); + + private static class Pair { public final String value; public final Pair next; diff --git a/classpath/java/io/RandomAccessFile.java b/classpath/java/io/RandomAccessFile.java index b6e88dd00e..da9a8356b6 100644 --- a/classpath/java/io/RandomAccessFile.java +++ b/classpath/java/io/RandomAccessFile.java @@ -10,6 +10,8 @@ package java.io; +import java.lang.IllegalArgumentException; + public class RandomAccessFile { private long peer; private File file; @@ -56,26 +58,68 @@ public class RandomAccessFile { this.position = position; } - public void readFully(byte[] buffer, int offset, int length) - throws IOException - { - if (peer == 0) throw new IOException(); - - if (length == 0) return; - - if (position + length > this.length) { - if (position + length > length()) throw new EOFException(); - } - - if (offset < 0 || offset + length > buffer.length) + public int skipBytes(int count) throws IOException { + if (position + count > length()) throw new IOException(); + this.position = position + count; + return count; + } + + public int read(byte b[], int off, int len) throws IOException { + if(b == null) + throw new IllegalArgumentException(); + if (peer == 0) + throw new IOException(); + if(len == 0) + return 0; + if (position + len > this.length) + throw new EOFException(); + if (off < 0 || off + len > b.length) throw new ArrayIndexOutOfBoundsException(); - - copy(peer, position, buffer, offset, length); - - position += length; + int bytesRead = readBytes(peer, position, b, off, len); + position += bytesRead; + return bytesRead; + } + + public int read(byte b[]) throws IOException { + if(b == null) + throw new IllegalArgumentException(); + if (peer == 0) + throw new IOException(); + if(b.length == 0) + return 0; + if (position + b.length > this.length) + throw new EOFException(); + int bytesRead = readBytes(peer, position, b, 0, b.length); + position += bytesRead; + return bytesRead; } - private static native void copy(long peer, long position, byte[] buffer, + public void readFully(byte b[], int off, int len) throws IOException { + if(b == null) + throw new IllegalArgumentException(); + if (peer == 0) + throw new IOException(); + if(len == 0) + return; + if (position + len > this.length) + throw new EOFException(); + if (off < 0 || off + len > b.length) + throw new ArrayIndexOutOfBoundsException(); + int n = 0; + do { + int count = readBytes(peer, position, b, off + n, len - n); + position += count; + if (count == 0) + throw new EOFException(); + n += count; + } while (n < len); + } + + public void readFully(byte b[]) throws IOException { + readFully(b, 0, b.length); + } + + private static native int readBytes(long peer, long position, byte[] buffer, int offset, int length); public void close() throws IOException { diff --git a/classpath/java/lang/Math.java b/classpath/java/lang/Math.java index 44eea9db17..5f4933244d 100644 --- a/classpath/java/lang/Math.java +++ b/classpath/java/lang/Math.java @@ -93,6 +93,12 @@ public final class Math { public static native double tan(double v); + public static native double cosh(double v); + + public static native double sinh(double v); + + public static native double tanh(double v); + public static native double acos(double v); public static native double asin(double v); diff --git a/makefile b/makefile index e679fd7d97..f62fcb2346 100755 --- a/makefile +++ b/makefile @@ -55,8 +55,10 @@ ifeq ($(codegen-targets),all) options := $(options)-all endif +aot-only = false root := $(shell (cd .. && pwd)) build = build/$(platform)-$(arch)$(options) +host-build-root = $(build)/host classpath-build = $(build)/classpath test-build = $(build)/test src = src @@ -64,6 +66,8 @@ classpath-src = classpath test = test win32 ?= $(root)/win32 win64 ?= $(root)/win64 +winrt ?= $(root)/winrt +wp8 ?= $(root)/wp8 classpath = avian @@ -138,7 +142,7 @@ ifneq ($(openjdk),) javahome = "$$($(native-path) "$(openjdk)/jre")" endif - classpath = openjdk + classpath = openjdk boot-classpath := "$(boot-classpath)$(path-separator)$$($(native-path) "$(openjdk)/jre/lib/rt.jar")" build-javahome = $(openjdk)/jre endif @@ -180,7 +184,7 @@ dlltool = dlltool vg = nice valgrind --num-callers=32 --db-attach=yes --freelist-vol=100000000 vg += --leak-check=full --suppressions=valgrind.supp db = gdb --args -javac = "$(JAVA_HOME)/bin/javac" +javac = "$(JAVA_HOME)/bin/javac" -encoding UTF-8 javah = "$(JAVA_HOME)/bin/javah" jar = "$(JAVA_HOME)/bin/jar" strip = strip @@ -188,6 +192,18 @@ strip-all = --strip-all rdynamic = -rdynamic +cflags_debug = -O0 -g3 +cflags_debug_fast = -O0 -g3 +cflags_stress = -O0 -g3 +cflags_stress_major = -O0 -g3 +ifeq ($(use-clang),true) + cflags_fast = -O4 -g3 + cflags_small = -Oz -g3 +else + cflags_fast = -O3 -g3 + cflags_small = -Os -g3 +endif + # note that we suppress the non-virtual-dtor warning because we never # use the delete operator, which means we don't need virtual # destructors: @@ -203,7 +219,7 @@ common-cflags = $(warnings) -fno-rtti -fno-exceptions -I$(classpath-src) \ -DUSE_ATOMIC_OPERATIONS -DAVIAN_JAVA_HOME=\"$(javahome)\" \ -DAVIAN_EMBED_PREFIX=\"$(embed-prefix)\" $(target-cflags) -asmflags = $(target-cflags) +asmflags = $(target-cflags) -I$(src) ifneq (,$(filter i386 x86_64,$(arch))) ifeq ($(use-frame-pointer),true) @@ -242,13 +258,29 @@ pointer-size = 8 so-prefix = lib so-suffix = .so +static-prefix = lib +static-suffix = .a + +output = -o $(1) +asm-output = -o $(1) +asm-input = -c $(1) +asm-format = S +as = $(cc) +ld = $(cxx) +build-ld = $(build-cc) + +static = -static shared = -shared +rpath = -Wl,-rpath=\$$ORIGIN -Wl,-z,origin + no-error = -Wno-error openjdk-extra-cflags = -fvisibility=hidden bootimage-cflags = -DTARGET_BYTES_PER_WORD=$(pointer-size) +bootimage-symbols = _binary_bootimage_bin_start:_binary_bootimage_bin_end +codeimage-symbols = _binary_codeimage_bin_start:_binary_codeimage_bin_end developer-dir := $(shell if test -d /Developer; then echo /Developer; \ else echo /Applications/Xcode.app/Contents/Developer; fi) @@ -358,6 +390,70 @@ ifeq ($(platform),freebsd) "-I$(JAVA_HOME)/include/freebsd" -I$(src) -pthread cflags = $(build-cflags) endif +ifeq ($(platform),android) + ifeq ($(build-platform),cygwin) + ndk = "$$(cygpath -u "$(ANDROID_NDK)")" + else + ndk = $(ANDROID_NDK) + endif + + ifeq ($(android-version),) + android-version = 5 + endif + + ifeq ($(android-toolchain),) + android-toolchain = 4.7 + endif + + ifeq ($(arch),arm) + android-toolchain-name = arm-linux-androideabi + android-toolchain-prefix = arm-linux-androideabi- + endif + ifeq ($(arch),i386) + android-toolchain-name = x86 + android-toolchain-prefix = i686-linux-android- + endif + + ifeq ($(android-arm-arch),) + android-arm-arch = armv5 + endif + + options := $(options)-api$(android-version)-$(android-toolchain)-$(android-arm-arch) + + build-cflags = $(common-cflags) -I$(src) + build-lflags = -lz -lpthread + ifeq ($(subst cygwin,windows,$(subst mingw32,windows,$(build-platform))),windows) + toolchain-host-platform = $(subst cygwin,windows,$(subst mingw32,windows,$(build-platform))) + build-system = windows + build-cxx = i686-w64-mingw32-g++ + build-cc = i686-w64-mingw32-gcc + sysroot = "$$(cygpath -w "$(ndk)/platforms/android-$(android-version)/arch-arm")" + build-cflags += "-I$(JAVA_HOME)/include/win32" + else + toolchain-host-platform = $(subst cygwin,windows,$(subst mingw32,windows,$(build-platform)))-* + sysroot = $(ndk)/platforms/android-$(android-version)/arch-arm + build-cflags += "-I$(JAVA_HOME)/include/linux" + build-lflags += -ldl + endif + toolchain = $(ndk)/toolchains/$(android-toolchain-name)-$(android-toolchain)/prebuilt/$(toolchain-host-platform) + cflags = "-I$(sysroot)/usr/include" "-I$(JAVA_HOME)/include/linux" $(common-cflags) "-I$(src)" -std=c++11 $(no-psabi) + lflags = "-L$(sysroot)/usr/lib" $(common-lflags) -llog + target-format = elf + use-lto = false + + ifeq ($(arch),arm) + cflags += -marm -march=$(android-arm-arch) -ftree-vectorize -ffast-math -mfloat-abi=softfp + endif + ifeq ($(arch),i386) + endif + + cxx = $(toolchain)/bin/$(android-toolchain-prefix)g++ --sysroot="$(sysroot)" + cc = $(toolchain)/bin/$(android-toolchain-prefix)gcc --sysroot="$(sysroot)" + as = $(cxx) + ar = $(toolchain)/bin/$(android-toolchain-prefix)ar + ranlib = $(toolchain)/bin/$(android-toolchain-prefix)ranlib + strip = $(toolchain)/bin/$(android-toolchain-prefix)strip +endif ifeq ($(platform),darwin) target-format = macho @@ -396,6 +492,7 @@ ifeq ($(platform),darwin) strip-all = -S -x so-suffix = .dylib shared = -dynamiclib + rpath = sdk-dir = $(developer-dir)/Platforms/iPhoneOS.platform/Developer/SDKs @@ -443,20 +540,23 @@ ifeq ($(platform),darwin) endif ifeq ($(platform),windows) - target-format = pe + ifeq ($(target-format),) + target-format = pe + endif inc = "$(win32)/include" lib = "$(win32)/lib" embed-prefix = c:/avian-embedded - system = windows so-prefix = so-suffix = .dll exe-suffix = .exe + rpath = - lflags = -L$(lib) $(common-lflags) -lws2_32 -liphlpapi -mwindows -mconsole + lflags = -L$(lib) $(common-lflags) -lws2_32 -liphlpapi -mconsole + bootimage-generator-lflags = -static-libstdc++ -static-libgcc cflags = -I$(inc) $(common-cflags) -DWINVER=0x0500 ifeq (,$(filter mingw32 cygwin,$(build-platform))) @@ -502,89 +602,217 @@ ifeq ($(platform),windows) shared += -Wl,--add-stdcall-alias endif - embed = $(build-embed)/embed.exe - embed-loader = $(build-embed-loader)/embed-loader.exe + embed = $(build-embed)/embed$(exe-suffix) + embed-loader = $(build-embed-loader)/embed-loader$(exe-suffix) embed-loader-o = $(build-embed)/embed-loader.o endif -ifeq ($(mode),debug) - optimization-cflags = -O0 -g3 - converter-cflags += -O0 -g3 - strip = : -endif -ifeq ($(mode),debug-fast) - optimization-cflags = -O0 -g3 -DNDEBUG - strip = : -endif -ifeq ($(mode),stress) - optimization-cflags = -O0 -g3 -DVM_STRESS - strip = : -endif -ifeq ($(mode),stress-major) - optimization-cflags = -O0 -g3 -DVM_STRESS -DVM_STRESS_MAJOR - strip = : -endif -ifeq ($(mode),fast) - ifeq ($(use-clang),true) - optimization-cflags = -O4 -g3 -DNDEBUG +ifeq ($(platform),wp8) + ifeq ($(shell uname -s | grep -i -c WOW64),1) + programFiles = Program Files (x86) else - optimization-cflags = -O3 -g3 -DNDEBUG + programFiles = Program Files endif - use-lto = true -endif -ifeq ($(mode),small) - ifeq ($(use-clang),true) - optimization-cflags = -Oz -g3 -DNDEBUG + ifeq ($(MSVS_ROOT),) + # Environment variable MSVS_ROOT not found. It should be something like + # "C:\$(programFiles)\Microsoft Visual Studio 11.0" + MSVS_ROOT = C:\$(programFiles)\Microsoft Visual Studio 11.0 + endif + ifeq ($(MSVC_ROOT),) + # Environment variable MSVC_ROOT not found. It should be something like + # "C:\$(programFiles)\Microsoft Visual Studio 11.0\VC" + MSVC_ROOT = $(MSVS_ROOT)\VC + endif + ifeq ($(WP80_SDK),) + # Environment variable WP8_SDK not found. It should be something like + # "C:\Program Files[ (x86)]\Microsoft Visual Studio 11.0\VC\WPSDK\WP80" + # TODO: Lookup in SOFTWARE\Microsoft\Microsoft SDKs\WindowsPhone\v8.0 + WP80_SDK = $(MSVS_ROOT)\VC\WPSDK\WP80 + endif + ifeq ($(WP80_KIT),) + # Environment variable WP8_KIT not found. It should be something like + # "c:\Program Files[ (x86)]\Windows Phone Kits\8.0" + # TODO: Lookup in SOFTWARE\Microsoft\Microsoft SDKs\WindowsPhone\v8.0 + WP80_KIT = C:\$(programFiles)\Windows Phone Kits\8.0 + endif + ifeq ($(WIN8_KIT),) + # Environment variable WIN8_KIT not found. It should be something like + # "c:\Program Files[ (x86)]\Windows Kits\8.0" + WIN8_KIT = C:\$(programFiles)\Windows Kits\8.0 + endif + ifeq ($(build-platform),cygwin) + windows-path = cygpath -w else - optimization-cflags = -Os -g3 -DNDEBUG + windows-path = $(native-path) endif - use-lto = true -endif + windows-java-home := $(shell $(windows-path) "$(JAVA_HOME)") + target-format = pe + ms_cl_compiler = wp8 + use-lto = false + supports_avian_executable = false + aot-only = true + ifneq ($(bootimage),true) + x := $(error Windows Phone 8 target requires bootimage=true) + endif + system = windows + build-system = windows + static-prefix = + static-suffix = .lib + so-prefix = + so-suffix = .dll + exe-suffix = .exe + manifest-flags = -MANIFEST:NO -ifeq ($(use-lto),true) - ifeq ($(use-clang),true) - optimization-cflags += -flto - lflags += $(optimization-cflags) - else -# only try to use LTO when GCC 4.6.0 or greater is available - gcc-major := $(shell $(cc) -dumpversion | cut -f1 -d.) - gcc-minor := $(shell $(cc) -dumpversion | cut -f2 -d.) - ifeq ($(shell expr 4 \< $(gcc-major) \ - \| \( 4 \<= $(gcc-major) \& 6 \<= $(gcc-minor) \)),1) - optimization-cflags += -flto - no-lto = -fno-lto - lflags += $(optimization-cflags) + ifeq ($(arch),arm) + wp8_arch = \x86_arm + vc_arch = \arm + w8kit_arch = arm + deps_arch = ARM + as = "$$(cygpath -u "$(WP80_SDK)\bin\x86_arm\armasm.exe")" + cxx = "$$(cygpath -u "$(WP80_SDK)\bin\x86_arm\cl.exe")" + ld = "$$(cygpath -u "$(WP80_SDK)\bin\x86_arm\link.exe")" + asmflags = -machine ARM -32 + asm-output = -o $(1) + asm-input = $(1) + machine_type = ARM + bootimage-symbols = binary_bootimage_bin_start:binary_bootimage_bin_end + codeimage-symbols = binary_codeimage_bin_start:binary_codeimage_bin_end + endif + ifeq ($(arch),i386) + wp8_arch = + vc_arch = + w8kit_arch = x86 + deps_arch = x86 + asmflags = $(target-cflags) -safeseh -nologo -Gd + as = "$$(cygpath -u "$(WP80_SDK)\bin\ml.exe")" + cxx = "$$(cygpath -u "$(WP80_SDK)\bin\cl.exe")" + ld = "$$(cygpath -u "$(WP80_SDK)\bin\link.exe")" + ifeq ($(mode),debug) + asmflags += -Zd endif + ifeq ($(mode),debug-fast) + asmflags += -Zd + endif + asm-output = $(output) + machine_type = X86 endif + + PATH := $(shell cygpath -u "$(MSVS_ROOT)\Common7\IDE"):$(shell cygpath -u "$(WP80_SDK)\bin$(wp8_arch)"):$(shell cygpath -u "$(WP80_SDK)\bin"):${PATH} + + build-cflags = $(common-cflags) -I$(src) -I$(inc) -mthreads + build-lflags = -lz -lpthread + + cflags = -nologo \ + -AI"$(WP80_KIT)\Windows Metadata" \ + -I"$(WP80_SDK)\include" -I"$(WP80_KIT)\Include" -I"$(WP80_KIT)\Include\minwin" -I"$(WP80_KIT)\Include\mincore" \ + -DWINAPI_FAMILY=WINAPI_FAMILY_PHONE_APP -D_USRDLL -D_WINDLL \ + -DAVIAN_VERSION=\"$(version)\" -D_JNI_IMPLEMENTATION_ \ + -DUSE_ATOMIC_OPERATIONS -DAVIAN_JAVA_HOME=\"$(javahome)\" \ + -DAVIAN_EMBED_PREFIX=\"$(embed-prefix)\" \ + -I"$(shell $(windows-path) "$(wp8)/zlib/upstream")" -I"$(shell $(windows-path) "$(wp8)/interop/avian-interop-client")" \ + -I"$(shell $(windows-path) "$(wp8)/include")" -I$(src) -I$(classpath-src) \ + -I"$(build)" \ + -I"$(windows-java-home)/include" -I"$(windows-java-home)/include/win32" \ + -DTARGET_BYTES_PER_WORD=$(pointer-size) \ + -Gd -EHsc + + common-lflags = $(classpath-lflags) + + ifeq ($(mode),debug) + build-type = Debug + endif + ifeq ($(mode),debug-fast) + build-type = Debug + endif + ifeq ($(mode),stress_major) + build-type = Release + endif + ifeq ($(mode),fast) + build-type = Release + endif + ifeq ($(mode),fast) + build-type = Release + endif + ifeq ($(mode),small) + build-type = Release + endif + + arflags = -MACHINE:$(machine_type) + lflags = $(common-lflags) -nologo \ + -MACHINE:$(machine_type) \ + -LIBPATH:"$(WP80_KIT)\lib\$(w8kit_arch)" -LIBPATH:"$(WP80_SDK)\lib$(vc_arch)" -LIBPATH:"$(WIN8_KIT)\Lib\win8\um\$(w8kit_arch)" \ + ws2_32.lib \ + "$(shell $(windows-path) "$(wp8)\lib\$(deps_arch)\$(build-type)\zlib.lib")" "$(shell $(windows-path) "$(wp8)\lib\$(deps_arch)\$(build-type)\ThreadEmulation.lib")" \ + "$(shell $(windows-path) "$(wp8)\lib\$(deps_arch)\$(build-type)\AvianInteropClient.lib")" + lflags += -NXCOMPAT -DYNAMICBASE -SUBSYSTEM:CONSOLE -TLBID:1 + lflags += -NODEFAULTLIB:"ole32.lib" -NODEFAULTLIB:"kernel32.lib" + lflags += PhoneAppModelHost.lib WindowsPhoneCore.lib -WINMD -WINMDFILE:$(subst $(so-suffix),.winmd,$(@)) + + cc = $(cxx) + asm-format = masm + shared = -dll + ar = "$$(cygpath -u "$(WP80_SDK)\bin\lib.exe")" + arflags += -nologo + ifeq ($(build-platform),cygwin) + build-cxx = i686-w64-mingw32-g++ + build-cc = i686-w64-mingw32-gcc + dlltool = i686-w64-mingw32-dlltool + ranlib = + strip = + endif + output = -Fo$(1) + + #TODO: -MT or -ZW? + cflags_debug = -Od -Zi -MDd + cflags_debug_fast = -Od -Zi -MDd + cflags_stress = -O0 -g3 -MD + cflags_stress_major = -O0 -g3 -MD + cflags_fast = -O2 -Zi -MD + cflags_small = -O1s -Zi -MD + # -GL [whole program optimization] in 'fast' and 'small' breaks compilation for some reason + + ifeq ($(mode),debug) + cflags += + lflags += + endif + ifeq ($(mode),debug-fast) + cflags += -DNDEBUG + lflags += + endif + ifeq ($(mode),stress_major) + cflags += + lflags += + endif + ifeq ($(mode),fast) + cflags += + lflags += + endif + # -LTCG is needed only if -GL is used + ifeq ($(mode),fast) + cflags += -DNDEBUG + lflags += -LTCG + arflags += + endif + ifeq ($(mode),small) + cflags += -DNDEBUG + lflags += -LTCG + arflags += + endif + + strip = : endif -cflags += $(optimization-cflags) - -ifneq ($(platform),darwin) -ifeq ($(arch),i386) -# this is necessary to support __sync_bool_compare_and_swap: - cflags += -march=i586 - lflags += -march=i586 -endif -endif - -output = -o $(1) -as := $(cc) -ld := $(cc) -build-ld := $(build-cc) - -static = -static - ifdef msvc - static = no-error = windows-path = $(native-path) windows-java-home := $(shell $(windows-path) "$(JAVA_HOME)") zlib := $(shell $(windows-path) "$(win32)/msvc") + ms_cl_compiler = regular cxx = "$(msvc)/BIN/cl.exe" cc = $(cxx) ld = "$(msvc)/BIN/link.exe" mt = "mt.exe" + manifest-flags = -MANIFEST -MANIFESTFILE:$(@).manifest cflags = -nologo -DAVIAN_VERSION=\"$(version)\" -D_JNI_IMPLEMENTATION_ \ -DUSE_ATOMIC_OPERATIONS -DAVIAN_JAVA_HOME=\"$(javahome)\" \ -DAVIAN_EMBED_PREFIX=\"$(embed-prefix)\" \ @@ -593,7 +821,7 @@ ifdef msvc -I"$(windows-java-home)/include" -I"$(windows-java-home)/include/win32" \ -DTARGET_BYTES_PER_WORD=$(pointer-size) - ifneq ($(lzma),) + ifneq ($(lzma),) cflags += -I$(shell $(windows-path) "$(lzma)") endif @@ -620,9 +848,70 @@ ifdef msvc strip = : endif +ifeq ($(mode),debug) + optimization-cflags = $(cflags_debug) + converter-cflags += $(cflags_debug) + strip = : +endif +ifeq ($(mode),debug-fast) + optimization-cflags = $(cflags_debug_fast) -DNDEBUG + strip = : +endif +ifeq ($(mode),stress) + optimization-cflags = $(cflags_stress) -DVM_STRESS + strip = : +endif +ifeq ($(mode),stress-major) + optimization-cflags = $(cflags_stress_major) -DVM_STRESS -DVM_STRESS_MAJOR + strip = : +endif +ifeq ($(mode),fast) + optimization-cflags = $(cflags_fast) -DNDEBUG + ifeq ($(use-lto),) + use-lto = true + endif +endif +ifeq ($(mode),small) + optimization-cflags = $(cflags_small) -DNDEBUG + ifeq ($(use-lto),) + use-lto = true + endif +endif + +ifeq ($(use-lto),true) + ifeq ($(use-clang),true) + optimization-cflags += -flto + lflags += $(optimization-cflags) + else +# only try to use LTO when GCC 4.6.0 or greater is available + gcc-major := $(shell $(cc) -dumpversion | cut -f1 -d.) + gcc-minor := $(shell $(cc) -dumpversion | cut -f2 -d.) + ifeq ($(shell expr 4 \< $(gcc-major) \ + \| \( 4 \<= $(gcc-major) \& 6 \<= $(gcc-minor) \)),1) + optimization-cflags += -flto + no-lto = -fno-lto + lflags += $(optimization-cflags) + endif + endif +endif + +cflags += $(optimization-cflags) + +ifndef ms_cl_compiler +ifneq ($(platform),darwin) +ifeq ($(arch),i386) +# this is necessary to support __sync_bool_compare_and_swap: + cflags += -march=i586 + lflags += -march=i586 +endif +endif +endif + +build-cflags += -DAVIAN_HOST_TARGET + c-objects = $(foreach x,$(1),$(patsubst $(2)/%.c,$(3)/%.o,$(x))) cpp-objects = $(foreach x,$(1),$(patsubst $(2)/%.cpp,$(3)/%.o,$(x))) -asm-objects = $(foreach x,$(1),$(patsubst $(2)/%.S,$(3)/%-asm.o,$(x))) +asm-objects = $(foreach x,$(1),$(patsubst $(2)/%.$(asm-format),$(3)/%-asm.o,$(x))) java-classes = $(foreach x,$(1),$(patsubst $(2)/%.java,$(3)/%.class,$(x))) generated-code = \ @@ -648,7 +937,7 @@ vm-sources = \ $(src)/jnienv.cpp \ $(src)/process.cpp -vm-asm-sources = $(src)/$(asm).S +vm-asm-sources = $(src)/$(asm).$(asm-format) target-asm = $(asm) @@ -677,7 +966,11 @@ ifeq ($(process),compile) $(src)/codegen/powerpc/assembler.cpp endif - vm-asm-sources += $(src)/compile-$(asm).S + vm-asm-sources += $(src)/compile-$(asm).$(asm-format) +endif +cflags += -DAVIAN_PROCESS_$(process) +ifeq ($(aot-only),true) + cflags += -DAVIAN_AOT_ONLY endif vm-cpp-objects = $(call cpp-objects,$(vm-sources),$(src),$(build)) @@ -810,10 +1103,10 @@ converter-objects = $(call cpp-objects,$(converter-sources),$(src),$(build)) converter-tool-objects = $(call cpp-objects,$(converter-tool-sources),$(src),$(build)) converter = $(build)/binaryToObject/binaryToObject -static-library = $(build)/lib$(name).a +static-library = $(build)/$(static-prefix)$(name)$(static-suffix) executable = $(build)/$(name)${exe-suffix} dynamic-library = $(build)/$(so-prefix)jvm$(so-suffix) -executable-dynamic = $(build)/$(name)-dynamic${exe-suffix} +executable-dynamic = $(build)/$(name)-dynamic$(exe-suffix) ifneq ($(classpath),avian) # Assembler, ConstantPool, and Stream are not technically needed for a @@ -920,9 +1213,15 @@ test-flags = -Djava.library.path=$(build) -cp $(build)/test test-args = $(test-flags) $(input) .PHONY: build +ifneq ($(supports_avian_executable),false) build: $(static-library) $(executable) $(dynamic-library) $(lzma-loader) \ $(lzma-encoder) $(executable-dynamic) $(classpath-dep) $(test-dep) \ $(test-extra-dep) $(embed) +else +build: $(static-library) $(dynamic-library) $(lzma-loader) \ + $(lzma-encoder) $(classpath-dep) $(test-dep) \ + $(test-extra-dep) $(embed) +endif $(test-dep): $(classpath-dep) @@ -962,12 +1261,24 @@ javadoc: -header "Avian v$(version)" \ -bottom "http://oss.readytalk.com/avian" +.PHONY: clean-current +clean-current: + @echo "removing $(build)" + rm -rf $(build) + .PHONY: clean clean: + @echo "removing $(build)" + rm -rf $(build) + +.PHONY: clean-all +clean-all: @echo "removing build" rm -rf build -$(build)/compile-x86-asm.o: $(src)/continuations-x86.S +ifeq ($(continuations),true) +$(build)/compile-x86-asm.o: $(src)/continuations-x86.$(asm-format) +endif gen-arg = $(shell echo $(1) | sed -e 's:$(build)/type-\(.*\)\.cpp:\1:') $(generated-code): %.cpp: $(src)/types.def $(generator) $(classpath-dep) @@ -1018,7 +1329,7 @@ endef define compile-asm-object @echo "compiling $(@)" @mkdir -p $(dir $(@)) - $(as) -I$(src) $(asmflags) -c $(<) -o $(@) + $(as) $(asmflags) $(call asm-output,$(@)) $(call asm-input,$(<)) endef $(vm-cpp-objects): $(build)/%.o: $(src)/%.cpp $(vm-depends) @@ -1029,10 +1340,13 @@ $(test-cpp-objects): $(test-build)/%.o: $(test)/%.cpp $(vm-depends) $(test-library): $(test-cpp-objects) @echo "linking $(@)" -ifdef msvc - $(ld) $(shared) $(lflags) $(^) -out:$(@) -PDB:$(@).pdb \ - -IMPLIB:$(test-build)/$(name).lib -MANIFESTFILE:$(@).manifest - $(mt) -manifest $(@).manifest -outputresource:"$(@);2" +ifdef ms_cl_compiler + $(ld) $(shared) $(lflags) $(^) -out:$(@) \ + -debug -PDB:$(subst $(so-suffix),.pdb,$(@)) \ + -IMPLIB:$(test-build)/$(name).lib $(manifest-flags) +ifdef mt + $(mt) -nologo -manifest $(@).manifest -outputresource:"$(@);2" +endif else $(ld) $(^) $(shared) $(lflags) -o $(@) endif @@ -1040,10 +1354,12 @@ endif ifdef embed $(embed): $(embed-objects) $(embed-loader-o) @echo "building $(embed)" -ifdef msvc - $(ld) $(lflags) $(^) -out:$(@) -PDB:$(@).pdb \ - -IMPLIB:$(@).lib -MANIFESTFILE:$(@).manifest - $(mt) -manifest $(@).manifest -outputresource:"$(@);1" +ifdef ms_cl_compiler + $(ld) $(lflags) $(^) -out:$(@) \ + -debug -PDB:$(subst $(exe-suffix),.pdb,$(@)) $(manifest-flags) +ifdef mt + $(mt) -nologo -manifest $(@).manifest -outputresource:"$(@);1" +endif else $(cxx) $(^) $(lflags) $(static) $(call output,$(@)) endif @@ -1061,10 +1377,12 @@ $(embed-loader-o): $(embed-loader) $(converter) $(embed-loader): $(embed-loader-objects) $(static-library) @mkdir -p $(dir $(@)) cd $(dir $(@)) && $(ar) x ../../../$(static-library) -ifdef msvc - $(ld) $(lflags) $(dir $(@))/*.o -out:$(@) -PDB:$(@).pdb \ - -IMPLIB:$(@).lib -MANIFESTFILE:$(@).manifest - $(mt) -manifest $(@).manifest -outputresource:"$(@);1" +ifdef ms_cl_compiler + $(ld) $(lflags) $(dir $(@))/*.o -out:$(@) \ + -debug -PDB:$(subst $(exe-suffix),.pdb,$(@)) $(manifest-flags) +ifdef mt + $(mt) -nologo -manifest $(@).manifest -outputresource:"$(@);1" +endif else $(dlltool) -z $(addsuffix .def,$(basename $(@))) $(dir $(@))/*.o $(dlltool) -d $(addsuffix .def,$(basename $(@))) -e $(addsuffix .exp,$(basename $(@))) @@ -1084,7 +1402,7 @@ $(build)/%.o: $(lzma)/C/%.c @mkdir -p $(dir $(@)) $(cxx) $(cflags) $(no-error) -c $$($(windows-path) $(<)) $(call output,$(@)) -$(vm-asm-objects): $(build)/%-asm.o: $(src)/%.S +$(vm-asm-objects): $(build)/%-asm.o: $(src)/%.$(asm-format) $(compile-asm-object) $(bootimage-generator-objects): $(build)/%.o: $(src)/%.cpp $(vm-depends) @@ -1171,14 +1489,19 @@ $(static-library): $(vm-objects) $(classpath-objects) $(vm-heapwalk-objects) \ $(javahome-object) $(boot-javahome-object) $(lzma-decode-objects) @echo "creating $(@)" rm -rf $(@) +ifdef ms_cl_compiler + $(ar) $(arflags) $(^) -out:$(@) +else $(ar) cru $(@) $(^) $(ranlib) $(@) +endif $(bootimage-object) $(codeimage-object): $(bootimage-generator) \ - $(build)/classpath.jar + $(openjdk-jar-dep) + @echo "generating bootimage and codeimage binaries from $(classpath-build) using $(<)" $(<) -cp $(classpath-build) -bootimage $(bootimage-object) -codeimage $(codeimage-object) \ - -bootimage-symbols _binary_bootimage_bin_start:_binary_bootimage_bin_end \ - -codeimage-symbols _binary_codeimage_bin_start:_binary_codeimage_bin_end + -bootimage-symbols $(bootimage-symbols) \ + -codeimage-symbols $(codeimage-symbols) executable-objects = $(vm-objects) $(classpath-objects) $(driver-object) \ $(vm-heapwalk-objects) $(boot-object) $(vm-classpath-objects) \ @@ -1187,10 +1510,12 @@ executable-objects = $(vm-objects) $(classpath-objects) $(driver-object) \ $(executable): $(executable-objects) @echo "linking $(@)" ifeq ($(platform),windows) -ifdef msvc - $(ld) $(lflags) $(executable-objects) -out:$(@) -PDB:$(@).pdb \ - -IMPLIB:$(@).lib -MANIFESTFILE:$(@).manifest - $(mt) -manifest $(@).manifest -outputresource:"$(@);1" +ifdef ms_cl_compiler + $(ld) $(lflags) $(executable-objects) -out:$(@) \ + -debug -PDB:$(subst $(exe-suffix),.pdb,$(@)) $(manifest-flags) +ifdef mt + $(mt) -nologo -manifest $(@).manifest -outputresource:"$(@);1" +endif else $(dlltool) -z $(@).def $(executable-objects) $(dlltool) -d $(@).def -e $(@).exp @@ -1202,9 +1527,11 @@ endif $(strip) $(strip-all) $(@) $(bootimage-generator): $(bootimage-generator-objects) - echo arch=$(arch) platform=$(platform) + echo building $(bootimage-generator) arch=$(build-arch) platform=$(bootimage-platform) $(MAKE) mode=$(mode) \ + build=$(host-build-root) \ arch=$(build-arch) \ + aot-only=false \ target-arch=$(arch) \ platform=$(bootimage-platform) \ target-format=$(target-format) \ @@ -1222,17 +1549,19 @@ $(build-bootimage-generator): \ $(lzma-decode-objects) $(lzma-encode-objects) @echo "linking $(@)" ifeq ($(platform),windows) -ifdef msvc - $(ld) $(lflags) $(^) -out:$(@) -PDB:$(@).pdb -IMPLIB:$(@).lib \ - -MANIFESTFILE:$(@).manifest - $(mt) -manifest $(@).manifest -outputresource:"$(@);1" +ifdef ms_cl_compiler + $(ld) $(bootimage-generator-lflags) $(lflags) $(^) -out:$(@) \ + -debug -PDB:$(subst $(exe-suffix),.pdb,$(@)) $(manifest-flags) +ifdef mt + $(mt) -nologo -manifest $(@).manifest -outputresource:"$(@);1" +endif else $(dlltool) -z $(@).def $(^) $(dlltool) -d $(@).def -e $(@).exp - $(ld) $(@).exp $(^) $(lflags) -o $(@) + $(ld) $(@).exp $(^) $(bootimage-generator-lflags) $(lflags) -o $(@) endif else - $(ld) $(^) $(rdynamic) $(lflags) -o $(@) + $(ld) $(^) $(rdynamic) $(bootimage-generator-lflags) $(lflags) -o $(@) endif $(dynamic-library): $(vm-objects) $(dynamic-object) $(classpath-objects) \ @@ -1240,10 +1569,13 @@ $(dynamic-library): $(vm-objects) $(dynamic-object) $(classpath-objects) \ $(classpath-libraries) $(javahome-object) $(boot-javahome-object) \ $(lzma-decode-objects) @echo "linking $(@)" -ifdef msvc - $(ld) $(shared) $(lflags) $(^) -out:$(@) -PDB:$(@).pdb \ - -IMPLIB:$(build)/$(name).lib -MANIFESTFILE:$(@).manifest - $(mt) -manifest $(@).manifest -outputresource:"$(@);2" +ifdef ms_cl_compiler + $(ld) $(shared) $(lflags) $(^) -out:$(@) \ + -debug -PDB:$(subst $(so-suffix),.pdb,$(@)) \ + -IMPLIB:$(subst $(so-suffix),.lib,$(@)) $(manifest-flags) +ifdef mt + $(mt) -nologo -manifest $(@).manifest -outputresource:"$(@);2" +endif else $(ld) $(^) $(version-script-flag) $(soname-flag) \ $(shared) $(lflags) $(bootimage-lflags) \ @@ -1255,13 +1587,15 @@ endif # Ubuntu 11.10 which may be fixable without disabling LTO. $(executable-dynamic): $(driver-dynamic-objects) $(dynamic-library) @echo "linking $(@)" -ifdef msvc +ifdef ms_cl_compiler $(ld) $(lflags) -LIBPATH:$(build) -DEFAULTLIB:$(name) \ - -PDB:$(@).pdb -IMPLIB:$(@).lib $(driver-dynamic-objects) -out:$(@) \ - -MANIFESTFILE:$(@).manifest - $(mt) -manifest $(@).manifest -outputresource:"$(@);1" + -debug -PDB:$(subst $(exe-suffix),.pdb,$(@)) + $(driver-dynamic-objects) -out:$(@) $(manifest-flags) +ifdef mt + $(mt) -nologo -manifest $(@).manifest -outputresource:"$(@);1" +endif else - $(ld) $(driver-dynamic-objects) -L$(build) -ljvm $(lflags) $(no-lto) -o $(@) + $(ld) $(driver-dynamic-objects) -L$(build) -ljvm $(lflags) $(no-lto) $(rpath) -o $(@) endif $(strip) $(strip-all) $(@) diff --git a/src/arm.h b/src/arm.h index 15299ec762..5593c86f92 100644 --- a/src/arm.h +++ b/src/arm.h @@ -71,33 +71,57 @@ namespace vm { inline void trap() { +#ifdef _MSC_VER + __debugbreak(); +#else asm("bkpt"); +#endif } +#ifndef _MSC_VER inline void memoryBarrier() { asm("nop"); } +#endif inline void storeStoreMemoryBarrier() { +#ifdef _MSC_VER + _ReadWriteBarrier(); +#else memoryBarrier(); +#endif } inline void storeLoadMemoryBarrier() { +#ifdef _MSC_VER + MemoryBarrier(); +#else memoryBarrier(); +#endif } inline void loadMemoryBarrier() { +#ifdef _MSC_VER + _ReadWriteBarrier(); +#else memoryBarrier(); +#endif } +#if !defined(AVIAN_AOT_ONLY) + +#if defined(__ANDROID__) +// http://code.google.com/p/android/issues/detail?id=1803 +extern "C" void __clear_cache (void *beg __attribute__((__unused__)), void *end __attribute__((__unused__))); +#endif inline void syncInstructionCache(const void* start, unsigned size) { @@ -112,6 +136,8 @@ syncInstructionCache(const void* start, unsigned size) #endif } +#endif // AVIAN_AOT_ONLY + #ifndef __APPLE__ typedef int (__kernel_cmpxchg_t)(int oldval, int newval, int *ptr); # define __kernel_cmpxchg (*(__kernel_cmpxchg_t *)0xffff0fc0) @@ -156,7 +182,7 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes, unsigned vfpIndex = 0; unsigned vfpBackfillIndex UNUSED = 0; - uintptr_t stack[(argumentCount * 8) / BytesPerWord]; // is > argumentSize to account for padding + RUNTIME_ARRAY(uintptr_t, stack, (argumentCount * 8) / BytesPerWord); // is > argumentSize to account for padding unsigned stackIndex = 0; unsigned ai = 0; diff --git a/src/arm.masm b/src/arm.masm new file mode 100644 index 0000000000..e7bd2d864c --- /dev/null +++ b/src/arm.masm @@ -0,0 +1,89 @@ +; Copyright (c) 2008-2011, Avian Contributors +; +; Permission to use, copy, modify, and/or distribute this software +; for any purpose with or without fee is hereby granted, provided +; that the above copyright notice and this permission notice appear +; in all copies. +; +; There is NO WARRANTY for this software. See license.txt for +; details. +; +; ORIGIN: https://github.com/gkvas/avian/tree/wince + + AREA text, CODE, ARM + + EXPORT vmNativeCall +vmNativeCall + ; arguments: + ; r0 -> r4 : function + ; r1 -> r5 : stackTotal + ; r2 : memoryTable + ; r3 : memoryCount + ; [sp, #0] -> r6 : gprTable + + mov ip, sp ; save stack frame + stmfd sp!, {r4-r6, lr} ; save clobbered non-volatile regs + + ; mv args into non-volatile regs + mov r4, r0 + mov r5, r1 + ldr r6, [ip] + + ; setup stack arguments if necessary + sub sp, sp, r5 ; allocate stack + mov ip, sp +loop + tst r3, r3 + ldrne r0, [r2], #4 + strne r0, [ip], #4 + subne r3, r3, #4 + bne loop + + ; setup argument registers if necessary + tst r6, r6 + ldmneia r6, {r0-r3} + + blx r4 ; call function + add sp, sp, r5 ; deallocate stack + + ldmfd sp!, {r4-r6, pc} ; restore non-volatile regs and return + + EXPORT vmJump +vmJump + mov lr, r0 + ldr r0, [sp] + ldr r1, [sp, #4] + mov sp, r2 + mov r8, r3 + bx lr + +CHECKPOINT_THREAD EQU 4 +CHECKPOINT_STACK EQU 24 + + EXPORT vmRun +vmRun + ; r0: function + ; r1: arguments + ; r2: checkpoint + stmfd sp!, {r4-r11, lr} + ; align stack + sub sp, sp, #12 + + str sp, [r2, #CHECKPOINT_STACK] + + mov r12, r0 + ldr r0, [r2, #CHECKPOINT_THREAD] + + blx r12 + + EXPORT vmRun_returnAddress +vmRun_returnAddress + add sp, sp, #12 + ldmfd sp!, {r4-r11, lr} + bx lr + + EXPORT vmTrap +vmTrap + bkpt 3 + + END \ No newline at end of file diff --git a/src/binaryToObject/pe.cpp b/src/binaryToObject/pe.cpp index 8d5d5fc444..186e491447 100644 --- a/src/binaryToObject/pe.cpp +++ b/src/binaryToObject/pe.cpp @@ -17,13 +17,17 @@ namespace { -#define IMAGE_SIZEOF_SHORT_NAME 8 +// --- winnt.h ---- +#define IMAGE_SIZEOF_SHORT_NAME 8 -#define IMAGE_FILE_RELOCS_STRIPPED 1 -#define IMAGE_FILE_LINE_NUMS_STRIPPED 4 -#define IMAGE_FILE_MACHINE_AMD64 0x8664 -#define IMAGE_FILE_MACHINE_I386 0x014c -#define IMAGE_FILE_32BIT_MACHINE 256 +#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 // Relocation info stripped from file. +#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 // Line nunbers stripped from file. +#define IMAGE_FILE_MACHINE_AMD64 0x8664 // AMD64 (K8) +#define IMAGE_FILE_MACHINE_I386 0x014c // Intel 386. +#define IMAGE_FILE_MACHINE_ARM 0x01c0 // ARM Little-Endian +#define IMAGE_FILE_MACHINE_THUMB 0x01c2 // ARM Thumb/Thumb-2 Little-Endian +#define IMAGE_FILE_MACHINE_ARMNT 0x01c4 // ARM Thumb-2 Little-Endian +#define IMAGE_FILE_32BIT_MACHINE 0x0100 // 32 bit word machine. #define IMAGE_SCN_ALIGN_1BYTES 0x100000 #define IMAGE_SCN_ALIGN_2BYTES 0x200000 @@ -73,6 +77,7 @@ struct IMAGE_SYMBOL { uint8_t StorageClass; uint8_t NumberOfAuxSymbols; } __attribute__((packed)); +// --- winnt.h ---- inline unsigned pad(unsigned n) @@ -82,7 +87,7 @@ pad(unsigned n) using namespace avian::tools; -template +template class WindowsPlatform : public Platform { public: @@ -202,12 +207,15 @@ public: int machine; int machineMask; - if (BytesPerWord == 8) { + if (Architecture == PlatformInfo::x86_64) { machine = IMAGE_FILE_MACHINE_AMD64; machineMask = 0; - } else { // if (BytesPerWord == 8) + } else if (Architecture == PlatformInfo::x86) { machine = IMAGE_FILE_MACHINE_I386; machineMask = IMAGE_FILE_32BIT_MACHINE; + } else if (Architecture == PlatformInfo::Arm) { + machine = IMAGE_FILE_MACHINE_ARMNT; + machineMask = IMAGE_FILE_32BIT_MACHINE; } int sectionMask; @@ -269,10 +277,11 @@ public: } WindowsPlatform(): - Platform(PlatformInfo(PlatformInfo::Pe, BytesPerWord == 4 ? PlatformInfo::x86 : PlatformInfo::x86_64)) {} + Platform(PlatformInfo(PlatformInfo::Pe, Architecture)) {} }; -WindowsPlatform<4> windows32Platform; -WindowsPlatform<8> windows64Platform; +WindowsPlatform<4, PlatformInfo::x86> windows32Platform; +WindowsPlatform<8, PlatformInfo::x86_64> windows64Platform; +WindowsPlatform<4, PlatformInfo::Arm> windowsRtPlatform; // Windows Phone 8 and Windows RT } // namespace diff --git a/src/bootimage.cpp b/src/bootimage.cpp index 894871af83..5a57a40e1c 100644 --- a/src/bootimage.cpp +++ b/src/bootimage.cpp @@ -342,7 +342,7 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, unsigned count = s.read2() - 1; if (count) { - Type types[count + 2]; + THREAD_RUNTIME_ARRAY(t, Type, types, count + 2); types[0] = Type_object; types[1] = Type_intptr_t; @@ -420,7 +420,7 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, object fields = allFields(t, typeMaps, c, &count, &array); PROTECT(t, fields); - Field memberFields[count + 1]; + THREAD_RUNTIME_ARRAY(t, Field, memberFields, count + 1); unsigned memberIndex; unsigned buildMemberOffset; @@ -444,7 +444,7 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, ++ memberIndex; } } else { - init(new (memberFields) Field, Type_object, 0, BytesPerWord, 0, + init(new (&memberFields[0]) Field, Type_object, 0, BytesPerWord, 0, TargetBytesPerWord); memberIndex = 1; @@ -454,15 +454,15 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, const unsigned StaticHeader = 3; - Field staticFields[count + StaticHeader]; + THREAD_RUNTIME_ARRAY(t, Field, staticFields, count + StaticHeader); - init(new (staticFields) Field, Type_object, 0, BytesPerWord, 0, + init(new (&staticFields[0]) Field, Type_object, 0, BytesPerWord, 0, TargetBytesPerWord); - init(new (staticFields + 1) Field, Type_intptr_t, BytesPerWord, + init(new (&staticFields[1]) Field, Type_intptr_t, BytesPerWord, BytesPerWord, TargetBytesPerWord, TargetBytesPerWord); - init(new (staticFields + 2) Field, Type_object, BytesPerWord * 2, + init(new (&staticFields[2]) Field, Type_object, BytesPerWord * 2, BytesPerWord, TargetBytesPerWord * 2, TargetBytesPerWord); unsigned staticIndex = StaticHeader; @@ -512,7 +512,7 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, buildStaticOffset = fieldOffset(t, field); - init(new (staticFields + staticIndex) Field, type, + init(new (&staticFields[staticIndex]) Field, type, buildStaticOffset, buildSize, targetStaticOffset, targetSize); @@ -526,7 +526,7 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, buildMemberOffset = fieldOffset(t, field); - init(new (memberFields + memberIndex) Field, type, + init(new (&memberFields[memberIndex]) Field, type, buildMemberOffset, buildSize, targetMemberOffset, targetSize); @@ -549,7 +549,7 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, ceilingDivide(targetMemberOffset, TargetBytesPerWord), memberIndex); for (unsigned i = 0; i < memberIndex; ++i) { - Field* f = memberFields + i; + Field* f = &memberFields[i]; expect(t, f->buildOffset < map->buildFixedSizeInWords * BytesPerWord); @@ -573,7 +573,7 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, TypeMap::SingletonKind); for (unsigned i = 0; i < staticIndex; ++i) { - Field* f = staticFields + i; + Field* f = &staticFields[i]; expect(t, f->buildOffset < map->buildFixedSizeInWords * BytesPerWord); @@ -1334,9 +1334,9 @@ writeBootImage2(Thread* t, OutputStream* bootimageOutput, OutputStream* codeOutp } ++ count; - Field fields[count]; + THREAD_RUNTIME_ARRAY(t, Field, fields, count); - init(new (fields) Field, Type_object, 0, BytesPerWord, 0, + init(new (&fields[0]) Field, Type_object, 0, BytesPerWord, 0, TargetBytesPerWord); unsigned buildOffset = BytesPerWord; @@ -1414,7 +1414,7 @@ writeBootImage2(Thread* t, OutputStream* bootimageOutput, OutputStream* codeOutp ++ targetOffset; } - init(new (fields + j) Field, type, buildOffset, buildSize, + init(new (&fields[j]) Field, type, buildOffset, buildSize, targetOffset, targetSize); buildOffset += buildSize; @@ -1449,7 +1449,7 @@ writeBootImage2(Thread* t, OutputStream* bootimageOutput, OutputStream* codeOutp targetArrayElementSize, arrayElementType); for (unsigned j = 0; j < fixedFieldCount; ++j) { - Field* f = fields + j; + Field* f = &fields[j]; expect(t, f->buildOffset < map->buildFixedSizeInWords * BytesPerWord); @@ -1646,10 +1646,10 @@ writeBootImage2(Thread* t, OutputStream* bootimageOutput, OutputStream* codeOutp Platform* platform = Platform::getPlatform(PlatformInfo((PlatformInfo::Format)AVIAN_TARGET_FORMAT, (PlatformInfo::Architecture)AVIAN_TARGET_ARCH)); - // if(!platform) { - // fprintf(stderr, "unsupported platform: %s/%s\n", os, architecture); - // return false; - // } + if(!platform) { + fprintf(stderr, "unsupported platform: target-format = %d / target-arch = %d\n", AVIAN_TARGET_FORMAT, AVIAN_TARGET_ARCH); + abort(); + } SymbolInfo bootimageSymbols[] = { SymbolInfo(0, bootimageStart), @@ -1768,7 +1768,7 @@ bool ArgParser::parse(int ac, const char** av) { } bool found = false; for(Arg* arg = first; arg; arg = arg->next) { - if(strcmp(arg->name, &av[i][1]) == 0) { + if(::strcmp(arg->name, &av[i][1]) == 0) { found = true; if (arg->desc == 0) { arg->value = "true"; diff --git a/src/codegen/arm/assembler.cpp b/src/codegen/arm/assembler.cpp index bb7328726e..849a53b0cd 100644 --- a/src/codegen/arm/assembler.cpp +++ b/src/codegen/arm/assembler.cpp @@ -8,9 +8,12 @@ There is NO WARRANTY for this software. See license.txt for details. */ -#include "codegen/assembler.h" #include "alloc-vector.h" +#include "codegen/assembler.h" + +#include "util/runtime-array.h" + #define CAST1(x) reinterpret_cast(x) #define CAST2(x) reinterpret_cast(x) #define CAST3(x) reinterpret_cast(x) @@ -18,7 +21,7 @@ using namespace vm; -namespace { +namespace local { namespace isa { // SYSTEM REGISTERS @@ -252,7 +255,7 @@ class MyBlock: public Assembler::Block { this->start = start; this->next = static_cast(next); - ::resolve(this); + local::resolve(this); return start + size + padding(this, size); } @@ -2150,7 +2153,7 @@ class MyArchitecture: public Assembler::Architecture { } virtual unsigned argumentFootprint(unsigned footprint) { - return ::argumentFootprint(footprint); + return local::argumentFootprint(footprint); } virtual bool argumentAlignment() { @@ -2239,7 +2242,7 @@ class MyArchitecture: public Assembler::Architecture { unsigned targetParameterFootprint, void** ip, void** stack) { - ::nextFrame(&con, static_cast(start), size, footprint, link, + local::nextFrame(&con, static_cast(start), size, footprint, link, mostRecent, targetParameterFootprint, ip, stack); } @@ -2552,19 +2555,20 @@ class MyAssembler: public Assembler { } virtual void pushFrame(unsigned argumentCount, ...) { - struct { + struct Argument { unsigned size; OperandType type; Operand* operand; - } arguments[argumentCount]; + }; + RUNTIME_ARRAY(Argument, arguments, argumentCount); va_list a; va_start(a, argumentCount); unsigned footprint = 0; for (unsigned i = 0; i < argumentCount; ++i) { - arguments[i].size = va_arg(a, unsigned); - arguments[i].type = static_cast(va_arg(a, int)); - arguments[i].operand = va_arg(a, Operand*); - footprint += ceilingDivide(arguments[i].size, TargetBytesPerWord); + RUNTIME_ARRAY_BODY(arguments)[i].size = va_arg(a, unsigned); + RUNTIME_ARRAY_BODY(arguments)[i].type = static_cast(va_arg(a, int)); + RUNTIME_ARRAY_BODY(arguments)[i].operand = va_arg(a, Operand*); + footprint += ceilingDivide(RUNTIME_ARRAY_BODY(arguments)[i].size, TargetBytesPerWord); } va_end(a); @@ -2576,19 +2580,23 @@ class MyAssembler: public Assembler { Register dst(arch_->argumentRegister(i)); apply(Move, - arguments[i].size, arguments[i].type, arguments[i].operand, - pad(arguments[i].size, TargetBytesPerWord), RegisterOperand, + RUNTIME_ARRAY_BODY(arguments)[i].size, + RUNTIME_ARRAY_BODY(arguments)[i].type, + RUNTIME_ARRAY_BODY(arguments)[i].operand, + pad(RUNTIME_ARRAY_BODY(arguments)[i].size, TargetBytesPerWord), RegisterOperand, &dst); - offset += ceilingDivide(arguments[i].size, TargetBytesPerWord); + offset += ceilingDivide(RUNTIME_ARRAY_BODY(arguments)[i].size, TargetBytesPerWord); } else { Memory dst(StackRegister, offset * TargetBytesPerWord); apply(Move, - arguments[i].size, arguments[i].type, arguments[i].operand, - pad(arguments[i].size, TargetBytesPerWord), MemoryOperand, &dst); + RUNTIME_ARRAY_BODY(arguments)[i].size, + RUNTIME_ARRAY_BODY(arguments)[i].type, + RUNTIME_ARRAY_BODY(arguments)[i].operand, + pad(RUNTIME_ARRAY_BODY(arguments)[i].size, TargetBytesPerWord), MemoryOperand, &dst); - offset += ceilingDivide(arguments[i].size, TargetBytesPerWord); + offset += ceilingDivide(RUNTIME_ARRAY_BODY(arguments)[i].size, TargetBytesPerWord); } } } @@ -2800,7 +2808,7 @@ class MyAssembler: public Assembler { bool jump = needJump(b); if (jump) { write4 - (dst + dstOffset, ::b((poolSize + TargetBytesPerWord - 8) >> 2)); + (dst + dstOffset, isa::b((poolSize + TargetBytesPerWord - 8) >> 2)); } dstOffset += poolSize + (jump ? TargetBytesPerWord : 0); @@ -2834,7 +2842,7 @@ class MyAssembler: public Assembler { } virtual Promise* offset(bool forTrace) { - return ::offset(&con, forTrace); + return local::offset(&con, forTrace); } virtual Block* endBlock(bool startNew) { @@ -2910,7 +2918,7 @@ namespace codegen { Assembler::Architecture* makeArchitectureArm(System* system, bool) { - return new (allocate(system, sizeof(MyArchitecture))) MyArchitecture(system); + return new (allocate(system, sizeof(local::MyArchitecture))) local::MyArchitecture(system); } } // namespace codegen diff --git a/src/common.h b/src/common.h index f401a22ecd..7cf763c4bd 100644 --- a/src/common.h +++ b/src/common.h @@ -94,7 +94,13 @@ typedef int64_t intptr_t; typedef uint64_t uintptr_t; # define UINT64_C(x) x##L # define ARCH_x86_64 -@ define BYTES_PER_WORD 8 +# define BYTES_PER_WORD 8 +# elif defined _M_ARM_FP +typedef int32_t intptr_t; +typedef uint32_t uintptr_t; +# define UINT64_C(x) x##LL +# define ARCH_arm +# define BYTES_PER_WORD 4 # else # error "unsupported architecture" # endif @@ -214,6 +220,9 @@ typedef intptr_t __attribute__((__may_alias__)) intptr_alias_t; type name; \ } MAKE_NAME(resource_)(name); +#ifdef _MSC_VER +# pragma warning( disable : 4291 ) +#endif inline void* operator new(size_t, void* p) throw() { return p; } namespace vm { diff --git a/src/compile-arm.masm b/src/compile-arm.masm new file mode 100644 index 0000000000..a9c1e59cef --- /dev/null +++ b/src/compile-arm.masm @@ -0,0 +1,252 @@ +; Copyright (c) 2008-2011, Avian Contributors +; +; Permission to use, copy, modify, and/or distribute this software +; for any purpose with or without fee is hereby granted, provided +; that the above copyright notice and this permission notice appear +; in all copies. +; +; There is NO WARRANTY for this software. See license.txt for +; details. +; +; ORIGIN: https://github.com/gkvas/avian/tree/wince + +; types.inc +VOID_TYPE equ 0 +INT8_TYPE equ 1 +INT16_TYPE equ 2 +INT32_TYPE equ 3 +INT64_TYPE equ 4 +FLOAT_TYPE equ 5 +DOUBLE_TYPE equ 6 +POINTER_TYPE equ 7 + +; target-fields.inc +;TARGET_BYTES_PER_WORD = 4 + +TARGET_THREAD_EXCEPTION equ 44 +TARGET_THREAD_EXCEPTIONSTACKADJUSTMENT equ 2164 +TARGET_THREAD_EXCEPTIONOFFSET equ 2168 +TARGET_THREAD_EXCEPTIONHANDLER equ 2172 + +TARGET_THREAD_IP equ 2144 +TARGET_THREAD_STACK equ 2148 +TARGET_THREAD_NEWSTACK equ 2152 +TARGET_THREAD_SCRATCH equ 2156 +TARGET_THREAD_CONTINUATION equ 2160 +TARGET_THREAD_TAILADDRESS equ 2176 +TARGET_THREAD_VIRTUALCALLTARGET equ 2180 +TARGET_THREAD_VIRTUALCALLINDEX equ 2184 +TARGET_THREAD_HEAPIMAGE equ 2188 +TARGET_THREAD_CODEIMAGE equ 2192 +TARGET_THREAD_THUNKTABLE equ 2196 +TARGET_THREAD_STACKLIMIT equ 2220 + + AREA text, CODE, ARM + +BYTES_PER_WORD equ 4 + +CONTINUATION_NEXT equ 4 +CONTINUATION_ADDRESS equ 16 +CONTINUATION_RETURN_ADDRESS_OFFSET equ 20 +CONTINUATION_FRAME_POINTER_OFFSET equ 24 +CONTINUATION_LENGTH equ 28 +CONTINUATION_BODY equ 32 + + EXPORT vmInvoke +vmInvoke + + ; arguments + ; r0 : thread + ; r1 : function + ; r2 : arguments + ; r3 : argumentFootprint + ; [sp, #0] : frameSize (not used) + ; [sp, #4] : returnType + + + ; save all non-volatile registers + stmfd sp!, {r4-r11, lr} + + ; save return type + ldr r4, [sp, #4] + str r4, [sp, #-4]! + + str sp, [r0, #TARGET_THREAD_SCRATCH] + + ; align stack, if necessary + eor r4, sp, r3 + tst r4, #4 + subne sp, sp, #4 + + ; copy arguments into place + sub sp, sp, r3 + mov r4, #0 + b vmInvoke_argumentTest + +vmInvoke_argumentLoop + ldr r5, [r2, r4] + str r5, [sp, r4] + add r4, r4, #BYTES_PER_WORD + +vmInvoke_argumentTest + cmp r4, r3 + blt vmInvoke_argumentLoop + + ; we use r8 to hold the thread pointer, by convention + mov r8, r0 + + ; load and call function address + blx r1 + + EXPORT vmInvoke_returnAddress +vmInvoke_returnAddress + ; restore stack pointer + ldr sp, [r8, #TARGET_THREAD_SCRATCH] + + ; clear MyThread::stack to avoid confusing another thread calling + ; java.lang.Thread.getStackTrace on this one. See + ; MyProcess::getStackTrace in compile.cpp for details on how we get + ; a reliable stack trace from a thread that might be interrupted at + ; any point in its execution. + mov r5, #0 + str r5, [r8, #TARGET_THREAD_STACK] + + EXPORT vmInvoke_safeStack +vmInvoke_safeStack + +;if AVIAN_CONTINUATIONS +; ; call the next continuation, if any +; ldr r5,[r8,#TARGET_THREAD_CONTINUATION] +; cmp r5,#0 +; beq vmInvoke_exit) +; +; ldr r6,[r5,#CONTINUATION_LENGTH] +; lsl r6,r6,#2 +; neg r7,r6 +; add r7,r7,#-80 +; mov r4,sp +; str r4,[sp,r7]! +; +; add r7,r5,#CONTINUATION_BODY +; +; mov r11,#0 +; b vmInvoke_continuationTest +; +;vmInvoke_continuationLoop +; ldr r9,[r7,r11] +; str r9,[sp,r11] +; add r11,r11,#4 +; +;vmInvoke_continuationTest +; cmp r11,r6 +; ble vmInvoke_continuationLoop) +; +; ldr r7,[r5,#CONTINUATION_RETURN_ADDRESS_OFFSET] +; ldr r10,vmInvoke_returnAddress_word +; ldr r11,vmInvoke_getAddress_word +;vmInvoke_getAddress +; add r11,pc,r11 +; ldr r11,[r11,r10] +; str r11,[sp,r7] +; +; ldr r7,[r5,#CONTINUATION_NEXT] +; str r7,[r8,#TARGET_THREAD_CONTINUATION] +; +; ; call the continuation unless we're handling an exception +; ldr r7,[r8,#TARGET_THREAD_EXCEPTION] +; cmp r7,#0 +; bne vmInvoke_handleException) +; ldr r7,[r5,#CONTINUATION_ADDRESS] +; bx r7 +; +;vmInvoke_handleException +; ; we're handling an exception - call the exception handler instead +; mov r11,#0 +; str r11,[r8,#TARGET_THREAD_EXCEPTION] +; ldr r11,[r8,#TARGET_THREAD_EXCEPTIONSTACKADJUSTMENT] +; ldr r9,[sp] +; neg r11,r11 +; str r9,[sp,r11]! +; ldr r11,[r8,#TARGET_THREAD_EXCEPTIONOFFSET] +; str r7,[sp,r11] +; +; ldr r7,[r8,#TARGET_THREAD_EXCEPTIONHANDLER] +; bx r7 +; +;vmInvoke_exit +;endif ; AVIAN_CONTINUATIONS + + mov ip, #0 + str ip, [r8, #TARGET_THREAD_STACK] + + ; restore return type + ldr ip, [sp], #4 + + ; restore callee-saved registers + ldmfd sp!, {r4-r11, lr} + +vmInvoke_return + bx lr + + EXPORT vmJumpAndInvoke +vmJumpAndInvoke +;if :DEF:AVIAN_CONTINUATIONS +; ; r0: thread +; ; r1: address +; ; r2: stack +; ; r3: argumentFootprint +; ; [sp,#0]: arguments +; ; [sp,#4]: frameSize +; +; ldr r5,[sp,#0] +; ldr r6,[sp,#4] +; +; ; allocate new frame, adding room for callee-saved registers, plus +; ; 4 bytes of padding since the calculation of frameSize assumes 4 +; ; bytes have already been allocated to save the return address, +; ; which is not true in this case +; sub r2,r2,r6 +; sub r2,r2,#84 +; +; mov r8,r0 +; +; ; copy arguments into place +; mov r6,#0 +; b vmJumpAndInvoke_argumentTest +; +;vmJumpAndInvoke_argumentLoop +; ldr r12,[r5,r6] +; str r12,[r2,r6] +; add r6,r6,#4 +; +;vmJumpAndInvoke_argumentTest +; cmp r6,r3 +; ble vmJumpAndInvoke_argumentLoop +; +; ; the arguments have been copied, so we can set the real stack +; ; pointer now +; mov sp,r2 +; +; ; set return address to vmInvoke_returnAddress +; ldr r10,vmInvoke_returnAddress_word) +; ldr r11,vmJumpAndInvoke_getAddress_word) +;vmJumpAndInvoke_getAddress +; add r11,pc,r11 +; ldr lr,[r11,r10] +; +; bx r1 +; +;vmInvoke_returnAddress_word +; .word GLOBAL(vmInvoke_returnAddress)(GOT) +;vmInvoke_getAddress_word +; .word _GLOBAL_OFFSET_TABLE_-(vmInvoke_getAddress)+8) +;vmJumpAndInvoke_getAddress_word +; .word _GLOBAL_OFFSET_TABLE_-(vmJumpAndInvoke_getAddress)+8) +; +;else ; not AVIAN_CONTINUATIONS + ; vmJumpAndInvoke should only be called when continuations are + ; enabled + bkpt 0 +;endif ; not AVIAN_CONTINUATIONS + + END \ No newline at end of file diff --git a/src/compile-x86.masm b/src/compile-x86.masm new file mode 100644 index 0000000000..f07d799faf --- /dev/null +++ b/src/compile-x86.masm @@ -0,0 +1,173 @@ +comment # + Copyright (c) 2008-2011, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. + + ORIGIN: https://github.com/gkvas/avian/tree/wince +# + +.586 +.MODEL FLAT, C + +comment # types.h # +VOID_TYPE equ 0 +INT8_TYPE equ 1 +INT16_TYPE equ 2 +INT32_TYPE equ 3 +INT64_TYPE equ 4 +FLOAT_TYPE equ 5 +DOUBLE_TYPE equ 6 +POINTER_TYPE equ 7 + +comment # target-fields.h # +ifdef TARGET_BYTES_PER_WORD + if TARGET_BYTES_PER_WORD eq 8 + +TARGET_THREAD_EXCEPTION equ 80 +TARGET_THREAD_EXCEPTIONSTACKADJUSTMENT equ 2256 +TARGET_THREAD_EXCEPTIONOFFSET equ 2264 +TARGET_THREAD_EXCEPTIONHANDLER equ 2272 + +TARGET_THREAD_IP equ 2216 +TARGET_THREAD_STACK equ 2224 +TARGET_THREAD_NEWSTACK equ 2232 +TARGET_THREAD_SCRATCH equ 2240 +TARGET_THREAD_CONTINUATION equ 2248 +TARGET_THREAD_TAILADDRESS equ 2280 +TARGET_THREAD_VIRTUALCALLTARGET equ 2288 +TARGET_THREAD_VIRTUALCALLINDEX equ 2296 +TARGET_THREAD_HEAPIMAGE equ 2304 +TARGET_THREAD_CODEIMAGE equ 2312 +TARGET_THREAD_THUNKTABLE equ 2320 +TARGET_THREAD_STACKLIMIT equ 2368 + + elseif TARGET_BYTES_PER_WORD eq 4 + +TARGET_THREAD_EXCEPTION equ 44 +TARGET_THREAD_EXCEPTIONSTACKADJUSTMENT equ 2164 +TARGET_THREAD_EXCEPTIONOFFSET equ 2168 +TARGET_THREAD_EXCEPTIONHANDLER equ 2172 + +TARGET_THREAD_IP equ 2144 +TARGET_THREAD_STACK equ 2148 +TARGET_THREAD_NEWSTACK equ 2152 +TARGET_THREAD_SCRATCH equ 2156 +TARGET_THREAD_CONTINUATION equ 2160 +TARGET_THREAD_TAILADDRESS equ 2176 +TARGET_THREAD_VIRTUALCALLTARGET equ 2180 +TARGET_THREAD_VIRTUALCALLINDEX equ 2184 +TARGET_THREAD_HEAPIMAGE equ 2188 +TARGET_THREAD_CODEIMAGE equ 2192 +TARGET_THREAD_THUNKTABLE equ 2196 +TARGET_THREAD_STACKLIMIT equ 2220 + + else + error + endif +else + error +endif + +ifdef AVIAN_USE_FRAME_POINTER + ALIGNMENT_ADJUSTMENT equ 0 +else + ALIGNMENT_ADJUSTMENT equ 12 +endif + +CALLEE_SAVED_REGISTER_FOOTPRINT equ 16 + ALIGNMENT_ADJUSTMENT + +_TEXT SEGMENT + +public C vmInvoke +vmInvoke: + push ebp + mov ebp,esp + + ; 8(%ebp): thread + ; 12(%ebp): function + ; 16(%ebp): arguments + ; 20(%ebp): argumentFootprint + ; 24(%ebp): frameSize + ; 28(%ebp): returnType + + ; allocate stack space for callee-saved registers + sub esp,offset CALLEE_SAVED_REGISTER_FOOTPRINT + + ; remember this stack position, since we won't be able to rely on + ; %rbp being restored when the call returns + mov eax,ds:dword ptr[8+ebp] + mov ds:dword ptr[TARGET_THREAD_SCRATCH+eax],esp + + mov ds:dword ptr[0+esp],ebx + mov ds:dword ptr[4+esp],esi + mov ds:dword ptr[8+esp],edi + + ; allocate stack space for arguments + sub esp,ds:dword ptr[24+ebp] + + ; we use ebx to hold the thread pointer, by convention + mov ebx,eax + + ; copy arguments into place + mov ecx,0 + mov edx,ds:dword ptr[16+ebp] + jmp LvmInvoke_argumentTest + +LvmInvoke_argumentLoop: + mov eax,ds:dword ptr[edx+ecx*1] + mov ds:dword ptr[esp+ecx*1],eax + add ecx,4 + +LvmInvoke_argumentTest: + cmp ecx,ds:dword ptr[20+ebp] + jb LvmInvoke_argumentLoop + + ; call function + call dword ptr[12+ebp] + +public vmInvoke_returnAddress +vmInvoke_returnAddress: + ; restore stack pointer + mov esp,ds:dword ptr[TARGET_THREAD_SCRATCH+ebx] + + ; clear MyThread::stack to avoid confusing another thread calling + ; java.lang.Thread.getStackTrace on this one. See + ; MyProcess::getStackTrace in compile.cpp for details on how we get + ; a reliable stack trace from a thread that might be interrupted at + ; any point in its execution. + mov ds:dword ptr[TARGET_THREAD_STACK+ebx],0 + +public vmInvoke_safeStack +vmInvoke_safeStack: + + ; restore callee-saved registers + mov ebx,ds:dword ptr[0+esp] + mov esi,ds:dword ptr[4+esp] + mov edi,ds:dword ptr[8+esp] + + add esp,offset CALLEE_SAVED_REGISTER_FOOTPRINT + + mov ecx,ds:dword ptr[28+esp] + + pop ebp + ret + +LgetPC: + mov esi,ds:dword ptr[esp] + ret + +public vmJumpAndInvoke +vmJumpAndInvoke: + ; vmJumpAndInvoke should only be called when continuations are + ; enabled + int 3 + +_TEXT ENDS + +END diff --git a/src/compile.cpp b/src/compile.cpp index bae11823d5..b01e56bee6 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -7392,8 +7392,9 @@ finish(MyThread* t, FixedAllocator* allocator, Context* context) { trap(); } - +#if !defined(AVIAN_AOT_ONLY) syncInstructionCache(start, codeSize); +#endif } void @@ -9155,7 +9156,9 @@ class MyProcessor: public Processor { virtual void dispose() { if (codeAllocator.base) { +#if !defined(AVIAN_AOT_ONLY) s->freeExecutable(codeAllocator.base, codeAllocator.capacity); +#endif } compilationHandlers->dispose(allocator); @@ -9316,11 +9319,13 @@ class MyProcessor: public Processor { } virtual void boot(Thread* t, BootImage* image, uint8_t* code) { +#if !defined(AVIAN_AOT_ONLY) if (codeAllocator.base == 0) { codeAllocator.base = static_cast (s->tryAllocateExecutable(ExecutableAreaSizeInBytes)); codeAllocator.capacity = ExecutableAreaSizeInBytes; } +#endif if (image and code) { local::boot(static_cast(t), image, code); @@ -9337,11 +9342,15 @@ class MyProcessor: public Processor { root(t, MethodTreeSentinal)); } +#ifdef AVIAN_AOT_ONLY + thunks = bootThunks; +#else local::compileThunks(static_cast(t), &codeAllocator); if (not (image and code)) { bootThunks = thunks; } +#endif segFaultHandler.m = t->m; expect(t, t->m->system->success diff --git a/src/interpret.cpp b/src/interpret.cpp index cb6adf28d3..9ef5a9d613 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -18,7 +18,7 @@ using namespace vm; -namespace { +namespace local { const unsigned FrameBaseOffset = 0; const unsigned FrameNextOffset = 1; @@ -647,7 +647,7 @@ invokeNative(Thread* t, object method) { THREAD_RESOURCE0(t, popFrame(static_cast(t))); unsigned footprint = methodParameterFootprint(t, method); - RUNTIME_ARRAY(uintptr_t, args, footprint); + THREAD_RUNTIME_ARRAY(t, uintptr_t, args, footprint); unsigned sp = frameBase(t, t->frame); unsigned argOffset = 0; if ((methodFlags(t, method) & ACC_STATIC) == 0) { @@ -2321,7 +2321,7 @@ interpret3(Thread* t, const int base) object class_ = resolveClassInPool(t, frameMethod(t, frame), index - 1); PROTECT(t, class_); - int32_t counts[dimensions]; + THREAD_RUNTIME_ARRAY(t, int32_t, counts, dimensions); for (int i = dimensions - 1; i >= 0; --i) { counts[i] = popInt(t); if (UNLIKELY(counts[i] < 0)) { @@ -3100,7 +3100,7 @@ class MyProcessor: public Processor { (&byteArrayBody(t, methodSpec(t, method), 0)); pushArguments(t, this_, spec, arguments); - return ::invoke(t, method); + return local::invoke(t, method); } virtual object @@ -3124,7 +3124,7 @@ class MyProcessor: public Processor { (&byteArrayBody(t, methodSpec(t, method), 0)); pushArguments(t, this_, spec, arguments); - return ::invoke(t, method); + return local::invoke(t, method); } virtual object @@ -3148,7 +3148,7 @@ class MyProcessor: public Processor { (&byteArrayBody(t, methodSpec(t, method), 0)); pushArguments(t, this_, spec, indirectObjects, arguments); - return ::invoke(t, method); + return local::invoke(t, method); } virtual object @@ -3174,7 +3174,7 @@ class MyProcessor: public Processor { assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0)); - return ::invoke(t, method); + return local::invoke(t, method); } virtual object getStackTrace(vm::Thread* t, vm::Thread*) { @@ -3254,8 +3254,8 @@ namespace vm { Processor* makeProcessor(System* system, Allocator* allocator, bool) { - return new (allocator->allocate(sizeof(MyProcessor))) - MyProcessor(system, allocator); + return new (allocator->allocate(sizeof(local::MyProcessor))) + local::MyProcessor(system, allocator); } } // namespace vm diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 966494320d..37d3a65f13 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -162,10 +162,12 @@ GetStringRegion(Thread* t, jstring s, jsize start, jsize length, jchar* dst) const jchar* JNICALL GetStringCritical(Thread* t, jstring s, jboolean* isCopy) { - if ((t->criticalLevel ++) == 0) { + if (t->criticalLevel == 0) { enter(t, Thread::ActiveState); } + ++ t->criticalLevel; + if (isCopy) { *isCopy = true; } @@ -3143,9 +3145,11 @@ SetDoubleArrayRegion(Thread* t, jdoubleArray array, jint offset, jint length, void* JNICALL GetPrimitiveArrayCritical(Thread* t, jarray array, jboolean* isCopy) { - if ((t->criticalLevel ++) == 0) { + if (t->criticalLevel == 0) { enter(t, Thread::ActiveState); } + + ++ t->criticalLevel; if (isCopy) { *isCopy = true; @@ -3711,16 +3715,6 @@ populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable) } // namespace vm -#define BOOTSTRAP_PROPERTY "avian.bootstrap" -#define CRASHDIR_PROPERTY "avian.crash.dir" -#define EMBED_PREFIX_PROPERTY "avian.embed.prefix" -#define CLASSPATH_PROPERTY "java.class.path" -#define JAVA_HOME_PROPERTY "java.home" -#define BOOTCLASSPATH_PREPEND_OPTION "bootclasspath/p" -#define BOOTCLASSPATH_OPTION "bootclasspath" -#define BOOTCLASSPATH_APPEND_OPTION "bootclasspath/a" -#define BOOTCLASSPATH_APPEND_OPTION "bootclasspath/a" - extern "C" JNIEXPORT jint JNICALL JNI_GetDefaultJavaVMInitArgs(void*) { @@ -3741,7 +3735,7 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args) unsigned heapLimit = 0; unsigned stackLimit = 0; - const char* bootLibrary = 0; + const char* bootLibraries = 0; const char* classpath = 0; const char* javaHome = AVIAN_JAVA_HOME; const char* embedPrefix = AVIAN_EMBED_PREFIX; @@ -3777,7 +3771,7 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args) if (strncmp(p, BOOTSTRAP_PROPERTY "=", sizeof(BOOTSTRAP_PROPERTY)) == 0) { - bootLibrary = p + sizeof(BOOTSTRAP_PROPERTY); + bootLibraries = p + sizeof(BOOTSTRAP_PROPERTY); } else if (strncmp(p, CRASHDIR_PROPERTY "=", sizeof(CRASHDIR_PROPERTY)) == 0) { @@ -3831,9 +3825,16 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args) *RUNTIME_ARRAY_BODY(bootClasspathBuffer) = 0; } + char* bootLibrary = bootLibraries ? strdup(bootLibraries) : 0; + char* bootLibraryEnd = bootLibrary ? strchr(bootLibrary, PATH_SEPARATOR) : 0; + if(bootLibraryEnd) + *bootLibraryEnd = 0; + Finder* bf = makeFinder (s, h, RUNTIME_ARRAY_BODY(bootClasspathBuffer), bootLibrary); Finder* af = makeFinder(s, h, classpath, bootLibrary); + if(bootLibrary) + free(bootLibrary); Processor* p = makeProcessor(s, h, true); const char** properties = static_cast diff --git a/src/jnienv.h b/src/jnienv.h index 5b8c46685b..8dbd1f8c7d 100644 --- a/src/jnienv.h +++ b/src/jnienv.h @@ -13,6 +13,16 @@ #include "machine.h" +#define BOOTSTRAP_PROPERTY "avian.bootstrap" +#define CRASHDIR_PROPERTY "avian.crash.dir" +#define EMBED_PREFIX_PROPERTY "avian.embed.prefix" +#define CLASSPATH_PROPERTY "java.class.path" +#define JAVA_HOME_PROPERTY "java.home" +#define BOOTCLASSPATH_PREPEND_OPTION "bootclasspath/p" +#define BOOTCLASSPATH_OPTION "bootclasspath" +#define BOOTCLASSPATH_APPEND_OPTION "bootclasspath/a" +#define BOOTCLASSPATH_APPEND_OPTION "bootclasspath/a" + namespace vm { void diff --git a/src/machine.cpp b/src/machine.cpp index cb4f4c066c..677a7f9b92 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -19,6 +19,11 @@ #include "util/runtime-array.h" +#if defined(PLATFORM_WINDOWS) +# define WIN32_LEAN_AND_MEAN +# include +#endif + using namespace vm; namespace { @@ -3005,6 +3010,14 @@ Machine::Machine(System* system, Heap* heap, Finder* bootFinder, populateJNITables(&javaVMVTable, &jniEnvVTable); + const char* bootstrapProperty = findProperty(this, BOOTSTRAP_PROPERTY); + const char* bootstrapPropertyDup = bootstrapProperty ? strdup(bootstrapProperty) : 0; + const char* bootstrapPropertyEnd = bootstrapPropertyDup + (bootstrapPropertyDup ? strlen(bootstrapPropertyDup) : 0); + char* codeLibraryName = (char*)bootstrapPropertyDup; + char* codeLibraryNameEnd = 0; + if (codeLibraryName && (codeLibraryNameEnd = strchr(codeLibraryName, system->pathSeparator()))) + *codeLibraryNameEnd = 0; + if (not system->success(system->make(&localThread)) or not system->success(system->make(&stateLock)) or not system->success(system->make(&heapLock)) or @@ -3012,10 +3025,25 @@ Machine::Machine(System* system, Heap* heap, Finder* bootFinder, not system->success(system->make(&referenceLock)) or not system->success(system->make(&shutdownLock)) or not system->success - (system->load(&libraries, findProperty(this, "avian.bootstrap")))) + (system->load(&libraries, bootstrapPropertyDup))) { system->abort(); } + + System::Library* additionalLibrary = 0; + while (codeLibraryNameEnd && codeLibraryNameEnd + 1 < bootstrapPropertyEnd) { + codeLibraryName = codeLibraryNameEnd + 1; + codeLibraryNameEnd = strchr(codeLibraryName, system->pathSeparator()); + if (codeLibraryNameEnd) + *codeLibraryNameEnd = 0; + + if (!system->success(system->load(&additionalLibrary, codeLibraryName))) + system->abort(); + libraries->setNext(additionalLibrary); + } + + if(bootstrapPropertyDup) + free((void*)bootstrapPropertyDup); } void @@ -4733,6 +4761,30 @@ visitRoots(Machine* m, Heap::Visitor* v) } } +void +logTrace(FILE* f, const char* fmt, ...) +{ + va_list a; + va_start(a, fmt); +#ifdef PLATFORM_WINDOWS + const unsigned length = _vscprintf(fmt, a); +#else + const unsigned length = vsnprintf(0, 0, fmt, a); +#endif + va_end(a); + + RUNTIME_ARRAY(char, buffer, length + 1); + va_start(a, fmt); + vsnprintf(&buffer[0], length + 1, fmt, a); + va_end(a); + buffer[length] = 0; + + ::fprintf(f, "%s", &buffer[0]); +#ifdef PLATFORM_WINDOWS + ::OutputDebugStringA(&buffer[0]); +#endif +} + void printTrace(Thread* t, object exception) { @@ -4742,19 +4794,19 @@ printTrace(Thread* t, object exception) for (object e = exception; e; e = throwableCause(t, e)) { if (e != exception) { - fprintf(errorLog(t), "caused by: "); + logTrace(errorLog(t), "caused by: "); } - fprintf(errorLog(t), "%s", &byteArrayBody + logTrace(errorLog(t), "%s", &byteArrayBody (t, className(t, objectClass(t, e)), 0)); - + if (throwableMessage(t, e)) { object m = throwableMessage(t, e); THREAD_RUNTIME_ARRAY(t, char, message, stringLength(t, m) + 1); stringChars(t, m, RUNTIME_ARRAY_BODY(message)); - fprintf(errorLog(t), ": %s\n", RUNTIME_ARRAY_BODY(message)); + logTrace(errorLog(t), ": %s\n", RUNTIME_ARRAY_BODY(message)); } else { - fprintf(errorLog(t), "\n"); + logTrace(errorLog(t), "\n"); } object trace = throwableTrace(t, e); @@ -4768,17 +4820,17 @@ printTrace(Thread* t, object exception) int line = t->m->processor->lineNumber (t, traceElementMethod(t, e), traceElementIp(t, e)); - fprintf(errorLog(t), " at %s.%s ", class_, method); + logTrace(errorLog(t), " at %s.%s ", class_, method); switch (line) { case NativeLine: - fprintf(errorLog(t), "(native)\n"); + logTrace(errorLog(t), "(native)\n"); break; case UnknownLine: - fprintf(errorLog(t), "(unknown line)\n"); + logTrace(errorLog(t), "(unknown line)\n"); break; default: - fprintf(errorLog(t), "(line %d)\n", line); + logTrace(errorLog(t), "(line %d)\n", line); } } } @@ -4788,7 +4840,7 @@ printTrace(Thread* t, object exception) } } - fflush(errorLog(t)); + ::fflush(errorLog(t)); } object diff --git a/src/machine.h b/src/machine.h index 7e75fa0efc..909b647c01 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1325,6 +1325,9 @@ checkDaemon(Thread* t); object& root(Thread* t, Machine::Root root); +#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) +# define vmRun vmRun_ +#endif extern "C" uint64_t vmRun(uint64_t (*function)(Thread*, uintptr_t*), uintptr_t* arguments, void* checkpoint); diff --git a/src/posix.cpp b/src/posix.cpp index 482b77c22a..4c320e0167 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -12,10 +12,21 @@ # define __STDC_CONSTANT_MACROS #endif +#include "sys/types.h" #ifdef __APPLE__ # include "CoreFoundation/CoreFoundation.h" # include "sys/ucontext.h" # undef assert +#elif defined(__ANDROID__) +# include /* for sigcontext */ +# include /* for stack_t */ + typedef struct ucontext { + unsigned long uc_flags; + struct ucontext *uc_link; + stack_t uc_stack; + struct sigcontext uc_mcontext; + unsigned long uc_sigmask; + } ucontext_t; #else # if defined __FreeBSD__ # include "limits.h" @@ -24,7 +35,7 @@ #endif #include "sys/mman.h" -#include "sys/types.h" + #include "sys/stat.h" #include "sys/time.h" #include "time.h" @@ -37,10 +48,10 @@ #include "stdint.h" #include "dirent.h" #include "sched.h" - #include "arch.h" #include "system.h" + #define ACQUIRE(x) MutexResource MAKE_NAME(mutexResource_) (x) using namespace vm; diff --git a/src/system.h b/src/system.h index c36aefacd9..ef69317f0b 100644 --- a/src/system.h +++ b/src/system.h @@ -121,8 +121,10 @@ class System { virtual bool success(Status) = 0; virtual void* tryAllocate(unsigned sizeInBytes) = 0; virtual void free(const void* p) = 0; +#if !defined(AVIAN_AOT_ONLY) virtual void* tryAllocateExecutable(unsigned sizeInBytes) = 0; virtual void freeExecutable(const void* p, unsigned sizeInBytes) = 0; +#endif virtual Status attach(Runnable*) = 0; virtual Status start(Runnable*) = 0; virtual Status make(Mutex**) = 0; diff --git a/src/windows.cpp b/src/windows.cpp index 532b66e161..02ebfc72b5 100644 --- a/src/windows.cpp +++ b/src/windows.cpp @@ -26,6 +26,71 @@ #include "arch.h" #include "system.h" +#if defined(WINAPI_FAMILY) + +#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + +#define WaitForSingleObject(hHandle, dwMilliseconds) \ + WaitForSingleObjectEx((hHandle), (dwMilliseconds), FALSE) + +#define CreateEvent(lpEventAttributes, bManualReset, bInitialState, lpName) \ + CreateEventEx((lpEventAttributes), (lpName), ((bManualReset)?CREATE_EVENT_MANUAL_RESET:0)|((bInitialState)?CREATE_EVENT_INITIAL_SET:0), EVENT_ALL_ACCESS) + +#define CreateMutex(lpEventAttributes, bInitialOwner, lpName) \ + CreateMutexEx((lpEventAttributes), (lpName), (bInitialOwner)?CREATE_MUTEX_INITIAL_OWNER:0, MUTEX_ALL_ACCESS) + +#include "thread-emulation.h" + +#endif + +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE) +// Headers in Windows Phone 8 DevKit contain severe error, so let's define needed functions on our own +extern "C" +{ +WINBASEAPI +_Ret_maybenull_ +HANDLE +WINAPI +CreateFileMappingFromApp( + _In_ HANDLE hFile, + _In_opt_ PSECURITY_ATTRIBUTES SecurityAttributes, + _In_ ULONG PageProtection, + _In_ ULONG64 MaximumSize, + _In_opt_ PCWSTR Name + ); + +WINBASEAPI +_Ret_maybenull_ __out_data_source(FILE) +PVOID +WINAPI +MapViewOfFileFromApp( + _In_ HANDLE hFileMappingObject, + _In_ ULONG DesiredAccess, + _In_ ULONG64 FileOffset, + _In_ SIZE_T NumberOfBytesToMap + ); + +WINBASEAPI +BOOL +WINAPI +UnmapViewOfFile( + _In_ LPCVOID lpBaseAddress + ); +} +#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE) + +#else + +#ifndef WINAPI_PARTITION_DESKTOP +#define WINAPI_PARTITION_DESKTOP 1 +#endif + +#ifndef WINAPI_FAMILY_PARTITION +#define WINAPI_FAMILY_PARTITION(x) (x) +#endif + +#endif + #define ACQUIRE(s, x) MutexResource MAKE_NAME(mutexResource_) (s, x) using namespace vm; @@ -57,8 +122,10 @@ const unsigned HandlerCount = 2; class MySystem; MySystem* system; +#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) LONG CALLBACK handleException(LPEXCEPTION_POINTERS e); +#endif DWORD WINAPI run(void* r) @@ -559,7 +626,9 @@ class MySystem: public System { }; MySystem(const char* crashDumpDirectory): +#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) oldHandler(0), +#endif crashDumpDirectory(crashDumpDirectory) { expect(this, system == 0); @@ -581,27 +650,35 @@ class MySystem: public System { int registerHandler(System::SignalHandler* handler, int index) { if (handler) { handlers[index] = handler; - + +#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) if (oldHandler == 0) { -#ifdef ARCH_x86_32 +# ifdef ARCH_x86_32 oldHandler = SetUnhandledExceptionFilter(handleException); -#elif defined ARCH_x86_64 +# elif defined ARCH_x86_64 AddVectoredExceptionHandler(1, handleException); oldHandler = reinterpret_cast(1); -#endif +# endif } +#else + #pragma message("TODO: http://msdn.microsoft.com/en-us/library/windowsphone/develop/system.windows.application.unhandledexception(v=vs.105).aspx") +#endif return 0; } else if (handlers[index]) { handlers[index] = 0; if (not findHandler()) { -#ifdef ARCH_x86_32 +#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# ifdef ARCH_x86_32 SetUnhandledExceptionFilter(oldHandler); oldHandler = 0; -#elif defined ARCH_x86_64 +# elif defined ARCH_x86_64 // do nothing, handlers are never "unregistered" anyway -#endif +# endif +#else + #pragma message("TODO: http://msdn.microsoft.com/en-us/library/windowsphone/develop/system.windows.application.unhandledexception(v=vs.105).aspx") +#endif } return 0; @@ -618,6 +695,7 @@ class MySystem: public System { if (p) ::free(const_cast(p)); } + #if !defined(AVIAN_AOT_ONLY) virtual void* tryAllocateExecutable(unsigned sizeInBytes) { return VirtualAlloc (0, sizeInBytes, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); @@ -627,6 +705,7 @@ class MySystem: public System { int r UNUSED = VirtualFree(const_cast(p), 0, MEM_RELEASE); assert(this, r); } + #endif virtual bool success(Status s) { return s == 0; @@ -677,6 +756,7 @@ class MySystem: public System { virtual Status visit(System::Thread* st UNUSED, System::Thread* sTarget, ThreadVisitor* visitor) { +#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) assert(this, st != sTarget); Thread* target = static_cast(sTarget); @@ -692,15 +772,15 @@ class MySystem: public System { rv = GetThreadContext(target->thread, &context); if (rv) { -#ifdef ARCH_x86_32 +# ifdef ARCH_x86_32 visitor->visit(reinterpret_cast(context.Eip), reinterpret_cast(context.Ebp), reinterpret_cast(context.Esp)); -#elif defined ARCH_x86_64 +# elif defined ARCH_x86_64 visitor->visit(reinterpret_cast(context.Rip), reinterpret_cast(context.Rbp), reinterpret_cast(context.Rsp)); -#endif +# endif success = true; } @@ -709,6 +789,10 @@ class MySystem: public System { } return (success ? 0 : 1); +#else + #pragma message("TODO: http://msdn.microsoft.com/en-us/library/windowsphone/develop/system.windows.application.unhandledexception(v=vs.105).aspx") + return false; +#endif } virtual uint64_t call(void* function, uintptr_t* arguments, uint8_t* types, @@ -719,15 +803,37 @@ class MySystem: public System { virtual Status map(System::Region** region, const char* name) { Status status = 1; - - HANDLE file = CreateFile(name, FILE_READ_DATA, FILE_SHARE_READ, 0, - OPEN_EXISTING, 0, 0); + size_t nameLen = strlen(name) * 2; + RUNTIME_ARRAY(wchar_t, wideName, nameLen + 1); + MultiByteToWideChar(CP_UTF8, 0, name, -1, wideName, nameLen + 1); +#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + HANDLE file = CreateFileW(wideName, FILE_READ_DATA, FILE_SHARE_READ, 0, + OPEN_EXISTING, 0, 0); +#else + HANDLE file = CreateFile2(wideName, GENERIC_READ, FILE_SHARE_READ, + OPEN_EXISTING, 0); +#endif if (file != INVALID_HANDLE_VALUE) { +#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) unsigned size = GetFileSize(file, 0); +#else + FILE_STANDARD_INFO info; + unsigned size = INVALID_FILE_SIZE; + if(GetFileInformationByHandleEx(file, FileStandardInfo, &info, sizeof(info))) + size = info.EndOfFile.QuadPart; +#endif if (size != INVALID_FILE_SIZE) { +#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) HANDLE mapping = CreateFileMapping(file, 0, PAGE_READONLY, 0, size, 0); +#else + HANDLE mapping = CreateFileMappingFromApp(file, 0, PAGE_READONLY, size, 0); +#endif if (mapping) { +#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) void* data = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0); +#else + void* data = MapViewOfFileFromApp(mapping, FILE_MAP_READ, 0, 0); +#endif if (data) { *region = new (allocate(this, sizeof(Region))) Region(this, static_cast(data), size, file, mapping); @@ -757,7 +863,12 @@ class MySystem: public System { memcpy(RUNTIME_ARRAY_BODY(buffer) + length, "\\*", 3); Directory* d = new (allocate(this, sizeof(Directory))) Directory(this); + +#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) d->handle = FindFirstFile(RUNTIME_ARRAY_BODY(buffer), &(d->data)); +#else + d->handle = FindFirstFileEx(RUNTIME_ARRAY_BODY(buffer), FindExInfoStandard, &(d->data), FindExSearchNameMatch, 0, 0); +#endif if (d->handle == INVALID_HANDLE_VALUE) { d->dispose(); } else { @@ -769,21 +880,21 @@ class MySystem: public System { } virtual FileType stat(const char* name, unsigned* length) { - struct _stat s; - int r = _stat(name, &s); - if (r == 0) { - if (S_ISREG(s.st_mode)) { - *length = s.st_size; - return TypeFile; - } else if (S_ISDIR(s.st_mode)) { - *length = 0; + size_t nameLen = strlen(name) * 2; + RUNTIME_ARRAY(wchar_t, wideName, nameLen + 1); + MultiByteToWideChar(CP_UTF8, 0, name, -1, wideName, nameLen + 1); + WIN32_FILE_ATTRIBUTE_DATA data; + if (GetFileAttributesExW + (wideName, GetFileExInfoStandard, &data)) + { + if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { return TypeDirectory; } else { - *length = 0; - return TypeUnknown; + *length = (data.nFileSizeHigh * static_cast(MAXDWORD + 1)) + + data.nFileSizeLow; + return TypeFile; } } else { - *length = 0; return TypeDoesNotExist; } } @@ -797,6 +908,7 @@ class MySystem: public System { } virtual const char* toAbsolutePath(Allocator* allocator, const char* name) { +#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) if (strncmp(name, "//", 2) == 0 or strncmp(name, "\\\\", 2) == 0 or strncmp(name + 1, ":/", 2) == 0 @@ -808,6 +920,10 @@ class MySystem: public System { GetCurrentDirectory(MAX_PATH, buffer); return append(allocator, buffer, "\\", name); } +#else + #pragma message("TODO:http://lunarfrog.com/blog/2012/05/21/winrt-folders-access/ Windows.ApplicationModel.Package.Current.InstalledLocation") + return copy(allocator, name); +#endif } virtual Status load(System::Library** lib, @@ -816,9 +932,22 @@ class MySystem: public System { HMODULE handle; unsigned nameLength = (name ? strlen(name) : 0); if (name) { - handle = LoadLibrary(name); + size_t nameLen = nameLength * 2; + RUNTIME_ARRAY(wchar_t, wideName, nameLen + 1); + MultiByteToWideChar(CP_UTF8, 0, name, -1, wideName, nameLen + 1); + +#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + handle = LoadLibraryW(wideName); +#else + handle = LoadPackagedLibrary(wideName, 0); +#endif } else { +#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) handle = GetModuleHandle(0); +#else + // Most of WinRT/WP8 applications can not host native object files inside main executable + assert(this, false); +#endif } if (handle) { @@ -866,7 +995,11 @@ class MySystem: public System { } virtual void yield() { +#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) SwitchToThread(); +#else + YieldProcessor(); +#endif } virtual void exit(int code) { @@ -887,10 +1020,14 @@ class MySystem: public System { HANDLE mutex; SignalHandler* handlers[HandlerCount]; +#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) LPTOP_LEVEL_EXCEPTION_FILTER oldHandler; +#endif const char* crashDumpDirectory; }; +#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + #pragma pack(push,4) struct MINIDUMP_EXCEPTION_INFORMATION { DWORD thread; @@ -1005,6 +1142,8 @@ handleException(LPEXCEPTION_POINTERS e) return EXCEPTION_CONTINUE_SEARCH; } +#endif + } // namespace namespace vm { diff --git a/src/x86.masm b/src/x86.masm new file mode 100644 index 0000000000..2f9dedcbd2 --- /dev/null +++ b/src/x86.masm @@ -0,0 +1,168 @@ +comment # + Copyright (c) 2008-2011, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. + + ORIGIN: https://github.com/gkvas/avian/tree/wince +# + +.586 +.MODEL FLAT, C + +VOID_TYPE equ 0 +INT8_TYPE equ 1 +INT16_TYPE equ 2 +INT32_TYPE equ 3 +INT64_TYPE equ 4 +FLOAT_TYPE equ 5 +DOUBLE_TYPE equ 6 +POINTER_TYPE equ 7 + +CHECKPOINT_THREAD equ 4 +CHECKPOINT_STACK equ 24 +CHECKPOINT_BASE equ 28 + +_TEXT SEGMENT + +public C detectFeature +detectFeature: + push ebp + mov ebp,esp + push edx + push ecx + push ebx + push esi + push edi + mov esi,ds:dword ptr[12+ebp] + mov edi,ds:dword ptr[8+ebp] + mov eax,1 + cpuid + and edx,esi + and ecx,edi + or ecx,edx + test ecx,ecx + je LNOSSE + mov eax,1 + jmp LSSEEND + +LNOSSE: + mov eax,0 + +LSSEEND: + pop edi + pop esi + pop ebx + pop ecx + pop edx + mov esp,ebp + pop ebp + ret + +public C vmNativeCall +vmNativeCall: + push ebp + mov ebp,esp + mov ecx,ds:dword ptr[16+ebp] + sub esp,ecx + mov ecx,0 + jmp Ltest + +Lloop: + mov eax,ecx + mov edx,ecx + add edx,esp + add eax,ds:dword ptr[12+ebp] + mov eax,ds:dword ptr[eax] + mov ds:dword ptr[edx],eax + add ecx,4 + +Ltest: + cmp ecx,ds:dword ptr[16+ebp] + jb Lloop + call dword ptr[8+ebp] + mov ecx,ds:dword ptr[20+ebp] + +Lvoid: + cmp ecx,offset VOID_TYPE + jne Lint64 + jmp Lexit + +Lint64: + cmp ecx,offset INT64_TYPE + jne Lfloat + jmp Lexit + +Lfloat: + cmp ecx,offset FLOAT_TYPE + jne Ldouble + fstp ds:dword ptr[8+ebp] + mov eax,ds:dword ptr[8+ebp] + jmp Lexit + +Ldouble: + cmp ecx,offset DOUBLE_TYPE + jne Lexit + fstp ds:qword ptr[8+ebp] + mov eax,ds:dword ptr[8+ebp] + mov edx,ds:dword ptr[12+ebp] + +Lexit: + mov esp,ebp + pop ebp + ret + +public C vmJump +vmJump: + mov esi,ds:dword ptr[4+esp] + mov ebp,ds:dword ptr[8+esp] + mov ebx,ds:dword ptr[16+esp] + mov eax,ds:dword ptr[20+esp] + mov edx,ds:dword ptr[24+esp] + mov esp,ds:dword ptr[12+esp] + jmp esi + +VMRUN_FRAME_SIZE equ 24 + +public C vmRun_ +vmRun_: + ; 8(%ebp): function + ; 12(%ebp): arguments + ; 16(%ebp): checkpoint + push ebp + mov ebp,esp + sub esp,offset VMRUN_FRAME_SIZE + + mov ds:dword ptr[8+esp],ebx + mov ds:dword ptr[12+esp],esi + mov ds:dword ptr[16+esp],edi + + mov eax,ds:dword ptr[12+ebp] + mov ds:dword ptr[4+esp],eax + + mov ecx,ds:dword ptr[16+ebp] + mov eax,ds:dword ptr[CHECKPOINT_THREAD+ecx] + mov ds:dword ptr[0+esp],eax + + mov ds:dword ptr[CHECKPOINT_STACK+ecx],esp + + call dword ptr[8+ebp] + +public C vmRun_returnAddress +vmRun_returnAddress: + + mov ebx,ds:dword ptr[8+esp] + mov esi,ds:dword ptr[12+esp] + mov edi,ds:dword ptr[16+esp] + + add esp,offset VMRUN_FRAME_SIZE + pop ebp + ret + +_TEXT ENDS +END \ No newline at end of file diff --git a/vm.pro b/vm.pro index 4cdb1654ee..8d1ab22177 100644 --- a/vm.pro +++ b/vm.pro @@ -71,6 +71,7 @@ -keep public class java.io.IOException -keep public class java.io.FileNotFoundException -keep public class java.net.SocketException +-keep public class java.util.Locale # ClassLoader.getSystemClassloader() depends on the existence of this class: