From 1fdc016e583043db89704c2e069581b4b9e5a8af Mon Sep 17 00:00:00 2001 From: jet Date: Tue, 5 Oct 2010 17:24:44 -0600 Subject: [PATCH 001/117] Beginning of branch. Being pushed for testing purposes. --- classpath/java-lang.cpp | 111 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/classpath/java-lang.cpp b/classpath/java-lang.cpp index 8303e3e4e1..06bc4e0c2d 100644 --- a/classpath/java-lang.cpp +++ b/classpath/java-lang.cpp @@ -229,6 +229,82 @@ Java_java_lang_Runtime_waitFor(JNIEnv* e, jclass, jlong pid) } return exitCode; } + +void getLocale(char* language, char* region) { + const char* lang = 0; + const char* reg = 0; + + unsigned locale = GetUserDefaultUILanguage(); + unsigned prilang = locale & 0x3ff; + unsigned sublang = locale >> 10; + + switch (prilang) { + case 0x004: { + lang = "zh"; + switch (sublang) { + case 0x01: reg = "Hant"; break; + case 0x02: reg = "Hans"; break; + case 0x03: reg = "HK"; break; + case 0x04: reg = "SG"; break; + } + } break; + case 0x006: lang = "da"; reg = "DK"; break; + case 0x007: lang = "de"; reg = "DE"; break; + case 0x009: { + lang = "en"; + switch (sublang) { + case 0x01: reg = "US"; break; + case 0x02: reg = "GB"; break; + case 0x03: reg = "AU"; break; + case 0x04: reg = "CA"; break; + case 0x05: reg = "NZ"; break; + case 0x06: reg = "IE"; break; + case 0x07: reg = "ZA"; break; + case 0x10: reg = "IN"; break; + } + } break; + case 0x00a: { + lang = "es"; + switch (sublang) { + case 0x01: case: 0x03: reg = "ES"; break; + case 0x02: reg = "MX"; break; + } + } break; + case 0x00c: { + lang = "fr"; + switch (sublang) { + case 0x01: reg = "FR"; break; + case 0x02: reg = "BE"; break; + case 0x03: reg = "CA"; break; + } + } break; + case 0x010: lang = "it"; reg = "IT"; break; + case 0x011: lang = "ja"; reg = "JP"; break; + case 0x012: lang = "ko"; reg = "KR"; break; + case 0x013: { + lang = "nl"; + switch (sublang) { + case 0x01: reg = "NL"; break; + case 0x02: reg = "BE"; break; + } + } break; + case 0x014: lang = "no"; reg = "NO"; break; + case 0x015: lang = "pl"; reg = "PL"; break; + case 0x016: { + lang = "pt"; + switch (sublang) { + case 0x01: reg = "BR"; break; + case 0x02: reg = "PT"; break; + } + } break; + case 0x018: lang = "ro"; reg = "RO"; break; + case 0x019: lang = "ru"; reg = "RU"; break; + case 0x01d: lang = "sv"; reg = "SE"; break; + } + + if (language) memcpy(language, lang, strlen(lang) * sizeof(char)); + if (region) memcpy(region, reg, strlen(reg) * sizeof(char)); +} #else extern "C" JNIEXPORT void JNICALL Java_java_lang_Runtime_exec(JNIEnv* e, jclass, @@ -352,6 +428,32 @@ Java_java_lang_Runtime_waitFor(JNIEnv*, jclass, jlong pid) return exitCode; } + +void getLocale(char* language, char* region) { + const char* LANG = getenv("LANG"); + + char dummy = '\0'; + char* lang = &dummy; + char* reg = &dummy; + + if (LANG) { + unsigned underscore = 0; + while (underscore < strlen(LANG) && *(LANG + underscore) != '_') ++underscore; + unsigned period = underscore + 1; + while (period < strlen(LANG) && *(LANG + period) != '.') ++period; + + unsigned reglen = period - underscore - 1; + char lang_[underscore + 1]; lang = lang_; + char reg_[reglen + 1]; reg = reg_; + + memcpy(lang, LANG, underscore * sizeof(char)); + memcpy(reg, LANG + underscore + 1, reglen * sizeof(char)); + lang[underscore] = reg[reglen] = '\0'; + } + + if (language) memcpy(language, lang, strlen(lang) * sizeof(char)); + if (region) memcpy(region, reg, strlen(reg) * sizeof(char)); +} #endif extern "C" JNIEXPORT jstring JNICALL @@ -452,6 +554,15 @@ Java_java_lang_System_getProperty(JNIEnv* e, jclass, jstring name, r = e->NewStringUTF(getenv("HOME")); } #endif + else if (strcmp(chars, "user.language") == 0) { + char lang[16]; + getLocale(lang, 0); + if (strlen(lang)) r = e->NewStringUTF(lang); + } else if (strcmp(chars, "user.region") == 0) { + char reg[16]; + getLocale(0, reg); + if (strlen(reg)) r = e->NewStringUTF(reg); + } e->ReleaseStringUTFChars(name, chars); } From 45e6cd5a60165859b17d3f8f0472d95ebc16eb25 Mon Sep 17 00:00:00 2001 From: JET Date: Tue, 5 Oct 2010 17:53:17 -0600 Subject: [PATCH 002/117] The localization properties are now functional. Only 16 languages are currently reported on Windows. --- classpath/java-lang.cpp | 15 ++++++++------- makefile | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/classpath/java-lang.cpp b/classpath/java-lang.cpp index 06bc4e0c2d..e0b45b1388 100644 --- a/classpath/java-lang.cpp +++ b/classpath/java-lang.cpp @@ -231,8 +231,9 @@ Java_java_lang_Runtime_waitFor(JNIEnv* e, jclass, jlong pid) } void getLocale(char* language, char* region) { - const char* lang = 0; - const char* reg = 0; + const char dummy = '\0'; + const char* lang = &dummy; + const char* reg = &dummy; unsigned locale = GetUserDefaultUILanguage(); unsigned prilang = locale & 0x3ff; @@ -266,7 +267,7 @@ void getLocale(char* language, char* region) { case 0x00a: { lang = "es"; switch (sublang) { - case 0x01: case: 0x03: reg = "ES"; break; + case 0x01: case 0x03: reg = "ES"; break; case 0x02: reg = "MX"; break; } } break; @@ -302,8 +303,8 @@ void getLocale(char* language, char* region) { case 0x01d: lang = "sv"; reg = "SE"; break; } - if (language) memcpy(language, lang, strlen(lang) * sizeof(char)); - if (region) memcpy(region, reg, strlen(reg) * sizeof(char)); + if (language) memcpy(language, lang, (strlen(lang) + 1) * sizeof(char)); + if (region) memcpy(region, reg, (strlen(reg) + 1) * sizeof(char)); } #else extern "C" JNIEXPORT void JNICALL @@ -451,8 +452,8 @@ void getLocale(char* language, char* region) { lang[underscore] = reg[reglen] = '\0'; } - if (language) memcpy(language, lang, strlen(lang) * sizeof(char)); - if (region) memcpy(region, reg, strlen(reg) * sizeof(char)); + if (language) memcpy(language, lang, (strlen(lang) + 1) * sizeof(char)); + if (region) memcpy(region, reg, (strlen(reg) + 1) * sizeof(char)); } #endif diff --git a/makefile b/makefile index f0dcab31a5..a8b450a7ed 100644 --- a/makefile +++ b/makefile @@ -190,7 +190,7 @@ ifeq ($(platform),windows) exe-suffix = .exe lflags = -L$(lib) $(common-lflags) -lws2_32 -mwindows -mconsole - cflags = -I$(inc) $(common-cflags) + cflags = -I$(inc) $(common-cflags) -DWINVER=0x0500 ifeq (,$(filter mingw32 cygwin,$(build-platform))) cxx = i586-mingw32msvc-g++ From 8feb5a8124e4b8a1cef2d7f9e0e84fcf25fa308e Mon Sep 17 00:00:00 2001 From: jet Date: Tue, 5 Oct 2010 22:29:41 -0600 Subject: [PATCH 003/117] Fixed bug where locale region became a copy of the language. --- classpath/java-lang.cpp | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/classpath/java-lang.cpp b/classpath/java-lang.cpp index e0b45b1388..31f4c65b7b 100644 --- a/classpath/java-lang.cpp +++ b/classpath/java-lang.cpp @@ -431,29 +431,24 @@ Java_java_lang_Runtime_waitFor(JNIEnv*, jclass, jlong pid) } void getLocale(char* language, char* region) { + unsigned langlen = 0, reglen = 0; const char* LANG = getenv("LANG"); - char dummy = '\0'; - char* lang = &dummy; - char* reg = &dummy; - if (LANG) { - unsigned underscore = 0; - while (underscore < strlen(LANG) && *(LANG + underscore) != '_') ++underscore; - unsigned period = underscore + 1; - while (period < strlen(LANG) && *(LANG + period) != '.') ++period; - - unsigned reglen = period - underscore - 1; - char lang_[underscore + 1]; lang = lang_; - char reg_[reglen + 1]; reg = reg_; - - memcpy(lang, LANG, underscore * sizeof(char)); - memcpy(reg, LANG + underscore + 1, reglen * sizeof(char)); - lang[underscore] = reg[reglen] = '\0'; + while (langlen < strlen(LANG) && *(LANG + langlen) != '_') ++langlen; + unsigned regend = langlen + 1; + while (regend < strlen(LANG) && *(LANG + regend) != '.') ++regend; + reglen = regend - langlen - 1; } - if (language) memcpy(language, lang, (strlen(lang) + 1) * sizeof(char)); - if (region) memcpy(region, reg, (strlen(reg) + 1) * sizeof(char)); + if (language) { + memcpy(language, LANG, langlen * sizeof(char)); + language[langlen] = '\0'; + } + if (region) { + memcpy(region, LANG + langlen + 1, reglen * sizeof(char)); + region[reglen] = '\0'; + } } #endif From cddc305a759c630beead7ea184fc7f773fcc89e8 Mon Sep 17 00:00:00 2001 From: jet Date: Thu, 7 Oct 2010 16:32:59 -0600 Subject: [PATCH 004/117] Locale error checking is now more robust. --- classpath/java-lang.cpp | 120 +++++++++++++++++++++++++++++----------- 1 file changed, 88 insertions(+), 32 deletions(-) diff --git a/classpath/java-lang.cpp b/classpath/java-lang.cpp index 31f4c65b7b..415ad9301e 100644 --- a/classpath/java-lang.cpp +++ b/classpath/java-lang.cpp @@ -18,6 +18,7 @@ #include "jni-util.h" #include "errno.h" #include "fcntl.h" +#include "ctype.h" #ifdef PLATFORM_WINDOWS @@ -132,6 +133,59 @@ namespace { #endif } +class Locale { + static const unsigned MINLEN = 2; + static const unsigned MAXLEN = 3; + static const unsigned FIELDSIZE = MAXLEN + 1; + + static const char* DEFAULT_LANGUAGE; + static const char* DEFAULT_REGION; + + char language[FIELDSIZE]; + char region[FIELDSIZE]; + + bool isLanguage(const char* language) { + if (!language) return false; + unsigned len = strlen(language); + if (len < MINLEN || len > MAXLEN) return false; + const char* p = language - 1; + while (islower(*++p)); + if (*p != '\0') return false; + return true; + } + + bool isRegion(const char* region) { + if (!region) return false; + unsigned len = strlen(region); + if ((len != 0 && len < MINLEN) || len > MAXLEN) return false; + const char* p = region - 1; + while (isupper(*++p)); + if (*p != '\0') return false; + return true; + } + +public: + Locale(const char* language = "", const char* region = "") { + if (!isLanguage(language) || !isRegion(region)) { + language = DEFAULT_LANGUAGE; + region = DEFAULT_REGION; + } + memcpy(this->language, language, strlen(language) + 1); + memcpy(this->region, region, strlen(region) + 1); + } + + Locale& operator=(const Locale& l) { + memcpy(language, l.language, FIELDSIZE); + memcpy(region, l.region, FIELDSIZE); + return *this; + } + + const char* getLanguage() { return reinterpret_cast(language); } + const char* getRegion() { return reinterpret_cast(region); } +}; +const char* Locale::DEFAULT_LANGUAGE = "en"; +const char* Locale::DEFAULT_REGION = ""; + #ifdef PLATFORM_WINDOWS extern "C" JNIEXPORT void JNICALL Java_java_lang_Runtime_exec(JNIEnv* e, jclass, @@ -230,14 +284,12 @@ Java_java_lang_Runtime_waitFor(JNIEnv* e, jclass, jlong pid) return exitCode; } -void getLocale(char* language, char* region) { - const char dummy = '\0'; - const char* lang = &dummy; - const char* reg = &dummy; - - unsigned locale = GetUserDefaultUILanguage(); - unsigned prilang = locale & 0x3ff; - unsigned sublang = locale >> 10; +Locale getLocale() { + const char* lang = ""; + const char* reg = ""; + unsigned langid = GetUserDefaultUILanguage(); + unsigned prilang = langid & 0x3ff; + unsigned sublang = langid >> 10; switch (prilang) { case 0x004: { @@ -301,10 +353,11 @@ void getLocale(char* language, char* region) { case 0x018: lang = "ro"; reg = "RO"; break; case 0x019: lang = "ru"; reg = "RU"; break; case 0x01d: lang = "sv"; reg = "SE"; break; + default: lang = "en"; } - if (language) memcpy(language, lang, (strlen(lang) + 1) * sizeof(char)); - if (region) memcpy(region, reg, (strlen(reg) + 1) * sizeof(char)); + Locale locale(lang, reg); + return locale; } #else extern "C" JNIEXPORT void JNICALL @@ -430,25 +483,30 @@ Java_java_lang_Runtime_waitFor(JNIEnv*, jclass, jlong pid) return exitCode; } -void getLocale(char* language, char* region) { - unsigned langlen = 0, reglen = 0; +Locale getLocale() { + Locale fallback; + const char* LANG = getenv("LANG"); + if (!LANG || strcmp(LANG, "C") == 0) return fallback; - if (LANG) { - while (langlen < strlen(LANG) && *(LANG + langlen) != '_') ++langlen; - unsigned regend = langlen + 1; - while (regend < strlen(LANG) && *(LANG + regend) != '.') ++regend; - reglen = regend - langlen - 1; - } + int len = strlen(LANG); + char buf[len]; + memcpy(buf, LANG, len); - if (language) { - memcpy(language, LANG, langlen * sizeof(char)); - language[langlen] = '\0'; - } - if (region) { - memcpy(region, LANG + langlen + 1, reglen * sizeof(char)); - region[reglen] = '\0'; - } + char* tracer = buf; + const char* reg; + + while (*tracer && *tracer != '_') ++tracer; + if (!*tracer) return fallback; + *tracer = '\0'; + reg = tracer++ + 1; + + while (*tracer && *tracer != '.') ++tracer; + if (tracer == reg) return fallback; + *tracer = '\0'; + + Locale locale(buf, reg); + return locale; } #endif @@ -551,13 +609,11 @@ Java_java_lang_System_getProperty(JNIEnv* e, jclass, jstring name, } #endif else if (strcmp(chars, "user.language") == 0) { - char lang[16]; - getLocale(lang, 0); - if (strlen(lang)) r = e->NewStringUTF(lang); + Locale locale = getLocale(); + if (strlen(locale.getLanguage())) r = e->NewStringUTF(locale.getLanguage()); } else if (strcmp(chars, "user.region") == 0) { - char reg[16]; - getLocale(0, reg); - if (strlen(reg)) r = e->NewStringUTF(reg); + Locale locale = getLocale(); + if (strlen(locale.getRegion())) r = e->NewStringUTF(locale.getRegion()); } e->ReleaseStringUTFChars(name, chars); From 0713f8d5cb39c810e2eee57f2cd4ba01fb406fcf Mon Sep 17 00:00:00 2001 From: jet Date: Thu, 14 Oct 2010 16:20:41 -0600 Subject: [PATCH 005/117] Locale system changes to better mimic Sun's VM. --- classpath/java-lang.cpp | 32 +++++++++++++++++--------------- classpath/java/util/Locale.java | 10 ++++++++-- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/classpath/java-lang.cpp b/classpath/java-lang.cpp index 415ad9301e..3b2c0ed52b 100644 --- a/classpath/java-lang.cpp +++ b/classpath/java-lang.cpp @@ -133,10 +133,9 @@ namespace { #endif } -class Locale { - static const unsigned MINLEN = 2; - static const unsigned MAXLEN = 3; - static const unsigned FIELDSIZE = MAXLEN + 1; +class Locale { // represents an ISO two-char language/country pair + static const unsigned FIELDLEN = 2; + static const unsigned FIELDSIZE = FIELDLEN + 1; static const char* DEFAULT_LANGUAGE; static const char* DEFAULT_REGION; @@ -147,7 +146,7 @@ class Locale { bool isLanguage(const char* language) { if (!language) return false; unsigned len = strlen(language); - if (len < MINLEN || len > MAXLEN) return false; + if (len != FIELDLEN) return false; const char* p = language - 1; while (islower(*++p)); if (*p != '\0') return false; @@ -157,7 +156,7 @@ class Locale { bool isRegion(const char* region) { if (!region) return false; unsigned len = strlen(region); - if ((len != 0 && len < MINLEN) || len > MAXLEN) return false; + if (len != FIELDLEN) return false; const char* p = region - 1; while (isupper(*++p)); if (*p != '\0') return false; @@ -165,13 +164,16 @@ class Locale { } public: - Locale(const char* language = "", const char* region = "") { - if (!isLanguage(language) || !isRegion(region)) { - language = DEFAULT_LANGUAGE; - region = DEFAULT_REGION; - } - memcpy(this->language, language, strlen(language) + 1); - memcpy(this->region, region, strlen(region) + 1); + Locale(const char* language = "") { + Locale l(language, ""); + *this = l; + } + + Locale(const char* language, const char* region) { + language = isLanguage(language) ? language : DEFAULT_LANGUAGE; + region = isRegion(region) ? region : DEFAULT_REGION; + memcpy(this->language, language, FIELDSIZE); + memcpy(this->region, region, FIELDSIZE); } Locale& operator=(const Locale& l) { @@ -295,8 +297,8 @@ Locale getLocale() { case 0x004: { lang = "zh"; switch (sublang) { - case 0x01: reg = "Hant"; break; - case 0x02: reg = "Hans"; break; + case 0x01: reg = "CN"; break; + case 0x02: reg = "TW"; break; case 0x03: reg = "HK"; break; case 0x04: reg = "SG"; break; } diff --git a/classpath/java/util/Locale.java b/classpath/java/util/Locale.java index c53b6f4ed1..8c756ff406 100644 --- a/classpath/java/util/Locale.java +++ b/classpath/java/util/Locale.java @@ -11,12 +11,18 @@ package java.util; public class Locale { - public static final Locale ENGLISH = new Locale("en", "us"); + private static final Locale DEFAULT; + public static final Locale ENGLISH = new Locale("en", ""); private final String language; private final String country; private final String variant; + static { + DEFAULT = new Locale(System.getProperty("user.language"), + System.getProperty("user.region")); + } + public Locale(String language, String country, String variant) { this.language = language; this.country = country; @@ -44,6 +50,6 @@ public class Locale { } public static Locale getDefault() { - return ENGLISH; + return DEFAULT; } } From 8c54446c67e2edef7b4aacc7661b4596f99816a6 Mon Sep 17 00:00:00 2001 From: JET Date: Mon, 8 Nov 2010 09:47:46 -0700 Subject: [PATCH 006/117] Fixed minor compiler warnings. --- classpath/java-lang.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/classpath/java-lang.cpp b/classpath/java-lang.cpp index 3b2c0ed52b..59f7acc8da 100644 --- a/classpath/java-lang.cpp +++ b/classpath/java-lang.cpp @@ -148,7 +148,7 @@ class Locale { // represents an ISO two-char language/country pair unsigned len = strlen(language); if (len != FIELDLEN) return false; const char* p = language - 1; - while (islower(*++p)); + while (islower(*++p)) ; if (*p != '\0') return false; return true; } @@ -158,7 +158,7 @@ class Locale { // represents an ISO two-char language/country pair unsigned len = strlen(region); if (len != FIELDLEN) return false; const char* p = region - 1; - while (isupper(*++p)); + while (isupper(*++p)) ; if (*p != '\0') return false; return true; } From 7270eb78790994fef8c42215bcd363d7c613a9d6 Mon Sep 17 00:00:00 2001 From: JET Date: Wed, 15 Dec 2010 15:18:43 -0700 Subject: [PATCH 007/117] Fixed behavior of Locale and implemented its toString(). --- classpath/java/util/Locale.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/classpath/java/util/Locale.java b/classpath/java/util/Locale.java index 8c756ff406..373506bdec 100644 --- a/classpath/java/util/Locale.java +++ b/classpath/java/util/Locale.java @@ -30,11 +30,11 @@ public class Locale { } public Locale(String language, String country) { - this(language, country, null); + this(language, country, ""); } public Locale(String language) { - this(language, null); + this(language, ""); } public String getLanguage() { @@ -52,4 +52,13 @@ public class Locale { public static Locale getDefault() { return DEFAULT; } + + public final String toString() { + boolean hasLanguage = language != ""; + boolean hasCountry = country != ""; + boolean hasVariant = variant != ""; + + if (!hasLanguage && !hasCountry) return ""; + return language + (hasCountry || hasVariant ? '_' + country : "") + (hasVariant ? '_' + variant : ""); + } } From 98166dcc61488f949235406e63d1ad6bbbe2dc3e Mon Sep 17 00:00:00 2001 From: JET Date: Tue, 21 Dec 2010 11:39:26 -0700 Subject: [PATCH 008/117] ASCII escapes in property files are now parsed, albeit crudely. --- classpath/java/util/Properties.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/classpath/java/util/Properties.java b/classpath/java/util/Properties.java index a09ba77808..b67d783c67 100644 --- a/classpath/java/util/Properties.java +++ b/classpath/java/util/Properties.java @@ -137,6 +137,19 @@ public class Properties extends Hashtable { } break; + case 'u': + if (escaped) { // ASCII Unicode escape + int most = Character.digit((char)in.read(), 16); + int more = Character.digit((char)in.read(), 16); + int less = Character.digit((char)in.read(), 16); + int least = Character.digit((char)in.read(), 16); + char utf16 = (char)(most << 12 | more << 8 | less << 4 | least); + append(utf16); + } else { + append(c); + } + break; + default: append(c); break; From 16b936a60035fb278594f684dc01db7395d0fade Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 1 Mar 2011 15:32:14 -0700 Subject: [PATCH 009/117] mention Linux/PowerPC support in readme.txt --- readme.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.txt b/readme.txt index 708c948d13..f4153af60d 100644 --- a/readme.txt +++ b/readme.txt @@ -51,7 +51,7 @@ Supported Platforms Avian can currently target the following platforms: - Linux (i386, x86_64 and ARM) + Linux (i386, x86_64, ARM, and 32-bit PowerPC) Windows (i386 and x86_64) Mac OS X (i386, x86_64 and 32-bit PowerPC) From fc45cf767b04acc1650ecb3b79e66a35e36c5f28 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 2 Mar 2011 08:29:44 -0700 Subject: [PATCH 010/117] implement JNIEnv::GetSuperclass; use vm::run in JNIEnv::GetObjectClass --- src/jnienv.cpp | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 3fb07db9ad..3d17a22949 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -430,12 +430,40 @@ GetDirectBufferCapacity(Thread*, jobject) return -1; } +uint64_t +getObjectClass(Thread* t, uintptr_t* arguments) +{ + jobject o = reinterpret_cast(arguments[0]); + + return reinterpret_cast + (makeLocalReference(t, getJClass(t, objectClass(t, *o)))); +} + jclass JNICALL GetObjectClass(Thread* t, jobject o) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o) }; - return makeLocalReference(t, getJClass(t, objectClass(t, *o))); + return reinterpret_cast(run(t, getObjectClass, arguments)); +} + +uint64_t +getSuperclass(Thread* t, uintptr_t* arguments) +{ + jclass c = reinterpret_cast(arguments[0]); + + object super = classSuper(t, jclassVmClass(t, *c)); + + return super ? reinterpret_cast + (makeLocalReference(t, getJClass(t, super))) : 0; +} + +jclass JNICALL +GetSuperclass(Thread* t, jclass c) +{ + uintptr_t arguments[] = { reinterpret_cast(c) }; + + return reinterpret_cast(run(t, getSuperclass, arguments)); } jboolean JNICALL @@ -2358,6 +2386,7 @@ populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable) envTable->GetDirectBufferCapacity = local::GetDirectBufferCapacity; envTable->DeleteLocalRef = local::DeleteLocalRef; envTable->GetObjectClass = local::GetObjectClass; + envTable->GetSuperclass = local::GetSuperclass; envTable->IsInstanceOf = local::IsInstanceOf; envTable->IsAssignableFrom = local::IsAssignableFrom; envTable->GetFieldID = local::GetFieldID; From 4db79b9be62606c8ea6c717a9415e2439928c22f Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 2 Mar 2011 08:35:45 -0700 Subject: [PATCH 011/117] implement various sun.misc.Unsafe and JVM_* methods --- src/classpath-openjdk.cpp | 67 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 65 insertions(+), 2 deletions(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 61bbc06dbf..64e50d4599 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -1585,6 +1585,16 @@ Avian_sun_misc_Unsafe_getIntVolatile return result; } +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_getLong__Ljava_lang_Object_2J +(Thread*, object, uintptr_t* arguments) +{ + object o = reinterpret_cast(arguments[1]); + int64_t offset; memcpy(&offset, arguments + 2, 8); + + return cast(o, offset); +} + extern "C" JNIEXPORT int64_t JNICALL Avian_sun_misc_Unsafe_getLongVolatile (Thread* t, object, uintptr_t* arguments) @@ -1666,6 +1676,19 @@ Avian_sun_misc_Unsafe_getObjectVolatile return value; } +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_putObjectVolatile +(Thread* t, object, uintptr_t* arguments) +{ + object o = reinterpret_cast(arguments[1]); + int64_t offset; memcpy(&offset, arguments + 2, 8); + object value = reinterpret_cast(arguments[4]); + + storeStoreMemoryBarrier(); + set(t, o, offset, reinterpret_cast(value)); + storeLoadMemoryBarrier(); +} + extern "C" JNIEXPORT int64_t JNICALL Avian_sun_misc_Unsafe_compareAndSwapInt (Thread*, object, uintptr_t* arguments) @@ -1744,6 +1767,16 @@ Avian_sun_misc_Unsafe_setMemory memset(reinterpret_cast(p), v, count); } +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_putByte__JB +(Thread*, object, uintptr_t* arguments) +{ + int64_t p; memcpy(&p, arguments + 1, 8); + int8_t v = arguments[3]; + + *reinterpret_cast(p) = v; +} + extern "C" JNIEXPORT void JNICALL Avian_sun_misc_Unsafe_putLong__JJ (Thread*, object, uintptr_t* arguments) @@ -2489,7 +2522,34 @@ EXPORT(JVM_AllocateNewArray)(Thread*, jobject, jclass, jint) { abort(); } extern "C" JNIEXPORT jobject JNICALL -EXPORT(JVM_LatestUserDefinedLoader)(Thread*) { abort(); } +EXPORT(JVM_LatestUserDefinedLoader)(Thread* t) +{ + ENTER(t, Thread::ActiveState); + + class Visitor: public Processor::StackVisitor { + public: + Visitor(Thread* t): + t(t), loader(0) + { } + + virtual bool visit(Processor::StackWalker* walker) { + object loader = classLoader(t, methodClass(t, walker->method())); + if (loader and loader != root(t, Machine::BootLoader)) { + this->loader = loader; + return false; + } else { + return true; + } + } + + Thread* t; + object loader; + } v(t); + + t->m->processor->walkStack(t, &v); + + return makeLocalReference(t, v.loader); +} extern "C" JNIEXPORT jclass JNICALL EXPORT(JVM_LoadClass0)(Thread*, jobject, jclass, @@ -3764,7 +3824,10 @@ EXPORT(JVM_SendTo)(jint, char*, int, int, struct sockaddr*, int) { abort(); } extern "C" JNIEXPORT jint JNICALL -EXPORT(JVM_SocketAvailable)(jint, jint*) { abort(); } +EXPORT(JVM_SocketAvailable)(jint socket, jint* count) +{ + return ioctl(socket, FIONREAD, count) < 0 ? 0 : 1; +} extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_GetSockName)(jint socket, struct sockaddr* address, From 8fb9523de540e6748cae0505b8d6853be5828135 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 4 Mar 2011 15:58:10 -0700 Subject: [PATCH 012/117] don't try to print null exception trace in printTrace It is possible to create an Exception with no stack trace by overriding Throwable.fillInStackTrace, so we can't assume any given instance will have one. --- src/machine.cpp | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/src/machine.cpp b/src/machine.cpp index a561006ca7..1f4e895148 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -3904,26 +3904,28 @@ printTrace(Thread* t, object exception) } object trace = throwableTrace(t, e); - for (unsigned i = 0; i < objectArrayLength(t, trace); ++i) { - object e = objectArrayBody(t, trace, i); - const int8_t* class_ = &byteArrayBody - (t, className(t, methodClass(t, traceElementMethod(t, e))), 0); - const int8_t* method = &byteArrayBody - (t, methodName(t, traceElementMethod(t, e)), 0); - int line = t->m->processor->lineNumber - (t, traceElementMethod(t, e), traceElementIp(t, e)); + if (trace) { + for (unsigned i = 0; i < objectArrayLength(t, trace); ++i) { + object e = objectArrayBody(t, trace, i); + const int8_t* class_ = &byteArrayBody + (t, className(t, methodClass(t, traceElementMethod(t, e))), 0); + const int8_t* method = &byteArrayBody + (t, methodName(t, traceElementMethod(t, e)), 0); + int line = t->m->processor->lineNumber + (t, traceElementMethod(t, e), traceElementIp(t, e)); - fprintf(stderr, " at %s.%s ", class_, method); + fprintf(stderr, " at %s.%s ", class_, method); - switch (line) { - case NativeLine: - fprintf(stderr, "(native)\n"); - break; - case UnknownLine: - fprintf(stderr, "(unknown line)\n"); - break; - default: - fprintf(stderr, "(line %d)\n", line); + switch (line) { + case NativeLine: + fprintf(stderr, "(native)\n"); + break; + case UnknownLine: + fprintf(stderr, "(unknown line)\n"); + break; + default: + fprintf(stderr, "(line %d)\n", line); + } } } From 874890e31793292f71be456ee5a27c194577fbc5 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 4 Mar 2011 16:01:50 -0700 Subject: [PATCH 013/117] assert exception parameter is not null in throw_ --- src/machine.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/machine.h b/src/machine.h index 6c3633000f..4031093138 100644 --- a/src/machine.h +++ b/src/machine.h @@ -2597,6 +2597,7 @@ inline void NO_RETURN throw_(Thread* t, object e) { assert(t, t->exception == 0); + assert(t, e); expect(t, not t->checkpoint->noThrow); From 78790a0f686819b6e9e8902f999bb696d2ed3bff Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 4 Mar 2011 16:55:31 -0700 Subject: [PATCH 014/117] fix OpenJDK JCE support This primarily required additions to classpath-openjdk.cpp to intercept ZipFile, ZipEntry, and JarFile native methods to consult embedded encryption policy jars when required. --- makefile | 5 +- src/classpath-openjdk.cpp | 538 ++++++++++++++++++++++++++++++++++++++ src/common.h | 10 + src/finder.cpp | 95 +------ src/finder.h | 88 +++++++ 5 files changed, 645 insertions(+), 91 deletions(-) diff --git a/makefile b/makefile index 35db15f9f9..d6fc68549d 100644 --- a/makefile +++ b/makefile @@ -90,7 +90,9 @@ ifneq ($(openjdk),) openjdk-jar-dep = $(build)/openjdk-jar.dep classpath-jar-dep = $(openjdk-jar-dep) javahome = $(embed-prefix)/javahomeJar - javahome-files = lib/zi lib/currency.data + javahome-files = lib/zi lib/currency.data lib/security/java.security \ + lib/security/java.policy lib/security/cacerts \ + lib/security/local_policy.jar lib/security/US_export_policy.jar ifeq ($(platform),windows) javahome-files += lib/tzmappings endif @@ -905,5 +907,6 @@ $(openjdk-jar-dep): $(jar) xf "$$($(native-path) "$(openjdk)/jre/lib/rt.jar")" && \ $(jar) xf "$$($(native-path) "$(openjdk)/jre/lib/jsse.jar")" && \ $(jar) xf "$$($(native-path) "$(openjdk)/jre/lib/jce.jar")" && \ + $(jar) xf "$$($(native-path) "$(openjdk)/jre/lib/ext/sunjce_provider.jar")" && \ $(jar) xf "$$($(native-path) "$(openjdk)/jre/lib/resources.jar")") @touch $(@) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 64e50d4599..4d50227a83 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -224,6 +224,9 @@ class MyClasspath : public Classpath { sb.append("/lib/jce.jar"); sb.append(s->pathSeparator()); sb.append(javaHome); + sb.append("/lib/ext/sunjce_provider.jar"); + sb.append(s->pathSeparator()); + sb.append(javaHome); sb.append("/lib/resources.jar"); sb.append('\0'); @@ -400,6 +403,13 @@ class MyClasspath : public Classpath { unsigned filePathField; unsigned fileDescriptorFdField; unsigned fileInputStreamFdField; + unsigned zipFileJzfileField; + unsigned zipEntryNameField; + unsigned zipEntryTimeField; + unsigned zipEntryCrcField; + unsigned zipEntrySizeField; + unsigned zipEntryCsizeField; + unsigned zipEntryMethodField; bool ranNetOnLoad; char buffer[BufferSize]; }; @@ -925,6 +935,438 @@ closeFile(Thread* t, object method, uintptr_t* arguments) } } +class ZipFile { + public: + class Entry { + public: + Entry(unsigned hash, const uint8_t* start, Entry* next): + hash(hash), start(start), next(next), entry(0) + { } + + Entry(int64_t entry): + hash(0), start(0), next(0), entry(entry) + { } + + unsigned hash; + const uint8_t* start; + Entry* next; + int64_t entry; + }; + + ZipFile(Thread* t, System::Region* region, unsigned entryCount): + region(region), + entryCount(entryCount), + indexSize(nextPowerOfTwo(entryCount)), + index(reinterpret_cast + (t->m->heap->allocate(sizeof(ZipFile::Entry*) * indexSize))), + file(0) + { + memset(index, 0, sizeof(ZipFile::Entry*) * indexSize); + } + + ZipFile(int64_t file): + region(0), entryCount(0), indexSize(0), index(0), file(file) + { } + + System::Region* region; + unsigned entryCount; + unsigned indexSize; + Entry** index; + int64_t file; + Entry entries[0]; +}; + +int64_t JNICALL +openZipFile(Thread* t, object method, uintptr_t* arguments) +{ + object path = reinterpret_cast(arguments[0]); + int mode = arguments[1]; + int64_t lastModified; memcpy(&lastModified, arguments + 2, 8); + + MyClasspath* cp = static_cast(t->m->classpath); + + THREAD_RUNTIME_ARRAY(t, char, p, stringLength(t, path) + 1); + stringChars(t, path, RUNTIME_ARRAY_BODY(p)); + replace('\\', '/', RUNTIME_ARRAY_BODY(p)); + + EmbeddedFile ef(cp, RUNTIME_ARRAY_BODY(p), stringLength(t, path)); + if (ef.jar) { + if (ef.jarLength == 0 or ef.pathLength == 0) { + throwNew(t, Machine::FileNotFoundExceptionType); + } + + Finder* finder = getFinder(t, ef.jar, ef.jarLength); + if (finder == 0) { + throwNew(t, Machine::FileNotFoundExceptionType); + } + + System::Region* r = finder->find(ef.path); + if (r == 0) { + throwNew(t, Machine::FileNotFoundExceptionType); + } + + const uint8_t* start = r->start(); + const uint8_t* end = start + r->length(); + unsigned entryCount = 0; + for (const uint8_t* p = end - CentralDirectorySearchStart; p > start;) { + if (get4(p) == CentralDirectorySignature) { + p = start + centralDirectoryOffset(p); + + while (p < end) { + if (get4(p) == EntrySignature) { + ++ entryCount; + + p = endOfEntry(p); + } else { + goto make; + } + } + } else { + -- p; + } + } + + make: + ZipFile* file = new + (t->m->heap->allocate + (sizeof(ZipFile) + (sizeof(ZipFile::Entry) * entryCount))) + ZipFile(t, r, entryCount); + + { unsigned position = 0; + for (const uint8_t* p = end - CentralDirectorySearchStart; p > start;) { + if (get4(p) == CentralDirectorySignature) { + p = start + centralDirectoryOffset(p); + + while (p < end) { + if (get4(p) == EntrySignature) { + unsigned h = hash(fileName(p), fileNameLength(p)); + unsigned i = h & (file->indexSize - 1); + + file->index[i] = new (file->entries + (position++)) + ZipFile::Entry(h, p, file->index[i]); + + p = endOfEntry(p); + } else { + goto exit; + } + } + } else { + -- p; + } + } + } + + exit: + return reinterpret_cast(file); + } else { + return reinterpret_cast + (new (t->m->heap->allocate(sizeof(ZipFile))) ZipFile + (longValue + (t, t->m->processor->invoke + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + 0, path, mode, lastModified)))); + } +} + +int64_t JNICALL +getZipFileEntryCount(Thread* t, object method, uintptr_t* arguments) +{ + int64_t peer; memcpy(&peer, arguments, 8); + + ZipFile* file = reinterpret_cast(peer); + if (file->region) { + return file->entryCount; + } else { + return intValue + (t, t->m->processor->invoke + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + 0, file->file)); + } +} + +ZipFile::Entry* +find(ZipFile* file, const char* path, unsigned pathLength) +{ + unsigned i = hash(path) & (file->indexSize - 1); + for (ZipFile::Entry* e = file->index[i]; e; e = e->next) { + const uint8_t* p = e->start; + if (equal(path, pathLength, fileName(p), fileNameLength(p))) { + return e; + } + } + return 0; +} + +int64_t JNICALL +getZipFileEntry(Thread* t, object method, uintptr_t* arguments) +{ + int64_t peer; memcpy(&peer, arguments, 8); + object path = reinterpret_cast(arguments[2]); + bool addSlash = arguments[3]; + + ZipFile* file = reinterpret_cast(peer); + if (file->region) { + THREAD_RUNTIME_ARRAY(t, char, p, stringLength(t, path) + 2); + stringChars(t, path, RUNTIME_ARRAY_BODY(p)); + replace('\\', '/', RUNTIME_ARRAY_BODY(p)); + if (addSlash) { + RUNTIME_ARRAY_BODY(p)[stringLength(t, path)] = '/'; + RUNTIME_ARRAY_BODY(p)[stringLength(t, path) + 1] = 0; + } + + return reinterpret_cast(find(file, p, stringLength(t, path))); + } else { + int64_t entry = longValue + (t, t->m->processor->invoke + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + 0, file->file, path, addSlash)); + + return entry ? reinterpret_cast + (new (t->m->heap->allocate(sizeof(ZipFile::Entry))) + ZipFile::Entry(entry)) : 0; + } +} + +int64_t JNICALL +getNextZipFileEntry(Thread* t, object method, uintptr_t* arguments) +{ + int64_t peer; memcpy(&peer, arguments, 8); + int index = arguments[2]; + + ZipFile* file = reinterpret_cast(peer); + if (file->region) { + return reinterpret_cast(file->entries + index); + } else { + int64_t entry = longValue + (t, t->m->processor->invoke + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + 0, file->file, index)); + + return entry ? reinterpret_cast + (new (t->m->heap->allocate(sizeof(ZipFile::Entry))) + ZipFile::Entry(entry)) : 0; + } +} + +void JNICALL +initializeZipEntryFields(Thread* t, object method, uintptr_t* arguments) +{ + object this_ = reinterpret_cast(arguments[0]); + int64_t peer; memcpy(&peer, arguments + 1, 8); + + ZipFile::Entry* entry = reinterpret_cast(peer); + if (entry->start) { + PROTECT(t, this_); + + MyClasspath* cp = static_cast(t->m->classpath); + + unsigned nameLength = fileNameLength(entry->start); + object array = makeByteArray(t, nameLength + 1); + memcpy(&byteArrayBody(t, array, 0), fileName(entry->start), nameLength); + byteArrayBody(t, array, nameLength) = 0; + + object name = t->m->classpath->makeString + (t, array, 0, byteArrayLength(t, array) - 1); + + set(t, this_, cp->zipEntryNameField, name); + + cast(this_, cp->zipEntryTimeField) + = fileTime(entry->start); + cast(this_, cp->zipEntryCrcField) + = fileCRC(entry->start); + cast(this_, cp->zipEntrySizeField) + = uncompressedSize(entry->start); + cast(this_, cp->zipEntryCsizeField) + = compressedSize(entry->start); + cast(this_, cp->zipEntryMethodField) + = compressionMethod(entry->start); + } else { + t->m->processor->invoke + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + this_, entry->entry); + } +} + +int64_t JNICALL +getZipFileEntryMethod(Thread* t, object method, uintptr_t* arguments) +{ + int64_t peer; memcpy(&peer, arguments, 8); + + ZipFile::Entry* entry = reinterpret_cast(peer); + if (entry->start) { + return compressionMethod(entry->start); + } else { + return intValue + (t, t->m->processor->invoke + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + 0, entry->entry)); + } +} + +int64_t JNICALL +getZipFileEntryCompressedSize(Thread* t, object method, uintptr_t* arguments) +{ + int64_t peer; memcpy(&peer, arguments, 8); + + ZipFile::Entry* entry = reinterpret_cast(peer); + if (entry->start) { + return compressedSize(entry->start); + } else { + return longValue + (t, t->m->processor->invoke + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + 0, entry->entry)); + } +} + +int64_t JNICALL +getZipFileEntryUncompressedSize(Thread* t, object method, uintptr_t* arguments) +{ + int64_t peer; memcpy(&peer, arguments, 8); + + ZipFile::Entry* entry = reinterpret_cast(peer); + if (entry->start) { + return uncompressedSize(entry->start); + } else { + return longValue + (t, t->m->processor->invoke + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + 0, entry->entry)); + } +} + +void JNICALL +freeZipFileEntry(Thread* t, object method, uintptr_t* arguments) +{ + int64_t filePeer; memcpy(&filePeer, arguments, 8); + int64_t entryPeer; memcpy(&entryPeer, arguments + 2, 8); + + ZipFile* file = reinterpret_cast(filePeer); + ZipFile::Entry* entry = reinterpret_cast(entryPeer); + if (file->region == 0) { + t->m->processor->invoke + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + 0, file->file, entry->entry); + } +} + +int64_t JNICALL +readZipFileEntry(Thread* t, object method, uintptr_t* arguments) +{ + int64_t filePeer; memcpy(&filePeer, arguments, 8); + int64_t entryPeer; memcpy(&entryPeer, arguments + 2, 8); + int64_t position; memcpy(&position, arguments + 4, 8); + object buffer = reinterpret_cast(arguments[6]); + int offset = arguments[7]; + int length = arguments[8]; + + ZipFile* file = reinterpret_cast(filePeer); + ZipFile::Entry* entry = reinterpret_cast(entryPeer); + if (file->region) { + unsigned size = uncompressedSize(entry->start); + if (position >= size) { + return -1; + } + + if (position + length > size) { + length = size - position; + } + + memcpy(&byteArrayBody(t, buffer, offset), + fileData(file->region->start() + localHeaderOffset(entry->start)) + + position, + length); + + return length; + } else { + return intValue + (t, t->m->processor->invoke + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + 0, file->file, entry->entry, position, buffer, offset, length)); + } +} + +int64_t JNICALL +getZipMessage(Thread* t, object method, uintptr_t* arguments) +{ + int64_t peer; memcpy(&peer, arguments, 8); + + ZipFile* file = reinterpret_cast(peer); + if (file->region) { + return 0; + } else { + return reinterpret_cast + (t->m->processor->invoke + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + 0, file->file)); + } +} + +int64_t JNICALL +getJarFileMetaInfEntryNames(Thread* t, object method, uintptr_t* arguments) +{ + object this_ = reinterpret_cast(arguments[0]); + + MyClasspath* cp = static_cast(t->m->classpath); + + int64_t peer = cast(this_, cp->zipFileJzfileField); + ZipFile* file = reinterpret_cast(peer); + if (file->region) { + return 0; + } else { + PROTECT(t, method); + + // OpenJDK's Java_java_util_jar_JarFile_getMetaInfEntryNames + // implementation expects to find a pointer to an instance of its + // jzfile structure in the ZipFile.jzfile field of the object we + // pass in. However, we can't pass this_ in, because its + // ZipFile.jzfile field points to a ZipFile instance, not a + // jzfile. So we pass in a temporary object instead which has the + // desired pointer at the same offset. We assume here that + // ZipFile.jzfile is the first field in that class and that + // Java_java_util_jar_JarFile_getMetaInfEntryNames will not look + // for any other fields in the object. + object pseudoThis = makeLong(t, file->file); + + return reinterpret_cast + (t->m->processor->invoke + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + pseudoThis)); + } +} + +void JNICALL +closeZipFile(Thread* t, object method, uintptr_t* arguments) +{ + int64_t peer; memcpy(&peer, arguments, 8); + + ZipFile* file = reinterpret_cast(peer); + if (file->region) { + file->region->dispose(); + t->m->heap->free(file, sizeof(ZipFile) + + (sizeof(ZipFile::Entry) * file->entryCount)); + } else { + t->m->processor->invoke + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + 0, file->file); + + t->m->heap->free(file, sizeof(ZipFile)); + } +} + int64_t JNICALL getBootstrapResource(Thread* t, object, uintptr_t* arguments) { @@ -1092,6 +1534,102 @@ interceptFileOperations(Thread* t) voidPointer(closeFile)); } + { object zipEntryClass = resolveClass + (t, root(t, Machine::BootLoader), "java/util/zip/ZipEntry"); + if (zipEntryClass == 0) return; + + object zipEntryNameField = findFieldInClass2 + (t, zipEntryClass, "name", "Ljava/lang/String;"); + if (zipEntryNameField == 0) return; + + cp->zipEntryNameField = fieldOffset(t, zipEntryNameField); + + object zipEntryTimeField = findFieldInClass2 + (t, zipEntryClass, "time", "J"); + if (zipEntryTimeField == 0) return; + + cp->zipEntryTimeField = fieldOffset(t, zipEntryTimeField); + + object zipEntryCrcField = findFieldInClass2 + (t, zipEntryClass, "crc", "J"); + if (zipEntryCrcField == 0) return; + + cp->zipEntryCrcField = fieldOffset(t, zipEntryCrcField); + + object zipEntrySizeField = findFieldInClass2 + (t, zipEntryClass, "size", "J"); + if (zipEntrySizeField == 0) return; + + cp->zipEntrySizeField = fieldOffset(t, zipEntrySizeField); + + object zipEntryCsizeField = findFieldInClass2 + (t, zipEntryClass, "csize", "J"); + if (zipEntryCsizeField == 0) return; + + cp->zipEntryCsizeField = fieldOffset(t, zipEntryCsizeField); + + object zipEntryMethodField = findFieldInClass2 + (t, zipEntryClass, "method", "I"); + if (zipEntryMethodField == 0) return; + + cp->zipEntryMethodField = fieldOffset(t, zipEntryMethodField); + + intercept(t, zipEntryClass, "initFields", "(J)V", + voidPointer(initializeZipEntryFields)); + } + + { object zipFileClass = resolveClass + (t, root(t, Machine::BootLoader), "java/util/zip/ZipFile"); + if (zipFileClass == 0) return; + + object zipFileJzfileField = findFieldInClass2 + (t, zipFileClass, "jzfile", "J"); + if (zipFileJzfileField == 0) return; + + cp->zipFileJzfileField = fieldOffset(t, zipFileJzfileField); + + intercept(t, zipFileClass, "open", "(Ljava/lang/String;IJ)J", + voidPointer(openZipFile)); + + intercept(t, zipFileClass, "getTotal", "(J)I", + voidPointer(getZipFileEntryCount)); + + intercept(t, zipFileClass, "getEntry", "(JLjava/lang/String;Z)J", + voidPointer(getZipFileEntry)); + + intercept(t, zipFileClass, "getNextEntry", "(JI)J", + voidPointer(getNextZipFileEntry)); + + intercept(t, zipFileClass, "getMethod", "(J)I", + voidPointer(getZipFileEntryMethod)); + + intercept(t, zipFileClass, "freeEntry", "(JJ)V", + voidPointer(freeZipFileEntry)); + + intercept(t, zipFileClass, "read", "(JJJ[BII)I", + voidPointer(readZipFileEntry)); + + intercept(t, zipFileClass, "getCSize", "(J)J", + voidPointer(getZipFileEntryCompressedSize)); + + intercept(t, zipFileClass, "getSize", "(J)J", + voidPointer(getZipFileEntryUncompressedSize)); + + intercept(t, zipFileClass, "getZipMessage", "(J)Ljava/lang/String;", + voidPointer(getZipMessage)); + + intercept(t, zipFileClass, "close", "(J)V", + voidPointer(closeZipFile)); + } + + { object jarFileClass = resolveClass + (t, root(t, Machine::BootLoader), "java/util/jar/JarFile"); + if (jarFileClass == 0) return; + + intercept(t, jarFileClass, "getMetaInfEntryNames", "()[Ljava/lang/String;", + voidPointer(getJarFileMetaInfEntryNames)); + } + { #ifdef PLATFORM_WINDOWS const char* const fsClassName = "java/io/WinNTFileSystem"; diff --git a/src/common.h b/src/common.h index 5c7160e54c..3f9860cc28 100644 --- a/src/common.h +++ b/src/common.h @@ -537,6 +537,16 @@ replace(char a, char b, char* dst, const char* src) dst[i] = 0; } +inline bool +equal(const void* a, unsigned al, const void* b, unsigned bl) +{ + if (al == bl) { + return memcmp(a, b, al) == 0; + } else { + return false; + } +} + class Machine; class Thread; diff --git a/src/finder.cpp b/src/finder.cpp index 2199dd5207..4352aa8adf 100644 --- a/src/finder.cpp +++ b/src/finder.cpp @@ -41,16 +41,6 @@ copy(Allocator* allocator, const char* a) return p; } -bool -equal(const void* a, unsigned al, const void* b, unsigned bl) -{ - if (al == bl) { - return memcmp(a, b, al) == 0; - } else { - return false; - } -} - class Element { public: class Iterator { @@ -233,9 +223,6 @@ class DataRegion: public System::Region { class JarIndex { public: - static const unsigned LocalHeaderSize = 30; - static const unsigned HeaderSize = 46; - enum CompressionMethod { Stored = 0, Deflated = 8 @@ -262,78 +249,6 @@ class JarIndex { memset(table, 0, sizeof(Node*) * capacity); } - static uint16_t get2(const uint8_t* p) { - return - (static_cast(p[1]) << 8) | - (static_cast(p[0]) ); - } - - static uint32_t get4(const uint8_t* p) { - return - (static_cast(p[3]) << 24) | - (static_cast(p[2]) << 16) | - (static_cast(p[1]) << 8) | - (static_cast(p[0]) ); - } - - static uint32_t signature(const uint8_t* p) { - return get4(p); - } - - static uint16_t compressionMethod(const uint8_t* centralHeader) { - return get2(centralHeader + 10); - } - - static uint32_t compressedSize(const uint8_t* centralHeader) { - return get4(centralHeader + 20); - } - - static uint32_t uncompressedSize(const uint8_t* centralHeader) { - return get4(centralHeader + 24); - } - - static uint16_t fileNameLength(const uint8_t* centralHeader) { - return get2(centralHeader + 28); - } - - static uint16_t extraFieldLength(const uint8_t* centralHeader) { - return get2(centralHeader + 30); - } - - static uint16_t commentFieldLength(const uint8_t* centralHeader) { - return get2(centralHeader + 32); - } - - static uint32_t localHeaderOffset(const uint8_t* centralHeader) { - return get4(centralHeader + 42); - } - - static uint16_t localFileNameLength(const uint8_t* localHeader) { - return get2(localHeader + 26); - } - - static uint16_t localExtraFieldLength(const uint8_t* localHeader) { - return get2(localHeader + 28); - } - - static uint32_t centralDirectoryOffset(const uint8_t* centralHeader) { - return get4(centralHeader + 16); - } - - static const uint8_t* fileName(const uint8_t* centralHeader) { - return centralHeader + 46; - } - - static const uint8_t* fileData(const uint8_t* localHeader) { - return localHeader + LocalHeaderSize + localFileNameLength(localHeader) + - localExtraFieldLength(localHeader); - } - - static const uint8_t* endOfEntry(const uint8_t* p) { - return p + HeaderSize + fileNameLength(p) + extraFieldLength(p) + - commentFieldLength(p); - } - static JarIndex* make(System* s, Allocator* allocator, unsigned capacity) { return new (allocator->allocate(sizeof(JarIndex) + (sizeof(Node*) * capacity))) @@ -347,14 +262,14 @@ class JarIndex { const uint8_t* start = region->start(); const uint8_t* end = start + region->length(); - const uint8_t* p = end - 22; + const uint8_t* p = end - CentralDirectorySearchStart; // Find end of central directory record while (p > start) { - if (signature(p) == 0x06054b50) { + if (signature(p) == CentralDirectorySignature) { p = region->start() + centralDirectoryOffset(p); while (p < end) { - if (signature(p) == 0x02014b50) { + if (signature(p) == EntrySignature) { index = index->add(hash(fileName(p), fileNameLength(p)), p); p = endOfEntry(p); @@ -495,8 +410,8 @@ class JarElement: public Element { virtual const char* next(unsigned* size) { if (position < index->position) { JarIndex::Node* n = index->nodes + (position++); - *size = JarIndex::fileNameLength(n->entry); - return reinterpret_cast(JarIndex::fileName(n->entry)); + *size = fileNameLength(n->entry); + return reinterpret_cast(fileName(n->entry)); } else { return 0; } diff --git a/src/finder.h b/src/finder.h index 7546fb8b9c..5f894290eb 100644 --- a/src/finder.h +++ b/src/finder.h @@ -17,6 +17,94 @@ namespace vm { +const unsigned LocalHeaderSize = 30; +const unsigned HeaderSize = 46; + +const unsigned CentralDirectorySignature = 0x06054b50; +const unsigned EntrySignature = 0x02014b50; + +const unsigned CentralDirectorySearchStart = 22; + +inline uint16_t get2(const uint8_t* p) { + return + (static_cast(p[1]) << 8) | + (static_cast(p[0]) ); +} + +inline uint32_t get4(const uint8_t* p) { + return + (static_cast(p[3]) << 24) | + (static_cast(p[2]) << 16) | + (static_cast(p[1]) << 8) | + (static_cast(p[0]) ); +} + +inline uint32_t signature(const uint8_t* p) { + return get4(p); +} + +inline uint16_t compressionMethod(const uint8_t* centralHeader) { + return get2(centralHeader + 10); +} + +inline uint32_t fileTime(const uint8_t* centralHeader) { + return get4(centralHeader + 12); +} + +inline uint32_t fileCRC(const uint8_t* centralHeader) { + return get4(centralHeader + 16); +} + +inline uint32_t compressedSize(const uint8_t* centralHeader) { + return get4(centralHeader + 20); +} + +inline uint32_t uncompressedSize(const uint8_t* centralHeader) { + return get4(centralHeader + 24); +} + +inline uint16_t fileNameLength(const uint8_t* centralHeader) { + return get2(centralHeader + 28); +} + +inline uint16_t extraFieldLength(const uint8_t* centralHeader) { + return get2(centralHeader + 30); +} + +inline uint16_t commentFieldLength(const uint8_t* centralHeader) { + return get2(centralHeader + 32); +} + +inline uint32_t localHeaderOffset(const uint8_t* centralHeader) { + return get4(centralHeader + 42); +} + +inline uint16_t localFileNameLength(const uint8_t* localHeader) { + return get2(localHeader + 26); +} + +inline uint16_t localExtraFieldLength(const uint8_t* localHeader) { + return get2(localHeader + 28); +} + +inline uint32_t centralDirectoryOffset(const uint8_t* centralHeader) { + return get4(centralHeader + 16); +} + +inline const uint8_t* fileName(const uint8_t* centralHeader) { + return centralHeader + 46; +} + +inline const uint8_t* fileData(const uint8_t* localHeader) { + return localHeader + LocalHeaderSize + localFileNameLength(localHeader) + + localExtraFieldLength(localHeader); +} + +inline const uint8_t* endOfEntry(const uint8_t* p) { + return p + HeaderSize + fileNameLength(p) + extraFieldLength(p) + + commentFieldLength(p); +} + inline bool readLine(const uint8_t* base, unsigned total, unsigned* start, unsigned* length) From 93b3d3d8a68869013f9a232153488865e77b1a4b Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 15 Mar 2011 17:17:26 -0600 Subject: [PATCH 015/117] fix IpPromise::resolved This method was returning true when it shouldn't have, and this led to an assertion failure when we actually tried to get the promise's value. --- src/compiler.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/compiler.cpp b/src/compiler.cpp index 01522a8ef7..2deeffe5a7 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -527,7 +527,8 @@ class IpPromise: public Promise { } virtual bool resolved() { - return c->machineCode != 0; + return c->machineCode != 0 + and c->logicalCode[logicalIp]->machineOffset->resolved(); } Context* c; From 51c8d7511a05174aeec0fdd2e1e358711d653ac9 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 15 Mar 2011 17:20:44 -0600 Subject: [PATCH 016/117] fix OS X PowerPC parameter passing We were not always placing parameters in the correct stack positions in the PowerPC implementations of dynamicCall and vmNativeCall. In particular, the first stack slot used to hold a parameter depends on the sizes and types of the preceding parameters which are passed in registers. --- src/powerpc.S | 73 ++++++++++++++++++++++++++------------------------- src/powerpc.h | 5 ++-- 2 files changed, 40 insertions(+), 38 deletions(-) diff --git a/src/powerpc.S b/src/powerpc.S index 96bf382cfb..5a075e1a11 100644 --- a/src/powerpc.S +++ b/src/powerpc.S @@ -36,13 +36,14 @@ GLOBAL(vmNativeCall): mflr r0 stw r0,RETURN_ADDRESS_OFFSET(r1) - // r3 aka r13: function - // r4 : stackTotal - // r5 : memoryTable - // r6 : memoryCount - // r7 : gprTable - // r8 : fprTable - // r9 aka r14: returnType + // r3 aka r13: function + // r4 : stackTotal + // r5 : memoryTable + // r6 : memoryCount + // r7 : memoryBase + // r8 : gprTable + // r9 : fprTable + // r10 aka r14: returnType // r15 : stack frame size // r16 : temporary @@ -51,34 +52,34 @@ GLOBAL(vmNativeCall): // allocate stack space, adding room for callee-saved registers and // scratch space for copying a FP return value into GPRs - subfic r10,r4,-48 - stwux r1,r1,r10 + subfic r11,r4,-48 + stwux r1,r1,r11 // save callee-saved registers used for local variables - add r10,r4,r1 + add r11,r4,r1 // save registers used for local variables - stw r13,0(r10) - stw r14,4(r10) - stw r15,8(r10) - stw r16,12(r10) - stw r17,16(r10) - stw r18,20(r10) - stw r19,24(r10) + stw r13,0(r11) + stw r14,4(r11) + stw r15,8(r11) + stw r16,12(r11) + stw r17,16(r11) + stw r18,20(r11) + stw r19,24(r11) // remember where we saved the local variables - mr r19,r10 + mr r19,r11 // save our argument registers so we can clobber them mr r13,r3 - mr r14,r9 + mr r14,r10 li r16,0 b LOCAL(test) LOCAL(loop): lwzx r17,r16,r5 - addi r18,r16,MEMORY_BASE + add r18,r16,r7 stwx r17,r18,r1 addi r16,r16,BYTES_PER_WORD @@ -87,33 +88,33 @@ LOCAL(test): blt LOCAL(loop) // do we need to load the floating point registers? - cmpwi r8,0 + cmpwi r9,0 beq LOCAL(gpr) // yes, we do - lfd f1,0(r8) - lfd f2,8(r8) - lfd f3,16(r8) - lfd f4,24(r8) - lfd f5,32(r8) - lfd f6,40(r8) - lfd f7,48(r8) - lfd f8,56(r8) + lfd f1,0(r9) + lfd f2,8(r9) + lfd f3,16(r9) + lfd f4,24(r9) + lfd f5,32(r9) + lfd f6,40(r9) + lfd f7,48(r9) + lfd f8,56(r9) #ifdef __APPLE__ - lfd f9,64(r8) - lfd f10,72(r8) - lfd f11,80(r8) - lfd f12,88(r8) - lfd f13,96(r8) + lfd f9,64(r9) + lfd f10,72(r9) + lfd f11,80(r9) + lfd f12,88(r9) + lfd f13,96(r9) #endif LOCAL(gpr): // do we need to load the general-purpose registers? - cmpwi r7,0 + cmpwi r8,0 beq LOCAL(call) // yes, we do - mr r16,r7 + mr r16,r8 lwz r3,0(r16) lwz r4,4(r16) lwz r5,8(r16) diff --git a/src/powerpc.h b/src/powerpc.h index 5fe4543cc7..9b877719d0 100644 --- a/src/powerpc.h +++ b/src/powerpc.h @@ -57,8 +57,8 @@ extern "C" uint64_t vmNativeCall(void* function, unsigned stackTotal, void* memoryTable, - unsigned memoryCount, void* gprTable, void* fprTable, - unsigned returnType); + unsigned memoryCount, unsigned memoryBase, + void* gprTable, void* fprTable, unsigned returnType); namespace vm { @@ -239,6 +239,7 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes, (function, (((1 + stackSkip + stackIndex) * BytesPerWord) + LinkageArea + 15) & -16, stack, stackIndex * BytesPerWord, + LinkageArea + (stackSkip * BytesPerWord), (gprIndex ? gprTable : 0), (fprIndex ? fprTable : 0), returnType); } From e5ecb5b549585caea5b8e3becc9e7ac94d159022 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 15 Mar 2011 17:27:17 -0600 Subject: [PATCH 017/117] add optional avian.error.log system property This property may be used to specify a file name to use for printing stack traces for unhandled exceptions. The default is stderr. --- src/machine.cpp | 19 ++++++++++--------- src/machine.h | 16 ++++++++++++++++ 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/machine.cpp b/src/machine.cpp index 1f4e895148..7c1863c8f3 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -2258,6 +2258,7 @@ Machine::Machine(System* system, Heap* heap, Finder* bootFinder, referenceLock(0), shutdownLock(0), libraries(0), + errorLog(0), types(0), roots(0), finalizers(0), @@ -3888,19 +3889,19 @@ printTrace(Thread* t, object exception) for (object e = exception; e; e = throwableCause(t, e)) { if (e != exception) { - fprintf(stderr, "caused by: "); + fprintf(errorLog(t), "caused by: "); } - fprintf(stderr, "%s", &byteArrayBody + fprintf(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(stderr, ": %s\n", RUNTIME_ARRAY_BODY(message)); + fprintf(errorLog(t), ": %s\n", RUNTIME_ARRAY_BODY(message)); } else { - fprintf(stderr, "\n"); + fprintf(errorLog(t), "\n"); } object trace = throwableTrace(t, e); @@ -3914,17 +3915,17 @@ printTrace(Thread* t, object exception) int line = t->m->processor->lineNumber (t, traceElementMethod(t, e), traceElementIp(t, e)); - fprintf(stderr, " at %s.%s ", class_, method); + fprintf(errorLog(t), " at %s.%s ", class_, method); switch (line) { case NativeLine: - fprintf(stderr, "(native)\n"); + fprintf(errorLog(t), "(native)\n"); break; case UnknownLine: - fprintf(stderr, "(unknown line)\n"); + fprintf(errorLog(t), "(unknown line)\n"); break; default: - fprintf(stderr, "(line %d)\n", line); + fprintf(errorLog(t), "(line %d)\n", line); } } } @@ -3934,7 +3935,7 @@ printTrace(Thread* t, object exception) } } - fflush(stderr); + fflush(errorLog(t)); } object diff --git a/src/machine.h b/src/machine.h index 4031093138..b784d6072a 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1298,6 +1298,7 @@ class Machine { System::Monitor* referenceLock; System::Monitor* shutdownLock; System::Library* libraries; + FILE* errorLog; object types; object roots; object finalizers; @@ -3577,6 +3578,21 @@ methodClone(Thread* t, object method) methodCode(t, method)); } +inline FILE* +errorLog(Thread* t) +{ + if (t->m->errorLog == 0) { + const char* path = findProperty(t, "avian.error.log"); + if (path) { + t->m->errorLog = vm::fopen(path, "wb"); + } else { + t->m->errorLog = stderr; + } + } + + return t->m->errorLog; +} + } // namespace vm void From a3a7a7a2de88599a9be83d8596462b144d0fe115 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 15 Mar 2011 13:27:36 -0600 Subject: [PATCH 018/117] use getcwd instead of getenv("PWD") to get working directory PWD is not always set, whereas getcwd is more reliable. --- src/classpath-openjdk.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 4d50227a83..131f7345ff 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -59,6 +59,7 @@ typedef int socklen_t; #else // not PLATFORM_WINDOWS # include +# include # include # include # include @@ -2586,7 +2587,10 @@ jvmInitProperties(Thread* t, uintptr_t* arguments) # endif local::setProperty(t, method, *properties, "java.io.tmpdir", "/tmp"); local::setProperty(t, method, *properties, "user.home", getenv("HOME")); - local::setProperty(t, method, *properties, "user.dir", getenv("PWD")); + + char buffer[PATH_MAX]; + local::setProperty(t, method, *properties, "user.dir", + getcwd(buffer, PATH_MAX)); #endif local::setProperty(t, method, *properties, "java.protocol.handler.pkgs", From e6cf992af74b993f278a61c31a16b7d2702b06fb Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 15 Mar 2011 13:43:36 -0600 Subject: [PATCH 019/117] uncomment testStatic call in DefineClass I had commented it out for debugging purposes and forgot to uncomment it. --- test/DefineClass.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/DefineClass.java b/test/DefineClass.java index ea3b6362ae..4cff3ecfde 100644 --- a/test/DefineClass.java +++ b/test/DefineClass.java @@ -49,7 +49,7 @@ public class DefineClass { } public static void main(String[] args) throws Exception { - //testStatic(); + testStatic(); testDerived(); } @@ -59,7 +59,7 @@ public class DefineClass { } public Class defineClass(String name, byte[] bytes) { - return super.defineClass(name, bytes, 0, bytes.length); + return defineClass(name, bytes, 0, bytes.length); } } From 48e569c65a966f9de50695769641758975c8e974 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 15 Mar 2011 17:51:32 -0600 Subject: [PATCH 020/117] add tail call test --- makefile | 7 ++++++- test/extra/Tails.java | 49 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 test/extra/Tails.java diff --git a/makefile b/makefile index d6fc68549d..d9921f3e3b 100644 --- a/makefile +++ b/makefile @@ -585,6 +585,11 @@ ifeq ($(continuations),true) extra.DynamicWind endif +ifeq ($(tails),true) + tail-tests = \ + extra.Tails +endif + class-name = $(patsubst $(1)/%.class,%,$(2)) class-names = $(foreach x,$(2),$(call class-name,$(1),$(x))) @@ -617,7 +622,7 @@ test: build $(library-path) /bin/sh $(test)/test.sh 2>/dev/null \ $(test-executable) $(mode) "$(test-flags)" \ $(call class-names,$(test-build),$(test-classes)) \ - $(continuation-tests) + $(continuation-tests) $(tail-tests) .PHONY: tarball tarball: diff --git a/test/extra/Tails.java b/test/extra/Tails.java new file mode 100644 index 0000000000..a99655531a --- /dev/null +++ b/test/extra/Tails.java @@ -0,0 +1,49 @@ +package extra; + +public class Tails { + private static final int Limit = 1000000; + + private static void expect(boolean v) { + if (! v) throw new RuntimeException(); + } + + private static int staticMethod(Interface i, int n) { + if (n < Limit) { + return i.interfaceMethod(n + 1); + } else { + return leafMethod(n); + } + } + + private static int leafMethod(int n) { + expect(new Throwable().getStackTrace().length == 2); + + return n; + } + + public static void main(String[] args) { + expect(staticMethod(new Foo(), 0) == Limit); + } + + private interface Interface { + public int interfaceMethod(int n); + } + + private static class Foo implements Interface { + public int interfaceMethod(int n) { + if (n < Limit) { + return virtualMethod(n + 1, 1, 2, 3, 4, 5); + } else { + return leafMethod(n); + } + } + + public int virtualMethod(int n, int a, int b, int c, int d, int e) { + if (n < Limit) { + return staticMethod(this, n + 1); + } else { + return leafMethod(n); + } + } + } +} From 453ceb42ab856286fddfcca6cce77475d283a91e Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 15 Mar 2011 17:52:02 -0600 Subject: [PATCH 021/117] implement lazy class/field/method resolution in JIT compiler Unlike the interpreter, the JIT compiler tries to resolve all the symbols referenced by a method when compiling that method. However, this can backfire if a symbol cannot be resolved: we end up throwing an e.g. NoClassDefFoundError for code which may never be executed. This is particularly troublesome for code which supports multiple APIs, choosing one at runtime. The solution is to defer to stub code for symbols which can't be resolved at JIT compile time. Such a stub will try again at runtime to resolve the needed symbol and throw an appropriate error if it still can't be found. --- classpath/avian/VMField.java | 1 + src/compile.cpp | 1423 +++++++++++++++++++++++++--------- src/interpret.cpp | 178 ++--- src/machine.cpp | 50 +- src/machine.h | 191 ++++- src/thunks.cpp | 18 + src/vector.h | 1 + src/zone.h | 2 + test/LazyLoading.java | 184 +++++ 9 files changed, 1508 insertions(+), 540 deletions(-) create mode 100644 test/LazyLoading.java diff --git a/classpath/avian/VMField.java b/classpath/avian/VMField.java index 699a68e5f8..70752ac943 100644 --- a/classpath/avian/VMField.java +++ b/classpath/avian/VMField.java @@ -15,6 +15,7 @@ public class VMField { public byte code; public short flags; public short offset; + public short index; public byte[] name; public byte[] spec; public FieldAddendum addendum; diff --git a/src/compile.cpp b/src/compile.cpp index c9b00f1d9b..584e39d4cf 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -1202,7 +1202,8 @@ class Context { dirtyRoots(false), leaf(true), eventLog(t->m->system, t->m->heap, 1024), - protector(this) + protector(this), + resource(this) { } Context(MyThread* t): @@ -1227,7 +1228,8 @@ class Context { dirtyRoots(false), leaf(true), eventLog(t->m->system, t->m->heap, 0), - protector(this) + protector(this), + resource(this) { } ~Context() { @@ -1244,6 +1246,10 @@ class Context { if (executableAllocator) { executableAllocator->free(executableStart, executableSize); } + + eventLog.dispose(); + + zone.dispose(); } MyThread* thread; @@ -1268,6 +1274,7 @@ class Context { bool leaf; Vector eventLog; MyProtector protector; + MyResource resource; }; unsigned @@ -2232,27 +2239,109 @@ void compile(MyThread* t, FixedAllocator* allocator, BootContext* bootContext, object method); +object +resolveMethod(Thread* t, object pair) +{ + object reference = pairSecond(t, pair); + PROTECT(t, reference); + + object class_ = resolveClassInObject + (t, classLoader(t, methodClass(t, pairFirst(t, pair))), reference, + ReferenceClass); + + return findInHierarchy + (t, class_, referenceName(t, reference), referenceSpec(t, reference), + findMethodInClass, Machine::NoSuchMethodErrorType); +} + +int64_t +prepareMethodForCall(MyThread* t, object target) +{ + if (unresolved(t, methodAddress(t, target))) { + PROTECT(t, target); + + compile(t, codeAllocator(t), 0, target); + } + + if (methodFlags(t, target) & ACC_NATIVE) { + t->trace->nativeMethod = target; + } + return methodAddress(t, target); +} + int64_t findInterfaceMethodFromInstance(MyThread* t, object method, object instance) { if (instance) { - object target = findInterfaceMethod(t, method, objectClass(t, instance)); - - if (unresolved(t, methodAddress(t, target))) { - PROTECT(t, target); - - compile(t, codeAllocator(t), 0, target); - } - - if (methodFlags(t, target) & ACC_NATIVE) { - t->trace->nativeMethod = target; - } - return methodAddress(t, target); + return prepareMethodForCall + (t, findInterfaceMethod(t, method, objectClass(t, instance))); } else { throwNew(t, Machine::NullPointerExceptionType); } } +int64_t +findInterfaceMethodFromInstanceAndReference +(MyThread* t, object pair, object instance) +{ + PROTECT(t, instance); + + object method = resolveMethod(t, pair); + + return findInterfaceMethodFromInstance(t, method, instance); +} + +int64_t +findSpecialMethodFromReference(MyThread* t, object pair) +{ + PROTECT(t, pair); + + object target = resolveMethod(t, pair); + + object class_ = methodClass(t, pairFirst(t, pair)); + if (isSpecialMethod(t, target, class_)) { + target = findVirtualMethod(t, target, classSuper(t, class_)); + } + + assert(t, (methodFlags(t, target) & ACC_STATIC) == 0); + + return prepareMethodForCall(t, target); +} + +int64_t +findStaticMethodFromReference(MyThread* t, object pair) +{ + object target = resolveMethod(t, pair); + + assert(t, methodFlags(t, target) & ACC_STATIC); + + return prepareMethodForCall(t, target); +} + +int64_t +findVirtualMethodFromReference(MyThread* t, object pair, object instance) +{ + PROTECT(t, instance); + + object target = resolveMethod(t, pair); + + target = findVirtualMethod(t, target, objectClass(t, instance)); + + assert(t, (methodFlags(t, target) & ACC_STATIC) == 0); + + return prepareMethodForCall(t, target); +} + +int64_t +getJClassFromReference(MyThread* t, object pair) +{ + return reinterpret_cast + (getJClass + (t, resolveClass + (t, classLoader(t, methodClass(t, pairFirst(t, pair))), + referenceName(t, pairSecond(t, pair))))); +} + int64_t compareDoublesG(uint64_t bi, uint64_t ai) { @@ -2575,6 +2664,16 @@ makeBlankObjectArray(MyThread* t, object class_, int32_t length) } } +uint64_t +makeBlankObjectArrayFromReference(MyThread* t, object pair, + int32_t length) +{ + return makeBlankObjectArray + (t, resolveClass + (t, classLoader(t, methodClass(t, pairFirst(t, pair))), + referenceName(t, pairSecond(t, pair))), length); +} + uint64_t makeBlankArray(MyThread* t, unsigned type, int32_t length) { @@ -2709,6 +2808,17 @@ makeMultidimensionalArray(MyThread* t, object class_, int32_t dimensions, (t, class_, static_cast(t->stack) + offset, dimensions)); } +uint64_t +makeMultidimensionalArrayFromReference(MyThread* t, object pair, + int32_t dimensions, + int32_t offset) +{ + return makeMultidimensionalArray + (t, resolveClass + (t, classLoader(t, methodClass(t, pairFirst(t, pair))), + referenceName(t, pairSecond(t, pair))), dimensions, offset); +} + void NO_RETURN throwArrayIndexOutOfBounds(MyThread* t) { @@ -2751,12 +2861,206 @@ checkCast(MyThread* t, object class_, object o) } } +void +checkCastFromReference(MyThread* t, object pair, object o) +{ + PROTECT(t, o); + + object c = resolveClass + (t, classLoader(t, methodClass(t, pairFirst(t, pair))), + referenceName(t, pairSecond(t, pair))); + + checkCast(t, c, o); +} + +object +resolveField(Thread* t, object pair) +{ + object reference = pairSecond(t, pair); + PROTECT(t, reference); + + object class_ = resolveClassInObject + (t, classLoader(t, methodClass(t, pairFirst(t, pair))), reference, + ReferenceClass); + + return findInHierarchy + (t, class_, referenceName(t, reference), referenceSpec(t, reference), + findFieldInClass, Machine::NoSuchFieldErrorType); +} + +uint64_t +getFieldValue(Thread* t, object target, object field) +{ + switch (fieldCode(t, field)) { + case ByteField: + case BooleanField: + return cast(target, fieldOffset(t, field)); + + case CharField: + case ShortField: + return cast(target, fieldOffset(t, field)); + + case FloatField: + case IntField: + return cast(target, fieldOffset(t, field)); + + case DoubleField: + case LongField: + return cast(target, fieldOffset(t, field)); + + case ObjectField: + return cast(target, fieldOffset(t, field)); + + default: + abort(t); + } +} + +uint64_t +getStaticFieldValueFromReference(MyThread* t, object pair) +{ + object field = resolveField(t, pair); + PROTECT(t, field); + + ACQUIRE_FIELD_FOR_READ(t, field); + + return getFieldValue(t, classStaticTable(t, fieldClass(t, field)), field); +} + +uint64_t +getFieldValueFromReference(MyThread* t, object pair, object instance) +{ + PROTECT(t, instance); + + object field = resolveField(t, pair); + PROTECT(t, field); + + ACQUIRE_FIELD_FOR_READ(t, field); + + return getFieldValue(t, instance, field); +} + +void +setStaticLongFieldValueFromReference(MyThread* t, object pair, uint64_t value) +{ + object field = resolveField(t, pair); + PROTECT(t, field); + + ACQUIRE_FIELD_FOR_WRITE(t, field); + + cast + (classStaticTable(t, fieldClass(t, field)), fieldOffset(t, field)) = value; +} + +void +setLongFieldValueFromReference(MyThread* t, object pair, object instance, + uint64_t value) +{ + PROTECT(t, instance); + + object field = resolveField(t, pair); + PROTECT(t, field); + + ACQUIRE_FIELD_FOR_WRITE(t, field); + + cast(instance, fieldOffset(t, field)) = value; +} + +void +setStaticObjectFieldValueFromReference(MyThread* t, object pair, object value) +{ + PROTECT(t, value); + + object field = resolveField(t, pair); + PROTECT(t, field); + + ACQUIRE_FIELD_FOR_WRITE(t, field); + + set(t, classStaticTable(t, fieldClass(t, field)), fieldOffset(t, field), + value); +} + +void +setObjectFieldValueFromReference(MyThread* t, object pair, object instance, + object value) +{ + PROTECT(t, instance); + PROTECT(t, value); + + object field = resolveField(t, pair); + PROTECT(t, field); + + ACQUIRE_FIELD_FOR_WRITE(t, field); + + set(t, instance, fieldOffset(t, field), value); +} + +void +setFieldValue(MyThread* t, object target, object field, uint32_t value) +{ + switch (fieldCode(t, field)) { + case ByteField: + case BooleanField: + cast(target, fieldOffset(t, field)) = value; + break; + + case CharField: + case ShortField: + cast(target, fieldOffset(t, field)) = value; + break; + + case FloatField: + case IntField: + cast(target, fieldOffset(t, field)) = value; + break; + + default: + abort(t); + } +} + +void +setStaticFieldValueFromReference(MyThread* t, object pair, uint32_t value) +{ + object field = resolveField(t, pair); + PROTECT(t, field); + + ACQUIRE_FIELD_FOR_WRITE(t, field); + + setFieldValue(t, classStaticTable(t, fieldClass(t, field)), field, value); +} + +void +setFieldValueFromReference(MyThread* t, object pair, object instance, + uint32_t value) +{ + PROTECT(t, instance); + object field = resolveField(t, pair); + PROTECT(t, field); + + ACQUIRE_FIELD_FOR_WRITE(t, field); + + setFieldValue(t, instance, field, value); +} + uint64_t instanceOf64(Thread* t, object class_, object o) { return instanceOf(t, class_, o); } +uint64_t +instanceOfFromReference(Thread* t, object pair, object o) +{ + PROTECT(t, o); + + object c = resolveClass + (t, classLoader(t, methodClass(t, pairFirst(t, pair))), + referenceName(t, pairSecond(t, pair))); + + return instanceOf64(t, c, o); +} + uint64_t makeNewGeneral64(Thread* t, object class_) { @@ -2769,6 +3073,15 @@ makeNew64(Thread* t, object class_) return reinterpret_cast(makeNew(t, class_)); } +uint64_t +makeNewFromReference(Thread* t, object pair) +{ + return makeNewGeneral64 + (t, resolveClass + (t, classLoader(t, methodClass(t, pairFirst(t, pair))), + referenceName(t, pairSecond(t, pair)))); +} + uint64_t getJClass64(Thread* t, object class_) { @@ -2837,6 +3150,29 @@ pushReturnValue(MyThread* t, Frame* frame, unsigned code, } } +Compiler::Operand* +popField(MyThread* t, Frame* frame, int code) +{ + switch (code) { + case ByteField: + case BooleanField: + case CharField: + case ShortField: + case FloatField: + case IntField: + return frame->popInt(); + + case DoubleField: + case LongField: + return frame->popLong(); + + case ObjectField: + return frame->popObject(); + + default: abort(t); + } +} + Compiler::OperandType operandTypeForFieldCode(Thread* t, unsigned code) { @@ -3004,6 +3340,74 @@ compileDirectInvoke(MyThread* t, Frame* frame, object target, bool tailCall) return tailCall; } +unsigned +methodReferenceParameterFootprint(Thread* t, object reference, bool isStatic) +{ + return parameterFootprint + (t, reinterpret_cast + (&byteArrayBody(t, referenceSpec(t, reference), 0)), isStatic); +} + +int +methodReferenceReturnCode(Thread* t, object reference) +{ + unsigned parameterCount; + unsigned returnCode; + scanMethodSpec + (t, reinterpret_cast + (&byteArrayBody(t, referenceSpec(t, reference), 0)), ¶meterCount, + &returnCode); + + return returnCode; +} + +void +compileReferenceInvoke(MyThread* t, Frame* frame, Compiler::Operand* method, + object reference, bool isStatic, bool tailCall) +{ + unsigned parameterFootprint + = methodReferenceParameterFootprint(t, reference, isStatic); + + int returnCode = methodReferenceReturnCode(t, reference); + + unsigned rSize = resultSize(t, returnCode); + + Compiler::Operand* result = frame->c->stackCall + (method, + tailCall ? Compiler::TailJump : 0, + frame->trace(0, 0), + rSize, + operandTypeForFieldCode(t, returnCode), + parameterFootprint); + + frame->pop(parameterFootprint); + + if (rSize) { + pushReturnValue(t, frame, returnCode, result); + } +} + +void +compileDirectReferenceInvoke(MyThread* t, Frame* frame, Thunk thunk, + object reference, bool isStatic, bool tailCall) +{ + Compiler* c = frame->c; + + PROTECT(t, reference); + + object pair = makePair(t, frame->context->method, reference); + + compileReferenceInvoke + (t, frame, c->call + (c->constant(getThunk(t, thunk), Compiler::AddressType), + 0, + frame->trace(0, 0), + BytesPerWord, + Compiler::AddressType, + 2, c->register_(t->arch->thread()), frame->append(pair)), + reference, isStatic, tailCall); +} + void handleMonitorEvent(MyThread* t, Frame* frame, intptr_t function) { @@ -3113,17 +3517,32 @@ returnsNext(MyThread* t, object code, unsigned ip) } bool -isTailCall(MyThread* t, object code, unsigned ip, object caller, object callee) +isTailCall(MyThread* t, object code, unsigned ip, object caller, + int calleeReturnCode) { return TailCalls and ((methodFlags(t, caller) & ACC_SYNCHRONIZED) == 0) and (not inTryBlock(t, code, ip - 1)) and (not needsReturnBarrier(t, caller)) and (methodReturnCode(t, caller) == VoidField - or methodReturnCode(t, caller) == methodReturnCode(t, callee)) + or methodReturnCode(t, caller) == calleeReturnCode) and returnsNext(t, code, ip); } +bool +isTailCall(MyThread* t, object code, unsigned ip, object caller, object callee) +{ + return isTailCall(t, code, ip, caller, methodReturnCode(t, callee)); +} + +bool +isReferenceTailCall(MyThread* t, object code, unsigned ip, object caller, + object calleeReference) +{ + return isTailCall + (t, code, ip, caller, methodReferenceReturnCode(t, calleeReference)); +} + void compile(MyThread* t, Frame* initialFrame, unsigned ip, int exceptionHandlerStart = -1); @@ -3524,19 +3943,34 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case anewarray: { uint16_t index = codeReadInt16(t, code, ip); - object class_ = resolveClassInPool(t, context->method, index - 1); + object reference = singletonObject + (t, codePool(t, methodCode(t, context->method)), index - 1); + + PROTECT(t, reference); + + object class_ = resolveClassInPool(t, context->method, index - 1, false); Compiler::Operand* length = frame->popInt(); + object argument; + Thunk thunk; + if (LIKELY(class_)) { + argument = class_; + thunk = makeBlankObjectArrayThunk; + } else { + argument = makePair(t, context->method, reference); + thunk = makeBlankObjectArrayFromReferenceThunk; + } + frame->pushObject (c->call - (c->constant - (getThunk(t, makeBlankObjectArrayThunk), Compiler::AddressType), + (c->constant(getThunk(t, thunk), Compiler::AddressType), 0, frame->trace(0, 0), BytesPerWord, Compiler::ObjectType, - 3, c->register_(t->arch->thread()), frame->append(class_), length)); + 3, c->register_(t->arch->thread()), frame->append(argument), + length)); } break; case areturn: { @@ -3594,17 +4028,33 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case checkcast: { uint16_t index = codeReadInt16(t, code, ip); - object class_ = resolveClassInPool(t, context->method, index - 1); + object reference = singletonObject + (t, codePool(t, methodCode(t, context->method)), index - 1); + + PROTECT(t, reference); + + object class_ = resolveClassInPool(t, context->method, index - 1, false); + + object argument; + Thunk thunk; + if (LIKELY(class_)) { + argument = class_; + thunk = checkCastThunk; + } else { + argument = makePair(t, context->method, reference); + thunk = checkCastFromReferenceThunk; + } Compiler::Operand* instance = c->peek(1, 0); c->call - (c->constant(getThunk(t, checkCastThunk), Compiler::AddressType), + (c->constant(getThunk(t, thunk), Compiler::AddressType), 0, frame->trace(0, 0), 0, Compiler::VoidType, - 3, c->register_(t->arch->thread()), frame->append(class_), instance); + 3, c->register_(t->arch->thread()), frame->append(argument), + instance); } break; case d2f: { @@ -3813,140 +4263,177 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case getstatic: { uint16_t index = codeReadInt16(t, code, ip); - object field = resolveField(t, context->method, index - 1); + object reference = singletonObject + (t, codePool(t, methodCode(t, context->method)), index - 1); - if ((fieldFlags(t, field) & ACC_VOLATILE) - and BytesPerWord == 4 - and (fieldCode(t, field) == DoubleField - or fieldCode(t, field) == LongField)) - { - PROTECT(t, field); + PROTECT(t, reference); - c->call - (c->constant - (getThunk(t, acquireMonitorForObjectThunk), Compiler::AddressType), - 0, frame->trace(0, 0), 0, Compiler::VoidType, 2, - c->register_(t->arch->thread()), - frame->append(field)); - } + object field = resolveField(t, context->method, index - 1, false); - Compiler::Operand* table; - - if (instruction == getstatic) { - assert(t, fieldFlags(t, field) & ACC_STATIC); - - PROTECT(t, field); - - if (fieldClass(t, field) != methodClass(t, context->method) - and classNeedsInit(t, fieldClass(t, field))) - { - c->call - (c->constant - (getThunk(t, tryInitClassThunk), Compiler::AddressType), - 0, - frame->trace(0, 0), - 0, - Compiler::VoidType, - 2, c->register_(t->arch->thread()), - frame->append(fieldClass(t, field))); - } - - table = frame->append(classStaticTable(t, fieldClass(t, field))); - } else { - assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0); - - table = frame->popObject(); - - if (inTryBlock(t, code, ip - 3)) { - c->saveLocals(); - frame->trace(0, 0); - } - } - - switch (fieldCode(t, field)) { - case ByteField: - case BooleanField: - frame->pushInt - (c->load - (1, 1, c->memory - (table, Compiler::IntegerType, fieldOffset(t, field), 0, 1), - BytesPerWord)); - break; - - case CharField: - frame->pushInt - (c->loadz - (2, 2, c->memory - (table, Compiler::IntegerType, fieldOffset(t, field), 0, 1), - BytesPerWord)); - break; - - case ShortField: - frame->pushInt - (c->load - (2, 2, c->memory - (table, Compiler::IntegerType, fieldOffset(t, field), 0, 1), - BytesPerWord)); - break; - - case FloatField: - frame->pushInt - (c->load - (4, 4, c->memory - (table, Compiler::FloatType, fieldOffset(t, field), 0, 1), - BytesPerWord)); - break; - - case IntField: - frame->pushInt - (c->load - (4, 4, c->memory - (table, Compiler::IntegerType, fieldOffset(t, field), 0, 1), - BytesPerWord)); - break; - - case DoubleField: - frame->pushLong - (c->load - (8, 8, c->memory - (table, Compiler::FloatType, fieldOffset(t, field), 0, 1), 8)); - break; - - case LongField: - frame->pushLong - (c->load - (8, 8, c->memory - (table, Compiler::IntegerType, fieldOffset(t, field), 0, 1), 8)); - break; - - case ObjectField: - frame->pushObject - (c->load - (BytesPerWord, BytesPerWord, - c->memory - (table, Compiler::ObjectType, fieldOffset(t, field), 0, 1), - BytesPerWord)); - break; - - default: - abort(t); - } - - if (fieldFlags(t, field) & ACC_VOLATILE) { - if (BytesPerWord == 4 + if (LIKELY(field)) { + if ((fieldFlags(t, field) & ACC_VOLATILE) + and BytesPerWord == 4 and (fieldCode(t, field) == DoubleField or fieldCode(t, field) == LongField)) { + PROTECT(t, field); + c->call (c->constant - (getThunk(t, releaseMonitorForObjectThunk), - Compiler::AddressType), + (getThunk(t, acquireMonitorForObjectThunk), Compiler::AddressType), 0, frame->trace(0, 0), 0, Compiler::VoidType, 2, c->register_(t->arch->thread()), frame->append(field)); - } else { - c->loadBarrier(); } + + Compiler::Operand* table; + + if (instruction == getstatic) { + assert(t, fieldFlags(t, field) & ACC_STATIC); + + PROTECT(t, field); + + if (fieldClass(t, field) != methodClass(t, context->method) + and classNeedsInit(t, fieldClass(t, field))) + { + c->call + (c->constant + (getThunk(t, tryInitClassThunk), Compiler::AddressType), + 0, + frame->trace(0, 0), + 0, + Compiler::VoidType, + 2, c->register_(t->arch->thread()), + frame->append(fieldClass(t, field))); + } + + table = frame->append(classStaticTable(t, fieldClass(t, field))); + } else { + assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0); + + table = frame->popObject(); + + if (inTryBlock(t, code, ip - 3)) { + c->saveLocals(); + frame->trace(0, 0); + } + } + + switch (fieldCode(t, field)) { + case ByteField: + case BooleanField: + frame->pushInt + (c->load + (1, 1, c->memory + (table, Compiler::IntegerType, fieldOffset(t, field), 0, 1), + BytesPerWord)); + break; + + case CharField: + frame->pushInt + (c->loadz + (2, 2, c->memory + (table, Compiler::IntegerType, fieldOffset(t, field), 0, 1), + BytesPerWord)); + break; + + case ShortField: + frame->pushInt + (c->load + (2, 2, c->memory + (table, Compiler::IntegerType, fieldOffset(t, field), 0, 1), + BytesPerWord)); + break; + + case FloatField: + frame->pushInt + (c->load + (4, 4, c->memory + (table, Compiler::FloatType, fieldOffset(t, field), 0, 1), + BytesPerWord)); + break; + + case IntField: + frame->pushInt + (c->load + (4, 4, c->memory + (table, Compiler::IntegerType, fieldOffset(t, field), 0, 1), + BytesPerWord)); + break; + + case DoubleField: + frame->pushLong + (c->load + (8, 8, c->memory + (table, Compiler::FloatType, fieldOffset(t, field), 0, 1), 8)); + break; + + case LongField: + frame->pushLong + (c->load + (8, 8, c->memory + (table, Compiler::IntegerType, fieldOffset(t, field), 0, 1), 8)); + break; + + case ObjectField: + frame->pushObject + (c->load + (BytesPerWord, BytesPerWord, + c->memory + (table, Compiler::ObjectType, fieldOffset(t, field), 0, 1), + BytesPerWord)); + break; + + default: + abort(t); + } + + if (fieldFlags(t, field) & ACC_VOLATILE) { + if (BytesPerWord == 4 + and (fieldCode(t, field) == DoubleField + or fieldCode(t, field) == LongField)) + { + c->call + (c->constant + (getThunk(t, releaseMonitorForObjectThunk), + Compiler::AddressType), + 0, frame->trace(0, 0), 0, Compiler::VoidType, 2, + c->register_(t->arch->thread()), + frame->append(field)); + } else { + c->loadBarrier(); + } + } + } else { + int fieldCode = vm::fieldCode + (t, byteArrayBody(t, referenceSpec(t, reference), 0)); + + object pair = makePair(t, context->method, reference); + + unsigned rSize = resultSize(t, fieldCode); + Compiler::OperandType rType = operandTypeForFieldCode(t, fieldCode); + + Compiler::Operand* result; + if (instruction == getstatic) { + result = c->call + (c->constant + (getThunk(t, getStaticFieldValueFromReferenceThunk), + Compiler::AddressType), + 0, frame->trace(0, 0), rSize, rType, 2, + c->register_(t->arch->thread()), frame->append(pair)); + } else { + Compiler::Operand* instance = frame->popObject(); + + result = c->call + (c->constant + (getThunk(t, getFieldValueFromReferenceThunk), + Compiler::AddressType), + 0, frame->trace(0, 0), rSize, rType, 3, + c->register_(t->arch->thread()), frame->append(pair), + instance); + } + + pushReturnValue(t, frame, fieldCode, result); } } break; @@ -4213,14 +4700,34 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case instanceof: { uint16_t index = codeReadInt16(t, code, ip); - object class_ = resolveClassInPool(t, context->method, index - 1); + object reference = singletonObject + (t, codePool(t, methodCode(t, context->method)), index - 1); + + PROTECT(t, reference); + + object class_ = resolveClassInPool(t, context->method, index - 1, false); + + Compiler::Operand* instance = frame->popObject(); + + object argument; + Thunk thunk; + TraceElement* trace; + if (LIKELY(class_)) { + argument = class_; + thunk = instanceOf64Thunk; + trace = 0; + } else { + argument = makePair(t, context->method, reference); + thunk = instanceOfFromReferenceThunk; + trace = frame->trace(0, 0); + } frame->pushInt (c->call - (c->constant(getThunk(t, instanceOf64Thunk), Compiler::AddressType), - 0, 0, 4, Compiler::IntegerType, - 3, c->register_(t->arch->thread()), frame->append(class_), - frame->popObject())); + (c->constant(getThunk(t, thunk), Compiler::AddressType), + 0, trace, 4, Compiler::IntegerType, + 3, c->register_(t->arch->thread()), frame->append(argument), + instance)); } break; case invokeinterface: { @@ -4229,30 +4736,48 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, uint16_t index = codeReadInt16(t, code, ip); ip += 2; - object target = resolveMethod(t, context->method, index - 1); + object reference = singletonObject + (t, codePool(t, methodCode(t, context->method)), index - 1); - assert(t, (methodFlags(t, target) & ACC_STATIC) == 0); + PROTECT(t, reference); - unsigned parameterFootprint = methodParameterFootprint(t, target); + object target = resolveMethod(t, context->method, index - 1, false); - unsigned instance = parameterFootprint - 1; + object argument; + Thunk thunk; + unsigned parameterFootprint; + int returnCode; + bool tailCall; + if (LIKELY(target)) { + assert(t, (methodFlags(t, target) & ACC_STATIC) == 0); - int returnCode = methodReturnCode(t, target); + argument = target; + thunk = findInterfaceMethodFromInstanceThunk; + parameterFootprint = methodParameterFootprint(t, target); + returnCode = methodReturnCode(t, target); + tailCall = isTailCall(t, code, ip, context->method, target); + } else { + argument = makePair(t, context->method, reference); + thunk = findInterfaceMethodFromInstanceAndReferenceThunk; + parameterFootprint = methodReferenceParameterFootprint + (t, reference, false); + returnCode = methodReferenceReturnCode(t, reference); + tailCall = isReferenceTailCall + (t, code, ip, context->method, reference); + } unsigned rSize = resultSize(t, returnCode); Compiler::Operand* result = c->stackCall (c->call - (c->constant - (getThunk(t, findInterfaceMethodFromInstanceThunk), - Compiler::AddressType), + (c->constant(getThunk(t, thunk), Compiler::AddressType), 0, frame->trace(0, 0), BytesPerWord, Compiler::AddressType, - 3, c->register_(t->arch->thread()), frame->append(target), - c->peek(1, instance)), - 0, + 3, c->register_(t->arch->thread()), frame->append(argument), + c->peek(1, parameterFootprint - 1)), + tailCall ? Compiler::TailJump : 0, frame->trace(0, 0), rSize, operandTypeForFieldCode(t, returnCode), @@ -4269,18 +4794,30 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, context->leaf = false; uint16_t index = codeReadInt16(t, code, ip); - object target = resolveMethod(t, context->method, index - 1); - object class_ = methodClass(t, context->method); - if (isSpecialMethod(t, target, class_)) { - target = findVirtualMethod(t, target, classSuper(t, class_)); + object reference = singletonObject + (t, codePool(t, methodCode(t, context->method)), index - 1); + + PROTECT(t, reference); + + object target = resolveMethod(t, context->method, index - 1, false); + + if (LIKELY(target)) { + object class_ = methodClass(t, context->method); + if (isSpecialMethod(t, target, class_)) { + target = findVirtualMethod(t, target, classSuper(t, class_)); + } + + assert(t, (methodFlags(t, target) & ACC_STATIC) == 0); + + bool tailCall = isTailCall(t, code, ip, context->method, target); + + compileDirectInvoke(t, frame, target, tailCall); + } else { + compileDirectReferenceInvoke + (t, frame, findSpecialMethodFromReferenceThunk, reference, false, + isReferenceTailCall(t, code, ip, context->method, reference)); } - - assert(t, (methodFlags(t, target) & ACC_STATIC) == 0); - - bool tailCall = isTailCall(t, code, ip, context->method, target); - - compileDirectInvoke(t, frame, target, tailCall); } break; case invokestatic: { @@ -4288,13 +4825,24 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, uint16_t index = codeReadInt16(t, code, ip); - object target = resolveMethod(t, context->method, index - 1); + object reference = singletonObject + (t, codePool(t, methodCode(t, context->method)), index - 1); - assert(t, methodFlags(t, target) & ACC_STATIC); + PROTECT(t, reference); - if (not intrinsic(t, frame, target)) { - bool tailCall = isTailCall(t, code, ip, context->method, target); - compileDirectInvoke(t, frame, target, tailCall); + object target = resolveMethod(t, context->method, index - 1, false); + + if (LIKELY(target)) { + assert(t, methodFlags(t, target) & ACC_STATIC); + + if (not intrinsic(t, frame, target)) { + bool tailCall = isTailCall(t, code, ip, context->method, target); + compileDirectInvoke(t, frame, target, tailCall); + } + } else { + compileDirectReferenceInvoke + (t, frame, findStaticMethodFromReferenceThunk, reference, true, + isReferenceTailCall(t, code, ip, context->method, reference)); } } break; @@ -4303,36 +4851,62 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, uint16_t index = codeReadInt16(t, code, ip); - object target = resolveMethod(t, context->method, index - 1); + object reference = singletonObject + (t, codePool(t, methodCode(t, context->method)), index - 1); - assert(t, (methodFlags(t, target) & ACC_STATIC) == 0); + PROTECT(t, reference); - unsigned parameterFootprint = methodParameterFootprint(t, target); + object target = resolveMethod(t, context->method, index - 1, false); - unsigned offset = ClassVtable + (methodOffset(t, target) * BytesPerWord); + if (LIKELY(target)) { + assert(t, (methodFlags(t, target) & ACC_STATIC) == 0); - Compiler::Operand* instance = c->peek(1, parameterFootprint - 1); + unsigned parameterFootprint = methodParameterFootprint(t, target); - unsigned rSize = resultSize(t, methodReturnCode(t, target)); + unsigned offset = ClassVtable + + (methodOffset(t, target) * BytesPerWord); - bool tailCall = isTailCall(t, code, ip, context->method, target); + Compiler::Operand* instance = c->peek(1, parameterFootprint - 1); - Compiler::Operand* result = c->stackCall - (c->memory - (c->and_ - (BytesPerWord, c->constant(PointerMask, Compiler::IntegerType), - c->memory(instance, Compiler::ObjectType, 0, 0, 1)), - Compiler::ObjectType, offset, 0, 1), - tailCall ? Compiler::TailJump : 0, - frame->trace(0, 0), - rSize, - operandTypeForFieldCode(t, methodReturnCode(t, target)), - parameterFootprint); + unsigned rSize = resultSize(t, methodReturnCode(t, target)); - frame->pop(parameterFootprint); + bool tailCall = isTailCall(t, code, ip, context->method, target); - if (rSize) { - pushReturnValue(t, frame, methodReturnCode(t, target), result); + Compiler::Operand* result = c->stackCall + (c->memory + (c->and_ + (BytesPerWord, c->constant(PointerMask, Compiler::IntegerType), + c->memory(instance, Compiler::ObjectType, 0, 0, 1)), + Compiler::ObjectType, offset, 0, 1), + tailCall ? Compiler::TailJump : 0, + frame->trace(0, 0), + rSize, + operandTypeForFieldCode(t, methodReturnCode(t, target)), + parameterFootprint); + + frame->pop(parameterFootprint); + + if (rSize) { + pushReturnValue(t, frame, methodReturnCode(t, target), result); + } + } else { + PROTECT(t, reference); + + object pair = makePair(t, context->method, reference); + + compileReferenceInvoke + (t, frame, c->call + (c->constant(getThunk(t, findVirtualMethodFromReferenceThunk), + Compiler::AddressType), + 0, + frame->trace(0, 0), + BytesPerWord, + Compiler::AddressType, + 3, c->register_(t->arch->thread()), frame->append(pair), + c->peek(1, methodReferenceParameterFootprint + (t, reference, false) - 1)), + reference, false, isReferenceTailCall + (t, code, ip, context->method, reference)); } } break; @@ -4502,22 +5076,44 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, if (singletonIsObject(t, pool, index - 1)) { object v = singletonObject(t, pool, index - 1); + + loadMemoryBarrier(); + if (objectClass(t, v) == type(t, Machine::ReferenceType)) { - v = resolveClassInPool(t, context->method, index - 1); + object reference = v; + PROTECT(t, reference); + + v = resolveClassInPool(t, context->method, index - 1, false); + + if (UNLIKELY(v == 0)) { + frame->pushObject + (c->call + (c->constant + (getThunk(t, getJClassFromReferenceThunk), + Compiler::AddressType), + 0, + frame->trace(0, 0), + BytesPerWord, + Compiler::ObjectType, + 2, c->register_(t->arch->thread()), + frame->append(makePair(t, context->method, reference)))); + } } - if (objectClass(t, v) == type(t, Machine::ClassType)) { - frame->pushObject - (c->call - (c->constant - (getThunk(t, getJClass64Thunk), Compiler::AddressType), - 0, - frame->trace(0, 0), - BytesPerWord, - Compiler::ObjectType, - 2, c->register_(t->arch->thread()), frame->append(v))); - } else { - frame->pushObject(frame->append(v)); + if (v) { + if (objectClass(t, v) == type(t, Machine::ClassType)) { + frame->pushObject + (c->call + (c->constant + (getThunk(t, getJClass64Thunk), Compiler::AddressType), + 0, + frame->trace(0, 0), + BytesPerWord, + Compiler::ObjectType, + 2, c->register_(t->arch->thread()), frame->append(v))); + } else { + frame->pushObject(frame->append(v)); + } } } else { frame->pushInt @@ -4746,8 +5342,22 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, uint16_t index = codeReadInt16(t, code, ip); uint8_t dimensions = codeBody(t, code, ip++); - object class_ = resolveClassInPool(t, context->method, index - 1); - PROTECT(t, class_); + object reference = singletonObject + (t, codePool(t, methodCode(t, context->method)), index - 1); + + PROTECT(t, reference); + + object class_ = resolveClassInPool(t, context->method, index - 1, false); + + object argument; + Thunk thunk; + if (LIKELY(class_)) { + argument = class_; + thunk = makeMultidimensionalArrayThunk; + } else { + argument = makePair(t, context->method, reference); + thunk = makeMultidimensionalArrayFromReferenceThunk; + } unsigned offset = localOffset @@ -4756,12 +5366,12 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, Compiler::Operand* result = c->call (c->constant - (getThunk(t, makeMultidimensionalArrayThunk), Compiler::AddressType), + (getThunk(t, thunk), Compiler::AddressType), 0, frame->trace(0, 0), BytesPerWord, Compiler::ObjectType, - 4, c->register_(t->arch->thread()), frame->append(class_), + 4, c->register_(t->arch->thread()), frame->append(argument), c->constant(dimensions, Compiler::IntegerType), c->constant(offset, Compiler::IntegerType)); @@ -4772,28 +5382,35 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case new_: { uint16_t index = codeReadInt16(t, code, ip); - object class_ = resolveClassInPool(t, context->method, index - 1); + object reference = singletonObject + (t, codePool(t, methodCode(t, context->method)), index - 1); - if (classVmFlags(t, class_) & (WeakReferenceFlag | HasFinalizerFlag)) { - frame->pushObject - (c->call - (c->constant - (getThunk(t, makeNewGeneral64Thunk), Compiler::AddressType), - 0, - frame->trace(0, 0), - BytesPerWord, - Compiler::ObjectType, - 2, c->register_(t->arch->thread()), frame->append(class_))); + PROTECT(t, reference); + + object class_ = resolveClassInPool(t, context->method, index - 1, false); + + object argument; + Thunk thunk; + if (LIKELY(class_)) { + argument = class_; + if (classVmFlags(t, class_) & (WeakReferenceFlag | HasFinalizerFlag)) { + thunk = makeNewGeneral64Thunk; + } else { + thunk = makeNew64Thunk; + } } else { - frame->pushObject - (c->call - (c->constant(getThunk(t, makeNew64Thunk), Compiler::AddressType), - 0, - frame->trace(0, 0), - BytesPerWord, - Compiler::ObjectType, - 2, c->register_(t->arch->thread()), frame->append(class_))); + argument = makePair(t, context->method, reference); + thunk = makeNewFromReferenceThunk; } + + frame->pushObject + (c->call + (c->constant(getThunk(t, thunk), Compiler::AddressType), + 0, + frame->trace(0, 0), + BytesPerWord, + Compiler::ObjectType, + 2, c->register_(t->arch->thread()), frame->append(argument))); } break; case newarray: { @@ -4826,165 +5443,237 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case putstatic: { uint16_t index = codeReadInt16(t, code, ip); - object field = resolveField(t, context->method, index - 1); + object reference = singletonObject + (t, codePool(t, methodCode(t, context->method)), index - 1); - object staticTable = 0; + PROTECT(t, reference); - if (instruction == putstatic) { - assert(t, fieldFlags(t, field) & ACC_STATIC); + object field = resolveField(t, context->method, index - 1, false); - if (fieldClass(t, field) != methodClass(t, context->method) - and classNeedsInit(t, fieldClass(t, field))) - { - PROTECT(t, field); + if (LIKELY(field)) { + int fieldCode = vm::fieldCode(t, field); + Compiler::Operand* value = popField(t, frame, fieldCode); - c->call - (c->constant - (getThunk(t, tryInitClassThunk), Compiler::AddressType), - 0, - frame->trace(0, 0), - 0, - Compiler::VoidType, - 2, c->register_(t->arch->thread()), - frame->append(fieldClass(t, field))); - } + object staticTable = 0; - staticTable = classStaticTable(t, fieldClass(t, field)); - } else { - assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0); + if (instruction == putstatic) { + assert(t, fieldFlags(t, field) & ACC_STATIC); - if (inTryBlock(t, code, ip - 3)) { - c->saveLocals(); - frame->trace(0, 0); - } - } + if (fieldClass(t, field) != methodClass(t, context->method) + and classNeedsInit(t, fieldClass(t, field))) + { + PROTECT(t, field); - if (fieldFlags(t, field) & ACC_VOLATILE) { - if (BytesPerWord == 4 - and (fieldCode(t, field) == DoubleField - or fieldCode(t, field) == LongField)) - { - PROTECT(t, field); + c->call + (c->constant + (getThunk(t, tryInitClassThunk), Compiler::AddressType), + 0, + frame->trace(0, 0), + 0, + Compiler::VoidType, + 2, c->register_(t->arch->thread()), + frame->append(fieldClass(t, field))); + } - c->call - (c->constant - (getThunk(t, acquireMonitorForObjectThunk), - Compiler::AddressType), - 0, frame->trace(0, 0), 0, Compiler::VoidType, 2, - c->register_(t->arch->thread()), frame->append(field)); + staticTable = classStaticTable(t, fieldClass(t, field)); } else { - c->storeStoreBarrier(); + assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0); + + if (inTryBlock(t, code, ip - 3)) { + c->saveLocals(); + frame->trace(0, 0); + } } - } - Compiler::Operand* value; - switch (fieldCode(t, field)) { - case ByteField: - case BooleanField: - case CharField: - case ShortField: - case FloatField: - case IntField: { - value = frame->popInt(); - } break; + Compiler::Operand* table; - case DoubleField: - case LongField: { - value = frame->popLong(); - } break; + if (instruction == putstatic) { + PROTECT(t, field); - case ObjectField: { - value = frame->popObject(); - } break; + table = frame->append(staticTable); + } else { + table = frame->popObject(); + } - default: abort(t); - } + if (fieldFlags(t, field) & ACC_VOLATILE) { + if (BytesPerWord == 4 + and (fieldCode == DoubleField or fieldCode == LongField)) + { + PROTECT(t, field); - Compiler::Operand* table; + c->call + (c->constant + (getThunk(t, acquireMonitorForObjectThunk), + Compiler::AddressType), + 0, frame->trace(0, 0), 0, Compiler::VoidType, 2, + c->register_(t->arch->thread()), frame->append(field)); + } else { + c->storeStoreBarrier(); + } + } - if (instruction == putstatic) { - PROTECT(t, field); + switch (fieldCode) { + case ByteField: + case BooleanField: + c->store + (BytesPerWord, value, 1, c->memory + (table, Compiler::IntegerType, fieldOffset(t, field), 0, 1)); + break; - table = frame->append(staticTable); - } else { - table = frame->popObject(); - } - - switch (fieldCode(t, field)) { - case ByteField: - case BooleanField: - c->store - (BytesPerWord, value, 1, c->memory - (table, Compiler::IntegerType, fieldOffset(t, field), 0, 1)); - break; - - case CharField: - case ShortField: - c->store - (BytesPerWord, value, 2, c->memory - (table, Compiler::IntegerType, fieldOffset(t, field), 0, 1)); - break; + case CharField: + case ShortField: + c->store + (BytesPerWord, value, 2, c->memory + (table, Compiler::IntegerType, fieldOffset(t, field), 0, 1)); + break; - case FloatField: - c->store - (BytesPerWord, value, 4, c->memory - (table, Compiler::FloatType, fieldOffset(t, field), 0, 1)); - break; + case FloatField: + c->store + (BytesPerWord, value, 4, c->memory + (table, Compiler::FloatType, fieldOffset(t, field), 0, 1)); + break; - case IntField: - c->store - (BytesPerWord, value, 4, c->memory - (table, Compiler::IntegerType, fieldOffset(t, field), 0, 1)); - break; + case IntField: + c->store + (BytesPerWord, value, 4, c->memory + (table, Compiler::IntegerType, fieldOffset(t, field), 0, 1)); + break; - case DoubleField: - c->store - (8, value, 8, c->memory - (table, Compiler::FloatType, fieldOffset(t, field), 0, 1)); - break; + case DoubleField: + c->store + (8, value, 8, c->memory + (table, Compiler::FloatType, fieldOffset(t, field), 0, 1)); + break; - case LongField: - c->store - (8, value, 8, c->memory - (table, Compiler::IntegerType, fieldOffset(t, field), 0, 1)); - break; + case LongField: + c->store + (8, value, 8, c->memory + (table, Compiler::IntegerType, fieldOffset(t, field), 0, 1)); + break; - case ObjectField: - if (instruction == putfield) { - c->call - (c->constant - (getThunk(t, setMaybeNullThunk), Compiler::AddressType), - 0, - frame->trace(0, 0), - 0, - Compiler::VoidType, - 4, c->register_(t->arch->thread()), table, - c->constant(fieldOffset(t, field), Compiler::IntegerType), value); - } else { - c->call - (c->constant(getThunk(t, setThunk), Compiler::AddressType), - 0, 0, 0, Compiler::VoidType, - 4, c->register_(t->arch->thread()), table, - c->constant(fieldOffset(t, field), Compiler::IntegerType), value); + case ObjectField: + if (instruction == putfield) { + c->call + (c->constant + (getThunk(t, setMaybeNullThunk), Compiler::AddressType), + 0, + frame->trace(0, 0), + 0, + Compiler::VoidType, + 4, c->register_(t->arch->thread()), table, + c->constant(fieldOffset(t, field), Compiler::IntegerType), + value); + } else { + c->call + (c->constant(getThunk(t, setThunk), Compiler::AddressType), + 0, 0, 0, Compiler::VoidType, + 4, c->register_(t->arch->thread()), table, + c->constant(fieldOffset(t, field), Compiler::IntegerType), + value); + } + break; + + default: abort(t); } - break; - default: abort(t); - } + if (fieldFlags(t, field) & ACC_VOLATILE) { + if (BytesPerWord == 4 + and (fieldCode == DoubleField or fieldCode == LongField)) + { + c->call + (c->constant + (getThunk(t, releaseMonitorForObjectThunk), + Compiler::AddressType), + 0, frame->trace(0, 0), 0, Compiler::VoidType, 2, + c->register_(t->arch->thread()), frame->append(field)); + } else { + c->storeLoadBarrier(); + } + } + } else { + int fieldCode = vm::fieldCode + (t, byteArrayBody(t, referenceSpec(t, reference), 0)); - if (fieldFlags(t, field) & ACC_VOLATILE) { - if (BytesPerWord == 4 - and (fieldCode(t, field) == DoubleField - or fieldCode(t, field) == LongField)) - { - c->call - (c->constant - (getThunk(t, releaseMonitorForObjectThunk), - Compiler::AddressType), - 0, frame->trace(0, 0), 0, Compiler::VoidType, 2, - c->register_(t->arch->thread()), frame->append(field)); - } else { - c->storeLoadBarrier(); + Compiler::Operand* value = popField(t, frame, fieldCode); + unsigned rSize = resultSize(t, fieldCode); + Compiler::OperandType rType = operandTypeForFieldCode(t, fieldCode); + + object pair = makePair(t, context->method, reference); + + switch (fieldCode) { + case ByteField: + case BooleanField: + case CharField: + case ShortField: + case FloatField: + case IntField: { + if (instruction == putstatic) { + c->call + (c->constant + (getThunk(t, setStaticFieldValueFromReferenceThunk), + Compiler::AddressType), + 0, frame->trace(0, 0), rSize, rType, 3, + c->register_(t->arch->thread()), frame->append(pair), + value); + } else { + Compiler::Operand* instance = frame->popObject(); + + c->call + (c->constant + (getThunk(t, setFieldValueFromReferenceThunk), + Compiler::AddressType), + 0, frame->trace(0, 0), rSize, rType, 4, + c->register_(t->arch->thread()), frame->append(pair), + instance, value); + } + } break; + + case DoubleField: + case LongField: { + if (instruction == putstatic) { + c->call + (c->constant + (getThunk(t, setStaticLongFieldValueFromReferenceThunk), + Compiler::AddressType), + 0, frame->trace(0, 0), rSize, rType, 4, + c->register_(t->arch->thread()), frame->append(pair), + static_cast(0), value); + } else { + Compiler::Operand* instance = frame->popObject(); + + c->call + (c->constant + (getThunk(t, setLongFieldValueFromReferenceThunk), + Compiler::AddressType), + 0, frame->trace(0, 0), rSize, rType, 5, + c->register_(t->arch->thread()), frame->append(pair), + instance, static_cast(0), value); + } + } break; + + case ObjectField: { + if (instruction == putstatic) { + c->call + (c->constant + (getThunk(t, setStaticObjectFieldValueFromReferenceThunk), + Compiler::AddressType), + 0, frame->trace(0, 0), rSize, rType, 3, + c->register_(t->arch->thread()), frame->append(pair), + value); + } else { + Compiler::Operand* instance = frame->popObject(); + + c->call + (c->constant + (getThunk(t, setObjectFieldValueFromReferenceThunk), + Compiler::AddressType), + 0, frame->trace(0, 0), rSize, rType, 4, + c->register_(t->arch->thread()), frame->append(pair), + instance, value); + } + } break; + + default: abort(t); } } } break; diff --git a/src/interpret.cpp b/src/interpret.cpp index 3da5ca97d5..482859e21f 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -1460,27 +1460,11 @@ interpret3(Thread* t, const int base) assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0); - if (UNLIKELY((fieldFlags(t, field) & ACC_VOLATILE) - and BytesPerWord == 4 - and (fieldCode(t, field) == DoubleField - or fieldCode(t, field) == LongField))) - { - PROTECT(t, field); - acquire(t, field); - } + PROTECT(t, field); + + ACQUIRE_FIELD_FOR_READ(t, field); pushField(t, popObject(t), field); - - if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) { - if (BytesPerWord == 4 - and (fieldCode(t, field) == DoubleField - or fieldCode(t, field) == LongField)) - { - release(t, field); - } else { - loadMemoryBarrier(); - } - } } else { exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; @@ -1498,26 +1482,9 @@ interpret3(Thread* t, const int base) if (UNLIKELY(classInit(t, fieldClass(t, field), 3))) goto invoke; - if (UNLIKELY((fieldFlags(t, field) & ACC_VOLATILE) - and BytesPerWord == 4 - and (fieldCode(t, field) == DoubleField - or fieldCode(t, field) == LongField))) - { - acquire(t, field); - } + ACQUIRE_FIELD_FOR_READ(t, field); pushField(t, classStaticTable(t, fieldClass(t, field)), field); - - if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) { - if (BytesPerWord == 4 - and (fieldCode(t, field) == DoubleField - or fieldCode(t, field) == LongField)) - { - release(t, field); - } else { - loadMemoryBarrier(); - } - } } goto loop; case goto_: { @@ -2460,80 +2427,61 @@ interpret3(Thread* t, const int base) assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0); PROTECT(t, field); - if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) { - if (BytesPerWord == 4 - and (fieldCode(t, field) == DoubleField - or fieldCode(t, field) == LongField)) - { - acquire(t, field); - } else { - storeStoreMemoryBarrier(); - } - } + { ACQUIRE_FIELD_FOR_WRITE(t, field); - switch (fieldCode(t, field)) { - case ByteField: - case BooleanField: - case CharField: - case ShortField: - case FloatField: - case IntField: { - int32_t value = popInt(t); - object o = popObject(t); - if (LIKELY(o)) { - switch (fieldCode(t, field)) { - case ByteField: - case BooleanField: - cast(o, fieldOffset(t, field)) = value; - break; + switch (fieldCode(t, field)) { + case ByteField: + case BooleanField: + case CharField: + case ShortField: + case FloatField: + case IntField: { + int32_t value = popInt(t); + object o = popObject(t); + if (LIKELY(o)) { + switch (fieldCode(t, field)) { + case ByteField: + case BooleanField: + cast(o, fieldOffset(t, field)) = value; + break; - case CharField: - case ShortField: - cast(o, fieldOffset(t, field)) = value; - break; + case CharField: + case ShortField: + cast(o, fieldOffset(t, field)) = value; + break; - case FloatField: - case IntField: - cast(o, fieldOffset(t, field)) = value; - break; + case FloatField: + case IntField: + cast(o, fieldOffset(t, field)) = value; + break; + } + } else { + exception = makeThrowable(t, Machine::NullPointerExceptionType); } - } else { - exception = makeThrowable(t, Machine::NullPointerExceptionType); - } - } break; + } break; - case DoubleField: - case LongField: { - int64_t value = popLong(t); - object o = popObject(t); - if (LIKELY(o)) { - cast(o, fieldOffset(t, field)) = value; - } else { - exception = makeThrowable(t, Machine::NullPointerExceptionType); - } - } break; + case DoubleField: + case LongField: { + int64_t value = popLong(t); + object o = popObject(t); + if (LIKELY(o)) { + cast(o, fieldOffset(t, field)) = value; + } else { + exception = makeThrowable(t, Machine::NullPointerExceptionType); + } + } break; - case ObjectField: { - object value = popObject(t); - object o = popObject(t); - if (LIKELY(o)) { - set(t, o, fieldOffset(t, field), value); - } else { - exception = makeThrowable(t, Machine::NullPointerExceptionType); - } - } break; + case ObjectField: { + object value = popObject(t); + object o = popObject(t); + if (LIKELY(o)) { + set(t, o, fieldOffset(t, field), value); + } else { + exception = makeThrowable(t, Machine::NullPointerExceptionType); + } + } break; - default: abort(t); - } - - if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) { - if (BytesPerWord == 4 - and (fieldCode(t, field) == DoubleField - or fieldCode(t, field) == LongField)) - { - release(t, field); - } else { - storeLoadMemoryBarrier(); + default: abort(t); } } @@ -2551,16 +2499,7 @@ interpret3(Thread* t, const int base) PROTECT(t, field); - if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) { - if (BytesPerWord == 4 - and (fieldCode(t, field) == DoubleField - or fieldCode(t, field) == LongField)) - { - acquire(t, field); - } else { - storeStoreMemoryBarrier(); - } - } + ACQUIRE_FIELD_FOR_WRITE(t, field); if (UNLIKELY(classInit(t, fieldClass(t, field), 3))) goto invoke; @@ -2603,17 +2542,6 @@ interpret3(Thread* t, const int base) default: abort(t); } - - if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) { - if (BytesPerWord == 4 - and (fieldCode(t, field) == DoubleField - or fieldCode(t, field) == LongField)) - { - release(t, field); - } else { - storeLoadMemoryBarrier(); - } - } } goto loop; case ret: { diff --git a/src/machine.cpp b/src/machine.cpp index 7c1863c8f3..e1bf8aadec 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1075,6 +1075,7 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool) code, flags, 0, // offset + i, singletonObject(t, pool, name - 1), singletonObject(t, pool, spec - 1), addendum, @@ -1270,20 +1271,6 @@ parseCode(Thread* t, Stream& s, object pool) return code; } -void -scanMethodSpec(Thread* t, const char* s, unsigned* parameterCount, - unsigned* returnCode) -{ - unsigned count = 0; - MethodSpecIterator it(t, s); - for (; it.hasNext(); it.next()) { - ++ count; - } - - *parameterCount = count; - *returnCode = fieldCode(t, *it.returnSpec()); -} - object addInterfaceMethods(Thread* t, object class_, object virtualMap, unsigned* virtualCount, bool makeList) @@ -2225,6 +2212,17 @@ doCollect(Thread* t, Heap::CollectionType type) } } +uint64_t +invokeLoadClass(Thread* t, uintptr_t* arguments) +{ + object method = reinterpret_cast(arguments[0]); + object loader = reinterpret_cast(arguments[1]); + object specString = reinterpret_cast(arguments[2]); + + return reinterpret_cast + (t->m->processor->invoke(t, method, loader, specString)); +} + } // namespace namespace vm { @@ -3342,8 +3340,6 @@ resolveClass(Thread* t, object loader, object spec, bool throw_) if (objectClass(t, loader) == type(t, Machine::SystemClassLoaderType)) { return resolveSystemClass(t, loader, spec, throw_); } else { - expect(t, throw_); - PROTECT(t, loader); PROTECT(t, spec); @@ -3384,9 +3380,23 @@ resolveClass(Thread* t, object loader, object spec, bool throw_) object specString = makeString(t, "%s", RUNTIME_ARRAY_BODY(s)); - object jc = t->m->processor->invoke(t, method, loader, specString); + uintptr_t arguments[] = { reinterpret_cast(method), + reinterpret_cast(loader), + reinterpret_cast(specString) }; + + object jc = reinterpret_cast + (runRaw(t, invokeLoadClass, arguments)); + if (LIKELY(jc)) { c = jclassVmClass(t, jc); + } else if (t->exception) { + if (throw_) { + object e = t->exception; + t->exception = 0; + vm::throw_(t, e); + } else { + t->exception = 0; + } } } @@ -3402,12 +3412,12 @@ resolveClass(Thread* t, object loader, object spec, bool throw_) hashMapInsert (t, classLoaderMap(t, loader), spec, c, byteArrayHash); - - return c; - } else { + } else if (throw_) { throwNew(t, Machine::ClassNotFoundExceptionType, "%s", &byteArrayBody(t, spec, 0)); } + + return c; } } diff --git a/src/machine.h b/src/machine.h index b784d6072a..11c9b7ce11 100644 --- a/src/machine.h +++ b/src/machine.h @@ -33,6 +33,12 @@ #define ACQUIRE_OBJECT(t, x) \ ObjectMonitorResource MAKE_NAME(monitorResource_) (t, x) +#define ACQUIRE_FIELD_FOR_READ(t, field) \ + FieldReadResource MAKE_NAME(monitorResource_) (t, field) + +#define ACQUIRE_FIELD_FOR_WRITE(t, field) \ + FieldReadResource MAKE_NAME(monitorResource_) (t, field) + #define ACQUIRE_RAW(t, x) RawMonitorResource MAKE_NAME(monitorResource_) (t, x) #define ENTER(t, state) StateResource MAKE_NAME(stateResource_) (t, state) @@ -2430,6 +2436,20 @@ fieldSize(Thread* t, object field) return fieldSize(t, fieldCode(t, field)); } +inline void +scanMethodSpec(Thread* t, const char* s, unsigned* parameterCount, + unsigned* returnCode) +{ + unsigned count = 0; + MethodSpecIterator it(t, s); + for (; it.hasNext(); it.next()) { + ++ count; + } + + *parameterCount = count; + *returnCode = fieldCode(t, *it.returnSpec()); +} + object findLoadedClass(Thread* t, object loader, object spec); @@ -2639,11 +2659,11 @@ findInHierarchyOrNull(Thread* t, object class_, object name, object spec, inline object findInHierarchy(Thread* t, object class_, object name, object spec, object (*find)(Thread*, object, object, object), - Machine::Type errorType) + Machine::Type errorType, bool throw_ = true) { object o = findInHierarchyOrNull(t, class_, name, spec, find); - if (o == 0) { + if (throw_ and o == 0) { throwNew(t, errorType, "%s %s not found in %s", &byteArrayBody(t, name, 0), &byteArrayBody(t, spec, 0), @@ -3332,93 +3352,208 @@ poolSize(Thread* t, object pool) inline object resolveClassInObject(Thread* t, object loader, object container, - unsigned classOffset) + unsigned classOffset, bool throw_ = true) { object o = cast(container, classOffset); + + loadMemoryBarrier(); + if (objectClass(t, o) == type(t, Machine::ByteArrayType)) { PROTECT(t, container); - o = resolveClass(t, loader, o); + o = resolveClass(t, loader, o, throw_); - set(t, container, classOffset, o); + if (o) { + storeStoreMemoryBarrier(); + + set(t, container, classOffset, o); + } } return o; } inline object -resolveClassInPool(Thread* t, object loader, object method, unsigned index) +resolveClassInPool(Thread* t, object loader, object method, unsigned index, + bool throw_ = true) { object o = singletonObject(t, codePool(t, methodCode(t, method)), index); + + loadMemoryBarrier(); + if (objectClass(t, o) == type(t, Machine::ReferenceType)) { PROTECT(t, method); - o = resolveClass(t, loader, referenceName(t, o)); + o = resolveClass(t, loader, referenceName(t, o), throw_); - set(t, codePool(t, methodCode(t, method)), - SingletonBody + (index * BytesPerWord), o); + if (o) { + storeStoreMemoryBarrier(); + + set(t, codePool(t, methodCode(t, method)), + SingletonBody + (index * BytesPerWord), o); + } } return o; } inline object -resolveClassInPool(Thread* t, object method, unsigned index) +resolveClassInPool(Thread* t, object method, unsigned index, + bool throw_ = true) { return resolveClassInPool(t, classLoader(t, methodClass(t, method)), - method, index); + method, index, throw_); } inline object resolve(Thread* t, object loader, object method, unsigned index, object (*find)(vm::Thread*, object, object, object), - Machine::Type errorType) + Machine::Type errorType, bool throw_ = true) { object o = singletonObject(t, codePool(t, methodCode(t, method)), index); - if (objectClass(t, o) == type(t, Machine::ReferenceType)) - { + + loadMemoryBarrier(); + + if (objectClass(t, o) == type(t, Machine::ReferenceType)) { PROTECT(t, method); object reference = o; PROTECT(t, reference); - object class_ = resolveClassInObject(t, loader, o, ReferenceClass); + object class_ = resolveClassInObject(t, loader, o, ReferenceClass, throw_); - o = findInHierarchy - (t, class_, referenceName(t, reference), referenceSpec(t, reference), - find, errorType); + if (class_) { + o = findInHierarchy + (t, class_, referenceName(t, reference), referenceSpec(t, reference), + find, errorType, throw_); - set(t, codePool(t, methodCode(t, method)), - SingletonBody + (index * BytesPerWord), o); + if (o) { + storeStoreMemoryBarrier(); + + set(t, codePool(t, methodCode(t, method)), + SingletonBody + (index * BytesPerWord), o); + } + } else { + o = 0; + } } return o; } inline object -resolveField(Thread* t, object loader, object method, unsigned index) +resolveField(Thread* t, object loader, object method, unsigned index, + bool throw_ = true) { return resolve(t, loader, method, index, findFieldInClass, - Machine::NoSuchFieldErrorType); + Machine::NoSuchFieldErrorType, throw_); } inline object -resolveField(Thread* t, object method, unsigned index) +resolveField(Thread* t, object method, unsigned index, bool throw_ = true) { return resolveField - (t, classLoader(t, methodClass(t, method)), method, index); + (t, classLoader(t, methodClass(t, method)), method, index, throw_); } +inline void +acquireFieldForRead(Thread* t, object field) +{ + if (UNLIKELY((fieldFlags(t, field) & ACC_VOLATILE) + and BytesPerWord == 4 + and (fieldCode(t, field) == DoubleField + or fieldCode(t, field) == LongField))) + { + acquire(t, field); + } +} + +inline void +releaseFieldForRead(Thread* t, object field) +{ + if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) { + if (BytesPerWord == 4 + and (fieldCode(t, field) == DoubleField + or fieldCode(t, field) == LongField)) + { + release(t, field); + } else { + loadMemoryBarrier(); + } + } +} + +class FieldReadResource { + public: + FieldReadResource(Thread* t, object o): o(o), protector(t, &(this->o)) { + acquireFieldForRead(protector.t, o); + } + + ~FieldReadResource() { + releaseFieldForRead(protector.t, o); + } + + private: + object o; + Thread::SingleProtector protector; +}; + +inline void +acquireFieldForWrite(Thread* t, object field) +{ + if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) { + if (BytesPerWord == 4 + and (fieldCode(t, field) == DoubleField + or fieldCode(t, field) == LongField)) + { + acquire(t, field); + } else { + storeStoreMemoryBarrier(); + } + } +} + +inline void +releaseFieldForWrite(Thread* t, object field) +{ + if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) { + if (BytesPerWord == 4 + and (fieldCode(t, field) == DoubleField + or fieldCode(t, field) == LongField)) + { + release(t, field); + } else { + storeLoadMemoryBarrier(); + } + } +} + +class FieldWriteResource { + public: + FieldWriteResource(Thread* t, object o): o(o), protector(t, &(this->o)) { + acquireFieldForWrite(protector.t, o); + } + + ~FieldWriteResource() { + releaseFieldForWrite(protector.t, o); + } + + private: + object o; + Thread::SingleProtector protector; +}; + inline object -resolveMethod(Thread* t, object loader, object method, unsigned index) +resolveMethod(Thread* t, object loader, object method, unsigned index, + bool throw_ = true) { return resolve(t, loader, method, index, findMethodInClass, - Machine::NoSuchMethodErrorType); + Machine::NoSuchMethodErrorType, throw_); } inline object -resolveMethod(Thread* t, object method, unsigned index) +resolveMethod(Thread* t, object method, unsigned index, bool throw_ = true) { return resolveMethod - (t, classLoader(t, methodClass(t, method)), method, index); + (t, classLoader(t, methodClass(t, method)), method, index, throw_); } object diff --git a/src/thunks.cpp b/src/thunks.cpp index 4d863ecca4..dce0885c96 100644 --- a/src/thunks.cpp +++ b/src/thunks.cpp @@ -1,5 +1,9 @@ THUNK(tryInitClass) THUNK(findInterfaceMethodFromInstance) +THUNK(findInterfaceMethodFromInstanceAndReference) +THUNK(findSpecialMethodFromReference) +THUNK(findStaticMethodFromReference) +THUNK(findVirtualMethodFromReference) THUNK(compareDoublesG) THUNK(compareDoublesL) THUNK(compareFloatsG) @@ -36,17 +40,31 @@ THUNK(intToFloat) THUNK(longToDouble) THUNK(longToFloat) THUNK(makeBlankObjectArray) +THUNK(makeBlankObjectArrayFromReference) THUNK(makeBlankArray) THUNK(lookUpAddress) THUNK(setMaybeNull) THUNK(acquireMonitorForObject) THUNK(releaseMonitorForObject) THUNK(makeMultidimensionalArray) +THUNK(makeMultidimensionalArrayFromReference) THUNK(throw_) THUNK(checkCast) +THUNK(checkCastFromReference) +THUNK(getStaticFieldValueFromReference) +THUNK(getFieldValueFromReference) +THUNK(setStaticFieldValueFromReference) +THUNK(setFieldValueFromReference) +THUNK(setStaticLongFieldValueFromReference) +THUNK(setLongFieldValueFromReference) +THUNK(setStaticObjectFieldValueFromReference) +THUNK(setObjectFieldValueFromReference) THUNK(instanceOf64) +THUNK(instanceOfFromReference) THUNK(makeNewGeneral64) THUNK(makeNew64) +THUNK(makeNewFromReference) THUNK(set) THUNK(getJClass64) +THUNK(getJClassFromReference) THUNK(gcIfNecessary) diff --git a/src/vector.h b/src/vector.h index b5aa9365b9..c952763dba 100644 --- a/src/vector.h +++ b/src/vector.h @@ -33,6 +33,7 @@ class Vector { void dispose() { if (data and minimumCapacity >= 0) { allocator->free(data, capacity); + data = 0; } } diff --git a/src/zone.h b/src/zone.h index fc412f3634..b73c0a8913 100644 --- a/src/zone.h +++ b/src/zone.h @@ -45,6 +45,8 @@ class Zone: public Allocator { next = seg->next; allocator->free(seg, sizeof(Segment) + seg->size); } + + segment = 0; } bool ensure(unsigned space) { diff --git a/test/LazyLoading.java b/test/LazyLoading.java new file mode 100644 index 0000000000..83dd4bc82c --- /dev/null +++ b/test/LazyLoading.java @@ -0,0 +1,184 @@ +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; + +public class LazyLoading { + private static boolean loadLazy; + + private static void expect(boolean v) { + if (! v) throw new RuntimeException(); + } + + private static File findClass(String name, File directory) { + for (File file: directory.listFiles()) { + if (file.isFile()) { + if (file.getName().equals(name + ".class")) { + return file; + } + } else if (file.isDirectory()) { + File result = findClass(name, file); + if (result != null) { + return result; + } + } + } + return null; + } + + private static byte[] read(File file) throws IOException { + byte[] bytes = new byte[(int) file.length()]; + FileInputStream in = new FileInputStream(file); + try { + if (in.read(bytes) != (int) file.length()) { + throw new RuntimeException(); + } + return bytes; + } finally { + in.close(); + } + } + + public static void main(String[] args) throws Exception { + Class c = new MyClassLoader(LazyLoading.class.getClassLoader()).loadClass + ("LazyLoading$Test"); + + c.getMethod("test").invoke(null); + } + + private static class MyClassLoader extends ClassLoader { + public MyClassLoader(ClassLoader parent) { + super(parent); + } + + protected Class findClass(String name) throws ClassNotFoundException { + try { + return defineClass + (name, read + (LazyLoading.findClass + (name, new File(System.getProperty("user.dir"))))); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public Class loadClass(String name) throws ClassNotFoundException { + if ("LazyLoading$Test".equals(name)) { + return findClass(name); + } else if ("LazyLoading$Lazy".equals(name) + || "LazyLoading$Interface".equals(name)) + { + if (loadLazy) { + return findClass(name); + } else { + throw new ClassNotFoundException(); + } + } else { + return super.loadClass(name); + } + } + + private Class defineClass(String name, byte[] bytes) { + return defineClass(name, bytes, 0, bytes.length); + } + } + + private static class Test { + public static void test() { + doTest(); + loadLazy = true; + doTest(); + } + + private static void doTest() { + if (loadLazy) { + // anewarray + Lazy[] array = new Lazy[1]; + + // new and invokespecial + Object lazy = new Lazy(); + + // checkcast + array[0] = (Lazy) lazy; + + // instanceof + expect(lazy instanceof Lazy); + + // invokeinterface + Interface i = array[0]; + expect(i.interfaceMethod() == 42); + + // invokestatic + expect(Lazy.staticMethod() == 43); + + // invokevirtual + expect(array[0].virtualMethod() == 44); + + // ldc + expect(Lazy.class == lazy.getClass()); + + // multianewarray + Lazy[][] multiarray = new Lazy[5][6]; + multiarray[2][3] = array[0]; + expect(multiarray[2][3] == array[0]); + + // getfield + expect(array[0].intField == 45); + + // getstatic + expect(Lazy.intStaticField == 46); + + // putfield int + array[0].intField = 47; + expect(array[0].intField == 47); + + // putfield long + array[0].longField = 48; + expect(array[0].longField == 48); + + // putfield object + Object x = new Object(); + array[0].objectField = x; + expect(array[0].objectField == x); + + // putstatic int + array[0].intStaticField = 49; + expect(array[0].intStaticField == 49); + + // putstatic long + array[0].longStaticField = 50; + expect(array[0].longStaticField == 50); + + // putstatic object + Object y = new Object(); + array[0].objectStaticField = y; + expect(array[0].objectStaticField == y); + } + } + } + + private interface Interface { + public int interfaceMethod(); + } + + private static class Lazy implements Interface { + public static int intStaticField = 46; + public static long longStaticField; + public static Object objectStaticField; + + public int intField = 45; + public long longField; + public Object objectField; + + public int interfaceMethod() { + return 42; + } + + public static int staticMethod() { + return 43; + } + + public int virtualMethod() { + return 44; + } + } +} From 7152c3fdb325885e71db62ead73355e6ac8035b0 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 15 Mar 2011 19:34:00 -0600 Subject: [PATCH 022/117] handle volatile fields properly in JNI Get/Set methods This commit ensures that we use the proper memory barriers or locking necessary to preserve volatile semantics for such fields when accessed or updated via JNI. --- classpath/avian/VMField.java | 2 +- src/jnienv.cpp | 818 ++++++++++++++++++++++++++++++----- src/machine.cpp | 3 +- src/machine.h | 1 + 4 files changed, 714 insertions(+), 110 deletions(-) diff --git a/classpath/avian/VMField.java b/classpath/avian/VMField.java index 70752ac943..8df0d426c5 100644 --- a/classpath/avian/VMField.java +++ b/classpath/avian/VMField.java @@ -15,7 +15,7 @@ public class VMField { public byte code; public short flags; public short offset; - public short index; + public int nativeID; public byte[] name; public byte[] spec; public FieldAddendum addendum; diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 3d17a22949..9ed2ce4815 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -20,12 +20,6 @@ namespace { namespace local { -const uintptr_t InterfaceMethodID -= (static_cast(1) << (BitsPerWord - 1)); - -const uintptr_t NonVirtualMethodID -= (static_cast(1) << (BitsPerWord - 2)); - jint JNICALL AttachCurrentThread(Machine* m, Thread** t, void*) { @@ -559,9 +553,11 @@ GetStaticMethodID(Thread* t, jclass c, const char* name, const char* spec) return run(t, getStaticMethodID, arguments); } -inline object +object getMethod(Thread* t, jmethodID m) { + assert(t, m); + object method = vectorBody(t, root(t, Machine::JNIMethodTable), m - 1); assert(t, (methodFlags(t, method) & ACC_STATIC) == 0); @@ -883,9 +879,11 @@ CallVoidMethod(Thread* t, jobject o, jmethodID m, ...) va_end(a); } -inline object +object getStaticMethod(Thread* t, jmethodID m) { + assert(t, m); + object method = vectorBody(t, root(t, Machine::JNIMethodTable), m - 1); assert(t, methodFlags(t, method) & ACC_STATIC); @@ -1143,6 +1141,24 @@ CallStaticVoidMethod(Thread* t, jclass c, jmethodID m, ...) va_end(a); } +jint +fieldID(Thread* t, object field) +{ + if (fieldNativeID(t, field) == 0) { + PROTECT(t, field); + + ACQUIRE(t, t->m->referenceLock); + + if (fieldNativeID(t, field) == 0) { + setRoot(t, Machine::JNIFieldTable, vectorAppend + (t, root(t, Machine::JNIFieldTable), field)); + fieldNativeID(t, field) = vectorSize(t, root(t, Machine::JNIFieldTable)); + } + } + + return fieldNativeID(t, field); +} + uint64_t getFieldID(Thread* t, uintptr_t* arguments) { @@ -1150,7 +1166,7 @@ getFieldID(Thread* t, uintptr_t* arguments) const char* name = reinterpret_cast(arguments[1]); const char* spec = reinterpret_cast(arguments[2]); - return fieldOffset(t, resolveField(t, jclassVmClass(t, *c), name, spec)); + return fieldID(t, resolveField(t, jclassVmClass(t, *c), name, spec)); } jfieldID JNICALL @@ -1173,293 +1189,881 @@ GetStaticFieldID(Thread* t, jclass c, const char* name, const char* spec) return run(t, getFieldID, arguments); } +object +getField(Thread* t, jfieldID f) +{ + assert(t, f); + + object field = vectorBody(t, root(t, Machine::JNIFieldTable), f - 1); + + assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0); + + return field; +} + +uint64_t +getObjectField(Thread* t, uintptr_t* arguments) +{ + jobject o = reinterpret_cast(arguments[0]); + object field = getField(t, arguments[1]); + + PROTECT(t, field); + ACQUIRE_FIELD_FOR_READ(t, field); + + return reinterpret_cast + (makeLocalReference(t, cast(*o, fieldOffset(t, field)))); +} + jobject JNICALL GetObjectField(Thread* t, jobject o, jfieldID field) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o), + field }; - return makeLocalReference(t, cast(*o, field)); + return reinterpret_cast(run(t, getObjectField, arguments)); +} + +uint64_t +getBooleanField(Thread* t, uintptr_t* arguments) +{ + jobject o = reinterpret_cast(arguments[0]); + object field = getField(t, arguments[1]); + + PROTECT(t, field); + ACQUIRE_FIELD_FOR_READ(t, field); + + return cast(*o, fieldOffset(t, field)); } jboolean JNICALL GetBooleanField(Thread* t, jobject o, jfieldID field) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o), + field }; - return cast(*o, field); + return run(t, getBooleanField, arguments); +} + +uint64_t +getByteField(Thread* t, uintptr_t* arguments) +{ + jobject o = reinterpret_cast(arguments[0]); + object field = getField(t, arguments[1]); + + PROTECT(t, field); + ACQUIRE_FIELD_FOR_READ(t, field); + + return cast(*o, fieldOffset(t, field)); } jbyte JNICALL GetByteField(Thread* t, jobject o, jfieldID field) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o), + field }; - return cast(*o, field); + return run(t, getByteField, arguments); +} + +uint64_t +getCharField(Thread* t, uintptr_t* arguments) +{ + jobject o = reinterpret_cast(arguments[0]); + object field = getField(t, arguments[1]); + + PROTECT(t, field); + ACQUIRE_FIELD_FOR_READ(t, field); + + return cast(*o, fieldOffset(t, field)); } jchar JNICALL GetCharField(Thread* t, jobject o, jfieldID field) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o), + field }; - return cast(*o, field); + return run(t, getCharField, arguments); +} + +uint64_t +getShortField(Thread* t, uintptr_t* arguments) +{ + jobject o = reinterpret_cast(arguments[0]); + object field = getField(t, arguments[1]); + + PROTECT(t, field); + ACQUIRE_FIELD_FOR_READ(t, field); + + return cast(*o, fieldOffset(t, field)); } jshort JNICALL GetShortField(Thread* t, jobject o, jfieldID field) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o), + field }; - return cast(*o, field); + return run(t, getShortField, arguments); +} + +uint64_t +getIntField(Thread* t, uintptr_t* arguments) +{ + jobject o = reinterpret_cast(arguments[0]); + object field = getField(t, arguments[1]); + + PROTECT(t, field); + ACQUIRE_FIELD_FOR_READ(t, field); + + return cast(*o, fieldOffset(t, field)); } jint JNICALL GetIntField(Thread* t, jobject o, jfieldID field) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o), + field }; - return cast(*o, field); + return run(t, getIntField, arguments); +} + +uint64_t +getLongField(Thread* t, uintptr_t* arguments) +{ + jobject o = reinterpret_cast(arguments[0]); + object field = getField(t, arguments[1]); + + PROTECT(t, field); + ACQUIRE_FIELD_FOR_READ(t, field); + + return cast(*o, fieldOffset(t, field)); } jlong JNICALL GetLongField(Thread* t, jobject o, jfieldID field) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o), + field }; - return cast(*o, field); + return run(t, getLongField, arguments); +} + +uint64_t +getFloatField(Thread* t, uintptr_t* arguments) +{ + jobject o = reinterpret_cast(arguments[0]); + object field = getField(t, arguments[1]); + + PROTECT(t, field); + ACQUIRE_FIELD_FOR_READ(t, field); + + return floatToBits(cast(*o, fieldOffset(t, field))); } jfloat JNICALL GetFloatField(Thread* t, jobject o, jfieldID field) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o), + field }; - return cast(*o, field); + return bitsToFloat(run(t, getFloatField, arguments)); +} + +uint64_t +getDoubleField(Thread* t, uintptr_t* arguments) +{ + jobject o = reinterpret_cast(arguments[0]); + object field = getField(t, arguments[1]); + + PROTECT(t, field); + ACQUIRE_FIELD_FOR_READ(t, field); + + return doubleToBits(cast(*o, fieldOffset(t, field))); } jdouble JNICALL GetDoubleField(Thread* t, jobject o, jfieldID field) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o), + field }; - return cast(*o, field); + return bitsToDouble(run(t, getDoubleField, arguments)); +} + +uint64_t +setObjectField(Thread* t, uintptr_t* arguments) +{ + jobject o = reinterpret_cast(arguments[0]); + object field = getField(t, arguments[1]); + jobject v = reinterpret_cast(arguments[2]); + + PROTECT(t, field); + ACQUIRE_FIELD_FOR_WRITE(t, field); + + set(t, *o, fieldOffset(t, field), (v ? *v : 0)); + + return 1; } void JNICALL SetObjectField(Thread* t, jobject o, jfieldID field, jobject v) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o), + field, + reinterpret_cast(v) }; - set(t, *o, field, (v ? *v : 0)); + run(t, setObjectField, arguments); +} + +uint64_t +setBooleanField(Thread* t, uintptr_t* arguments) +{ + jobject o = reinterpret_cast(arguments[0]); + object field = getField(t, arguments[1]); + jboolean v = arguments[2]; + + PROTECT(t, field); + ACQUIRE_FIELD_FOR_WRITE(t, field); + + cast(*o, fieldOffset(t, field)) = v; + + return 1; } void JNICALL SetBooleanField(Thread* t, jobject o, jfieldID field, jboolean v) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o), + field, + v }; - cast(*o, field) = v; + run(t, setBooleanField, arguments); +} + +uint64_t +setByteField(Thread* t, uintptr_t* arguments) +{ + jobject o = reinterpret_cast(arguments[0]); + object field = getField(t, arguments[1]); + jbyte v = arguments[2]; + + PROTECT(t, field); + ACQUIRE_FIELD_FOR_WRITE(t, field); + + cast(*o, fieldOffset(t, field)) = v; + + return 1; } void JNICALL SetByteField(Thread* t, jobject o, jfieldID field, jbyte v) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o), + field, + v }; - cast(*o, field) = v; + run(t, setByteField, arguments); +} + +uint64_t +setCharField(Thread* t, uintptr_t* arguments) +{ + jobject o = reinterpret_cast(arguments[0]); + object field = getField(t, arguments[1]); + jchar v = arguments[2]; + + PROTECT(t, field); + ACQUIRE_FIELD_FOR_WRITE(t, field); + + cast(*o, fieldOffset(t, field)) = v; + + return 1; } void JNICALL SetCharField(Thread* t, jobject o, jfieldID field, jchar v) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o), + field, + v }; - cast(*o, field) = v; + run(t, setCharField, arguments); +} + +uint64_t +setShortField(Thread* t, uintptr_t* arguments) +{ + jobject o = reinterpret_cast(arguments[0]); + object field = getField(t, arguments[1]); + jshort v = arguments[2]; + + PROTECT(t, field); + ACQUIRE_FIELD_FOR_WRITE(t, field); + + cast(*o, fieldOffset(t, field)) = v; + + return 1; } void JNICALL SetShortField(Thread* t, jobject o, jfieldID field, jshort v) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o), + field, + v }; - cast(*o, field) = v; + run(t, setShortField, arguments); +} + +uint64_t +setIntField(Thread* t, uintptr_t* arguments) +{ + jobject o = reinterpret_cast(arguments[0]); + object field = getField(t, arguments[1]); + jint v = arguments[2]; + + PROTECT(t, field); + ACQUIRE_FIELD_FOR_WRITE(t, field); + + cast(*o, fieldOffset(t, field)) = v; + + return 1; } void JNICALL SetIntField(Thread* t, jobject o, jfieldID field, jint v) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o), + field, + v }; - cast(*o, field) = v; + run(t, setIntField, arguments); +} + +uint64_t +setLongField(Thread* t, uintptr_t* arguments) +{ + jobject o = reinterpret_cast(arguments[0]); + object field = getField(t, arguments[1]); + jlong v; memcpy(&v, arguments + 2, sizeof(jlong)); + + PROTECT(t, field); + ACQUIRE_FIELD_FOR_WRITE(t, field); + + cast(*o, fieldOffset(t, field)) = v; + + return 1; } void JNICALL SetLongField(Thread* t, jobject o, jfieldID field, jlong v) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[2 + (sizeof(jlong) / BytesPerWord)]; + arguments[0] = reinterpret_cast(o); + arguments[1] = field; + memcpy(arguments + 2, &v, sizeof(jlong)); - cast(*o, field) = v; + run(t, setLongField, arguments); +} + +uint64_t +setFloatField(Thread* t, uintptr_t* arguments) +{ + jobject o = reinterpret_cast(arguments[0]); + object field = getField(t, arguments[1]); + jfloat v = bitsToFloat(arguments[2]); + + PROTECT(t, field); + ACQUIRE_FIELD_FOR_WRITE(t, field); + + cast(*o, fieldOffset(t, field)) = v; + + return 1; } void JNICALL SetFloatField(Thread* t, jobject o, jfieldID field, jfloat v) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o), + field, + floatToBits(v) }; - cast(*o, field) = v; + run(t, setFloatField, arguments); +} + +uint64_t +setDoubleField(Thread* t, uintptr_t* arguments) +{ + jobject o = reinterpret_cast(arguments[0]); + object field = getField(t, arguments[1]); + jdouble v = bitsToDouble(arguments[2]); + + PROTECT(t, field); + ACQUIRE_FIELD_FOR_WRITE(t, field); + + cast(*o, fieldOffset(t, field)) = v; + + return 1; } void JNICALL SetDoubleField(Thread* t, jobject o, jfieldID field, jdouble v) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o), + field, + doubleToBits(v) }; - cast(*o, field) = v; + run(t, setDoubleField, arguments); +} + +object +getStaticField(Thread* t, jfieldID f) +{ + assert(t, f); + + object field = vectorBody(t, root(t, Machine::JNIFieldTable), f - 1); + + assert(t, fieldFlags(t, field) & ACC_STATIC); + + return field; +} + +uint64_t +getStaticObjectField(Thread* t, uintptr_t* arguments) +{ + jobject c = reinterpret_cast(arguments[0]); + object field = getStaticField(t, arguments[1]); + + PROTECT(t, field); + ACQUIRE_FIELD_FOR_READ(t, field); + + return reinterpret_cast + (makeLocalReference + (t, cast + (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)))); } jobject JNICALL -GetStaticObjectField(Thread* t, jclass c, jfieldID field) +GetStaticObjectField(Thread* t, jobject c, jfieldID field) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(c), + field }; - return makeLocalReference - (t, cast(classStaticTable(t, jclassVmClass(t, *c)), field)); + return reinterpret_cast(run(t, getStaticObjectField, arguments)); +} + +uint64_t +getStaticBooleanField(Thread* t, uintptr_t* arguments) +{ + jobject c = reinterpret_cast(arguments[0]); + object field = getStaticField(t, arguments[1]); + + PROTECT(t, field); + ACQUIRE_FIELD_FOR_READ(t, field); + + return cast + (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)); } jboolean JNICALL -GetStaticBooleanField(Thread* t, jclass c, jfieldID field) +GetStaticBooleanField(Thread* t, jobject c, jfieldID field) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(c), + field }; - return cast(classStaticTable(t, jclassVmClass(t, *c)), field); + return run(t, getStaticBooleanField, arguments); +} + +uint64_t +getStaticByteField(Thread* t, uintptr_t* arguments) +{ + jobject c = reinterpret_cast(arguments[0]); + object field = getStaticField(t, arguments[1]); + + PROTECT(t, field); + ACQUIRE_FIELD_FOR_READ(t, field); + + return cast + (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)); } jbyte JNICALL -GetStaticByteField(Thread* t, jclass c, jfieldID field) +GetStaticByteField(Thread* t, jobject c, jfieldID field) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(c), + field }; - return cast(classStaticTable(t, jclassVmClass(t, *c)), field); + return run(t, getStaticByteField, arguments); +} + +uint64_t +getStaticCharField(Thread* t, uintptr_t* arguments) +{ + jobject c = reinterpret_cast(arguments[0]); + object field = getStaticField(t, arguments[1]); + + PROTECT(t, field); + ACQUIRE_FIELD_FOR_READ(t, field); + + return cast + (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)); } jchar JNICALL -GetStaticCharField(Thread* t, jclass c, jfieldID field) +GetStaticCharField(Thread* t, jobject c, jfieldID field) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(c), + field }; - return cast(classStaticTable(t, jclassVmClass(t, *c)), field); + return run(t, getStaticCharField, arguments); +} + +uint64_t +getStaticShortField(Thread* t, uintptr_t* arguments) +{ + jobject c = reinterpret_cast(arguments[0]); + object field = getStaticField(t, arguments[1]); + + PROTECT(t, field); + ACQUIRE_FIELD_FOR_READ(t, field); + + return cast + (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)); } jshort JNICALL -GetStaticShortField(Thread* t, jclass c, jfieldID field) +GetStaticShortField(Thread* t, jobject c, jfieldID field) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(c), + field }; - return cast(classStaticTable(t, jclassVmClass(t, *c)), field); + return run(t, getStaticShortField, arguments); +} + +uint64_t +getStaticIntField(Thread* t, uintptr_t* arguments) +{ + jobject c = reinterpret_cast(arguments[0]); + object field = getStaticField(t, arguments[1]); + + PROTECT(t, field); + ACQUIRE_FIELD_FOR_READ(t, field); + + return cast + (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)); } jint JNICALL -GetStaticIntField(Thread* t, jclass c, jfieldID field) +GetStaticIntField(Thread* t, jobject c, jfieldID field) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(c), + field }; - return cast(classStaticTable(t, jclassVmClass(t, *c)), field); + return run(t, getStaticIntField, arguments); +} + +uint64_t +getStaticLongField(Thread* t, uintptr_t* arguments) +{ + jobject c = reinterpret_cast(arguments[0]); + object field = getStaticField(t, arguments[1]); + + PROTECT(t, field); + ACQUIRE_FIELD_FOR_READ(t, field); + + return cast + (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)); } jlong JNICALL -GetStaticLongField(Thread* t, jclass c, jfieldID field) +GetStaticLongField(Thread* t, jobject c, jfieldID field) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(c), + field }; - return cast(classStaticTable(t, jclassVmClass(t, *c)), field); + return run(t, getStaticLongField, arguments); +} + +uint64_t +getStaticFloatField(Thread* t, uintptr_t* arguments) +{ + jobject c = reinterpret_cast(arguments[0]); + object field = getStaticField(t, arguments[1]); + + PROTECT(t, field); + ACQUIRE_FIELD_FOR_READ(t, field); + + return floatToBits + (cast + (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field))); } jfloat JNICALL -GetStaticFloatField(Thread* t, jclass c, jfieldID field) +GetStaticFloatField(Thread* t, jobject c, jfieldID field) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(c), + field }; - return cast(classStaticTable(t, jclassVmClass(t, *c)), field); + return bitsToFloat(run(t, getStaticFloatField, arguments)); +} + +uint64_t +getStaticDoubleField(Thread* t, uintptr_t* arguments) +{ + jobject c = reinterpret_cast(arguments[0]); + object field = getStaticField(t, arguments[1]); + + PROTECT(t, field); + ACQUIRE_FIELD_FOR_READ(t, field); + + return doubleToBits + (cast + (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field))); } jdouble JNICALL -GetStaticDoubleField(Thread* t, jclass c, jfieldID field) +GetStaticDoubleField(Thread* t, jobject c, jfieldID field) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(c), + field }; - return cast(classStaticTable(t, jclassVmClass(t, *c)), field); + return bitsToDouble(run(t, getStaticDoubleField, arguments)); } -void JNICALL -SetStaticObjectField(Thread* t, jclass c, jfieldID field, jobject v) +uint64_t +setStaticObjectField(Thread* t, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); - - set(t, classStaticTable(t, jclassVmClass(t, *c)), field, (v ? *v : 0)); -} - -void JNICALL -SetStaticBooleanField(Thread* t, jclass c, jfieldID field, jboolean v) -{ - ENTER(t, Thread::ActiveState); + jobject c = reinterpret_cast(arguments[0]); + object field = getStaticField(t, arguments[1]); + jobject v = reinterpret_cast(arguments[2]); - cast(classStaticTable(t, jclassVmClass(t, *c)), field) = v; + PROTECT(t, field); + ACQUIRE_FIELD_FOR_WRITE(t, field); + + set(t, classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field), + (v ? *v : 0)); + + return 1; } void JNICALL -SetStaticByteField(Thread* t, jclass c, jfieldID field, jbyte v) +SetStaticObjectField(Thread* t, jobject c, jfieldID field, jobject v) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(c), + field, + reinterpret_cast(v) }; - cast(classStaticTable(t, jclassVmClass(t, *c)), field) = v; + run(t, setStaticObjectField, arguments); +} + +uint64_t +setStaticBooleanField(Thread* t, uintptr_t* arguments) +{ + jobject c = reinterpret_cast(arguments[0]); + object field = getStaticField(t, arguments[1]); + jboolean v = arguments[2]; + + PROTECT(t, field); + ACQUIRE_FIELD_FOR_WRITE(t, field); + + cast + (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)) = v; + + return 1; } void JNICALL -SetStaticCharField(Thread* t, jclass c, jfieldID field, jchar v) +SetStaticBooleanField(Thread* t, jobject c, jfieldID field, jboolean v) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(c), + field, + v }; - cast(classStaticTable(t, jclassVmClass(t, *c)), field) = v; + run(t, setStaticBooleanField, arguments); +} + +uint64_t +setStaticByteField(Thread* t, uintptr_t* arguments) +{ + jobject c = reinterpret_cast(arguments[0]); + object field = getStaticField(t, arguments[1]); + jbyte v = arguments[2]; + + PROTECT(t, field); + ACQUIRE_FIELD_FOR_WRITE(t, field); + + cast + (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)) = v; + + return 1; } void JNICALL -SetStaticShortField(Thread* t, jclass c, jfieldID field, jshort v) +SetStaticByteField(Thread* t, jobject c, jfieldID field, jbyte v) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(c), + field, + v }; - cast(classStaticTable(t, jclassVmClass(t, *c)), field) = v; + run(t, setStaticByteField, arguments); +} + +uint64_t +setStaticCharField(Thread* t, uintptr_t* arguments) +{ + jobject c = reinterpret_cast(arguments[0]); + object field = getStaticField(t, arguments[1]); + jchar v = arguments[2]; + + PROTECT(t, field); + ACQUIRE_FIELD_FOR_WRITE(t, field); + + cast + (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)) = v; + + return 1; } void JNICALL -SetStaticIntField(Thread* t, jclass c, jfieldID field, jint v) +SetStaticCharField(Thread* t, jobject c, jfieldID field, jchar v) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(c), + field, + v }; - cast(classStaticTable(t, jclassVmClass(t, *c)), field) = v; + run(t, setStaticCharField, arguments); +} + +uint64_t +setStaticShortField(Thread* t, uintptr_t* arguments) +{ + jobject c = reinterpret_cast(arguments[0]); + object field = getStaticField(t, arguments[1]); + jshort v = arguments[2]; + + PROTECT(t, field); + ACQUIRE_FIELD_FOR_WRITE(t, field); + + cast + (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)) = v; + + return 1; } void JNICALL -SetStaticLongField(Thread* t, jclass c, jfieldID field, jlong v) +SetStaticShortField(Thread* t, jobject c, jfieldID field, jshort v) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(c), + field, + v }; - cast(classStaticTable(t, jclassVmClass(t, *c)), field) = v; + run(t, setStaticShortField, arguments); +} + +uint64_t +setStaticIntField(Thread* t, uintptr_t* arguments) +{ + jobject c = reinterpret_cast(arguments[0]); + object field = getStaticField(t, arguments[1]); + jint v = arguments[2]; + + PROTECT(t, field); + ACQUIRE_FIELD_FOR_WRITE(t, field); + + cast + (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)) = v; + + return 1; } void JNICALL -SetStaticFloatField(Thread* t, jclass c, jfieldID field, jfloat v) +SetStaticIntField(Thread* t, jobject c, jfieldID field, jint v) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(c), + field, + v }; - cast(classStaticTable(t, jclassVmClass(t, *c)), field) = v; + run(t, setStaticIntField, arguments); +} + +uint64_t +setStaticLongField(Thread* t, uintptr_t* arguments) +{ + jobject c = reinterpret_cast(arguments[0]); + object field = getStaticField(t, arguments[1]); + jlong v; memcpy(&v, arguments + 2, sizeof(jlong)); + + PROTECT(t, field); + ACQUIRE_FIELD_FOR_WRITE(t, field); + + cast + (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)) = v; + + return 1; } void JNICALL -SetStaticDoubleField(Thread* t, jclass c, jfieldID field, jdouble v) +SetStaticLongField(Thread* t, jobject c, jfieldID field, jlong v) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[2 + (sizeof(jlong) / BytesPerWord)]; + arguments[0] = reinterpret_cast(c); + arguments[1] = field; + memcpy(arguments + 2, &v, sizeof(jlong)); - cast(classStaticTable(t, jclassVmClass(t, *c)), field) = v; + run(t, setStaticLongField, arguments); +} + +uint64_t +setStaticFloatField(Thread* t, uintptr_t* arguments) +{ + jobject c = reinterpret_cast(arguments[0]); + object field = getStaticField(t, arguments[1]); + jfloat v = bitsToFloat(arguments[2]); + + PROTECT(t, field); + ACQUIRE_FIELD_FOR_WRITE(t, field); + + cast + (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)) = v; + + return 1; +} + +void JNICALL +SetStaticFloatField(Thread* t, jobject c, jfieldID field, jfloat v) +{ + uintptr_t arguments[] = { reinterpret_cast(c), + field, + floatToBits(v) }; + + run(t, setStaticFloatField, arguments); +} + +uint64_t +setStaticDoubleField(Thread* t, uintptr_t* arguments) +{ + jobject c = reinterpret_cast(arguments[0]); + object field = getStaticField(t, arguments[1]); + jdouble v = bitsToDouble(arguments[2]); + + PROTECT(t, field); + ACQUIRE_FIELD_FOR_WRITE(t, field); + + cast + (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)) = v; + + return 1; +} + +void JNICALL +SetStaticDoubleField(Thread* t, jobject c, jfieldID field, jdouble v) +{ + uintptr_t arguments[] = { reinterpret_cast(c), + field, + doubleToBits(v) }; + + run(t, setStaticDoubleField, arguments); } jobject JNICALL @@ -2318,8 +2922,6 @@ append(char** p, const char* value, unsigned length, char tail) uint64_t boot(Thread* t, uintptr_t*) { - t->javaThread = t->m->classpath->makeThread(t, 0); - setRoot(t, Machine::NullPointerException, makeThrowable (t, Machine::NullPointerExceptionType)); diff --git a/src/machine.cpp b/src/machine.cpp index e1bf8aadec..016fe4bf97 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1075,7 +1075,7 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool) code, flags, 0, // offset - i, + 0, // native ID singletonObject(t, pool, name - 1), singletonObject(t, pool, spec - 1), addendum, @@ -2388,6 +2388,7 @@ Thread::init() setRoot(this, Machine::ClassRuntimeDataTable, makeVector(this, 0, 0)); setRoot(this, Machine::MethodRuntimeDataTable, makeVector(this, 0, 0)); setRoot(this, Machine::JNIMethodTable, makeVector(this, 0, 0)); + setRoot(this, Machine::JNIFieldTable, makeVector(this, 0, 0)); m->localThread->set(this); diff --git a/src/machine.h b/src/machine.h index 11c9b7ce11..a9f6122e97 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1256,6 +1256,7 @@ class Machine { ClassRuntimeDataTable, MethodRuntimeDataTable, JNIMethodTable, + JNIFieldTable, ShutdownHooks, FinalizerThread, ObjectsToFinalize, From 44020482e503c9ead92318844d226998a1952e7f Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 17 Mar 2011 08:43:01 -0600 Subject: [PATCH 023/117] fix GC safety bugs in classpath-openjdk.cpp --- src/classpath-openjdk.cpp | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 131f7345ff..d9af4a95bb 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -793,6 +793,8 @@ readBytesFromFile(Thread* t, object method, uintptr_t* arguments) (this_, cp->fileInputStreamFdField), cp->fileDescriptorFdField); if (fd >= VirtualFileBase) { + PROTECT(t, dst); + ACQUIRE(t, t->m->referenceLock); object region = arrayBody @@ -1539,6 +1541,8 @@ interceptFileOperations(Thread* t) (t, root(t, Machine::BootLoader), "java/util/zip/ZipEntry"); if (zipEntryClass == 0) return; + PROTECT(t, zipEntryClass); + object zipEntryNameField = findFieldInClass2 (t, zipEntryClass, "name", "Ljava/lang/String;"); if (zipEntryNameField == 0) return; @@ -1583,6 +1587,8 @@ interceptFileOperations(Thread* t) (t, root(t, Machine::BootLoader), "java/util/zip/ZipFile"); if (zipFileClass == 0) return; + PROTECT(t, zipFileClass); + object zipFileJzfileField = findFieldInClass2 (t, zipFileClass, "jzfile", "J"); if (zipFileJzfileField == 0) return; @@ -2763,7 +2769,7 @@ jvmFillInStackTrace(Thread* t, uintptr_t* arguments) object trace = getTrace(t, 1); set(t, *throwable, ThrowableTrace, trace); - + return 1; } @@ -3489,20 +3495,30 @@ EXPORT(JVM_IsPrimitiveClass)(Thread* t, jclass c) return (classVmFlags(t, jclassVmClass(t, *c)) & PrimitiveFlag) != 0; } -extern "C" JNIEXPORT jclass JNICALL -EXPORT(JVM_GetComponentType)(Thread* t, jclass c) +uint64_t +jvmGetComponentType(Thread* t, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + jclass c = reinterpret_cast(arguments[0]); uint8_t n = byteArrayBody(t, className(t, jclassVmClass(t, *c)), 1); if (n != 'L' and n != '[') { - return makeLocalReference(t, getJClass(t, primitiveClass(t, n))); + return reinterpret_cast + (makeLocalReference(t, getJClass(t, primitiveClass(t, n)))); } else { - return makeLocalReference - (t, getJClass(t, classStaticTable(t, jclassVmClass(t, *c)))); + return reinterpret_cast + (makeLocalReference + (t, getJClass(t, classStaticTable(t, jclassVmClass(t, *c))))); } } +extern "C" JNIEXPORT jclass JNICALL +EXPORT(JVM_GetComponentType)(Thread* t, jclass c) +{ + uintptr_t arguments[] = { reinterpret_cast(c) }; + + return reinterpret_cast(run(t, jvmGetComponentType, arguments)); +} + extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_GetClassModifiers)(Thread* t, jclass c) { From 110e2e1d525c04c24abc2f22037db981be99eed4 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 17 Mar 2011 08:46:46 -0600 Subject: [PATCH 024/117] fix putstatic code order regression in compile.cpp Also, ensure that class is initialized before getting or setting static fields in lazy loading code. --- src/compile.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index 584e39d4cf..1345834013 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -2922,6 +2922,8 @@ getStaticFieldValueFromReference(MyThread* t, object pair) object field = resolveField(t, pair); PROTECT(t, field); + initClass(t, fieldClass(t, field)); + ACQUIRE_FIELD_FOR_READ(t, field); return getFieldValue(t, classStaticTable(t, fieldClass(t, field)), field); @@ -2946,6 +2948,8 @@ setStaticLongFieldValueFromReference(MyThread* t, object pair, uint64_t value) object field = resolveField(t, pair); PROTECT(t, field); + initClass(t, fieldClass(t, field)); + ACQUIRE_FIELD_FOR_WRITE(t, field); cast @@ -2974,6 +2978,8 @@ setStaticObjectFieldValueFromReference(MyThread* t, object pair, object value) object field = resolveField(t, pair); PROTECT(t, field); + initClass(t, fieldClass(t, field)); + ACQUIRE_FIELD_FOR_WRITE(t, field); set(t, classStaticTable(t, fieldClass(t, field)), fieldOffset(t, field), @@ -3025,6 +3031,8 @@ setStaticFieldValueFromReference(MyThread* t, object pair, uint32_t value) object field = resolveField(t, pair); PROTECT(t, field); + initClass(t, fieldClass(t, field)); + ACQUIRE_FIELD_FOR_WRITE(t, field); setFieldValue(t, classStaticTable(t, fieldClass(t, field)), field, value); @@ -5452,7 +5460,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, if (LIKELY(field)) { int fieldCode = vm::fieldCode(t, field); - Compiler::Operand* value = popField(t, frame, fieldCode); object staticTable = 0; @@ -5485,6 +5492,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, } } + Compiler::Operand* value = popField(t, frame, fieldCode); + Compiler::Operand* table; if (instruction == putstatic) { @@ -7828,7 +7837,7 @@ class ArgumentList { default: addInt(cast(objectArrayBody(t, arguments, index++), BytesPerWord)); - break; + break; } } } From 3f87129cbcefa9a094e78d55553e78d283cd1715 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 17 Mar 2011 08:48:47 -0600 Subject: [PATCH 025/117] use correct names for primitive classes in type generator --- src/type-generator.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/type-generator.cpp b/src/type-generator.cpp index aed82c3f35..afd20cd796 100644 --- a/src/type-generator.cpp +++ b/src/type-generator.cpp @@ -2177,8 +2177,22 @@ writeNameInitialization(Output* out, Object* type) { out->write("nameClass(t, Machine::"); out->write(capitalize(typeName(type))); - out->write("Type, \"vm::"); - out->write(typeName(type)); + out->write("Type, \""); + if (equal(typeName(type), "jbyte") + or equal(typeName(type), "jboolean") + or equal(typeName(type), "jshort") + or equal(typeName(type), "jchar") + or equal(typeName(type), "jint") + or equal(typeName(type), "jlong") + or equal(typeName(type), "jfloat") + or equal(typeName(type), "jdouble") + or equal(typeName(type), "jvoid")) + { + out->write(typeName(type) + 1); + } else { + out->write("vm::"); + out->write(typeName(type)); + } out->write("\");\n"); } From 366dfc009ca62f0f077fcf6efa6bcaff27110353 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 17 Mar 2011 08:49:41 -0600 Subject: [PATCH 026/117] fix mode=stress thinko and GC safety issue in machine.cpp --- src/machine.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/machine.cpp b/src/machine.cpp index 016fe4bf97..a855d34eb8 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -602,8 +602,8 @@ postCollect(Thread* t) uint64_t invoke(Thread* t, uintptr_t* arguments) { - object m = reinterpret_cast(arguments[0]); - object o = reinterpret_cast(arguments[1]); + object m = *reinterpret_cast(arguments[0]); + object o = *reinterpret_cast(arguments[1]); t->m->processor->invoke(t, m, o); @@ -622,8 +622,11 @@ finalizeObject(Thread* t, object o) and vm::strcmp(reinterpret_cast("()V"), &byteArrayBody(t, methodSpec(t, m), 0)) == 0) { - uintptr_t arguments[] = { reinterpret_cast(m), - reinterpret_cast(o) }; + PROTECT(t, m); + PROTECT(t, o); + + uintptr_t arguments[] = { reinterpret_cast(&m), + reinterpret_cast(&o) }; run(t, invoke, arguments); @@ -2155,7 +2158,7 @@ void doCollect(Thread* t, Heap::CollectionType type) { #ifdef VM_STRESS - bool stress = (t->flags |= Thread::StressFlag); + bool stress = (t->flags & Thread::StressFlag) != 0; if (not stress) atomicOr(&(t->flags), Thread::StressFlag); #endif From 0922dd3429d53327a7b9fc22de382b22125aef0a Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 17 Mar 2011 09:41:23 -0600 Subject: [PATCH 027/117] swap NativeLine and UnknownLine values to match Sun's convention --- src/machine.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/machine.h b/src/machine.h index a9f6122e97..2aaa2ad098 100644 --- a/src/machine.h +++ b/src/machine.h @@ -138,8 +138,8 @@ enum StackTag { ObjectTag }; -const int NativeLine = -1; -const int UnknownLine = -2; +const int NativeLine = -2; +const int UnknownLine = -1; // class vmFlags: const unsigned ReferenceFlag = 1 << 0; From 023e1d93d54b53c0d440d706caad04efc5583638 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 17 Mar 2011 09:41:52 -0600 Subject: [PATCH 028/117] return null for non-array classes in JVM_GetComponentType --- src/classpath-openjdk.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index d9af4a95bb..de5dd46c1a 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -3500,14 +3500,18 @@ jvmGetComponentType(Thread* t, uintptr_t* arguments) { jclass c = reinterpret_cast(arguments[0]); - uint8_t n = byteArrayBody(t, className(t, jclassVmClass(t, *c)), 1); - if (n != 'L' and n != '[') { - return reinterpret_cast - (makeLocalReference(t, getJClass(t, primitiveClass(t, n)))); + if (classArrayDimensions(t, jclassVmClass(t, *c))) { + uint8_t n = byteArrayBody(t, className(t, jclassVmClass(t, *c)), 1); + if (n != 'L' and n != '[') { + return reinterpret_cast + (makeLocalReference(t, getJClass(t, primitiveClass(t, n)))); + } else { + return reinterpret_cast + (makeLocalReference + (t, getJClass(t, classStaticTable(t, jclassVmClass(t, *c))))); + } } else { - return reinterpret_cast - (makeLocalReference - (t, getJClass(t, classStaticTable(t, jclassVmClass(t, *c))))); + return 0; } } From 86733a25f47dc521fbd07069655bb1da8dab4612 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 17 Mar 2011 21:24:35 -0600 Subject: [PATCH 029/117] increase executable area size to 30MB Big applications can exceed the 16MB limit we previously used. Increasing this above 30MB (if/when desired) will require changes to the ARM and PowerPC JIT code to work around immediate branch encoding limits on those platforms, --- src/compile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compile.cpp b/src/compile.cpp index 1345834013..8e7f2ef1ee 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -56,7 +56,7 @@ const unsigned MaxNativeCallFootprint = 4; const unsigned InitialZoneCapacityInBytes = 64 * 1024; -const unsigned ExecutableAreaSizeInBytes = 16 * 1024 * 1024; +const unsigned ExecutableAreaSizeInBytes = 30 * 1024 * 1024; enum Root { CallTable, From 8a28578ef5527867ff7b67e5993231b606dc1b1f Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 17 Mar 2011 21:32:37 -0600 Subject: [PATCH 030/117] don't defer to previous handler in signal handler It isn't necessarily safe or desireable to call the previous handler even if it's non-null, so we ignore it entirely except to reinstate it when unregistering our own handler. --- src/posix.cpp | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/src/posix.cpp b/src/posix.cpp index 3fcbb218de..2a5c7daf78 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -865,7 +865,7 @@ class MySystem: public System { }; void -handleSignal(int signal, siginfo_t* info, void* context) +handleSignal(int signal, siginfo_t*, void* context) { ucontext_t* c = static_cast(context); @@ -943,22 +943,14 @@ handleSignal(int signal, siginfo_t* info, void* context) default: abort(); } - if (system->oldHandlers[index].sa_flags & SA_SIGINFO - and system->oldHandlers[index].sa_sigaction) - { - system->oldHandlers[index].sa_sigaction(signal, info, context); - } else if (system->oldHandlers[index].sa_handler) { - system->oldHandlers[index].sa_handler(signal); - } else { - switch (signal) { - case VisitSignal: - case InterruptSignal: - case PipeSignal: - break; + switch (signal) { + case VisitSignal: + case InterruptSignal: + case PipeSignal: + break; - default: - abort(); - } + default: + abort(); } } From 7004c0ddf3a28880ba65f40df2bff17b173c266e Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 17 Mar 2011 21:42:15 -0600 Subject: [PATCH 031/117] various fixes and additions to increase app compatiblity The main changes here are: * fixes for runtime annotation support * proper support for runtime generic type introspection * throw NoClassDefFoundErrors instead of ClassNotFoundExceptions where appropriate --- classpath/avian/Addendum.java | 3 +- classpath/avian/MethodAddendum.java | 1 + src/builtin.cpp | 3 +- src/classpath-avian.cpp | 3 +- src/classpath-openjdk.cpp | 125 ++++++++++++++++++++-------- src/machine.cpp | 123 +++++++++++++++++++++------ src/machine.h | 15 ++-- 7 files changed, 204 insertions(+), 69 deletions(-) diff --git a/classpath/avian/Addendum.java b/classpath/avian/Addendum.java index 248ee68ec1..b363ecfc7c 100644 --- a/classpath/avian/Addendum.java +++ b/classpath/avian/Addendum.java @@ -12,5 +12,6 @@ package avian; public class Addendum { public Object pool; - public Object annotationTable; + public Object annotationTable; + public Object signature; } diff --git a/classpath/avian/MethodAddendum.java b/classpath/avian/MethodAddendum.java index a2e40a5261..597c169179 100644 --- a/classpath/avian/MethodAddendum.java +++ b/classpath/avian/MethodAddendum.java @@ -12,4 +12,5 @@ package avian; public class MethodAddendum extends Addendum { public Object exceptionTable; + public Object annotationDefault; } diff --git a/src/builtin.cpp b/src/builtin.cpp index 240ec9628a..004915d001 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -42,7 +42,8 @@ search(Thread* t, object loader, object name, object resolveSystemClassThrow(Thread* t, object loader, object spec) { - return resolveSystemClass(t, loader, spec, true); + return resolveSystemClass + (t, loader, spec, true, Machine::ClassNotFoundExceptionType); } } // namespace diff --git a/src/classpath-avian.cpp b/src/classpath-avian.cpp index 9efba455e4..c719b89545 100644 --- a/src/classpath-avian.cpp +++ b/src/classpath-avian.cpp @@ -610,7 +610,8 @@ Avian_avian_Classes_resolveVMClass object loader = reinterpret_cast(arguments[0]); object spec = reinterpret_cast(arguments[1]); - return reinterpret_cast(resolveClass(t, loader, spec)); + return reinterpret_cast + (resolveClass(t, loader, spec, true, Machine::ClassNotFoundExceptionType)); } extern "C" JNIEXPORT int64_t JNICALL diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index de5dd46c1a..b7b0752eb0 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -277,7 +277,10 @@ class MyClasspath : public Classpath { } array = charArray; + } else { + expect(t, objectClass(t, array) == type(t, Machine::CharArrayType)); } + return vm::makeString(t, array, offset, length, 0); } @@ -2118,6 +2121,16 @@ Avian_sun_misc_Unsafe_getInt__Ljava_lang_Object_2J return cast(o, offset); } +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_getFloat__Ljava_lang_Object_2J +(Thread*, object, uintptr_t* arguments) +{ + object o = reinterpret_cast(arguments[1]); + int64_t offset; memcpy(&offset, arguments + 2, 8); + + return cast(o, offset); +} + extern "C" JNIEXPORT int64_t JNICALL Avian_sun_misc_Unsafe_getIntVolatile (Thread*, object, uintptr_t* arguments) @@ -2177,6 +2190,17 @@ Avian_sun_misc_Unsafe_putInt__Ljava_lang_Object_2JI cast(o, offset) = value; } +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_putFloat__Ljava_lang_Object_2JF +(Thread*, object, uintptr_t* arguments) +{ + object o = reinterpret_cast(arguments[1]); + int64_t offset; memcpy(&offset, arguments + 2, 8); + int32_t value = arguments[4]; + + cast(o, offset) = value; +} + extern "C" JNIEXPORT int64_t JNICALL Avian_sun_misc_Unsafe_getBoolean (Thread*, object, uintptr_t* arguments) @@ -3248,21 +3272,10 @@ jvmFindClassFromClassLoader(Thread* t, uintptr_t* arguments) jobject loader = reinterpret_cast(arguments[2]); jboolean throwError = arguments[3]; - THREAD_RESOURCE(t, jboolean, throwError, { - if (t->exception and throwError) { - object exception = t->exception; - t->exception = 0; - - t->exception = makeThrowable - (t, Machine::NoClassDefFoundErrorType, - throwableMessage(t, exception), - throwableTrace(t, exception), - throwableCause(t, exception)); - } - }); - object c = resolveClass - (t, loader ? *loader : root(t, Machine::BootLoader), name); + (t, loader ? *loader : root(t, Machine::BootLoader), name, true, + throwError ? Machine::NoClassDefFoundErrorType + : Machine::ClassNotFoundExceptionType); if (init) { PROTECT(t, c); @@ -3542,9 +3555,19 @@ EXPORT(JVM_GetDeclaringClass)(Thread*, jclass) } extern "C" JNIEXPORT jstring JNICALL -EXPORT(JVM_GetClassSignature)(Thread*, jclass) +EXPORT(JVM_GetClassSignature)(Thread* t, jclass c) { - // todo: implement properly + ENTER(t, Thread::ActiveState); + + object addendum = classAddendum(t, jclassVmClass(t, *c)); + if (addendum) { + object signature = addendumSignature(t, addendum); + if (signature) { + return makeLocalReference + (t, t->m->classpath->makeString + (t, signature, 0, byteArrayLength(t, signature) - 1)); + } + } return 0; } @@ -3605,16 +3628,30 @@ jvmGetClassDeclaredMethods(Thread* t, uintptr_t* arguments) methodAddendum(t, vmMethod)); PROTECT(t, exceptionTypes); - object signature = t->m->classpath->makeString - (t, methodSpec(t, vmMethod), 0, byteArrayLength - (t, methodSpec(t, vmMethod)) - 1); + object signature; + object annotationTable; + object annotationDefault; + object addendum = methodAddendum(t, vmMethod); + if (addendum) { + signature = addendumSignature(t, addendum); + if (signature) { + signature = t->m->classpath->makeString + (t, signature, 0, byteArrayLength(t, signature) - 1); + } - object annotationTable = methodAddendum(t, vmMethod) == 0 - ? 0 : addendumAnnotationTable(t, methodAddendum(t, vmMethod)); + annotationTable = addendumAnnotationTable(t, addendum); - if (annotationTable) { + annotationDefault = methodAddendumAnnotationDefault(t, addendum); + } else { + signature = 0; + annotationTable = 0; + annotationDefault = 0; + } + + if (annotationTable or annotationDefault) { PROTECT(t, signature); PROTECT(t, annotationTable); + PROTECT(t, annotationDefault); object runtimeData = getClassRuntimeData(t, jclassVmClass(t, *c)); @@ -3624,8 +3661,8 @@ jvmGetClassDeclaredMethods(Thread* t, uintptr_t* arguments) object method = makeJmethod (t, true, *c, i, name, returnType, parameterTypes, exceptionTypes, - methodFlags(t, vmMethod), signature, 0, annotationTable, 0, 0, 0, 0, - 0, 0, 0); + methodFlags(t, vmMethod), signature, 0, annotationTable, 0, + annotationDefault, 0, 0, 0, 0, 0); assert(t, ai < objectArrayLength(t, array)); @@ -3685,12 +3722,21 @@ jvmGetClassDeclaredFields(Thread* t, uintptr_t* arguments) type = getJClass(t, type); - object signature = t->m->classpath->makeString - (t, fieldSpec(t, vmField), 0, byteArrayLength - (t, fieldSpec(t, vmField)) - 1); + object signature; + object annotationTable; + object addendum = fieldAddendum(t, vmField); + if (addendum) { + signature = addendumSignature(t, addendum); + if (signature) { + signature = t->m->classpath->makeString + (t, signature, 0, byteArrayLength(t, signature) - 1); + } - object annotationTable = fieldAddendum(t, vmField) == 0 - ? 0 : addendumAnnotationTable(t, fieldAddendum(t, vmField)); + annotationTable = addendumAnnotationTable(t, addendum); + } else { + signature = 0; + annotationTable = 0; + } if (annotationTable) { PROTECT(t, signature); @@ -3767,12 +3813,21 @@ jvmGetClassDeclaredConstructors(Thread* t, uintptr_t* arguments) methodAddendum(t, vmMethod)); PROTECT(t, exceptionTypes); - object signature = t->m->classpath->makeString - (t, methodSpec(t, vmMethod), 0, byteArrayLength - (t, methodSpec(t, vmMethod)) - 1); + object signature; + object annotationTable; + object addendum = methodAddendum(t, vmMethod); + if (addendum) { + signature = addendumSignature(t, addendum); + if (signature) { + signature = t->m->classpath->makeString + (t, signature, 0, byteArrayLength(t, signature) - 1); + } - object annotationTable = methodAddendum(t, vmMethod) == 0 - ? 0 : addendumAnnotationTable(t, methodAddendum(t, vmMethod)); + annotationTable = addendumAnnotationTable(t, addendum); + } else { + signature = 0; + annotationTable = 0; + } if (annotationTable) { PROTECT(t, signature); @@ -4405,7 +4460,7 @@ extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_GetSockOpt)(jint socket, int level, int optionName, char* optionValue, int* optionLength) { - socklen_t length; + socklen_t length = *optionLength; int rv = getsockopt(socket, level, optionName, optionValue, &length); *optionLength = length; return rv; diff --git a/src/machine.cpp b/src/machine.cpp index a855d34eb8..f59d672434 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -954,7 +954,8 @@ addInterfaces(Thread* t, object class_, object map) } void -parseInterfaceTable(Thread* t, Stream& s, object class_, object pool) +parseInterfaceTable(Thread* t, Stream& s, object class_, object pool, + Machine::Type throwType) { PROTECT(t, class_); PROTECT(t, pool); @@ -971,7 +972,8 @@ parseInterfaceTable(Thread* t, Stream& s, object class_, object pool) object name = referenceName(t, singletonObject(t, pool, s.read2() - 1)); PROTECT(t, name); - object interface = resolveClass(t, classLoader(t, class_), name); + object interface = resolveClass + (t, classLoader(t, class_), name, true, throwType); PROTECT(t, interface); @@ -1047,6 +1049,8 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool) unsigned value = 0; + addendum = 0; + unsigned code = fieldCode (t, byteArrayBody(t, singletonObject(t, pool, spec - 1), 0)); @@ -1059,14 +1063,28 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool) &byteArrayBody(t, name, 0)) == 0) { value = s.read2(); + } else if (vm::strcmp(reinterpret_cast("Signature"), + &byteArrayBody(t, name, 0)) == 0) + { + if (addendum == 0) { + addendum = makeFieldAddendum(t, pool, 0, 0); + } + + set(t, addendum, AddendumSignature, + singletonObject(t, pool, s.read2() - 1)); } else if (vm::strcmp(reinterpret_cast ("RuntimeVisibleAnnotations"), &byteArrayBody(t, name, 0)) == 0) { + if (addendum == 0) { + addendum = makeFieldAddendum(t, pool, 0, 0); + } + object body = makeByteArray(t, length); s.read(reinterpret_cast(&byteArrayBody(t, body, 0)), length); - addendum = makeFieldAddendum(t, pool, body); + + set(t, addendum, AddendumAnnotationTable, body); } else { s.skip(length); } @@ -1387,6 +1405,7 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool) unsigned name = s.read2(); unsigned spec = s.read2(); + addendum = 0; code = 0; unsigned attributeCount = s.read2(); @@ -1402,7 +1421,7 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool) &byteArrayBody(t, name, 0)) == 0) { if (addendum == 0) { - addendum = makeMethodAddendum(t, pool, 0, 0); + addendum = makeMethodAddendum(t, pool, 0, 0, 0, 0); } unsigned exceptionCount = s.read2(); object body = makeShortArray(t, exceptionCount); @@ -1410,16 +1429,40 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool) shortArrayBody(t, body, i) = s.read2(); } set(t, addendum, MethodAddendumExceptionTable, body); + } else if (vm::strcmp(reinterpret_cast + ("AnnotationDefault"), + &byteArrayBody(t, name, 0)) == 0) + { + if (addendum == 0) { + addendum = makeMethodAddendum(t, pool, 0, 0, 0, 0); + } + + object body = makeByteArray(t, length); + s.read(reinterpret_cast(&byteArrayBody(t, body, 0)), + length); + + set(t, addendum, MethodAddendumAnnotationDefault, body); + } else if (vm::strcmp(reinterpret_cast("Signature"), + &byteArrayBody(t, name, 0)) == 0) + { + if (addendum == 0) { + addendum = makeMethodAddendum(t, pool, 0, 0, 0, 0); + } + + set(t, addendum, AddendumSignature, + singletonObject(t, pool, s.read2() - 1)); } else if (vm::strcmp(reinterpret_cast ("RuntimeVisibleAnnotations"), &byteArrayBody(t, name, 0)) == 0) { if (addendum == 0) { - addendum = makeMethodAddendum(t, pool, 0, 0); + addendum = makeMethodAddendum(t, pool, 0, 0, 0, 0); } + object body = makeByteArray(t, length); s.read(reinterpret_cast(&byteArrayBody(t, body, 0)), length); + set(t, addendum, AddendumAnnotationTable, body); } else { s.skip(length); @@ -1632,6 +1675,12 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool) void parseAttributeTable(Thread* t, Stream& s, object class_, object pool) { + PROTECT(t, class_); + PROTECT(t, pool); + + object addendum = 0; + PROTECT(t, addendum); + unsigned attributeCount = s.read2(); for (unsigned j = 0; j < attributeCount; ++j) { object name = singletonObject(t, pool, s.read2() - 1); @@ -1641,20 +1690,33 @@ parseAttributeTable(Thread* t, Stream& s, object class_, object pool) &byteArrayBody(t, name, 0)) == 0) { set(t, class_, ClassSourceFile, singletonObject(t, pool, s.read2() - 1)); + } else if (vm::strcmp(reinterpret_cast("Signature"), + &byteArrayBody(t, name, 0)) == 0) + { + if (addendum == 0) { + addendum = makeClassAddendum(t, pool, 0, 0); + } + + set(t, addendum, AddendumSignature, + singletonObject(t, pool, s.read2() - 1)); } else if (vm::strcmp(reinterpret_cast ("RuntimeVisibleAnnotations"), &byteArrayBody(t, name, 0)) == 0) { + if (addendum == 0) { + addendum = makeClassAddendum(t, pool, 0, 0); + } + object body = makeByteArray(t, length); s.read(reinterpret_cast(&byteArrayBody(t, body, 0)), length); - object addendum = makeClassAddendum(t, pool, body); - - set(t, class_, ClassAddendum, addendum); + set(t, addendum, AddendumAnnotationTable, body); } else { s.skip(length); } } + + set(t, class_, ClassAddendum, addendum); } void @@ -1713,6 +1775,7 @@ updateBootstrapClass(Thread* t, object bootstrapClass, object class_) set(t, bootstrapClass, ClassFieldTable, classFieldTable(t, class_)); set(t, bootstrapClass, ClassMethodTable, classMethodTable(t, class_)); set(t, bootstrapClass, ClassStaticTable, classStaticTable(t, class_)); + set(t, bootstrapClass, ClassAddendum, classAddendum(t, class_)); updateClassTables(t, bootstrapClass, class_); } @@ -1765,7 +1828,8 @@ makeArrayClass(Thread* t, object loader, unsigned dimensions, object spec, } object -makeArrayClass(Thread* t, object loader, object spec, bool throw_) +makeArrayClass(Thread* t, object loader, object spec, bool throw_, + Machine::Type throwType) { PROTECT(t, loader); PROTECT(t, spec); @@ -1807,7 +1871,7 @@ makeArrayClass(Thread* t, object loader, object spec, bool throw_) byteArrayEqual); if (elementClass == 0) { - elementClass = resolveClass(t, loader, elementSpec, throw_); + elementClass = resolveClass(t, loader, elementSpec, throw_, throwType); if (elementClass == 0) return 0; } @@ -1820,7 +1884,8 @@ makeArrayClass(Thread* t, object loader, object spec, bool throw_) } object -resolveArrayClass(Thread* t, object loader, object spec, bool throw_) +resolveArrayClass(Thread* t, object loader, object spec, bool throw_, + Machine::Type throwType) { object c = hashMapFind (t, root(t, Machine::BootstrapClassMap), spec, byteArrayHash, @@ -1840,7 +1905,7 @@ resolveArrayClass(Thread* t, object loader, object spec, bool throw_) if (c) { return c; } else { - return makeArrayClass(t, loader, spec, throw_); + return makeArrayClass(t, loader, spec, throw_, throwType); } } } @@ -3145,7 +3210,8 @@ primitiveSize(Thread* t, unsigned code) } object -parseClass(Thread* t, object loader, const uint8_t* data, unsigned size) +parseClass(Thread* t, object loader, const uint8_t* data, unsigned size, + Machine::Type throwType) { PROTECT(t, loader); @@ -3199,7 +3265,8 @@ parseClass(Thread* t, object loader, const uint8_t* data, unsigned size) unsigned super = s.read2(); if (super) { object sc = resolveClass - (t, loader, referenceName(t, singletonObject(t, pool, super - 1))); + (t, loader, referenceName(t, singletonObject(t, pool, super - 1)), + true, throwType); set(t, class_, ClassSuper, sc); @@ -3208,7 +3275,7 @@ parseClass(Thread* t, object loader, const uint8_t* data, unsigned size) & (ReferenceFlag | WeakReferenceFlag | HasFinalizerFlag)); } - parseInterfaceTable(t, s, class_, pool); + parseInterfaceTable(t, s, class_, pool, throwType); parseFieldTable(t, s, class_, pool); @@ -3249,7 +3316,8 @@ parseClass(Thread* t, object loader, const uint8_t* data, unsigned size) } object -resolveSystemClass(Thread* t, object loader, object spec, bool throw_) +resolveSystemClass(Thread* t, object loader, object spec, bool throw_, + Machine::Type throwType) { PROTECT(t, loader); PROTECT(t, spec); @@ -3269,7 +3337,7 @@ resolveSystemClass(Thread* t, object loader, object spec, bool throw_) } if (byteArrayBody(t, spec, 0) == '[') { - class_ = resolveArrayClass(t, loader, spec, throw_); + class_ = resolveArrayClass(t, loader, spec, throw_, throwType); } else { THREAD_RUNTIME_ARRAY(t, char, file, byteArrayLength(t, spec) + 6); memcpy(RUNTIME_ARRAY_BODY(file), @@ -3291,7 +3359,8 @@ resolveSystemClass(Thread* t, object loader, object spec, bool throw_) { THREAD_RESOURCE(t, System::Region*, region, region->dispose()); // parse class file - class_ = parseClass(t, loader, region->start(), region->length()); + class_ = parseClass + (t, loader, region->start(), region->length(), throwType); } if (Verbose) { @@ -3318,8 +3387,7 @@ resolveSystemClass(Thread* t, object loader, object spec, bool throw_) hashMapInsert(t, classLoaderMap(t, loader), spec, class_, byteArrayHash); } else if (throw_) { - throwNew(t, Machine::ClassNotFoundExceptionType, "%s", - &byteArrayBody(t, spec, 0)); + throwNew(t, throwType, "%s", &byteArrayBody(t, spec, 0)); } } @@ -3339,10 +3407,11 @@ findLoadedClass(Thread* t, object loader, object spec) } object -resolveClass(Thread* t, object loader, object spec, bool throw_) +resolveClass(Thread* t, object loader, object spec, bool throw_, + Machine::Type throwType) { if (objectClass(t, loader) == type(t, Machine::SystemClassLoaderType)) { - return resolveSystemClass(t, loader, spec, throw_); + return resolveSystemClass(t, loader, spec, throw_, throwType); } else { PROTECT(t, loader); PROTECT(t, spec); @@ -3353,7 +3422,7 @@ resolveClass(Thread* t, object loader, object spec, bool throw_) } if (byteArrayBody(t, spec, 0) == '[') { - c = resolveArrayClass(t, loader, spec, throw_); + c = resolveArrayClass(t, loader, spec, throw_, throwType); } else { if (root(t, Machine::LoadClassMethod) == 0) { object m = resolveMethod @@ -3383,6 +3452,7 @@ resolveClass(Thread* t, object loader, object spec, bool throw_) (&byteArrayBody(t, spec, 0))); object specString = makeString(t, "%s", RUNTIME_ARRAY_BODY(s)); + PROTECT(t, specString); uintptr_t arguments[] = { reinterpret_cast(method), reinterpret_cast(loader), @@ -3395,7 +3465,9 @@ resolveClass(Thread* t, object loader, object spec, bool throw_) c = jclassVmClass(t, jc); } else if (t->exception) { if (throw_) { - object e = t->exception; + object e = type(t, throwType) == objectClass(t, t->exception) + ? t->exception + : makeThrowable(t, throwType, specString, 0, t->exception); t->exception = 0; vm::throw_(t, e); } else { @@ -3417,8 +3489,7 @@ resolveClass(Thread* t, object loader, object spec, bool throw_) hashMapInsert (t, classLoaderMap(t, loader), spec, c, byteArrayHash); } else if (throw_) { - throwNew(t, Machine::ClassNotFoundExceptionType, "%s", - &byteArrayBody(t, spec, 0)); + throwNew(t, throwType, "%s", &byteArrayBody(t, spec, 0)); } return c; diff --git a/src/machine.h b/src/machine.h index 2aaa2ad098..dca89f1637 100644 --- a/src/machine.h +++ b/src/machine.h @@ -2466,21 +2466,26 @@ object parseUtf8(Thread* t, const char* data, unsigned length); object -parseClass(Thread* t, object loader, const uint8_t* data, unsigned length); +parseClass(Thread* t, object loader, const uint8_t* data, unsigned length, + Machine::Type throwType = Machine::NoClassDefFoundErrorType); object -resolveClass(Thread* t, object loader, object name, bool throw_ = true); +resolveClass(Thread* t, object loader, object name, bool throw_ = true, + Machine::Type throwType = Machine::NoClassDefFoundErrorType); inline object -resolveClass(Thread* t, object loader, const char* name, bool throw_ = true) +resolveClass(Thread* t, object loader, const char* name, bool throw_ = true, + Machine::Type throwType = Machine::NoClassDefFoundErrorType) { PROTECT(t, loader); object n = makeByteArray(t, "%s", name); - return resolveClass(t, loader, n, throw_); + return resolveClass(t, loader, n, throw_, throwType); } object -resolveSystemClass(Thread* t, object loader, object name, bool throw_ = true); +resolveSystemClass +(Thread* t, object loader, object name, bool throw_ = true, + Machine::Type throwType = Machine::NoClassDefFoundErrorType); inline object resolveSystemClass(Thread* t, object loader, const char* name) From 61552b6b8afda786a93c27eb3f97dad505c9652d Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 19 Mar 2011 15:10:52 -0600 Subject: [PATCH 032/117] check for and handle instances of sun.misc.Cleaner during GC OpenJDK uses an alternative to Object.finalize for resource cleanup in the form of sun.misc.Cleaner. Normally, OpenJDK's java.lang.ref.Reference.ReferenceHandler thread handles this, calling Cleaner.clean on any instances it finds in its "pending" queue. However, Avian handles reference queuing internally, so it never actually adds anything to that queue, so the VM must call Cleaner.clean itself. --- classpath/sun/misc/Cleaner.java | 13 ++++++ src/machine.cpp | 76 ++++++++++++++++++++++----------- src/machine.h | 1 + src/types.def | 7 +++ 4 files changed, 73 insertions(+), 24 deletions(-) create mode 100644 classpath/sun/misc/Cleaner.java diff --git a/classpath/sun/misc/Cleaner.java b/classpath/sun/misc/Cleaner.java new file mode 100644 index 0000000000..d4dd733f48 --- /dev/null +++ b/classpath/sun/misc/Cleaner.java @@ -0,0 +1,13 @@ +/* Copyright (c) 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. */ + +package sun.misc; + +public class Cleaner { } diff --git a/src/machine.cpp b/src/machine.cpp index f59d672434..9b23e72e8a 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -379,26 +379,33 @@ referenceTargetUnreachable(Thread* t, Heap::Visitor* v, object* p) v->visit(p); jreferenceTarget(t, *p) = 0; - if (jreferenceQueue(t, *p) - and t->m->heap->status(jreferenceQueue(t, *p)) != Heap::Unreachable) - { - // queue is reachable - add the reference + if (objectClass(t, *p) == type(t, Machine::CleanerType)) { + object reference = *p; + *p = jreferenceVmNext(t, reference); + jreferenceVmNext(t, reference) = t->m->cleanerQueue; + t->m->cleanerQueue = reference; + } else { + if (jreferenceQueue(t, *p) + and t->m->heap->status(jreferenceQueue(t, *p)) != Heap::Unreachable) + { + // queue is reachable - add the reference - v->visit(&jreferenceQueue(t, *p)); + v->visit(&jreferenceQueue(t, *p)); - object q = jreferenceQueue(t, *p); + object q = jreferenceQueue(t, *p); - if (referenceQueueFront(t, q)) { - set(t, *p, JreferenceJNext, referenceQueueFront(t, q)); - } else { - set(t, *p, JreferenceJNext, *p); + if (referenceQueueFront(t, q)) { + set(t, *p, JreferenceJNext, referenceQueueFront(t, q)); + } else { + set(t, *p, JreferenceJNext, *p); + } + set(t, q, ReferenceQueueFront, *p); + + jreferenceQueue(t, *p) = 0; } - set(t, q, ReferenceQueueFront, *p); - jreferenceQueue(t, *p) = 0; + *p = jreferenceVmNext(t, *p); } - - *p = jreferenceVmNext(t, *p); } void @@ -446,6 +453,7 @@ postVisit(Thread* t, Heap::Visitor* v) bool major = m->heap->collectionType() == Heap::MajorCollection; assert(t, m->finalizeQueue == 0); + assert(t, m->cleanerQueue == 0); object firstNewTenuredFinalizer = 0; object lastNewTenuredFinalizer = 0; @@ -611,13 +619,13 @@ invoke(Thread* t, uintptr_t* arguments) } void -finalizeObject(Thread* t, object o) +finalizeObject(Thread* t, object o, const char* name) { for (object c = objectClass(t, o); c; c = classSuper(t, c)) { for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, c)); ++i) { object m = arrayBody(t, classMethodTable(t, c), i); - if (vm::strcmp(reinterpret_cast("finalize"), + if (vm::strcmp(reinterpret_cast(name), &byteArrayBody(t, methodName(t, m), 0)) == 0 and vm::strcmp(reinterpret_cast("()V"), &byteArrayBody(t, methodSpec(t, m), 0)) == 0) @@ -2254,19 +2262,36 @@ doCollect(Thread* t, Heap::CollectionType type) if (not stress) atomicAnd(&(t->flags), ~Thread::StressFlag); #endif - object f = t->m->finalizeQueue; + object finalizeQueue = t->m->finalizeQueue; + PROTECT(t, finalizeQueue); t->m->finalizeQueue = 0; - for (; f; f = finalizerNext(t, f)) { + for (; finalizeQueue; finalizeQueue = finalizerNext(t, finalizeQueue)) { void (*function)(Thread*, object); - memcpy(&function, &finalizerFinalize(t, f), BytesPerWord); + memcpy(&function, &finalizerFinalize(t, finalizeQueue), BytesPerWord); if (function) { - function(t, finalizerTarget(t, f)); + function(t, finalizerTarget(t, finalizeQueue)); } else { - setRoot(t, Machine::ObjectsToFinalize, makePair - (t, finalizerTarget(t, f), root(t, Machine::ObjectsToFinalize))); + setRoot(t, Machine::ObjectsToFinalize, makeFinalizeNode + (t, finalizerTarget(t, finalizeQueue), + const_cast("finalize"), + root(t, Machine::ObjectsToFinalize))); } } + object cleanerQueue = t->m->cleanerQueue; + PROTECT(t, cleanerQueue); + t->m->cleanerQueue = 0; + while (cleanerQueue) { + setRoot(t, Machine::ObjectsToFinalize, makeFinalizeNode + (t, cleanerQueue, + const_cast("clean"), + root(t, Machine::ObjectsToFinalize))); + + object tmp = cleanerQueue; + cleanerQueue = jreferenceVmNext(t, cleanerQueue); + jreferenceVmNext(t, tmp) = 0; + } + if (root(t, Machine::ObjectsToFinalize) and m->finalizeThread == 0) { m->finalizeThread = m->processor->makeThread (m, root(t, Machine::FinalizerThread), m->rootThread); @@ -2330,6 +2355,7 @@ Machine::Machine(System* system, Heap* heap, Finder* bootFinder, finalizers(0), tenuredFinalizers(0), finalizeQueue(0), + cleanerQueue(0), weakReferences(0), tenuredWeakReferences(0), unsafe(false), @@ -4099,8 +4125,10 @@ runFinalizeThread(Thread* t) } } - for (; list; list = pairSecond(t, list)) { - finalizeObject(t, pairFirst(t, list)); + for (; list; list = finalizeNodeNext(t, list)) { + finalizeObject + (t, finalizeNodeTarget(t, list), + static_cast(finalizeNodeMethodName(t, list))); } } } diff --git a/src/machine.h b/src/machine.h index dca89f1637..23b4d3b943 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1311,6 +1311,7 @@ class Machine { object finalizers; object tenuredFinalizers; object finalizeQueue; + object cleanerQueue; object weakReferences; object tenuredWeakReferences; bool unsafe; diff --git a/src/types.def b/src/types.def index 8b8d980ffc..d68fc7436a 100644 --- a/src/types.def +++ b/src/types.def @@ -106,6 +106,11 @@ (void* finalize) (nogc object next)) +(type finalizeNode + (object target) + (void* methodName) + (object next)) + (type hashMap (uint32_t size) (object array)) @@ -294,6 +299,8 @@ (type phantomReference java/lang/ref/PhantomReference) +(type cleaner sun/misc/Cleaner) + (type byteArray [B (extends jobject) (array int8_t body)) From 5b830343ba4f879732d45e6d437bc8ff421c07be Mon Sep 17 00:00:00 2001 From: JET Date: Wed, 23 Mar 2011 17:06:33 -0600 Subject: [PATCH 033/117] Properties.java UTF-16 support refactoring. --- classpath/java/util/Properties.java | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/classpath/java/util/Properties.java b/classpath/java/util/Properties.java index c37de95878..10b5c90687 100644 --- a/classpath/java/util/Properties.java +++ b/classpath/java/util/Properties.java @@ -85,7 +85,18 @@ public class Properties extends Hashtable { } abstract int readCharacter() throws IOException; - + + char readUtf16() throws IOException { + char c = 0; + for (int i = 0; i < 4; ++i) { + int digit = Character.digit((char)readCharacter(), 16); + if (digit == -1) throw new IOException("Invalid Unicode escape encountered."); + c <<= 4; + c |= digit; + } + return c; + } + void parse(Map map) throws IOException { @@ -149,17 +160,11 @@ public class Properties extends Hashtable { break; case 'u': - if (escaped) { // ASCII Unicode escape - int most = Character.digit((char)in.read(), 16); - int more = Character.digit((char)in.read(), 16); - int less = Character.digit((char)in.read(), 16); - int least = Character.digit((char)in.read(), 16); - char utf16 = (char)(most << 12 | more << 8 | less << 4 | least); - append(utf16); + if (escaped) { + append(readUtf16()); } else { append(c); - } - break; + } break; default: append(c); From d928d695ffb48c70b920ebb9e6b861e53572430e Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 25 Mar 2011 18:14:34 -0600 Subject: [PATCH 034/117] try harder in low memory situations in Zone::allocate Instead of giving up when the backing allocator's tryAllocate method returns null, we switch to the allocate method to show we mean business. This makes use of zones more robust under low memory situations since it allows us to exceed the soft memory ceiling when the only alternative is to abort. --- src/zone.h | 46 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/src/zone.h b/src/zone.h index b73c0a8913..426315e4ae 100644 --- a/src/zone.h +++ b/src/zone.h @@ -49,21 +49,23 @@ class Zone: public Allocator { segment = 0; } - bool ensure(unsigned space) { - if (segment == 0 or position + space > segment->size) { - unsigned size = max - (space, max - (minimumFootprint, segment == 0 ? 0 : segment->size * 2)) - + sizeof(Segment); + static unsigned padToPage(unsigned size) { + return (size + (LikelyPageSizeInBytes - 1)) + & ~(LikelyPageSizeInBytes - 1); + } - // pad to page size - size = (size + (LikelyPageSizeInBytes - 1)) - & ~(LikelyPageSizeInBytes - 1); + bool tryEnsure(unsigned space) { + if (segment == 0 or position + space > segment->size) { + unsigned size = padToPage + (max + (space, max + (minimumFootprint, segment == 0 ? 0 : segment->size * 2)) + + sizeof(Segment)); void* p = allocator->tryAllocate(size); if (p == 0) { - size = space + sizeof(Segment); - void* p = allocator->tryAllocate(size); + size = padToPage(space + sizeof(Segment)); + p = allocator->tryAllocate(size); if (p == 0) { return false; } @@ -75,9 +77,19 @@ class Zone: public Allocator { return true; } + void ensure(unsigned space) { + if (segment == 0 or position + space > segment->size) { + unsigned size = padToPage(space + sizeof(Segment)); + + segment = new (allocator->allocate(size)) + Segment(segment, size - sizeof(Segment)); + position = 0; + } + } + virtual void* tryAllocate(unsigned size) { size = pad(size); - if (ensure(size)) { + if (tryEnsure(size)) { void* r = segment->data + position; position += size; return r; @@ -88,8 +100,14 @@ class Zone: public Allocator { virtual void* allocate(unsigned size) { void* p = tryAllocate(size); - expect(s, p); - return p; + if (p) { + return p; + } else { + ensure(size); + void* r = segment->data + position; + position += size; + return r; + } } virtual void free(const void*, unsigned) { From 960bd282969ff51559c52d9df249188e57dc1b15 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 25 Mar 2011 18:21:15 -0600 Subject: [PATCH 035/117] preallocate monitor node in monitorWait If we don't preallocate the memory we need to reacquire the lock after we finish waiting, we risk an OOME which may unwind the stack into code which assumes we still have acquire the lock successfully. --- src/machine.h | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/machine.h b/src/machine.h index 23b4d3b943..2ece9003e0 100644 --- a/src/machine.h +++ b/src/machine.h @@ -2794,11 +2794,13 @@ atomicCompareAndSwapObject(Thread* t, object target, unsigned offset, // Queue Algorithm: http://www.cs.rochester.edu/u/michael/PODC96.html inline void -monitorAtomicAppendAcquire(Thread* t, object monitor) +monitorAtomicAppendAcquire(Thread* t, object monitor, object node) { - PROTECT(t, monitor); + if (node == 0) { + PROTECT(t, monitor); - object node = makeMonitorNode(t, t, 0); + node = makeMonitorNode(t, t, 0); + } while (true) { object tail = monitorAcquireTail(t, monitor); @@ -2878,14 +2880,15 @@ monitorTryAcquire(Thread* t, object monitor) } inline void -monitorAcquire(Thread* t, object monitor) +monitorAcquire(Thread* t, object monitor, object node = 0) { if (not monitorTryAcquire(t, monitor)) { PROTECT(t, monitor); + PROTECT(t, node); ACQUIRE(t, t->lock); - monitorAtomicAppendAcquire(t, monitor); + monitorAtomicAppendAcquire(t, monitor, node); // note that we don't try to acquire the lock until we're first in // line, both because it's fair and because we don't support @@ -3009,6 +3012,11 @@ monitorWait(Thread* t, object monitor, int64_t time) PROTECT(t, monitor); + // pre-allocate monitor node so we don't get an OutOfMemoryError + // when we try to re-acquire the monitor below + object monitorNode = makeMonitorNode(t, t, 0); + PROTECT(t, monitorNode); + { ACQUIRE(t, t->lock); monitorAppendWait(t, monitor); @@ -3023,7 +3031,7 @@ monitorWait(Thread* t, object monitor, int64_t time) interrupted = t->lock->wait(t->systemThread, time); } - monitorAcquire(t, monitor); + monitorAcquire(t, monitor, monitorNode); monitorDepth(t, monitor) = depth; From 3e93d5d337eed59cd63b8057f2e6298ced726a2d Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 25 Mar 2011 18:27:02 -0600 Subject: [PATCH 036/117] fix Value::home integer overflow A method with a large number of local variable slots may imply offsets larger than a int8_t can represent, so we now use an int16_t instead. --- src/compiler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler.cpp b/src/compiler.cpp index 2deeffe5a7..a5f6aeb373 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -326,7 +326,7 @@ class Value: public Compiler::Operand { Site* target; Value* buddy; Value* nextWord; - int8_t home; + int16_t home; ValueType type; uint8_t wordIndex; }; From b9f8188544aa44c5a2b8ab8e24165d37276bccb8 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 25 Mar 2011 18:37:02 -0600 Subject: [PATCH 037/117] don't try to release monitor if we get OOME when trying to acquire it We can't blindly try release the monitors for all synchronized methods when unwinding the stack since we may not have finished acquiring the most recent one when the exception was thrown. --- src/compile.cpp | 43 ++++++++++++++++++++++++++++++++----------- src/interpret.cpp | 30 ++++++++++++++++++------------ src/thunks.cpp | 1 + 3 files changed, 51 insertions(+), 23 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index 8e7f2ef1ee..2176f17d57 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -235,7 +235,8 @@ class MyThread: public Thread { : makeArchitecture(m->system, useNativeFeatures)), transition(0), traceContext(0), - stackLimit(0) + stackLimit(0), + methodLockIsClean(true) { arch->acquire(); } @@ -256,6 +257,7 @@ class MyThread: public Thread { Context* transition; TraceContext* traceContext; uintptr_t stackLimit; + bool methodLockIsClean; }; void @@ -1982,16 +1984,23 @@ void releaseLock(MyThread* t, object method, void* stack) { if (methodFlags(t, method) & ACC_SYNCHRONIZED) { - object lock; - if (methodFlags(t, method) & ACC_STATIC) { - lock = methodClass(t, method); - } else { - lock = *localObject - (t, stackForFrame(t, stack, method), method, - savedTargetIndex(t, method)); - } + if (t->methodLockIsClean) { + object lock; + if (methodFlags(t, method) & ACC_STATIC) { + lock = methodClass(t, method); + } else { + lock = *localObject + (t, stackForFrame(t, stack, method), method, + savedTargetIndex(t, method)); + } - release(t, lock); + release(t, lock); + } else { + // got an exception while trying to acquire the lock for a + // synchronized method -- don't try to release it, since we + // never succeeded in acquiring it. + t->methodLockIsClean = true; + } } } @@ -2764,6 +2773,18 @@ acquireMonitorForObject(MyThread* t, object o) } } +void +acquireMonitorForObjectOnEntrance(MyThread* t, object o) +{ + if (LIKELY(o)) { + t->methodLockIsClean = false; + acquire(t, o); + t->methodLockIsClean = true; + } else { + throwNew(t, Machine::NullPointerExceptionType); + } +} + void releaseMonitorForObject(MyThread* t, object o) { @@ -3456,7 +3477,7 @@ handleEntrance(MyThread* t, Frame* frame) } handleMonitorEvent - (t, frame, getThunk(t, acquireMonitorForObjectThunk)); + (t, frame, getThunk(t, acquireMonitorForObjectOnEntranceThunk)); } void diff --git a/src/interpret.cpp b/src/interpret.cpp index 482859e21f..13f3b9e853 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -322,15 +322,29 @@ setLocalLong(Thread* t, unsigned index, uint64_t value) void pushFrame(Thread* t, object method) { - if (t->frame >= 0) { - pokeInt(t, t->frame + FrameIpOffset, t->ip); - } - t->ip = 0; + PROTECT(t, method); unsigned parameterFootprint = methodParameterFootprint(t, method); unsigned base = t->sp - parameterFootprint; unsigned locals = parameterFootprint; + if (methodFlags(t, method) & ACC_SYNCHRONIZED) { + // Try to acquire the monitor before doing anything else. + // Otherwise, if we were to push the frame first, we risk trying + // to release a monitor we never successfully acquired when we try + // to pop the frame back off. + if (methodFlags(t, method) & ACC_STATIC) { + acquire(t, methodClass(t, method)); + } else { + acquire(t, peekObject(t, base)); + } + } + + if (t->frame >= 0) { + pokeInt(t, t->frame + FrameIpOffset, t->ip); + } + t->ip = 0; + if ((methodFlags(t, method) & ACC_NATIVE) == 0) { t->code = methodCode(t, method); @@ -349,14 +363,6 @@ pushFrame(Thread* t, object method) pokeInt(t, frame + FrameBaseOffset, base); pokeObject(t, frame + FrameMethodOffset, method); pokeInt(t, t->frame + FrameIpOffset, 0); - - if (methodFlags(t, method) & ACC_SYNCHRONIZED) { - if (methodFlags(t, method) & ACC_STATIC) { - acquire(t, methodClass(t, method)); - } else { - acquire(t, peekObject(t, base)); - } - } } void diff --git a/src/thunks.cpp b/src/thunks.cpp index dce0885c96..9279cbb811 100644 --- a/src/thunks.cpp +++ b/src/thunks.cpp @@ -45,6 +45,7 @@ THUNK(makeBlankArray) THUNK(lookUpAddress) THUNK(setMaybeNull) THUNK(acquireMonitorForObject) +THUNK(acquireMonitorForObjectOnEntrance) THUNK(releaseMonitorForObject) THUNK(makeMultidimensionalArray) THUNK(makeMultidimensionalArrayFromReference) From 838cf9fdd1818dadd11c90e9b5fc7839f14ecdad Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 25 Mar 2011 19:11:38 -0600 Subject: [PATCH 038/117] avoid calling doCollect recursively We must not allocate heap objects from doCollect, since it might trigger a GC while one is already in progress, which can cause trouble when we're still queuing up objects to finalize, among other things. To avoid this, I've added extra fields to the finalizer and cleaner types which we can use to link instances up during GC without allocating new memory. --- src/machine.cpp | 82 ++++++++++++++++++++++++++----------------------- src/machine.h | 3 +- src/types.def | 12 +++----- 3 files changed, 50 insertions(+), 47 deletions(-) diff --git a/src/machine.cpp b/src/machine.cpp index 9b23e72e8a..cc949c5ca6 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -364,8 +364,18 @@ finalizerTargetUnreachable(Thread* t, Heap::Visitor* v, object* p) object finalizer = *p; *p = finalizerNext(t, finalizer); - finalizerNext(t, finalizer) = t->m->finalizeQueue; - t->m->finalizeQueue = finalizer; + + void (*function)(Thread*, object); + memcpy(&function, &finalizerFinalize(t, finalizer), BytesPerWord); + + if (function) { + finalizerNext(t, finalizer) = t->m->finalizeQueue; + t->m->finalizeQueue = finalizer; + } else { + set(t, finalizer, FinalizerQueueTarget, finalizerTarget(t, finalizer)); + set(t, finalizer, FinalizerQueueNext, root(t, Machine::ObjectsToFinalize)); + setRoot(t, Machine::ObjectsToFinalize, finalizer); + } } void @@ -382,8 +392,9 @@ referenceTargetUnreachable(Thread* t, Heap::Visitor* v, object* p) if (objectClass(t, *p) == type(t, Machine::CleanerType)) { object reference = *p; *p = jreferenceVmNext(t, reference); - jreferenceVmNext(t, reference) = t->m->cleanerQueue; - t->m->cleanerQueue = reference; + + set(t, reference, CleanerQueueNext, root(t, Machine::ObjectsToClean)); + setRoot(t, Machine::ObjectsToClean, reference); } else { if (jreferenceQueue(t, *p) and t->m->heap->status(jreferenceQueue(t, *p)) != Heap::Unreachable) @@ -453,7 +464,6 @@ postVisit(Thread* t, Heap::Visitor* v) bool major = m->heap->collectionType() == Heap::MajorCollection; assert(t, m->finalizeQueue == 0); - assert(t, m->cleanerQueue == 0); object firstNewTenuredFinalizer = 0; object lastNewTenuredFinalizer = 0; @@ -2230,6 +2240,11 @@ class HeapClient: public Heap::Client { void doCollect(Thread* t, Heap::CollectionType type) { + expect(t, not t->m->collecting); + + t->m->collecting = true; + THREAD_RESOURCE0(t, t->m->collecting = false); + #ifdef VM_STRESS bool stress = (t->flags & Thread::StressFlag) != 0; if (not stress) atomicOr(&(t->flags), Thread::StressFlag); @@ -2263,36 +2278,16 @@ doCollect(Thread* t, Heap::CollectionType type) #endif object finalizeQueue = t->m->finalizeQueue; - PROTECT(t, finalizeQueue); t->m->finalizeQueue = 0; for (; finalizeQueue; finalizeQueue = finalizerNext(t, finalizeQueue)) { void (*function)(Thread*, object); memcpy(&function, &finalizerFinalize(t, finalizeQueue), BytesPerWord); - if (function) { - function(t, finalizerTarget(t, finalizeQueue)); - } else { - setRoot(t, Machine::ObjectsToFinalize, makeFinalizeNode - (t, finalizerTarget(t, finalizeQueue), - const_cast("finalize"), - root(t, Machine::ObjectsToFinalize))); - } + function(t, finalizerTarget(t, finalizeQueue)); } - object cleanerQueue = t->m->cleanerQueue; - PROTECT(t, cleanerQueue); - t->m->cleanerQueue = 0; - while (cleanerQueue) { - setRoot(t, Machine::ObjectsToFinalize, makeFinalizeNode - (t, cleanerQueue, - const_cast("clean"), - root(t, Machine::ObjectsToFinalize))); - - object tmp = cleanerQueue; - cleanerQueue = jreferenceVmNext(t, cleanerQueue); - jreferenceVmNext(t, tmp) = 0; - } - - if (root(t, Machine::ObjectsToFinalize) and m->finalizeThread == 0) { + if ((root(t, Machine::ObjectsToFinalize) or root(t, Machine::ObjectsToClean)) + and m->finalizeThread == 0) + { m->finalizeThread = m->processor->makeThread (m, root(t, Machine::FinalizerThread), m->rootThread); @@ -2355,10 +2350,10 @@ Machine::Machine(System* system, Heap* heap, Finder* bootFinder, finalizers(0), tenuredFinalizers(0), finalizeQueue(0), - cleanerQueue(0), weakReferences(0), tenuredWeakReferences(0), unsafe(false), + collecting(false), triedBuiltinOnLoad(false), dumpedHeapOnOOM(false), heapPoolIndex(0) @@ -3810,7 +3805,7 @@ addFinalizer(Thread* t, object target, void (*finalize)(Thread*, object)) void* function; memcpy(&function, &finalize, BytesPerWord); - object f = makeFinalizer(t, 0, function, 0); + object f = makeFinalizer(t, 0, function, 0, 0, 0); finalizerTarget(t, f) = target; finalizerNext(t, f) = t->m->finalizers; t->m->finalizers = f; @@ -4104,14 +4099,18 @@ makeTrace(Thread* t, Thread* target) void runFinalizeThread(Thread* t) { - object list = 0; - PROTECT(t, list); + object finalizeList = 0; + PROTECT(t, finalizeList); + + object cleanList = 0; + PROTECT(t, cleanList); while (true) { { ACQUIRE(t, t->m->stateLock); while (t->m->finalizeThread - and root(t, Machine::ObjectsToFinalize) == 0) + and root(t, Machine::ObjectsToFinalize) == 0 + and root(t, Machine::ObjectsToClean) == 0) { ENTER(t, Thread::IdleState); t->m->stateLock->wait(t->systemThread, 0); @@ -4120,15 +4119,20 @@ runFinalizeThread(Thread* t) if (t->m->finalizeThread == 0) { return; } else { - list = root(t, Machine::ObjectsToFinalize); + finalizeList = root(t, Machine::ObjectsToFinalize); setRoot(t, Machine::ObjectsToFinalize, 0); + + cleanList = root(t, Machine::ObjectsToClean); + setRoot(t, Machine::ObjectsToClean, 0); } } - for (; list; list = finalizeNodeNext(t, list)) { - finalizeObject - (t, finalizeNodeTarget(t, list), - static_cast(finalizeNodeMethodName(t, list))); + for (; finalizeList; finalizeList = finalizerQueueNext(t, finalizeList)) { + finalizeObject(t, finalizerQueueTarget(t, finalizeList), "finalize"); + } + + for (; cleanList; cleanList = cleanerQueueNext(t, cleanList)) { + finalizeObject(t, cleanList, "clean"); } } } diff --git a/src/machine.h b/src/machine.h index 2ece9003e0..e6c72da833 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1260,6 +1260,7 @@ class Machine { ShutdownHooks, FinalizerThread, ObjectsToFinalize, + ObjectsToClean, NullPointerException, ArithmeticException, ArrayIndexOutOfBoundsException, @@ -1311,10 +1312,10 @@ class Machine { object finalizers; object tenuredFinalizers; object finalizeQueue; - object cleanerQueue; object weakReferences; object tenuredWeakReferences; bool unsafe; + bool collecting; bool triedBuiltinOnLoad; bool dumpedHeapOnOOM; JavaVMVTable javaVMVTable; diff --git a/src/types.def b/src/types.def index d68fc7436a..cf04647e06 100644 --- a/src/types.def +++ b/src/types.def @@ -104,12 +104,9 @@ (type finalizer (nogc object target) (void* finalize) - (nogc object next)) - -(type finalizeNode - (object target) - (void* methodName) - (object next)) + (nogc object next) + (object queueTarget) + (object queueNext)) (type hashMap (uint32_t size) @@ -299,7 +296,8 @@ (type phantomReference java/lang/ref/PhantomReference) -(type cleaner sun/misc/Cleaner) +(type cleaner sun/misc/Cleaner + (object queueNext)) (type byteArray [B (extends jobject) From 20baef4e69aefaa0f49873fd224de157c21bebee Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 25 Mar 2011 18:47:56 -0600 Subject: [PATCH 039/117] implement File.toString --- classpath/java/io/File.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/classpath/java/io/File.java b/classpath/java/io/File.java index 3c97db5e4a..ec5338035e 100644 --- a/classpath/java/io/File.java +++ b/classpath/java/io/File.java @@ -82,6 +82,10 @@ public class File { } } + public String toString() { + return getPath(); + } + public String getPath() { return path; } From 7b4b43e119ed062e0673ac3ab778c3870f8eedaf Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 25 Mar 2011 18:50:31 -0600 Subject: [PATCH 040/117] implement JVM_CompileClass and JVM_CompileClasses stubs These don't currently do anything but return false. --- src/classpath-openjdk.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index b7b0752eb0..6387cafe5b 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -2843,10 +2843,16 @@ extern "C" JNIEXPORT jboolean JNICALL EXPORT(JVM_IsSilentCompiler)(Thread*, jclass) { abort(); } extern "C" JNIEXPORT jboolean JNICALL -EXPORT(JVM_CompileClass)(Thread*, jclass, jclass) { abort(); } +EXPORT(JVM_CompileClass)(Thread*, jclass, jclass) +{ + return false; +} extern "C" JNIEXPORT jboolean JNICALL -EXPORT(JVM_CompileClasses)(Thread*, jclass, jstring) { abort(); } +EXPORT(JVM_CompileClasses)(Thread*, jclass, jstring) +{ + return false; +} extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_CompilerCommand)(Thread*, jclass, jobject) { abort(); } From 639ef500790cc314b8572ecde2284faf81f62c97 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 25 Mar 2011 18:54:09 -0600 Subject: [PATCH 041/117] handle null caller in JVM_GetCallerClass --- src/classpath-openjdk.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 6387cafe5b..7df324fb12 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -3223,8 +3223,10 @@ EXPORT(JVM_GetCallerClass)(Thread* t, int target) { ENTER(t, Thread::ActiveState); - return makeLocalReference - (t, getJClass(t, methodClass(t, getCaller(t, target)))); + object method = getCaller(t, target); + + return method ? makeLocalReference + (t, getJClass(t, methodClass(t, method))) : 0; } extern "C" JNIEXPORT jclass JNICALL From 31eb047391668d3487b8306f97ea63bb6c91aba2 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 25 Mar 2011 18:55:25 -0600 Subject: [PATCH 042/117] handle redundant, unreachable gotos in JIT compiler I recently encountered a Batik JAR with a method containing a redundant goto which confused the JIT compiler because it was refered to in the exception handler and line number tables despite being unreachable. I don't know how such code was generated, but this commit ensures the compiler can handle it. --- src/compile.cpp | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index 2176f17d57..2ecbad7fb9 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -5875,6 +5875,25 @@ logCompile(MyThread* t, const void* code, unsigned size, const char* class_, } } +unsigned +resolveIp(MyThread* t, object code, unsigned ip) +{ + switch (codeBody(t, code, ip)) { + case goto_: { + unsigned tmp = ip + 1; + return ip + codeReadInt16(t, code, tmp); + } + + case goto_w: { + unsigned tmp = ip + 1; + return ip + codeReadInt32(t, code, tmp); + } + + default: + return ip; + } +} + object translateExceptionHandlerTable(MyThread* t, Compiler* c, object method, intptr_t start) @@ -5900,7 +5919,10 @@ translateExceptionHandlerTable(MyThread* t, Compiler* c, object method, (t, oldTable, i); intArrayBody(t, newIndex, i * 3) - = c->machineIp(exceptionHandlerStart(oldHandler))->value() - start; + = c->machineIp + (resolveIp + (t, methodCode(t, method), + exceptionHandlerStart(oldHandler)))->value() - start; intArrayBody(t, newIndex, (i * 3) + 1) = c->machineIp(exceptionHandlerEnd(oldHandler))->value() - start; @@ -5940,7 +5962,8 @@ translateLineNumberTable(MyThread* t, Compiler* c, object code, intptr_t start) LineNumber* newLine = lineNumberTableBody(t, newTable, i); lineNumberIp(newLine) - = c->machineIp(lineNumberIp(oldLine))->value() - start; + = c->machineIp(resolveIp(t, code, lineNumberIp(oldLine)))->value() + - start; lineNumberLine(newLine) = lineNumberLine(oldLine); } @@ -6842,7 +6865,8 @@ compile(MyThread* t, Context* context) c->restoreState(state); ExceptionHandler* eh = exceptionHandlerTableBody(t, eht, i); - unsigned start = exceptionHandlerStart(eh); + unsigned start = resolveIp + (t, methodCode(t, context->method), exceptionHandlerStart(eh)); if ((not RUNTIME_ARRAY_BODY(visited)[i]) and context->visitTable[start]) @@ -7917,6 +7941,17 @@ invoke(Thread* thread, object method, ArgumentList* arguments) { MyThread* t = static_cast(thread); + if (false) { + PROTECT(t, method); + + compile(t, local::codeAllocator(static_cast(t)), 0, + resolveMethod + (t, root(t, Machine::AppLoader), + "foo/ClassName", + "methodName", + "()V")); + } + uintptr_t stackLimit = t->stackLimit; uintptr_t stackPosition = reinterpret_cast(&t); if (stackLimit == 0) { From 3dd091c67af81f8b385d85fbdc82fa40524ba09a Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 25 Mar 2011 19:14:21 -0600 Subject: [PATCH 043/117] implement jar and file URL stream handlers --- classpath/avian/SystemClassLoader.java | 7 +- classpath/avian/file/Handler.java | 44 +++++++++++++ classpath/avian/jar/Handler.java | 84 ++++++++++++++++++++++++ classpath/java/net/JarURLConnection.java | 22 +++++++ classpath/java/net/URL.java | 8 ++- classpath/java/net/URLStreamHandler.java | 4 +- classpath/java/util/jar/JarEntry.java | 15 +++++ classpath/java/util/jar/JarFile.java | 77 ++++++++++++++++++++++ classpath/java/util/zip/ZipEntry.java | 1 + classpath/java/util/zip/ZipFile.java | 54 ++++++++++++--- src/builtin.cpp | 11 ++-- src/finder.cpp | 37 ++++++++++- src/finder.h | 1 + 13 files changed, 342 insertions(+), 23 deletions(-) create mode 100644 classpath/avian/file/Handler.java create mode 100644 classpath/avian/jar/Handler.java create mode 100644 classpath/java/net/JarURLConnection.java create mode 100644 classpath/java/util/jar/JarEntry.java create mode 100644 classpath/java/util/jar/JarFile.java diff --git a/classpath/avian/SystemClassLoader.java b/classpath/avian/SystemClassLoader.java index 6edd8b7a68..6334f82916 100644 --- a/classpath/avian/SystemClassLoader.java +++ b/classpath/avian/SystemClassLoader.java @@ -34,12 +34,13 @@ public class SystemClassLoader extends ClassLoader { return c == null ? null : getClass(c); } - private native boolean resourceExists(String name); + private native String resourceURLPrefix(String name); protected URL findResource(String name) { - if (resourceExists(name)) { + String prefix = resourceURLPrefix(name); + if (prefix != null) { try { - return new URL("resource:" + name); + return new URL(prefix + name); } catch (MalformedURLException ignored) { } } return null; diff --git a/classpath/avian/file/Handler.java b/classpath/avian/file/Handler.java new file mode 100644 index 0000000000..14ff26db37 --- /dev/null +++ b/classpath/avian/file/Handler.java @@ -0,0 +1,44 @@ +/* Copyright (c) 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. */ + +package avian.file; + +import java.net.URL; +import java.net.URLStreamHandler; +import java.net.URLConnection; +import java.io.IOException; +import java.io.FileNotFoundException; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; + +public class Handler extends URLStreamHandler { + protected URLConnection openConnection(URL url) { + return new FileURLConnection(url); + } + + private static class FileURLConnection extends URLConnection { + public FileURLConnection(URL url) { + super(url); + } + + public int getContentLength() { + return (int) new File(url.getFile()).length(); + } + + public InputStream getInputStream() throws IOException { + return new FileInputStream(url.getFile()); + } + + public void connect() { + // ignore + } + } +} diff --git a/classpath/avian/jar/Handler.java b/classpath/avian/jar/Handler.java new file mode 100644 index 0000000000..fcd79625c3 --- /dev/null +++ b/classpath/avian/jar/Handler.java @@ -0,0 +1,84 @@ +/* Copyright (c) 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. */ + +package avian.jar; + +import java.net.URL; +import java.net.MalformedURLException; +import java.net.URLStreamHandler; +import java.net.JarURLConnection; +import java.net.URLConnection; +import java.io.IOException; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.util.jar.JarFile; +import java.util.jar.JarEntry; + +public class Handler extends URLStreamHandler { + protected URLConnection openConnection(URL url) { + return new MyJarURLConnection(url); + } + + protected void parseURL(URL url, String s, int start, int end) + throws MalformedURLException + { + // skip "jar:" + s = s.toString().substring(4); + int index = s.indexOf("!/"); + if (index < 0) { + throw new MalformedURLException(); + } + + URL file = new URL(s.substring(0, index)); + if (! "file".equals(file.getProtocol())) { + throw new RuntimeException + ("protocol " + file.getProtocol() + " not yet supported"); + } + + url.set("jar", "", -1, s, null); + } + + private static class MyJarURLConnection extends JarURLConnection { + private final JarFile file; + private final JarEntry entry; + + public MyJarURLConnection(URL url) { + super(url); + + String s = url.getFile(); + int index = s.indexOf("!/"); + + try { + this.file = new JarFile(new URL(s.substring(0, index)).getFile()); + this.entry = this.file.getJarEntry(s.substring(index + 2)); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public JarFile getJarFile() throws IOException { + return file; + } + + public int getContentLength() { + return entry.getSize(); + } + + public InputStream getInputStream() throws IOException { + return file.getInputStream(entry); + } + + public void connect() { + // ignore + } + } +} diff --git a/classpath/java/net/JarURLConnection.java b/classpath/java/net/JarURLConnection.java new file mode 100644 index 0000000000..ee50574a02 --- /dev/null +++ b/classpath/java/net/JarURLConnection.java @@ -0,0 +1,22 @@ +/* Copyright (c) 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. */ + +package java.net; + +import java.io.IOException; +import java.util.jar.JarFile; + +public abstract class JarURLConnection extends URLConnection { + public JarURLConnection(URL url) { + super(url); + } + + public abstract JarFile getJarFile() throws IOException; +} diff --git a/classpath/java/net/URL.java b/classpath/java/net/URL.java index 2b405b307e..874eec964b 100644 --- a/classpath/java/net/URL.java +++ b/classpath/java/net/URL.java @@ -73,13 +73,17 @@ public final class URL { { if ("resource".equals(protocol)) { return new avian.resource.Handler(); + } else if ("file".equals(protocol)) { + return new avian.file.Handler(); + } else if ("jar".equals(protocol)) { + return new avian.jar.Handler(); } else { throw new MalformedURLException("unknown protocol: " + protocol); } } - protected void set(String protocol, String host, int port, String file, - String ref) + public void set(String protocol, String host, int port, String file, + String ref) { this.protocol = protocol; this.host = host; diff --git a/classpath/java/net/URLStreamHandler.java b/classpath/java/net/URLStreamHandler.java index 928f0285ba..5c72deada1 100644 --- a/classpath/java/net/URLStreamHandler.java +++ b/classpath/java/net/URLStreamHandler.java @@ -13,7 +13,9 @@ package java.net; import java.io.IOException; public abstract class URLStreamHandler { - protected void parseURL(URL url, String s, int start, int end) { + protected void parseURL(URL url, String s, int start, int end) + throws MalformedURLException + { String protocol = s.substring(0, start - 1); s = s.substring(start, end); diff --git a/classpath/java/util/jar/JarEntry.java b/classpath/java/util/jar/JarEntry.java new file mode 100644 index 0000000000..9f92c29713 --- /dev/null +++ b/classpath/java/util/jar/JarEntry.java @@ -0,0 +1,15 @@ +/* Copyright (c) 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. */ + +package java.util.jar; + +import java.util.zip.ZipEntry; + +public abstract class JarEntry extends ZipEntry { } diff --git a/classpath/java/util/jar/JarFile.java b/classpath/java/util/jar/JarFile.java new file mode 100644 index 0000000000..af9e34f975 --- /dev/null +++ b/classpath/java/util/jar/JarFile.java @@ -0,0 +1,77 @@ +/* Copyright (c) 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. */ + +package java.util.jar; + +import java.io.File; +import java.io.IOException; +import java.util.Enumeration; +import java.util.zip.ZipFile; +import java.util.zip.ZipEntry; + +public class JarFile extends ZipFile { + public JarFile(String name) throws IOException { + super(name); + } + + public JarFile(File file) throws IOException { + super(file); + } + + public Enumeration entries() { + return (Enumeration) makeEnumeration(JarEntryFactory.Instance); + } + + public JarEntry getJarEntry(String name) { + return (JarEntry) getEntry(JarEntryFactory.Instance, name); + } + + private static class MyJarEntry extends JarEntry { + public final Window window; + public final int pointer; + + public MyJarEntry(Window window, int pointer) { + this.window = window; + this.pointer = pointer; + } + + public String getName() { + try { + return entryName(window, pointer); + } catch (IOException e) { + return null; + } + } + + public int getCompressedSize() { + try { + return compressedSize(window, pointer); + } catch (IOException e) { + return 0; + } + } + + public int getSize() { + try { + return uncompressedSize(window, pointer); + } catch (IOException e) { + return 0; + } + } + } + + private static class JarEntryFactory implements EntryFactory { + public static final JarEntryFactory Instance = new JarEntryFactory(); + + public ZipEntry makeEntry(Window window, int pointer) { + return new MyJarEntry(window, pointer); + } + } +} diff --git a/classpath/java/util/zip/ZipEntry.java b/classpath/java/util/zip/ZipEntry.java index f2d944907f..9f18369c52 100644 --- a/classpath/java/util/zip/ZipEntry.java +++ b/classpath/java/util/zip/ZipEntry.java @@ -13,4 +13,5 @@ package java.util.zip; public abstract class ZipEntry { public abstract String getName(); public abstract int getCompressedSize(); + public abstract int getSize(); } diff --git a/classpath/java/util/zip/ZipFile.java b/classpath/java/util/zip/ZipFile.java index d59885496f..2bbb13c35a 100644 --- a/classpath/java/util/zip/ZipFile.java +++ b/classpath/java/util/zip/ZipFile.java @@ -63,13 +63,23 @@ public class ZipFile { return index.size(); } + protected Enumeration makeEnumeration + (EntryFactory factory) + { + return new MyEnumeration(factory, window, index.values().iterator()); + } + public Enumeration entries() { - return new MyEnumeration(window, index.values().iterator()); + return makeEnumeration(ZipEntryFactory.Instance); + } + + protected ZipEntry getEntry(EntryFactory factory, String name) { + Integer pointer = index.get(name); + return (pointer == null ? null : factory.makeEntry(window, pointer)); } public ZipEntry getEntry(String name) { - Integer pointer = index.get(name); - return (pointer == null ? null : new MyZipEntry(window, pointer)); + return getEntry(ZipEntryFactory.Instance, name); } public InputStream getInputStream(ZipEntry entry) throws IOException { @@ -126,7 +136,7 @@ public class ZipFile { return get2(w, p + 28); } - private static String entryName(Window w, int p) throws IOException { + protected static String entryName(Window w, int p) throws IOException { int length = entryNameLength(w, p); return new String(w.data, w.seek(p + 46, length), length); } @@ -135,10 +145,14 @@ public class ZipFile { return get2(w, p + 10); } - private static int compressedSize(Window w, int p) throws IOException { + protected static int compressedSize(Window w, int p) throws IOException { return get4(w, p + 20); } + protected static int uncompressedSize(Window w, int p) throws IOException { + return get4(w, p + 24); + } + private static int fileNameLength(Window w, int p) throws IOException { return get2(w, p + 28); } @@ -186,7 +200,7 @@ public class ZipFile { file.close(); } - private static class Window { + protected static class Window { private final RandomAccessFile file; public final byte[] data; public int start; @@ -255,13 +269,37 @@ public class ZipFile { return 0; } } + + public int getSize() { + try { + return uncompressedSize(window, pointer); + } catch (IOException e) { + return 0; + } + } + } + + protected interface EntryFactory { + public ZipEntry makeEntry(Window window, int pointer); + } + + private static class ZipEntryFactory implements EntryFactory { + public static final ZipEntryFactory Instance = new ZipEntryFactory(); + + public ZipEntry makeEntry(Window window, int pointer) { + return new MyZipEntry(window, pointer); + } } private static class MyEnumeration implements Enumeration { + private final EntryFactory factory; private final Window window; private final Iterator iterator; - public MyEnumeration(Window window, Iterator iterator) { + public MyEnumeration(EntryFactory factory, Window window, + Iterator iterator) + { + this.factory = factory; this.window = window; this.iterator = iterator; } @@ -271,7 +309,7 @@ public class ZipFile { } public ZipEntry nextElement() { - return new MyZipEntry(window, iterator.next()); + return factory.makeEntry(window, iterator.next()); } } diff --git a/src/builtin.cpp b/src/builtin.cpp index 004915d001..41a6fda597 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -69,7 +69,7 @@ Avian_avian_SystemClassLoader_findVMClass } extern "C" JNIEXPORT int64_t JNICALL -Avian_avian_SystemClassLoader_resourceExists +Avian_avian_SystemClassLoader_resourceURLPrefix (Thread* t, object, uintptr_t* arguments) { object loader = reinterpret_cast(arguments[0]); @@ -79,13 +79,10 @@ Avian_avian_SystemClassLoader_resourceExists THREAD_RUNTIME_ARRAY(t, char, n, stringLength(t, name) + 1); stringChars(t, name, RUNTIME_ARRAY_BODY(n)); - unsigned length; - bool r = static_cast(systemClassLoaderFinder(t, loader))->stat - (RUNTIME_ARRAY_BODY(n), &length) == System::TypeFile; + const char* name = static_cast + (systemClassLoaderFinder(t, loader))->urlPrefix(RUNTIME_ARRAY_BODY(n)); -// fprintf(stderr, "resource %s exists? %d\n", n, r); - - return r; + return name ? reinterpret_cast(makeString(t, "%s", name)) : 0; } else { throwNew(t, Machine::NullPointerExceptionType); } diff --git a/src/finder.cpp b/src/finder.cpp index 4352aa8adf..c144d0fed6 100644 --- a/src/finder.cpp +++ b/src/finder.cpp @@ -55,6 +55,7 @@ class Element { virtual System::Region* find(const char* name) = 0; virtual System::FileType stat(const char* name, unsigned* length, bool tryDirectory) = 0; + virtual const char* urlPrefix() = 0; virtual void dispose() = 0; Element* next; @@ -123,7 +124,8 @@ class DirectoryElement: public Element { }; DirectoryElement(System* s, Allocator* allocator, const char* name): - s(s), allocator(allocator), name(name) + s(s), allocator(allocator), name(name), + urlPrefix_(append(allocator, "file:", name, "/")) { } virtual Element::Iterator* iterator() { @@ -157,14 +159,20 @@ class DirectoryElement: public Element { return type; } + virtual const char* urlPrefix() { + return urlPrefix_; + } + virtual void dispose() { allocator->free(name, strlen(name) + 1); + allocator->free(urlPrefix_, strlen(urlPrefix_) + 1); allocator->free(this, sizeof(*this)); } System* s; Allocator* allocator; const char* name; + const char* urlPrefix_; }; class PointerRegion: public System::Region { @@ -428,7 +436,9 @@ class JarElement: public Element { }; JarElement(System* s, Allocator* allocator, const char* name): - s(s), allocator(allocator), name(name), region(0), index(0) + s(s), allocator(allocator), name(name), + urlPrefix_(name ? append(allocator, "jar:file:", name, "!/") : 0), + region(0), index(0) { } JarElement(System* s, Allocator* allocator, const uint8_t* jarData, @@ -436,6 +446,7 @@ class JarElement: public Element { s(s), allocator(allocator), name(0), + urlPrefix_(name ? append(allocator, "jar:file:", name, "!/") : 0), region(new (allocator->allocate(sizeof(PointerRegion))) PointerRegion(s, allocator, jarData, jarLength)), index(JarIndex::open(s, allocator, region)) @@ -485,12 +496,17 @@ class JarElement: public Element { : System::TypeDoesNotExist); } + virtual const char* urlPrefix() { + return urlPrefix_; + } + virtual void dispose() { dispose(sizeof(*this)); } virtual void dispose(unsigned size) { allocator->free(name, strlen(name) + 1); + allocator->free(urlPrefix_, strlen(urlPrefix_) + 1); if (index) { index->dispose(); } @@ -503,6 +519,7 @@ class JarElement: public Element { System* s; Allocator* allocator; const char* name; + const char* urlPrefix_; System::Region* region; JarIndex* index; }; @@ -535,6 +552,10 @@ class BuiltinElement: public JarElement { } } + virtual const char* urlPrefix() { + return "resource:"; + } + virtual void dispose() { library->disposeAll(); if (libraryName) { @@ -769,6 +790,18 @@ class MyFinder: public Finder { return System::TypeDoesNotExist; } + virtual const char* urlPrefix(const char* name) { + for (Element* e = path_; e; e = e->next) { + unsigned length; + System::FileType type = e->stat(name, &length, true); + if (type != System::TypeDoesNotExist) { + return e->urlPrefix(); + } + } + + return 0; + } + virtual const char* path() { return pathString; } diff --git a/src/finder.h b/src/finder.h index 5f894290eb..d2c252b451 100644 --- a/src/finder.h +++ b/src/finder.h @@ -167,6 +167,7 @@ class Finder { virtual System::FileType stat(const char* name, unsigned* length, bool tryDirectory = false) = 0; + virtual const char* urlPrefix(const char* name) = 0; virtual const char* path() = 0; virtual void dispose() = 0; }; From ba0cc803a600699f71d8d5bccc259bed0349fca3 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 26 Mar 2011 11:15:52 -0600 Subject: [PATCH 044/117] implement various JVM_* methods This includes a proper implementation of JVM_ActiveProcessorCount, as well as JVM_SetLength and JVM_NewMultiArray. Also, we now accept up to JNI_VERSION_1_6 in JVM_IsSupportedJNIVersion. --- src/classpath-openjdk.cpp | 112 ++++++++++++++++++++++++++++---------- src/machine.cpp | 31 +++++++++++ src/machine.h | 4 ++ src/process.h | 31 ----------- 4 files changed, 118 insertions(+), 60 deletions(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 7df324fb12..cc2074396c 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -2733,7 +2733,13 @@ EXPORT(JVM_MaxMemory)() extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_ActiveProcessorCount)() { - return 1; +#ifdef PLATFORM_WINDOWS + SYSTEM_INFO si; + GetSystemInfo(&si); + return si.dwNumberOfProcessors; +#else + return sysconf(_SC_NPROCESSORS_ONLN); +#endif } uint64_t @@ -2780,7 +2786,7 @@ EXPORT(JVM_FindLibraryEntry)(void* library, const char* name) extern "C" JNIEXPORT jboolean JNICALL EXPORT(JVM_IsSupportedJNIVersion)(jint version) { - return version <= JNI_VERSION_1_4; + return version <= JNI_VERSION_1_6; } extern "C" JNIEXPORT jboolean JNICALL @@ -3165,14 +3171,9 @@ extern "C" JNIEXPORT void JNICALL EXPORT(JVM_SetPrimitiveArrayElement)(Thread*, jobject, jint, jvalue, unsigned char) { abort(); } -uint64_t -jvmNewArray(Thread* t, uintptr_t* arguments) +object +makeNewArray(Thread* t, object c, unsigned length) { - jclass elementClass = reinterpret_cast(arguments[0]); - jint length = arguments[1]; - - object c = jclassVmClass(t, *elementClass); - if (classVmFlags(t, c) & PrimitiveFlag) { const char* name = reinterpret_cast (&byteArrayBody(t, local::getClassName(t, c), 0)); @@ -3180,32 +3181,34 @@ jvmNewArray(Thread* t, uintptr_t* arguments) switch (*name) { case 'b': if (name[1] == 'o') { - return reinterpret_cast - (makeLocalReference(t, makeBooleanArray(t, length))); + return makeBooleanArray(t, length); } else { - return reinterpret_cast - (makeLocalReference(t, makeByteArray(t, length))); + return makeByteArray(t, length); } - case 'c': return reinterpret_cast - (makeLocalReference(t, makeCharArray(t, length))); - case 'd': return reinterpret_cast - (makeLocalReference(t, makeDoubleArray(t, length))); - case 'f': return reinterpret_cast - (makeLocalReference(t, makeFloatArray(t, length))); - case 'i': return reinterpret_cast - (makeLocalReference(t, makeIntArray(t, length))); - case 'l': return reinterpret_cast - (makeLocalReference(t, makeLongArray(t, length))); - case 's': return reinterpret_cast - (makeLocalReference(t, makeShortArray(t, length))); + case 'c': return makeCharArray(t, length); + case 'd': return makeDoubleArray(t, length); + case 'f': return makeFloatArray(t, length); + case 'i': return makeIntArray(t, length); + case 'l': return makeLongArray(t, length); + case 's': return makeShortArray(t, length); default: abort(t); } } else { - return reinterpret_cast - (makeLocalReference(t, makeObjectArray(t, c, length))); + return makeObjectArray(t, c, length); } } +uint64_t +jvmNewArray(Thread* t, uintptr_t* arguments) +{ + jclass elementClass = reinterpret_cast(arguments[0]); + jint length = arguments[1]; + + return reinterpret_cast + (makeLocalReference + (t, makeNewArray(t, jclassVmClass(t, *elementClass), length))); +} + extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_NewArray)(Thread* t, jclass elementClass, jint length) { @@ -3215,8 +3218,41 @@ EXPORT(JVM_NewArray)(Thread* t, jclass elementClass, jint length) return reinterpret_cast(run(t, jvmNewArray, arguments)); } +uint64_t +jvmNewMultiArray(Thread* t, uintptr_t* arguments) +{ + jclass elementClass = reinterpret_cast(arguments[0]); + jintArray dimensions = reinterpret_cast(arguments[1]); + + THREAD_RUNTIME_ARRAY(t, int32_t, counts, intArrayLength(t, *dimensions)); + for (int i = intArrayLength(t, *dimensions) - 1; i >= 0; --i) { + RUNTIME_ARRAY_BODY(counts)[i] = intArrayBody(t, *dimensions, i); + if (UNLIKELY(RUNTIME_ARRAY_BODY(counts)[i] < 0)) { + throwNew(t, Machine::NegativeArraySizeExceptionType, "%d", + RUNTIME_ARRAY_BODY(counts)[i]); + return 0; + } + } + + object array = makeNewArray + (t, jclassVmClass(t, *elementClass), RUNTIME_ARRAY_BODY(counts)[0]); + PROTECT(t, array); + + populateMultiArray(t, array, RUNTIME_ARRAY_BODY(counts), 0, + intArrayLength(t, *dimensions)); + + return reinterpret_cast(makeLocalReference(t, array)); +} + extern "C" JNIEXPORT jobject JNICALL -EXPORT(JVM_NewMultiArray)(Thread*, jclass, jintArray) { abort(); } +EXPORT(JVM_NewMultiArray)(Thread* t, jclass elementClass, + jintArray dimensions) +{ + uintptr_t arguments[] = { reinterpret_cast(elementClass), + reinterpret_cast(dimensions) }; + + return reinterpret_cast(run(t, jvmNewMultiArray, arguments)); +} extern "C" JNIEXPORT jclass JNICALL EXPORT(JVM_GetCallerClass)(Thread* t, int target) @@ -4338,7 +4374,25 @@ EXPORT(JVM_Lseek)(jint fd, jlong offset, jint seek) } extern "C" JNIEXPORT jint JNICALL -EXPORT(JVM_SetLength)(jint, jlong) { abort(); } +EXPORT(JVM_SetLength)(jint fd, jlong length) +{ +#ifdef PLATFORM_WINDOWS + HANDLE h = reinterpret_cast(_get_osfhandle(fd)); + if (h == INVALID_HANDLE_VALUE) { + errno = EBADF; + return -1; + } + + if (SetEndOfFile(h, length)) { + return 0; + } else { + errno = EIO; + return -1; + } +#else + return ftruncate(fd, length); +#endif +} extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_Sync)(jint fd) diff --git a/src/machine.cpp b/src/machine.cpp index cc949c5ca6..6335ef8ad4 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -4210,6 +4210,37 @@ defineClass(Thread* t, object loader, const uint8_t* buffer, unsigned length) return c; } +void +populateMultiArray(Thread* t, object array, int32_t* counts, + unsigned index, unsigned dimensions) +{ + if (index + 1 == dimensions or counts[index] == 0) { + return; + } + + PROTECT(t, array); + + object spec = className(t, objectClass(t, array)); + PROTECT(t, spec); + + object elementSpec = makeByteArray(t, byteArrayLength(t, spec) - 1); + memcpy(&byteArrayBody(t, elementSpec, 0), + &byteArrayBody(t, spec, 1), + byteArrayLength(t, spec) - 1); + + object class_ = resolveClass + (t, classLoader(t, objectClass(t, array)), elementSpec); + PROTECT(t, class_); + + for (int32_t i = 0; i < counts[index]; ++i) { + object a = makeArray(t, counts[index + 1]); + setObjectClass(t, a, class_); + set(t, array, ArrayBody + (i * BytesPerWord), a); + + populateMultiArray(t, a, counts, index + 1, dimensions); + } +} + void noop() { } diff --git a/src/machine.h b/src/machine.h index e6c72da833..559b665d6f 100644 --- a/src/machine.h +++ b/src/machine.h @@ -3701,6 +3701,10 @@ unregisterNatives(Thread* t, object c) } } +void +populateMultiArray(Thread* t, object array, int32_t* counts, + unsigned index, unsigned dimensions); + object getCaller(Thread* t, unsigned target); diff --git a/src/process.h b/src/process.h index 27f7788a6b..45de6d975c 100644 --- a/src/process.h +++ b/src/process.h @@ -56,37 +56,6 @@ isSpecialMethod(Thread* t, object method, object class_) and isSuperclass(t, methodClass(t, method), class_); } -inline void -populateMultiArray(Thread* t, object array, int32_t* counts, - unsigned index, unsigned dimensions) -{ - if (index + 1 == dimensions or counts[index] == 0) { - return; - } - - PROTECT(t, array); - - object spec = className(t, objectClass(t, array)); - PROTECT(t, spec); - - object elementSpec = makeByteArray(t, byteArrayLength(t, spec) - 1); - memcpy(&byteArrayBody(t, elementSpec, 0), - &byteArrayBody(t, spec, 1), - byteArrayLength(t, spec) - 1); - - object class_ = resolveClass - (t, classLoader(t, objectClass(t, array)), elementSpec); - PROTECT(t, class_); - - for (int32_t i = 0; i < counts[index]; ++i) { - object a = makeArray(t, counts[index + 1]); - setObjectClass(t, a, class_); - set(t, array, ArrayBody + (i * BytesPerWord), a); - - populateMultiArray(t, a, counts, index + 1, dimensions); - } -} - void resolveNative(Thread* t, object method); From 3fd6af152fc1244dcb12008825db8af89b15e8ab Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 26 Mar 2011 11:45:33 -0600 Subject: [PATCH 045/117] fix Windows and GCC 3.4 builds --- src/classpath-openjdk.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index cc2074396c..09a1ed69bf 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -952,6 +952,10 @@ class ZipFile { Entry(int64_t entry): hash(0), start(0), next(0), entry(entry) { } + + Entry(): + hash(0), start(0), next(0), entry(0) + { } unsigned hash; const uint8_t* start; @@ -4383,7 +4387,14 @@ EXPORT(JVM_SetLength)(jint fd, jlong length) return -1; } - if (SetEndOfFile(h, length)) { + long high = length >> 32; + DWORD r = SetFilePointer(h, static_cast(length), &high, FILE_BEGIN); + if (r == 0xFFFFFFFF and GetLastError() != NO_ERROR) { + errno = EIO; + return -1; + } + + if (SetEndOfFile(h)) { return 0; } else { errno = EIO; @@ -4505,7 +4516,14 @@ EXPORT(JVM_SendTo)(jint, char*, int, extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_SocketAvailable)(jint socket, jint* count) { +#ifdef PLATFORM_WINDOWS + unsigned long c = *count; + int r = ioctlsocket(socket, FIONREAD, &c); + *count = c; + return r; +#else return ioctl(socket, FIONREAD, count) < 0 ? 0 : 1; +#endif } extern "C" JNIEXPORT jint JNICALL From d02d7c9846d09150095e9a6171af8281d7809e9c Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 26 Mar 2011 12:00:40 -0600 Subject: [PATCH 046/117] fix IllegalAccessException in LazyLoading test --- test/LazyLoading.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/LazyLoading.java b/test/LazyLoading.java index 83dd4bc82c..ace2ebf5d0 100644 --- a/test/LazyLoading.java +++ b/test/LazyLoading.java @@ -82,7 +82,7 @@ public class LazyLoading { } } - private static class Test { + public static class Test { public static void test() { doTest(); loadLazy = true; From 01b3f1cb93b35f73a839bd415f266abe5b163c96 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 26 Mar 2011 14:43:03 -0600 Subject: [PATCH 047/117] fix GCC 4.6 unused variable warnings --- src/compile.cpp | 2 +- src/heap.cpp | 4 ++-- src/x86.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index 2ecbad7fb9..0e71c7e239 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -6859,7 +6859,7 @@ compile(MyThread* t, Context* context) memset(RUNTIME_ARRAY_BODY(visited), 0, visitCount * sizeof(bool)); while (visitCount) { - bool progress = false; + bool progress UNUSED = false; for (unsigned i = 0; i < exceptionHandlerTableLength(t, eht); ++i) { c->restoreState(state); diff --git a/src/heap.cpp b/src/heap.cpp index c2474cf653..909eee40eb 100644 --- a/src/heap.cpp +++ b/src/heap.cpp @@ -1434,7 +1434,7 @@ visitDirtyFixies(Context* c, Fixie** p) while (*p) { Fixie* f = *p; - bool wasDirty = false; + bool wasDirty UNUSED = false; bool clean = true; uintptr_t* mask = f->mask(); @@ -1527,7 +1527,7 @@ void collect(Context* c, Segment::Map* map, unsigned start, unsigned end, bool* dirty, bool expectDirty UNUSED) { - bool wasDirty = false; + bool wasDirty UNUSED = false; for (Segment::Map::Iterator it(map, start, end); it.hasMore();) { wasDirty = true; if (map->child) { diff --git a/src/x86.cpp b/src/x86.cpp index 5c250f449a..cf5bca82a0 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -2865,7 +2865,7 @@ class MyArchitecture: public Assembler::Architecture { virtual void updateCall(UnaryOperation op, void* returnAddress, void* newTarget) { - bool assertAlignment; + bool assertAlignment UNUSED; switch (op) { case AlignedCall: op = Call; From 6bd9ec37356a38456dd8eef4a882abe6d9ce222b Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 26 Mar 2011 14:44:08 -0600 Subject: [PATCH 048/117] enable link time optimization when using GCC 4.6 or greater --- makefile | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/makefile b/makefile index d9921f3e3b..8d83a40982 100644 --- a/makefile +++ b/makefile @@ -354,9 +354,22 @@ ifeq ($(mode),stress-major) endif ifeq ($(mode),fast) optimization-cflags = -O3 -g3 -DNDEBUG + use-lto = true endif ifeq ($(mode),small) optimization-cflags = -Os -g3 -DNDEBUG + use-lto = true +endif + +ifeq ($(use-lto),true) +# 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 + lflags += $(optimization-cflags) + endif endif cflags += $(optimization-cflags) From 16a8777fd23b9eabf69cf6e7dfe7580bf63d9100 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 26 Mar 2011 18:20:45 -0600 Subject: [PATCH 049/117] override getResource(s) in SystemClassLoader OpenJDK's java.lang.ClassLoader.getResource makes use of sun.misc.Launcher to load bootstrap resources, which is not appropriate for the Avian build, so we override it to ensure we get the behavior we want. --- classpath/avian/SystemClassLoader.java | 42 ++++++++++++++++++++++++++ classpath/java/lang/ClassLoader.java | 2 +- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/classpath/avian/SystemClassLoader.java b/classpath/avian/SystemClassLoader.java index 6334f82916..defb9d490a 100644 --- a/classpath/avian/SystemClassLoader.java +++ b/classpath/avian/SystemClassLoader.java @@ -12,6 +12,7 @@ package avian; import java.net.URL; import java.net.MalformedURLException; +import java.io.IOException; import java.util.Collection; import java.util.Collections; import java.util.ArrayList; @@ -46,6 +47,47 @@ public class SystemClassLoader extends ClassLoader { return null; } + // OpenJDK's java.lang.ClassLoader.getResource makes use of + // sun.misc.Launcher to load bootstrap resources, which is not + // appropriate for the Avian build, so we override it to ensure we + // get the behavior we want. This implementation is the same as + // that of Avian's java.lang.ClassLoader.getResource. + public URL getResource(String path) { + URL url = null; + ClassLoader parent = getParent(); + if (parent != null) { + url = parent.getResource(path); + } + + if (url == null) { + url = findResource(path); + } + + return url; + } + + // As above, we override this method to avoid inappropriate behavior + // in OpenJDK's java.lang.ClassLoader.getResources. + public Enumeration getResources(String name) throws IOException { + Collection urls = new ArrayList(5); + + ClassLoader parent = getParent(); + if (parent != null) { + for (Enumeration e = parent.getResources(name); + e.hasMoreElements();) + { + urls.add(e.nextElement()); + } + } + + URL url = findResource(name); + if (url != null) { + urls.add(url); + } + + return Collections.enumeration(urls); + } + protected Enumeration findResources(String name) { Collection urls = new ArrayList(1); URL url = findResource(name); diff --git a/classpath/java/lang/ClassLoader.java b/classpath/java/lang/ClassLoader.java index b2ee0b7f75..e245e4c9f1 100644 --- a/classpath/java/lang/ClassLoader.java +++ b/classpath/java/lang/ClassLoader.java @@ -93,7 +93,7 @@ public abstract class ClassLoader { avian.Classes.link(c.vmClass, this); } - private ClassLoader getParent() { + public final ClassLoader getParent() { return parent; } From 89947f465512f0418f08e4db7cf6684c68ebbac8 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 26 Mar 2011 19:01:48 -0600 Subject: [PATCH 050/117] set default thread context classloader to app loader, not boot loader --- src/classpath-openjdk.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 09a1ed69bf..be6a0bbed9 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -305,7 +305,7 @@ class MyClasspath : public Classpath { setObjectClass(t, thread, type(t, Machine::ThreadType)); threadPriority(t, thread) = NormalPriority; threadGroup(t, thread) = group; - threadContextClassLoader(t, thread) = root(t, Machine::BootLoader); + threadContextClassLoader(t, thread) = root(t, Machine::AppLoader); PROTECT(t, thread); From 0f38673baacf733964748a1d1bc242a0e8bf8630 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 26 Mar 2011 19:55:23 -0600 Subject: [PATCH 051/117] fix line number and exception handler scope regression It turns out commit 31eb047 was too aggressive and led to incorrect calculation of line numbers for machine addresses, as well as potentially incorrect exception handler scope calculation. This fixes the regression. --- src/compile.cpp | 70 ++++++++++++++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 27 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index 0e71c7e239..e2ffb7c3d5 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -5876,32 +5876,46 @@ logCompile(MyThread* t, const void* code, unsigned size, const char* class_, } unsigned -resolveIp(MyThread* t, object code, unsigned ip) +resolveIp(MyThread* t, Context* context, object code, unsigned ip) { - switch (codeBody(t, code, ip)) { - case goto_: { - unsigned tmp = ip + 1; - return ip + codeReadInt16(t, code, tmp); - } - - case goto_w: { - unsigned tmp = ip + 1; - return ip + codeReadInt32(t, code, tmp); - } - - default: + if (context->visitTable[ip]) { return ip; + } else { + // Very rarely, we'll encounter an unreachable goto which is + // referred to by the exception handler table or line number + // table. This can be a problem if we need to determine the + // corresponding machine address for the bytecode instruction + // since we never generated any machine code for it. For now, we + // just follow the goto. The "proper" fix is probably to go ahead + // and generate machine code even though it's unreachable; that + // will protect us against unreachable instructions which aren't + // gotos as well. + switch (codeBody(t, code, ip)) { + case goto_: { + unsigned tmp = ip + 1; + return ip + codeReadInt16(t, code, tmp); + } + + case goto_w: { + unsigned tmp = ip + 1; + return ip + codeReadInt32(t, code, tmp); + } + + default: + return ip; + } } } object -translateExceptionHandlerTable(MyThread* t, Compiler* c, object method, - intptr_t start) +translateExceptionHandlerTable(MyThread* t, Context* context, intptr_t start) { - object oldTable = codeExceptionHandlerTable(t, methodCode(t, method)); + Compiler* c = context->compiler; + + object oldTable = codeExceptionHandlerTable + (t, methodCode(t, context->method)); if (oldTable) { - PROTECT(t, method); PROTECT(t, oldTable); unsigned length = exceptionHandlerTableLength(t, oldTable); @@ -5921,7 +5935,7 @@ translateExceptionHandlerTable(MyThread* t, Compiler* c, object method, intArrayBody(t, newIndex, i * 3) = c->machineIp (resolveIp - (t, methodCode(t, method), + (t, context, methodCode(t, context->method), exceptionHandlerStart(oldHandler)))->value() - start; intArrayBody(t, newIndex, (i * 3) + 1) @@ -5933,7 +5947,7 @@ translateExceptionHandlerTable(MyThread* t, Compiler* c, object method, object type; if (exceptionHandlerCatchType(oldHandler)) { type = resolveClassInPool - (t, method, exceptionHandlerCatchType(oldHandler) - 1); + (t, context->method, exceptionHandlerCatchType(oldHandler) - 1); } else { type = 0; } @@ -5948,11 +5962,10 @@ translateExceptionHandlerTable(MyThread* t, Compiler* c, object method, } object -translateLineNumberTable(MyThread* t, Compiler* c, object code, intptr_t start) +translateLineNumberTable(MyThread* t, Context* context, intptr_t start) { - object oldTable = codeLineNumberTable(t, code); + object oldTable = codeLineNumberTable(t, methodCode(t, context->method)); if (oldTable) { - PROTECT(t, code); PROTECT(t, oldTable); unsigned length = lineNumberTableLength(t, oldTable); @@ -5962,7 +5975,10 @@ translateLineNumberTable(MyThread* t, Compiler* c, object code, intptr_t start) LineNumber* newLine = lineNumberTableBody(t, newTable, i); lineNumberIp(newLine) - = c->machineIp(resolveIp(t, code, lineNumberIp(oldLine)))->value() + = context->compiler->machineIp + (resolveIp + (t, context, methodCode(t, context->method), lineNumberIp(oldLine))) + ->value() - start; lineNumberLine(newLine) = lineNumberLine(oldLine); @@ -6682,13 +6698,12 @@ finish(MyThread* t, FixedAllocator* allocator, Context* context) } { object newExceptionHandlerTable = translateExceptionHandlerTable - (t, c, context->method, reinterpret_cast(start)); + (t, context, reinterpret_cast(start)); PROTECT(t, newExceptionHandlerTable); object newLineNumberTable = translateLineNumberTable - (t, c, methodCode(t, context->method), - reinterpret_cast(start)); + (t, context, reinterpret_cast(start)); object code = methodCode(t, context->method); @@ -6866,7 +6881,8 @@ compile(MyThread* t, Context* context) ExceptionHandler* eh = exceptionHandlerTableBody(t, eht, i); unsigned start = resolveIp - (t, methodCode(t, context->method), exceptionHandlerStart(eh)); + (t, context, methodCode(t, context->method), + exceptionHandlerStart(eh)); if ((not RUNTIME_ARRAY_BODY(visited)[i]) and context->visitTable[start]) From d5ae053f114edca25095544fe029bb8889fd965b Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 26 Mar 2011 23:13:05 -0600 Subject: [PATCH 052/117] handle invokevirtual calls to non-virtual methods OpenJDK's sun.reflect.MethodAccessorGenerator can generate invokevirtual calls to private methods (which we normally consider non-virtual); we must compile them as non-virtual calls since they aren't in the vtable. --- src/compile.cpp | 54 ++++++++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index e2ffb7c3d5..89f39fe662 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -4890,33 +4890,41 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, if (LIKELY(target)) { assert(t, (methodFlags(t, target) & ACC_STATIC) == 0); - unsigned parameterFootprint = methodParameterFootprint(t, target); - - unsigned offset = ClassVtable - + (methodOffset(t, target) * BytesPerWord); - - Compiler::Operand* instance = c->peek(1, parameterFootprint - 1); - - unsigned rSize = resultSize(t, methodReturnCode(t, target)); - bool tailCall = isTailCall(t, code, ip, context->method, target); - Compiler::Operand* result = c->stackCall - (c->memory - (c->and_ - (BytesPerWord, c->constant(PointerMask, Compiler::IntegerType), - c->memory(instance, Compiler::ObjectType, 0, 0, 1)), - Compiler::ObjectType, offset, 0, 1), - tailCall ? Compiler::TailJump : 0, - frame->trace(0, 0), - rSize, - operandTypeForFieldCode(t, methodReturnCode(t, target)), - parameterFootprint); + if (LIKELY(methodVirtual(t, target))) { + unsigned parameterFootprint = methodParameterFootprint(t, target); - frame->pop(parameterFootprint); + unsigned offset = ClassVtable + + (methodOffset(t, target) * BytesPerWord); - if (rSize) { - pushReturnValue(t, frame, methodReturnCode(t, target), result); + Compiler::Operand* instance = c->peek(1, parameterFootprint - 1); + + unsigned rSize = resultSize(t, methodReturnCode(t, target)); + + Compiler::Operand* result = c->stackCall + (c->memory + (c->and_ + (BytesPerWord, c->constant(PointerMask, Compiler::IntegerType), + c->memory(instance, Compiler::ObjectType, 0, 0, 1)), + Compiler::ObjectType, offset, 0, 1), + tailCall ? Compiler::TailJump : 0, + frame->trace(0, 0), + rSize, + operandTypeForFieldCode(t, methodReturnCode(t, target)), + parameterFootprint); + + frame->pop(parameterFootprint); + + if (rSize) { + pushReturnValue(t, frame, methodReturnCode(t, target), result); + } + } else { + // OpenJDK generates invokevirtual calls to private methods + // (e.g. readObject and writeObject for serialization), so + // we must handle such cases here. + + compileDirectInvoke(t, frame, target, tailCall); } } else { PROTECT(t, reference); From ad79bbcbd5fa6e9eea5e0a463691dc99e638182f Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 26 Mar 2011 23:21:37 -0600 Subject: [PATCH 053/117] update class loader map when creating new array class This ensures that we don't create redundant array classes later. --- src/machine.cpp | 51 +++++++++++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/src/machine.cpp b/src/machine.cpp index 6335ef8ad4..3cd14aa5ad 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1845,6 +1845,23 @@ makeArrayClass(Thread* t, object loader, unsigned dimensions, object spec, return c; } +void +saveLoadedClass(Thread* t, object loader, object c) +{ + PROTECT(t, loader); + PROTECT(t, c); + + ACQUIRE(t, t->m->classLock); + + if (classLoaderMap(t, loader) == 0) { + object map = makeHashMap(t, 0, 0); + set(t, loader, ClassLoaderMap, map); + } + + hashMapInsert + (t, classLoaderMap(t, loader), className(t, c), c, byteArrayHash); +} + object makeArrayClass(Thread* t, object loader, object spec, bool throw_, Machine::Type throwType) @@ -1895,10 +1912,21 @@ makeArrayClass(Thread* t, object loader, object spec, bool throw_, PROTECT(t, elementClass); - object class_ = findLoadedClass(t, classLoader(t, elementClass), spec); + ACQUIRE(t, t->m->classLock); - return class_ ? class_ : makeArrayClass + object class_ = findLoadedClass(t, classLoader(t, elementClass), spec); + if (class_) { + return class_; + } + + class_ = makeArrayClass (t, classLoader(t, elementClass), dimensions, spec, elementClass); + + PROTECT(t, class_); + + saveLoadedClass(t, classLoader(t, elementClass), class_); + + return class_; } object @@ -3500,15 +3528,7 @@ resolveClass(Thread* t, object loader, object spec, bool throw_, if (LIKELY(c)) { PROTECT(t, c); - ACQUIRE(t, t->m->classLock); - - if (classLoaderMap(t, loader) == 0) { - object map = makeHashMap(t, 0, 0); - set(t, loader, ClassLoaderMap, map); - } - - hashMapInsert - (t, classLoaderMap(t, loader), spec, c, byteArrayHash); + saveLoadedClass(t, loader, c); } else if (throw_) { throwNew(t, throwType, "%s", &byteArrayBody(t, spec, 0)); } @@ -4196,15 +4216,8 @@ defineClass(Thread* t, object loader, const uint8_t* buffer, unsigned length) if (c) { PROTECT(t, c); - ACQUIRE(t, t->m->classLock); - if (classLoaderMap(t, loader) == 0) { - object map = makeHashMap(t, 0, 0); - set(t, loader, ClassLoaderMap, map); - } - - hashMapInsert - (t, classLoaderMap(t, loader), className(t, c), c, byteArrayHash); + saveLoadedClass(t, loader, c); } return c; From ba028b86bff87b549fbb4eaebae8ac8bb6e82c60 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 26 Mar 2011 23:24:05 -0600 Subject: [PATCH 054/117] set java.vm.vendor system property during startup --- src/classpath-openjdk.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index be6a0bbed9..065a2090ca 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -2630,6 +2630,9 @@ jvmInitProperties(Thread* t, uintptr_t* arguments) local::setProperty(t, method, *properties, "java.protocol.handler.pkgs", "avian"); + local::setProperty(t, method, *properties, "java.vm.vendor", + "Avian Contributors"); + local::setProperty (t, method, *properties, "java.home", static_cast(t->m->classpath)->javaHome); From 686cbc3637ce8a9c586b7654d2ecf3340004cdbf Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 26 Mar 2011 23:24:48 -0600 Subject: [PATCH 055/117] implement JVM_ResolveClass This just reuses code in avian.Classes which was formerly only used in the Avian classpath build. --- classpath/avian/Classes.java | 8 ++++---- makefile | 2 ++ src/builtin.cpp | 25 +++++++++++++++++++++++++ src/classpath-avian.cpp | 25 ------------------------- src/classpath-openjdk.cpp | 21 ++++++++++++++++++++- 5 files changed, 51 insertions(+), 30 deletions(-) diff --git a/classpath/avian/Classes.java b/classpath/avian/Classes.java index 3e18f4c0df..b2fc407d90 100644 --- a/classpath/avian/Classes.java +++ b/classpath/avian/Classes.java @@ -53,7 +53,7 @@ public class Classes { return c; } catch (ClassNotFoundException e) { NoClassDefFoundError error = new NoClassDefFoundError - (new String(nameBytes, offset, length, false)); + (new String(nameBytes, offset, length)); error.initCause(e); throw error; } @@ -96,7 +96,7 @@ public class Classes { case 's': { byte[] data = (byte[]) Singleton.getObject(pool, read2(in) - 1); - return new String(data, 0, data.length - 1, false); + return new String(data, 0, data.length - 1); } case 'e': { @@ -106,7 +106,7 @@ public class Classes { return Enum.valueOf (SystemClassLoader.getClass (loadVMClass(loader, typeName, 1, typeName.length - 3)), - new String(name, 0, name.length - 1, false)); + new String(name, 0, name.length - 1)); } case 'c':{ @@ -143,7 +143,7 @@ public class Classes { for (int i = 2; i < annotation.length; i += 2) { byte[] name = (byte[]) Singleton.getObject(pool, read2(in) - 1); - annotation[i] = new String(name, 0, name.length - 1, false); + annotation[i] = new String(name, 0, name.length - 1); annotation[i + 1] = parseAnnotationValue(loader, pool, in); } diff --git a/makefile b/makefile index 8d83a40982..0b5aa693d2 100644 --- a/makefile +++ b/makefile @@ -552,12 +552,14 @@ ifneq ($(classpath),avian) $(classpath-src)/avian/Callback.java \ $(classpath-src)/avian/CallbackReceiver.java \ $(classpath-src)/avian/ClassAddendum.java \ + $(classpath-src)/avian/Classes.java \ $(classpath-src)/avian/ConstantPool.java \ $(classpath-src)/avian/Continuations.java \ $(classpath-src)/avian/FieldAddendum.java \ $(classpath-src)/avian/IncompatibleContinuationException.java \ $(classpath-src)/avian/Machine.java \ $(classpath-src)/avian/MethodAddendum.java \ + $(classpath-src)/avian/Singleton.java \ $(classpath-src)/avian/Stream.java \ $(classpath-src)/avian/SystemClassLoader.java \ $(classpath-src)/avian/VMClass.java \ diff --git a/src/builtin.cpp b/src/builtin.cpp index 41a6fda597..06b45f0646 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -48,6 +48,31 @@ resolveSystemClassThrow(Thread* t, object loader, object spec) } // namespace +extern "C" JNIEXPORT void JNICALL +Avian_avian_Classes_acquireClassLock +(Thread* t, object, uintptr_t*) +{ + acquire(t, t->m->classLock); +} + +extern "C" JNIEXPORT void JNICALL +Avian_avian_Classes_releaseClassLock +(Thread* t, object, uintptr_t*) +{ + release(t, t->m->classLock); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_avian_Classes_resolveVMClass +(Thread* t, object, uintptr_t* arguments) +{ + object loader = reinterpret_cast(arguments[0]); + object spec = reinterpret_cast(arguments[1]); + + return reinterpret_cast + (resolveClass(t, loader, spec, true, Machine::ClassNotFoundExceptionType)); +} + extern "C" JNIEXPORT int64_t JNICALL Avian_avian_SystemClassLoader_findLoadedVMClass (Thread* t, object, uintptr_t* arguments) diff --git a/src/classpath-avian.cpp b/src/classpath-avian.cpp index c719b89545..af1e337fcc 100644 --- a/src/classpath-avian.cpp +++ b/src/classpath-avian.cpp @@ -589,31 +589,6 @@ Avian_java_lang_Thread_yield t->m->system->yield(); } -extern "C" JNIEXPORT void JNICALL -Avian_avian_Classes_acquireClassLock -(Thread* t, object, uintptr_t*) -{ - acquire(t, t->m->classLock); -} - -extern "C" JNIEXPORT void JNICALL -Avian_avian_Classes_releaseClassLock -(Thread* t, object, uintptr_t*) -{ - release(t, t->m->classLock); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_avian_Classes_resolveVMClass -(Thread* t, object, uintptr_t* arguments) -{ - object loader = reinterpret_cast(arguments[0]); - object spec = reinterpret_cast(arguments[1]); - - return reinterpret_cast - (resolveClass(t, loader, spec, true, Machine::ClassNotFoundExceptionType)); -} - extern "C" JNIEXPORT int64_t JNICALL Avian_avian_Classes_primitiveClass (Thread* t, object, uintptr_t* arguments) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 065a2090ca..46fbd7e326 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -3312,8 +3312,27 @@ EXPORT(JVM_FindPrimitiveClass)(Thread* t, const char* name) } } +uint64_t +jvmResolveClass(Thread* t, uintptr_t* arguments) +{ + jclass c = reinterpret_cast(arguments[0]); + + object method = resolveMethod + (t, root(t, Machine::BootLoader), "avian/Classes", "link", + "(Lavian/VMClass;)V"); + + t->m->processor->invoke(t, method, 0, jclassVmClass(t, *c)); + + return 1; +} + extern "C" JNIEXPORT void JNICALL -EXPORT(JVM_ResolveClass)(Thread*, jclass) { abort(); } +EXPORT(JVM_ResolveClass)(Thread* t, jclass c) +{ + uintptr_t arguments[] = { reinterpret_cast(c) }; + + run(t, jvmResolveClass, arguments); +} uint64_t jvmFindClassFromClassLoader(Thread* t, uintptr_t* arguments) From d16bf5763441bcb34b0dc6a884e39edbd6841edf Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 27 Mar 2011 14:12:41 -0600 Subject: [PATCH 056/117] implement JVM_MaxObjectInspectionAge stub and Unsafe.getShort --- src/classpath-openjdk.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 46fbd7e326..13f58186ee 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -2115,6 +2115,16 @@ Avian_sun_misc_Unsafe_putObject set(t, o, offset, reinterpret_cast(value)); } +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_getShort__Ljava_lang_Object_2J +(Thread*, object, uintptr_t* arguments) +{ + object o = reinterpret_cast(arguments[1]); + int64_t offset; memcpy(&offset, arguments + 2, 8); + + return cast(o, offset); +} + extern "C" JNIEXPORT int64_t JNICALL Avian_sun_misc_Unsafe_getInt__Ljava_lang_Object_2J (Thread*, object, uintptr_t* arguments) @@ -2711,7 +2721,10 @@ EXPORT(JVM_GC)() } extern "C" JNIEXPORT jlong JNICALL -EXPORT(JVM_MaxObjectInspectionAge)(void) { abort(); } +EXPORT(JVM_MaxObjectInspectionAge)(void) +{ + return 0; +} extern "C" JNIEXPORT void JNICALL EXPORT(JVM_TraceInstructions)(jboolean) { abort(); } From 8283e1da46eb8f079570c7e8793ba778d78c95e3 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 27 Mar 2011 14:13:36 -0600 Subject: [PATCH 057/117] ignore instances of DelegatingClassLoader in JVM_LatestUserDefinedLoader --- src/classpath-openjdk.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 13f58186ee..544d1c47a7 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -3138,7 +3138,13 @@ EXPORT(JVM_LatestUserDefinedLoader)(Thread* t) virtual bool visit(Processor::StackWalker* walker) { object loader = classLoader(t, methodClass(t, walker->method())); - if (loader and loader != root(t, Machine::BootLoader)) { + if (loader + and loader != root(t, Machine::BootLoader) + and strcmp + (&byteArrayBody(t, className(t, objectClass(t, loader)), 0), + reinterpret_cast + ("sun/reflect/DelegatingClassLoader"))) + { this->loader = loader; return false; } else { From c75cf7ebb69dbda4de94ff40e1122f088487beb1 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 27 Mar 2011 14:15:05 -0600 Subject: [PATCH 058/117] release all resources in resetFrame Code including subroutines and conditionals can result in frame and register resources being held by values which aren't in scope when resetFrame is called, so we need to clean them up after cleaning the in-scope values. --- src/compiler.cpp | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/src/compiler.cpp b/src/compiler.cpp index a5f6aeb373..8ef83acad2 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -218,7 +218,8 @@ class LogicalInstruction { class Resource { public: Resource(bool reserved = false): - value(0), site(0), freezeCount(0), referenceCount(0), reserved(reserved) + value(0), site(0), previousAcquired(0), nextAcquired(0), freezeCount(0), + referenceCount(0), reserved(reserved) { } virtual void freeze(Context*, Value*) = 0; @@ -229,6 +230,8 @@ class Resource { Value* value; Site* site; + Resource* previousAcquired; + Resource* nextAcquired; uint8_t freezeCount; uint8_t referenceCount; bool reserved; @@ -379,6 +382,7 @@ class Context { (static_cast (zone->allocate(sizeof(RegisterResource) * registerLimit))), frameResources(0), + acquiredResources(0), firstConstant(0), lastConstant(0), machineCode(0), @@ -426,6 +430,7 @@ class Context { uint8_t floatRegisterLimit; RegisterResource* registerResources; FrameResource* frameResources; + Resource* acquiredResources; ConstantPoolNode* firstConstant; ConstantPoolNode* lastConstant; uint8_t* machineCode; @@ -2586,6 +2591,12 @@ acquire(Context* c, Resource* resource, Value* value, Site* site) steal(c, resource, value); } + if (c->acquiredResources) { + c->acquiredResources->previousAcquired = resource; + resource->nextAcquired = c->acquiredResources; + } + c->acquiredResources = resource; + resource->value = value; resource->site = site; } @@ -2605,6 +2616,21 @@ release(Context* c, Resource* resource, Value* value UNUSED, Site* site UNUSED) assert(c, buddies(resource->value, value)); assert(c, site == resource->site); + + Resource* next = resource->nextAcquired; + if (next) { + next->previousAcquired = resource->previousAcquired; + resource->nextAcquired = 0; + } + + Resource* previous = resource->previousAcquired; + if (previous) { + previous->nextAcquired = next; + resource->previousAcquired = 0; + } else { + assert(c, c->acquiredResources == resource); + c->acquiredResources = next; + } resource->value = 0; resource->site = 0; @@ -5527,6 +5553,15 @@ resetFrame(Context* c, Event* e) FrameIterator::Element el = it.next(c); clearSites(c, el.value); } + + for (Resource* r = c->acquiredResources; r;) { + Resource* next = r->nextAcquired; + Value* v = r->value; + if (v) { + clearSites(c, v); + } + r = next; + } } void From 62e10cf992b91b3b2f15ac912fc10e8a88afda0f Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 27 Mar 2011 20:22:59 -0600 Subject: [PATCH 059/117] return only non-negative values from takeHash Some broken code implicitly relies on System.identityHashCode always returning a non-negative number (e.g. old versions of com/sun/xml/bind/v2/util/CollisionCheckStack.hash). --- src/machine.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/machine.h b/src/machine.h index 559b665d6f..c73a11d0b3 100644 --- a/src/machine.h +++ b/src/machine.h @@ -2260,7 +2260,11 @@ markHashTaken(Thread* t, object o) inline uint32_t takeHash(Thread*, object o) { - return reinterpret_cast(o) / BytesPerWord; + // some broken code implicitly relies on System.identityHashCode + // always returning a non-negative number (e.g. old versions of + // com/sun/xml/bind/v2/util/CollisionCheckStack.hash), hence the "& + // 0x7FFFFFFF": + return (reinterpret_cast(o) / BytesPerWord) & 0x7FFFFFFF; } inline uint32_t From 56e832d3e8463fada55c8ae7529730cfa87e9526 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 27 Mar 2011 20:25:47 -0600 Subject: [PATCH 060/117] fix JVM_GetArrayElement and JVM_SetArrayElement The old versions only handled object arrays properly, but they need to handle primitive arrays as well. --- src/classpath-openjdk.cpp | 87 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 84 insertions(+), 3 deletions(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 544d1c47a7..c58472c065 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -3173,12 +3173,62 @@ EXPORT(JVM_GetArrayLength)(Thread* t, jobject array) return cast(*array, BytesPerWord); } +uint64_t +jvmGetArrayElement(Thread* t, uintptr_t* arguments) +{ + jobject array = reinterpret_cast(arguments[0]); + jint index = arguments[1]; + + switch (byteArrayBody(t, className(t, objectClass(t, *array)), 1)) { + case 'Z': + return reinterpret_cast + (makeLocalReference + (t, makeBoolean(t, cast(*array, ArrayBody + index)))); + case 'B': + return reinterpret_cast + (makeLocalReference + (t, makeByte(t, cast(*array, ArrayBody + index)))); + case 'C': + return reinterpret_cast + (makeLocalReference + (t, makeChar(t, cast(*array, ArrayBody + (index * 2))))); + case 'S': + return reinterpret_cast + (makeLocalReference + (t, makeShort(t, cast(*array, ArrayBody + (index * 2))))); + case 'I': + return reinterpret_cast + (makeLocalReference + (t, makeInt(t, cast(*array, ArrayBody + (index * 4))))); + case 'F': + return reinterpret_cast + (makeLocalReference + (t, makeFloat(t, cast(*array, ArrayBody + (index * 4))))); + case 'J': + return reinterpret_cast + (makeLocalReference + (t, makeLong(t, cast(*array, ArrayBody + (index * 8))))); + case 'D': + return reinterpret_cast + (makeLocalReference + (t, makeDouble(t, cast(*array, ArrayBody + (index * 8))))); + case 'L': + case '[': + return reinterpret_cast + (makeLocalReference + (t, cast(*array, ArrayBody + (index * BytesPerWord)))); + default: + abort(t); + } +} + extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_GetArrayElement)(Thread* t, jobject array, jint index) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(array), + index }; - return makeLocalReference(t, objectArrayBody(t, *array, index)); + return reinterpret_cast(run(t, jvmGetArrayElement, arguments)); } extern "C" JNIEXPORT jvalue JNICALL @@ -3190,7 +3240,38 @@ EXPORT(JVM_SetArrayElement)(Thread* t, jobject array, jint index, { ENTER(t, Thread::ActiveState); - set(t, *array, ArrayBody + (index * BytesPerWord), (value ? *value : 0)); + switch (byteArrayBody(t, className(t, objectClass(t, *array)), 1)) { + case 'Z': + cast(*array, ArrayBody + index) = booleanValue(t, *value); + break; + case 'B': + cast(*array, ArrayBody + index) = byteValue(t, *value); + break; + case 'C': + cast(*array, ArrayBody + (index * 2)) = charValue(t, *value); + break; + case 'S': + cast(*array, ArrayBody + (index * 2)) = shortValue(t, *value); + break; + case 'I': + cast(*array, ArrayBody + (index * 4)) = intValue(t, *value); + break; + case 'F': + cast(*array, ArrayBody + (index * 4)) = floatValue(t, *value); + break; + case 'J': + cast(*array, ArrayBody + (index * 8)) = longValue(t, *value); + break; + case 'D': + cast(*array, ArrayBody + (index * 8)) = doubleValue(t, *value); + break; + case 'L': + case '[': + set(t, *array, ArrayBody + (index * BytesPerWord), (value ? *value : 0)); + break; + default: + abort(t); + } } extern "C" JNIEXPORT void JNICALL From 9fe41b2afc09c3500f050b96be368095a6b23802 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 27 Mar 2011 20:29:31 -0600 Subject: [PATCH 061/117] only return declared interfaces from Class.getInterfaces The result of Class.getInterfaces should not include interfaces declared to be implemented/extended by superclasses/superinterfaces, only those declared by the class itself. This is important because it influences how java.io.ObjectStreamClass calculates serial version IDs. --- classpath/avian/ClassAddendum.java | 4 +++- src/classpath-openjdk.cpp | 33 +++++++++++++++--------------- src/machine.cpp | 19 ++++++++++++++--- 3 files changed, 35 insertions(+), 21 deletions(-) diff --git a/classpath/avian/ClassAddendum.java b/classpath/avian/ClassAddendum.java index 4382e7f717..1719addfa4 100644 --- a/classpath/avian/ClassAddendum.java +++ b/classpath/avian/ClassAddendum.java @@ -10,4 +10,6 @@ package avian; -public class ClassAddendum extends Addendum { } +public class ClassAddendum extends Addendum { + public Object[] interfaceTable; +} diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index c58472c065..6769fc1666 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -3553,28 +3553,27 @@ jvmGetClassInterfaces(Thread* t, uintptr_t* arguments) { jclass c = reinterpret_cast(arguments[0]); - object table = classInterfaceTable(t, jclassVmClass(t, *c)); - if (table) { - PROTECT(t, table); + object addendum = classAddendum(t, jclassVmClass(t, *c)); + if (addendum) { + object table = classAddendumInterfaceTable(t, addendum); + if (table) { + PROTECT(t, table); - unsigned stride = - (classFlags(t, jclassVmClass(t, *c)) & ACC_INTERFACE) == 0 ? 2 : 1; + object array = makeObjectArray(t, arrayLength(t, table)); + PROTECT(t, array); - object array = makeObjectArray - (t, type(t, Machine::JclassType), arrayLength(t, table) / stride); - PROTECT(t, array); + for (unsigned i = 0; i < arrayLength(t, table); ++i) { + object c = getJClass(t, arrayBody(t, table, i)); + set(t, array, ArrayBody + (i * BytesPerWord), c); + } - for (unsigned i = 0; i < objectArrayLength(t, array); ++i) { - object interface = getJClass(t, arrayBody(t, table, i * stride)); - set(t, array, ArrayBody + (i * BytesPerWord), interface); + return reinterpret_cast(makeLocalReference(t, array)); } - - return reinterpret_cast(makeLocalReference(t, array)); - } else { - return reinterpret_cast - (makeLocalReference - (t, makeObjectArray(t, type(t, Machine::JclassType), 0))); } + + return reinterpret_cast + (makeLocalReference + (t, makeObjectArray(t, type(t, Machine::JclassType), 0))); } extern "C" JNIEXPORT jobjectArray JNICALL diff --git a/src/machine.cpp b/src/machine.cpp index 3cd14aa5ad..94117cef1e 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -986,6 +986,17 @@ parseInterfaceTable(Thread* t, Stream& s, object class_, object pool, } unsigned count = s.read2(); + object table = 0; + PROTECT(t, table); + + if (count) { + table = makeArray(t, count); + if (classAddendum(t, class_) == 0) { + object addendum = makeClassAddendum(t, pool, 0, 0, table); + set(t, class_, ClassAddendum, addendum); + } + } + for (unsigned i = 0; i < count; ++i) { object name = referenceName(t, singletonObject(t, pool, s.read2() - 1)); PROTECT(t, name); @@ -995,6 +1006,8 @@ parseInterfaceTable(Thread* t, Stream& s, object class_, object pool, PROTECT(t, interface); + set(t, table, ArrayBody + (i * BytesPerWord), interface); + hashMapInsertMaybe(t, map, name, interface, byteArrayHash, byteArrayEqual); addInterfaces(t, interface, map); @@ -1696,7 +1709,7 @@ parseAttributeTable(Thread* t, Stream& s, object class_, object pool) PROTECT(t, class_); PROTECT(t, pool); - object addendum = 0; + object addendum = classAddendum(t, class_); PROTECT(t, addendum); unsigned attributeCount = s.read2(); @@ -1712,7 +1725,7 @@ parseAttributeTable(Thread* t, Stream& s, object class_, object pool) &byteArrayBody(t, name, 0)) == 0) { if (addendum == 0) { - addendum = makeClassAddendum(t, pool, 0, 0); + addendum = makeClassAddendum(t, pool, 0, 0, 0); } set(t, addendum, AddendumSignature, @@ -1722,7 +1735,7 @@ parseAttributeTable(Thread* t, Stream& s, object class_, object pool) &byteArrayBody(t, name, 0)) == 0) { if (addendum == 0) { - addendum = makeClassAddendum(t, pool, 0, 0); + addendum = makeClassAddendum(t, pool, 0, 0, 0); } object body = makeByteArray(t, length); From 3e92f18ab0bc0d0b103aca041eb13585142f1812 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 27 Mar 2011 21:15:54 -0600 Subject: [PATCH 062/117] remove redundant conditional from resetFrame --- src/compiler.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/compiler.cpp b/src/compiler.cpp index 8ef83acad2..126f8a9d72 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -5556,10 +5556,7 @@ resetFrame(Context* c, Event* e) for (Resource* r = c->acquiredResources; r;) { Resource* next = r->nextAcquired; - Value* v = r->value; - if (v) { - clearSites(c, v); - } + clearSites(c, r->value); r = next; } } From 572f2d81eb4771b86066647aff05524e63929894 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 28 Mar 2011 08:54:37 -0600 Subject: [PATCH 063/117] handle case where value has acquired more than one resource in resetFrame --- src/compiler.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/compiler.cpp b/src/compiler.cpp index 126f8a9d72..c61bd223ad 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -5554,10 +5554,8 @@ resetFrame(Context* c, Event* e) clearSites(c, el.value); } - for (Resource* r = c->acquiredResources; r;) { - Resource* next = r->nextAcquired; - clearSites(c, r->value); - r = next; + while (c->acquiredResources) { + clearSites(c, c->acquiredResources->value); } } From 6506760dd9ef3e143bcab2ce819d7ad2535fd106 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 28 Mar 2011 08:55:20 -0600 Subject: [PATCH 064/117] implement Unsafe.putByte --- src/classpath-openjdk.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 6769fc1666..87536f7509 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -2193,6 +2193,17 @@ Avian_sun_misc_Unsafe_getLongVolatile return result; } +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_putByte__Ljava_lang_Object_2JB +(Thread*, object, uintptr_t* arguments) +{ + object o = reinterpret_cast(arguments[1]); + int64_t offset; memcpy(&offset, arguments + 2, 8); + int8_t value = arguments[4]; + + cast(o, offset) = value; +} + extern "C" JNIEXPORT void JNICALL Avian_sun_misc_Unsafe_putInt__Ljava_lang_Object_2JI (Thread*, object, uintptr_t* arguments) From 916e6787de58c8b46e8bc169f161675cf0b427a8 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 31 Mar 2011 18:58:59 -0600 Subject: [PATCH 065/117] set Thread.blocker during thread construction This avoids an NPE in Thread.blockedOn. --- src/classpath-openjdk.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 87536f7509..b2afce9437 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -309,6 +309,9 @@ class MyClasspath : public Classpath { PROTECT(t, thread); + object blockerLock = makeJobject(t); + set(t, thread, ThreadBlockerLock, blockerLock); + const unsigned BufferSize = 256; char buffer[BufferSize]; unsigned length = vm::snprintf(buffer, BufferSize, "Thread-%p", thread); From 384682431a4ccdde6cd79e3b0675679ab230f9db Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 31 Mar 2011 19:00:42 -0600 Subject: [PATCH 066/117] implement JVM_GetSystemPackages stub --- src/classpath-openjdk.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index b2afce9437..3f93dab966 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -3128,8 +3128,21 @@ EXPORT(JVM_GetSystemPackage)(Thread*, jstring) return 0; } +uint64_t +jvmGetSystemPackages(Thread* t, uintptr_t*) +{ + return reinterpret_cast + (makeLocalReference + (t, makeObjectArray + (t, resolveClass + (t, root(t, Machine::BootLoader), "java/lang/Package"), 0))); +} + extern "C" JNIEXPORT jobjectArray JNICALL -EXPORT(JVM_GetSystemPackages)(Thread*) { abort(); } +EXPORT(JVM_GetSystemPackages)(Thread* t) +{ + return reinterpret_cast(run(t, jvmGetSystemPackages, 0)); +} extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_AllocateNewObject)(Thread*, jobject, jclass, From 8d9412c1e85fece0c3854b78a5c1dc57d9da6c2a Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 31 Mar 2011 19:02:03 -0600 Subject: [PATCH 067/117] remove redundant statement in parseUtf8 VM heap allocated memory is already zero'd out, so there's no need to explicitly end strings with a null character. --- src/machine.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/machine.cpp b/src/machine.cpp index 94117cef1e..4b50be2011 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -758,7 +758,6 @@ parseUtf8(Thread* t, Stream& s, unsigned length) value = v; } - byteArrayBody(t, value, vi) = 0; return value; } From 1c7abe782d9a35969b549b157e51b39911072bde Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 31 Mar 2011 19:16:57 -0600 Subject: [PATCH 068/117] specify valid code source for system classes This enables use of a class's protection domain to determine what JAR or directory it came from. --- classpath/avian/OpenJDK.java | 18 +++++++- classpath/avian/VMClass.java | 3 +- classpath/java/security/CodeSource.java | 15 ++++++- classpath/java/security/cert/Certificate.java | 13 ++++++ src/classpath-openjdk.cpp | 17 ++++--- src/compile.cpp | 4 +- src/finder.cpp | 45 ++++++++++++++++++- src/finder.h | 1 + src/interpret.cpp | 2 +- src/machine.cpp | 19 +++++++- 10 files changed, 120 insertions(+), 17 deletions(-) create mode 100644 classpath/java/security/cert/Certificate.java diff --git a/classpath/avian/OpenJDK.java b/classpath/avian/OpenJDK.java index 877a7c2289..dcddbc0f67 100644 --- a/classpath/avian/OpenJDK.java +++ b/classpath/avian/OpenJDK.java @@ -10,14 +10,28 @@ package avian; +import java.net.URL; +import java.net.MalformedURLException; +import java.security.CodeSource; import java.security.AllPermission; import java.security.Permissions; import java.security.ProtectionDomain; +import java.security.cert.Certificate; public class OpenJDK { - public static ProtectionDomain getProtectionDomain() { + public static ProtectionDomain getProtectionDomain(VMClass c) { + CodeSource source = null; + if (c.source != null) { + try { + source = new CodeSource + (new URL(new String(c.source, 0, c.source.length - 1)), + (Certificate[]) null); + } catch (MalformedURLException ignored) { } + } + Permissions p = new Permissions(); p.add(new AllPermission()); - return new ProtectionDomain(null, p); + + return new ProtectionDomain(source, p); } } diff --git a/classpath/avian/VMClass.java b/classpath/avian/VMClass.java index b32ff7f689..5a3fdc662f 100644 --- a/classpath/avian/VMClass.java +++ b/classpath/avian/VMClass.java @@ -25,7 +25,8 @@ public class VMClass { public VMMethod[] virtualTable; public VMField[] fieldTable; public VMMethod[] methodTable; - public avian.ClassAddendum addendum; + public ClassAddendum addendum; public Object staticTable; public ClassLoader loader; + public byte[] source; } diff --git a/classpath/java/security/CodeSource.java b/classpath/java/security/CodeSource.java index 030597fa22..296f38c128 100644 --- a/classpath/java/security/CodeSource.java +++ b/classpath/java/security/CodeSource.java @@ -10,4 +10,17 @@ package java.security; -public class CodeSource { } +import java.net.URL; +import java.security.cert.Certificate; + +public class CodeSource { + private final URL url; + + public CodeSource(URL url, Certificate[] certificates) { + this.url = url; + } + + public URL getLocation() { + return url; + } +} diff --git a/classpath/java/security/cert/Certificate.java b/classpath/java/security/cert/Certificate.java new file mode 100644 index 0000000000..8b32abb2e4 --- /dev/null +++ b/classpath/java/security/cert/Certificate.java @@ -0,0 +1,13 @@ +/* Copyright (c) 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. */ + +package java.security.cert; + +public abstract class Certificate { } diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 3f93dab966..89fab1ff16 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -3667,22 +3667,25 @@ EXPORT(JVM_SetClassSigners)(Thread* t, jclass c, jobjectArray signers) } uint64_t -jvmGetProtectionDomain(Thread* t, uintptr_t*) +jvmGetProtectionDomain(Thread* t, uintptr_t* arguments) { - object openJDK = resolveClass - (t, root(t, Machine::BootLoader), "avian/OpenJDK"); + jclass c = reinterpret_cast(arguments[0]); object method = resolveMethod - (t, openJDK, "getProtectionDomain", "()Ljava/security/ProtectionDomain;"); + (t, root(t, Machine::BootLoader), "avian/OpenJDK", "getProtectionDomain", + "(Lavian/VMClass;)Ljava/security/ProtectionDomain;"); return reinterpret_cast - (makeLocalReference(t, t->m->processor->invoke(t, method, 0))); + (makeLocalReference + (t, t->m->processor->invoke(t, method, 0, jclassVmClass(t, *c)))); } extern "C" JNIEXPORT jobject JNICALL -EXPORT(JVM_GetProtectionDomain)(Thread* t, jclass) +EXPORT(JVM_GetProtectionDomain)(Thread* t, jclass c) { - return reinterpret_cast(run(t, jvmGetProtectionDomain, 0)); + uintptr_t arguments[] = { reinterpret_cast(c) }; + + return reinterpret_cast(run(t, jvmGetProtectionDomain, arguments)); } extern "C" JNIEXPORT void JNICALL diff --git a/src/compile.cpp b/src/compile.cpp index 89f39fe662..b80b589f9e 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -8234,8 +8234,8 @@ class MyProcessor: public Processor { { return vm::makeClass (t, flags, vmFlags, fixedSize, arrayElementSize, arrayDimensions, - 0, objectMask, name, sourceFile, super, interfaceTable, - virtualTable, fieldTable, methodTable, staticTable, addendum, loader, + 0, objectMask, name, sourceFile, super, interfaceTable, virtualTable, + fieldTable, methodTable, staticTable, addendum, loader, 0, vtableLength); } diff --git a/src/finder.cpp b/src/finder.cpp index c144d0fed6..62474040d9 100644 --- a/src/finder.cpp +++ b/src/finder.cpp @@ -32,6 +32,17 @@ append(Allocator* allocator, const char* a, const char* b, const char* c) return p; } +const char* +append(Allocator* allocator, const char* a, const char* b) +{ + unsigned al = strlen(a); + unsigned bl = strlen(b); + char* p = static_cast(allocator->allocate((al + bl) + 1)); + memcpy(p, a, al); + memcpy(p + al, b, bl + 1); + return p; +} + const char* copy(Allocator* allocator, const char* a) { @@ -56,6 +67,7 @@ class Element { virtual System::FileType stat(const char* name, unsigned* length, bool tryDirectory) = 0; virtual const char* urlPrefix() = 0; + virtual const char* sourceUrl() = 0; virtual void dispose() = 0; Element* next; @@ -125,7 +137,8 @@ class DirectoryElement: public Element { DirectoryElement(System* s, Allocator* allocator, const char* name): s(s), allocator(allocator), name(name), - urlPrefix_(append(allocator, "file:", name, "/")) + urlPrefix_(append(allocator, "file:", name, "/")), + sourceUrl_(append(allocator, "file:", name)) { } virtual Element::Iterator* iterator() { @@ -163,9 +176,14 @@ class DirectoryElement: public Element { return urlPrefix_; } + virtual const char* sourceUrl() { + return sourceUrl_; + } + virtual void dispose() { allocator->free(name, strlen(name) + 1); allocator->free(urlPrefix_, strlen(urlPrefix_) + 1); + allocator->free(sourceUrl_, strlen(sourceUrl_) + 1); allocator->free(this, sizeof(*this)); } @@ -173,6 +191,7 @@ class DirectoryElement: public Element { Allocator* allocator; const char* name; const char* urlPrefix_; + const char* sourceUrl_; }; class PointerRegion: public System::Region { @@ -438,6 +457,7 @@ class JarElement: public Element { JarElement(System* s, Allocator* allocator, const char* name): s(s), allocator(allocator), name(name), urlPrefix_(name ? append(allocator, "jar:file:", name, "!/") : 0), + sourceUrl_(name ? append(allocator, "file:", name) : 0), region(0), index(0) { } @@ -447,6 +467,7 @@ class JarElement: public Element { allocator(allocator), name(0), urlPrefix_(name ? append(allocator, "jar:file:", name, "!/") : 0), + sourceUrl_(name ? append(allocator, "file:", name) : 0), region(new (allocator->allocate(sizeof(PointerRegion))) PointerRegion(s, allocator, jarData, jarLength)), index(JarIndex::open(s, allocator, region)) @@ -500,6 +521,10 @@ class JarElement: public Element { return urlPrefix_; } + virtual const char* sourceUrl() { + return sourceUrl_; + } + virtual void dispose() { dispose(sizeof(*this)); } @@ -507,6 +532,7 @@ class JarElement: public Element { virtual void dispose(unsigned size) { allocator->free(name, strlen(name) + 1); allocator->free(urlPrefix_, strlen(urlPrefix_) + 1); + allocator->free(sourceUrl_, strlen(sourceUrl_) + 1); if (index) { index->dispose(); } @@ -520,6 +546,7 @@ class JarElement: public Element { Allocator* allocator; const char* name; const char* urlPrefix_; + const char* sourceUrl_; System::Region* region; JarIndex* index; }; @@ -556,6 +583,10 @@ class BuiltinElement: public JarElement { return "resource:"; } + virtual const char* sourceUrl() { + return 0; + } + virtual void dispose() { library->disposeAll(); if (libraryName) { @@ -802,6 +833,18 @@ class MyFinder: public Finder { return 0; } + virtual const char* sourceUrl(const char* name) { + for (Element* e = path_; e; e = e->next) { + unsigned length; + System::FileType type = e->stat(name, &length, true); + if (type != System::TypeDoesNotExist) { + return e->sourceUrl(); + } + } + + return 0; + } + virtual const char* path() { return pathString; } diff --git a/src/finder.h b/src/finder.h index d2c252b451..ed03ee9473 100644 --- a/src/finder.h +++ b/src/finder.h @@ -168,6 +168,7 @@ class Finder { unsigned* length, bool tryDirectory = false) = 0; virtual const char* urlPrefix(const char* name) = 0; + virtual const char* sourceUrl(const char* name) = 0; virtual const char* path() = 0; virtual void dispose() = 0; }; diff --git a/src/interpret.cpp b/src/interpret.cpp index 13f3b9e853..c06b167f95 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -2982,7 +2982,7 @@ class MyProcessor: public Processor { return vm::makeClass (t, flags, vmFlags, fixedSize, arrayElementSize, arrayDimensions, 0, objectMask, name, sourceFile, super, interfaceTable, virtualTable, - fieldTable, methodTable, addendum, staticTable, loader, 0); + fieldTable, methodTable, addendum, staticTable, loader, 0, 0); } virtual void diff --git a/src/machine.cpp b/src/machine.cpp index 4b50be2011..aeb7b8263f 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -3320,6 +3320,7 @@ parseClass(Thread* t, object loader, const uint8_t* data, unsigned size, 0, // addendum 0, // static table loader, + 0, // source 0);// vtable length PROTECT(t, class_); @@ -3389,6 +3390,8 @@ resolveSystemClass(Thread* t, object loader, object spec, bool throw_, (t, classLoaderMap(t, loader), spec, byteArrayHash, byteArrayEqual); if (class_ == 0) { + PROTECT(t, class_); + if (classLoaderParent(t, loader)) { class_ = resolveSystemClass (t, classLoaderParent(t, loader), spec, false); @@ -3430,6 +3433,20 @@ resolveSystemClass(Thread* t, object loader, object spec, bool throw_, class_); } + { const char* source = static_cast + (systemClassLoaderFinder(t, loader))->sourceUrl + (RUNTIME_ARRAY_BODY(file)); + + if (source) { + unsigned length = strlen(source); + object array = makeByteArray(t, length + 1); + memcpy(&byteArrayBody(t, array, 0), source, length); + array = internByteArray(t, array); + + set(t, class_, ClassSource, array); + } + } + object bootstrapClass = hashMapFind (t, root(t, Machine::BootstrapClassMap), spec, byteArrayHash, byteArrayEqual); @@ -3444,8 +3461,6 @@ resolveSystemClass(Thread* t, object loader, object spec, bool throw_, } if (class_) { - PROTECT(t, class_); - hashMapInsert(t, classLoaderMap(t, loader), spec, class_, byteArrayHash); } else if (throw_) { throwNew(t, throwType, "%s", &byteArrayBody(t, spec, 0)); From ef865300803164ca2061c59f38ad5b079bffbe51 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 31 Mar 2011 19:43:49 -0600 Subject: [PATCH 069/117] call static initializer of superclass before that of class itself Also, assume any class which has an ancestor class which has a static initializer needs initialization even if it doesn't have one itself, per the Java Language Spec. --- src/compile.cpp | 11 ----- src/interpret.cpp | 108 ++++++---------------------------------------- src/machine.cpp | 31 ++++++++++--- src/processor.h | 3 -- 4 files changed, 40 insertions(+), 113 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index b80b589f9e..21ce8d231d 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -8250,17 +8250,6 @@ class MyProcessor: public Processor { } } - virtual bool - isInitializing(Thread* t, object c) - { - for (Thread::ClassInitStack* s = t->classInitStack; s; s = s->next) { - if (s->class_ == c) { - return true; - } - } - return false; - } - virtual void visitObjects(Thread* vmt, Heap::Visitor* v) { diff --git a/src/interpret.cpp b/src/interpret.cpp index c06b167f95..afb56c70ff 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -26,8 +26,6 @@ const unsigned FrameMethodOffset = 2; const unsigned FrameIpOffset = 3; const unsigned FrameFootprint = 4; -class ClassInitList; - class Thread: public vm::Thread { public: Thread(Machine* m, object javaThread, vm::Thread* parent): @@ -35,39 +33,16 @@ class Thread: public vm::Thread { ip(0), sp(0), frame(-1), - code(0), - classInitList(0) + code(0) { } unsigned ip; unsigned sp; int frame; object code; - ClassInitList* classInitList; uintptr_t stack[StackSizeInWords]; }; -class ClassInitList { - public: - ClassInitList(Thread* t, object class_, ClassInitList* next): - t(t), class_(class_), next(next) - { } - - static void push(Thread* t, object class_) { - t->classInitList = new (t->m->heap->allocate(sizeof(ClassInitList))) - ClassInitList(t, class_, t->classInitList); - } - - void pop() { - t->classInitList = next; - t->m->heap->free(this, sizeof(ClassInitList)); - } - - Thread* t; - object class_; - ClassInitList* next; -}; - inline void pushObject(Thread* t, object o) { @@ -377,15 +352,6 @@ popFrame(Thread* t) release(t, peekObject(t, frameBase(t, t->frame))); } } - - if (UNLIKELY(methodVmFlags(t, method) & ClassInitFlag) - and t->classInitList - and t->classInitList->class_ == methodClass(t, method)) - { - t->classInitList->pop(); - - postInitClass(t, methodClass(t, method)); - } t->sp = frameBase(t, t->frame); t->frame = frameNext(t, t->frame); @@ -691,32 +657,6 @@ invokeNative(Thread* t, object method) } } -bool -classInit2(Thread* t, object class_, unsigned ipOffset) -{ - PROTECT(t, class_); - - if (preInitClass(t, class_)) { - ClassInitList::push(t, class_); - - t->code = classInitializer(t, class_); - t->ip -= ipOffset; - return true; - } else { - return false; - } -} - -inline bool -classInit(Thread* t, object class_, unsigned ipOffset) -{ - if (UNLIKELY(classVmFlags(t, class_) & NeedInitFlag)) { - return classInit2(t, class_, ipOffset); - } else { - return false; - } -} - inline void store(Thread* t, unsigned index) { @@ -822,9 +762,7 @@ interpret3(Thread* t, const int base) goto throw_; } - if (UNLIKELY(classInit(t, methodClass(t, frameMethod(t, frame)), 0))) { - goto invoke; - } + initClass(t, methodClass(t, frameMethod(t, frame))); loop: instruction = codeBody(t, code, ip++); @@ -1486,7 +1424,7 @@ interpret3(Thread* t, const int base) PROTECT(t, field); - if (UNLIKELY(classInit(t, fieldClass(t, field), 3))) goto invoke; + initClass(t, fieldClass(t, field)); ACQUIRE_FIELD_FOR_READ(t, field); @@ -1864,7 +1802,10 @@ interpret3(Thread* t, const int base) object class_ = methodClass(t, frameMethod(t, frame)); if (isSpecialMethod(t, method, class_)) { class_ = classSuper(t, class_); - if (UNLIKELY(classInit(t, class_, 3))) goto invoke; + PROTECT(t, method); + PROTECT(t, class_); + + initClass(t, class_); code = findVirtualMethod(t, method, class_); } else { @@ -1884,7 +1825,7 @@ interpret3(Thread* t, const int base) object method = resolveMethod(t, frameMethod(t, frame), index - 1); PROTECT(t, method); - if (UNLIKELY(classInit(t, methodClass(t, method), 3))) goto invoke; + initClass(t, methodClass(t, method)); code = method; } goto invoke; @@ -1897,7 +1838,10 @@ interpret3(Thread* t, const int base) unsigned parameterFootprint = methodParameterFootprint(t, method); if (LIKELY(peekObject(t, sp - parameterFootprint))) { object class_ = objectClass(t, peekObject(t, sp - parameterFootprint)); - if (UNLIKELY(classInit(t, class_, 3))) goto invoke; + PROTECT(t, method); + PROTECT(t, class_); + + initClass(t, class_); code = findVirtualMethod(t, method, class_); goto invoke; @@ -2358,7 +2302,7 @@ interpret3(Thread* t, const int base) object class_ = resolveClassInPool(t, frameMethod(t, frame), index - 1); PROTECT(t, class_); - if (UNLIKELY(classInit(t, class_, 3))) goto invoke; + initClass(t, class_); pushObject(t, make(t, class_)); } goto loop; @@ -2507,7 +2451,7 @@ interpret3(Thread* t, const int base) ACQUIRE_FIELD_FOR_WRITE(t, field); - if (UNLIKELY(classInit(t, fieldClass(t, field), 3))) goto invoke; + initClass(t, fieldClass(t, field)); object table = classStaticTable(t, fieldClass(t, field)); @@ -2991,26 +2935,6 @@ class MyProcessor: public Processor { // ignore } - virtual bool - isInitializing(vm::Thread* vmt, object c) - { - Thread* t = static_cast(vmt); - - for (ClassInitList* list = t->classInitList; list; list = list->next) { - if (list->class_ == c) { - return true; - } - } - - for (Thread::ClassInitStack* s = t->classInitStack; s; s = s->next) { - if (s->class_ == c) { - return true; - } - } - - return false; - } - virtual void visitObjects(vm::Thread* vmt, Heap::Visitor* v) { @@ -3023,10 +2947,6 @@ class MyProcessor: public Processor { v->visit(reinterpret_cast(t->stack + (i * 2) + 1)); } } - - for (ClassInitList* list = t->classInitList; list; list = list->next) { - v->visit(reinterpret_cast(&(list->class_))); - } } virtual void diff --git a/src/machine.cpp b/src/machine.cpp index aeb7b8263f..4ba7426ac0 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -2351,6 +2351,17 @@ invokeLoadClass(Thread* t, uintptr_t* arguments) (t->m->processor->invoke(t, method, loader, specString)); } +bool +isInitializing(Thread* t, object c) +{ + for (Thread::ClassInitStack* s = t->classInitStack; s; s = s->next) { + if (s->class_ == c) { + return true; + } + } + return false; +} + } // namespace namespace vm { @@ -3187,7 +3198,7 @@ classInitializer(Thread* t, object class_) return o; } } - abort(t); + return 0; } unsigned @@ -3334,7 +3345,8 @@ parseClass(Thread* t, object loader, const uint8_t* data, unsigned size, classVmFlags(t, class_) |= (classVmFlags(t, sc) - & (ReferenceFlag | WeakReferenceFlag | HasFinalizerFlag)); + & (ReferenceFlag | WeakReferenceFlag | HasFinalizerFlag + | NeedInitFlag)); } parseInterfaceTable(t, s, class_, pool, throwType); @@ -3648,7 +3660,7 @@ preInitClass(Thread* t, object c) // If the class is currently being initialized and this the thread // which is initializing it, we should not try to initialize it // recursively. - if (t->m->processor->isInitializing(t, c)) { + if (isInitializing(t, c)) { return false; } @@ -3695,12 +3707,21 @@ initClass(Thread* t, object c) { PROTECT(t, c); + object super = classSuper(t, c); + if (super) { + initClass(t, super); + } + if (preInitClass(t, c)) { OBJECT_RESOURCE(t, c, postInitClass(t, c)); - Thread::ClassInitStack stack(t, c); + object initializer = classInitializer(t, c); - t->m->processor->invoke(t, classInitializer(t, c), 0); + if (initializer) { + Thread::ClassInitStack stack(t, c); + + t->m->processor->invoke(t, initializer, 0); + } } } diff --git a/src/processor.h b/src/processor.h index 0b71ed1782..f790491439 100644 --- a/src/processor.h +++ b/src/processor.h @@ -81,9 +81,6 @@ class Processor { virtual void initVtable(Thread* t, object c) = 0; - virtual bool - isInitializing(Thread* t, object c) = 0; - virtual void visitObjects(Thread* t, Heap::Visitor* v) = 0; From b0ae6343ad271b7367eb4b3d038efb4eec59d78f Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 31 Mar 2011 19:47:26 -0600 Subject: [PATCH 070/117] provide proper implementations of JVM_GetDeclaredClasses, JVM_GetDeclaringClass --- classpath/avian/ClassAddendum.java | 1 + classpath/avian/OpenJDK.java | 27 ++++++++ src/classpath-openjdk.cpp | 98 +++++++++++++++++++++++++----- src/machine.cpp | 33 +++++++++- src/types.def | 6 ++ 5 files changed, 148 insertions(+), 17 deletions(-) diff --git a/classpath/avian/ClassAddendum.java b/classpath/avian/ClassAddendum.java index 1719addfa4..ff11591046 100644 --- a/classpath/avian/ClassAddendum.java +++ b/classpath/avian/ClassAddendum.java @@ -12,4 +12,5 @@ package avian; public class ClassAddendum extends Addendum { public Object[] interfaceTable; + public Object[] innerClassTable; } diff --git a/classpath/avian/OpenJDK.java b/classpath/avian/OpenJDK.java index dcddbc0f67..de9c6f1f40 100644 --- a/classpath/avian/OpenJDK.java +++ b/classpath/avian/OpenJDK.java @@ -34,4 +34,31 @@ public class OpenJDK { return new ProtectionDomain(source, p); } + + private static byte[] replace(int a, int b, byte[] s, int offset, + int length) + { + byte[] array = new byte[length]; + for (int i = 0; i < length; ++i) { + byte c = s[i]; + array[i] = (byte) (c == a ? b : c); + } + return array; + } + + public static Class getDeclaringClass(VMClass c) { + try { + String name = new String + (replace('/', '.', c.name, 0, c.name.length - 1), 0, + c.name.length - 1); + int index = name.lastIndexOf("$"); + if (index == -1) { + return null; + } else { + return c.loader.loadClass(name.substring(0, index)); + } + } catch (ClassNotFoundException e) { + return null; + } + } } diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 89fab1ff16..127565f2f4 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -3743,31 +3743,101 @@ EXPORT(JVM_GetClassModifiers)(Thread* t, jclass c) return classFlags(t, jclassVmClass(t, *c)); } +uint64_t +jvmGetDeclaredClasses(Thread* t, uintptr_t* arguments) +{ + jclass c = reinterpret_cast(arguments[0]); + + object addendum = classAddendum(t, jclassVmClass(t, *c)); + if (addendum) { + object table = classAddendumInnerClassTable(t, addendum); + if (table) { + PROTECT(t, table); + + unsigned count = 0; + for (unsigned i = 0; i < arrayLength(t, table); ++i) { + if (innerClassReferenceOuter(t, arrayBody(t, table, i))) { + ++ count; + } + } + + object result = makeObjectArray(t, count); + PROTECT(t, result); + + for (unsigned i = 0; i < arrayLength(t, table); ++i) { + if (innerClassReferenceOuter(t, arrayBody(t, table, i))) { + object inner = getJClass + (t, resolveClass + (t, classLoader(t, jclassVmClass(t, *c)), referenceName + (t, innerClassReferenceInner(t, arrayBody(t, table, i))))); + + -- count; + set(t, result, ArrayBody + (count * BytesPerWord), inner); + } + } + + return reinterpret_cast(makeLocalReference(t, result)); + } + } + + return reinterpret_cast + (makeLocalReference(t, makeObjectArray(t, 0))); +} + extern "C" JNIEXPORT jobjectArray JNICALL -EXPORT(JVM_GetDeclaredClasses)(Thread*, jclass) { abort(); } +EXPORT(JVM_GetDeclaredClasses)(Thread* t, jclass c) +{ + uintptr_t arguments[] = { reinterpret_cast(c) }; + + return reinterpret_cast(run(t, jvmGetDeclaredClasses, arguments)); +} + +uint64_t +jvmGetDeclaringClass(Thread* t, uintptr_t* arguments) +{ + jclass c = reinterpret_cast(arguments[0]); + + object method = resolveMethod + (t, root(t, Machine::BootLoader), "avian/OpenJDK", "getDeclaringClass", + "(Lavian/VMClass;)Ljava/lang/Class;"); + + return reinterpret_cast + (makeLocalReference + (t, t->m->processor->invoke(t, method, 0, jclassVmClass(t, *c)))); +} extern "C" JNIEXPORT jclass JNICALL -EXPORT(JVM_GetDeclaringClass)(Thread*, jclass) +EXPORT(JVM_GetDeclaringClass)(Thread* t, jclass c) { - // todo: implement properly + uintptr_t arguments[] = { reinterpret_cast(c) }; + + return reinterpret_cast(run(t, jvmGetDeclaringClass, arguments)); +} + +uint64_t +jvmGetClassSignature(Thread* t, uintptr_t* arguments) +{ + jclass c = reinterpret_cast(arguments[0]); + + object addendum = classAddendum(t, jclassVmClass(t, *c)); + if (addendum) { + object signature = addendumSignature(t, addendum); + if (signature) { + return reinterpret_cast + (makeLocalReference + (t, t->m->classpath->makeString + (t, signature, 0, byteArrayLength(t, signature) - 1))); + } + } return 0; } extern "C" JNIEXPORT jstring JNICALL EXPORT(JVM_GetClassSignature)(Thread* t, jclass c) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(c) }; - object addendum = classAddendum(t, jclassVmClass(t, *c)); - if (addendum) { - object signature = addendumSignature(t, addendum); - if (signature) { - return makeLocalReference - (t, t->m->classpath->makeString - (t, signature, 0, byteArrayLength(t, signature) - 1)); - } - } - return 0; + return reinterpret_cast(run(t, jvmGetClassSignature, arguments)); } extern "C" JNIEXPORT jbyteArray JNICALL diff --git a/src/machine.cpp b/src/machine.cpp index 4ba7426ac0..245b30577b 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -991,7 +991,7 @@ parseInterfaceTable(Thread* t, Stream& s, object class_, object pool, if (count) { table = makeArray(t, count); if (classAddendum(t, class_) == 0) { - object addendum = makeClassAddendum(t, pool, 0, 0, table); + object addendum = makeClassAddendum(t, pool, 0, 0, table, 0); set(t, class_, ClassAddendum, addendum); } } @@ -1724,17 +1724,44 @@ parseAttributeTable(Thread* t, Stream& s, object class_, object pool) &byteArrayBody(t, name, 0)) == 0) { if (addendum == 0) { - addendum = makeClassAddendum(t, pool, 0, 0, 0); + addendum = makeClassAddendum(t, pool, 0, 0, 0, 0); } set(t, addendum, AddendumSignature, singletonObject(t, pool, s.read2() - 1)); + } else if (vm::strcmp(reinterpret_cast("InnerClasses"), + &byteArrayBody(t, name, 0)) == 0) + { + if (addendum == 0) { + addendum = makeClassAddendum(t, pool, 0, 0, 0, 0); + } + + unsigned innerClassCount = s.read2(); + object table = makeArray(t, innerClassCount); + PROTECT(t, table); + + for (unsigned i = 0; i < innerClassCount; ++i) { + int16_t inner = s.read2(); + int16_t outer = s.read2(); + int16_t name = s.read2(); + int16_t flags = s.read2(); + + object reference = makeInnerClassReference + (t, inner ? singletonObject(t, pool, inner - 1) : 0, + outer ? singletonObject(t, pool, outer - 1) : 0, + name ? singletonObject(t, pool, name - 1) : 0, + flags); + + set(t, table, ArrayBody + (i * BytesPerWord), reference); + } + + set(t, addendum, ClassAddendumInnerClassTable, table); } else if (vm::strcmp(reinterpret_cast ("RuntimeVisibleAnnotations"), &byteArrayBody(t, name, 0)) == 0) { if (addendum == 0) { - addendum = makeClassAddendum(t, pool, 0, 0, 0); + addendum = makeClassAddendum(t, pool, 0, 0, 0, 0); } object body = makeByteArray(t, length); diff --git a/src/types.def b/src/types.def index cf04647e06..1ac0d915ea 100644 --- a/src/types.def +++ b/src/types.def @@ -161,6 +161,12 @@ (void* value) (object next)) +(type innerClassReference + (object inner) + (object outer) + (object name) + (int16_t flags)) + (type continuationContext (object next) (object before) From 706f9d91ad8b336db9ba6e32a1942200e0efb412 Mon Sep 17 00:00:00 2001 From: JET Date: Tue, 5 Apr 2011 15:13:29 -0600 Subject: [PATCH 071/117] Fixed bug with *nix LANG var region parsing. --- classpath/java-lang.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/classpath/java-lang.cpp b/classpath/java-lang.cpp index 48fdacc01a..779682c8c0 100644 --- a/classpath/java-lang.cpp +++ b/classpath/java-lang.cpp @@ -471,8 +471,8 @@ Locale getLocale() { if (!LANG || strcmp(LANG, "C") == 0) return fallback; int len = strlen(LANG); - char buf[len]; - memcpy(buf, LANG, len); + char buf[len + 1]; // + 1 for the '\0' char + memcpy(buf, LANG, len + 1); char* tracer = buf; const char* reg; @@ -480,7 +480,7 @@ Locale getLocale() { while (*tracer && *tracer != '_') ++tracer; if (!*tracer) return fallback; *tracer = '\0'; - reg = tracer++ + 1; + reg = ++tracer; while (*tracer && *tracer != '.') ++tracer; if (tracer == reg) return fallback; From af9288f4ee584e781142d0bb541cc2ff180d8f8c Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 7 Apr 2011 14:26:54 -0600 Subject: [PATCH 072/117] don't abort when parsing malformed UTF8 strings Previously, we would abort the process if we encountered a truncated multibyte character in parseUtf8NonAscii (called by the JNI method NewStringUTF). Now we simply terminate the string at that point. --- src/machine.cpp | 5 ++--- src/stream.h | 8 ++------ 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/machine.cpp b/src/machine.cpp index 245b30577b..a4bf4c1d0e 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -718,7 +718,6 @@ parseUtf8NonAscii(Thread* t, Stream& s, object bytesSoFar, unsigned byteCount, value = v; } - charArrayBody(t, value, vi) = 0; return value; } @@ -4239,8 +4238,8 @@ parseUtf8(Thread* t, const char* data, unsigned length) public: Client(Thread* t): t(t) { } - virtual void NO_RETURN handleError() { - vm::abort(t); + virtual void handleError() { + // vm::abort(t); } private: diff --git a/src/stream.h b/src/stream.h index bd7542e496..3e438d465e 100644 --- a/src/stream.h +++ b/src/stream.h @@ -19,7 +19,7 @@ class Stream { public: class Client { public: - virtual void NO_RETURN handleError() = 0; + virtual void handleError() = 0; }; Stream(Client* client, const uint8_t* data, unsigned size): @@ -44,11 +44,7 @@ class Stream { void read(uint8_t* data, unsigned size) { if (size > this->size - position_) { - // GCC 4.4 will give us an uninitialized value warning in read1 - // unless we do this: (it's smart enough to track data flow - // across functions but not smart enough to see we won't return - // from Client::handleError) - *data = 0; + memset(data, 0, size); client->handleError(); } else { From 60db8cc047df0cb8f175c449ed454edff31ed058 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 8 Apr 2011 18:46:43 -0600 Subject: [PATCH 073/117] add some commented-out debug code to defineClass When uncommented, this code will write each defined class to disk, which allows one to examine e.g. dynamically-generated classes using e.g. javap. --- src/machine.cpp | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/machine.cpp b/src/machine.cpp index a4bf4c1d0e..bc6d1bdf63 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -4287,12 +4287,25 @@ defineClass(Thread* t, object loader, const uint8_t* buffer, unsigned length) PROTECT(t, loader); object c = parseClass(t, loader, buffer, length); + + // char name[byteArrayLength(t, className(t, c))]; + // memcpy(name, &byteArrayBody(t, className(t, c), 0), + // byteArrayLength(t, className(t, c))); + // replace('/', '-', name); - if (c) { - PROTECT(t, c); + // const unsigned BufferSize = 1024; + // char path[BufferSize]; + // snprintf(path, BufferSize, "/tmp/avian-define-class/%s.class", name); - saveLoadedClass(t, loader, c); - } + // FILE* file = fopen(path, "wb"); + // if (file) { + // fwrite(buffer, length, 1, file); + // fclose(file); + // } + + PROTECT(t, c); + + saveLoadedClass(t, loader, c); return c; } From 36aa0d67922ed874345123b93ea11476950b5410 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 8 Apr 2011 18:50:22 -0600 Subject: [PATCH 074/117] improve handling of unusual bytecode in JIT compiler Bytecode generated by compilers other than javac or ecj (such as jython's dynamically generated classes) can contain unreachable code and exception handlers which apply to more than one try/catch scope. Previously, the VM's JIT compiler did not handle either of these cases well, hence this commit. --- src/compile.cpp | 251 ++++++++++++++++++++++++++++++------------------ 1 file changed, 159 insertions(+), 92 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index 21ce8d231d..8e06e89a01 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -5883,36 +5883,75 @@ logCompile(MyThread* t, const void* code, unsigned size, const char* class_, } } -unsigned -resolveIp(MyThread* t, Context* context, object code, unsigned ip) +int +resolveIpForwards(Context* context, int start, int end) { - if (context->visitTable[ip]) { - return ip; - } else { - // Very rarely, we'll encounter an unreachable goto which is - // referred to by the exception handler table or line number - // table. This can be a problem if we need to determine the - // corresponding machine address for the bytecode instruction - // since we never generated any machine code for it. For now, we - // just follow the goto. The "proper" fix is probably to go ahead - // and generate machine code even though it's unreachable; that - // will protect us against unreachable instructions which aren't - // gotos as well. - switch (codeBody(t, code, ip)) { - case goto_: { - unsigned tmp = ip + 1; - return ip + codeReadInt16(t, code, tmp); - } - - case goto_w: { - unsigned tmp = ip + 1; - return ip + codeReadInt32(t, code, tmp); - } - - default: - return ip; - } + while (start < end and context->visitTable[start] == 0) { + ++ start; } + + if (start >= end) { + return -1; + } else { + return start; + } +} + +int +resolveIpBackwards(Context* context, int start, int end) +{ + while (start >= end and context->visitTable[start] == 0) { + -- start; + } + + if (start < end) { + return -1; + } else { + return start; + } +} + +object +truncateIntArray(Thread* t, object array, unsigned length) +{ + expect(t, intArrayLength(t, array) > length); + + PROTECT(t, array); + + object newArray = makeIntArray(t, length); + memcpy(&intArrayBody(t, newArray, 0), &intArrayBody(t, array, 0), + length * 4); + + return newArray; +} + +object +truncateArray(Thread* t, object array, unsigned length) +{ + expect(t, arrayLength(t, array) > length); + + PROTECT(t, array); + + object newArray = makeArray(t, length); + memcpy(&arrayBody(t, newArray, 0), &arrayBody(t, array, 0), + length * BytesPerWord); + + return newArray; +} + +object +truncateLineNumberTable(Thread* t, object table, unsigned length) +{ + expect(t, lineNumberTableLength(t, table) > length); + + PROTECT(t, table); + + object newTable = makeLineNumberTable(t, length); + memcpy(lineNumberTableBody(t, newTable, 0), + lineNumberTableBody(t, table, 0), + length * sizeof(LineNumber)); + + return newTable; } object @@ -5934,35 +5973,52 @@ translateExceptionHandlerTable(MyThread* t, Context* context, intptr_t start) object newTable = makeArray(t, length + 1); PROTECT(t, newTable); - set(t, newTable, ArrayBody, newIndex); - - for (unsigned i = 0; i < length; ++i) { + unsigned ni = 0; + for (unsigned oi = 0; oi < length; ++ oi) { ExceptionHandler* oldHandler = exceptionHandlerTableBody - (t, oldTable, i); + (t, oldTable, oi); - intArrayBody(t, newIndex, i * 3) - = c->machineIp - (resolveIp - (t, context, methodCode(t, context->method), - exceptionHandlerStart(oldHandler)))->value() - start; + int handlerStart = resolveIpForwards + (context, exceptionHandlerStart(oldHandler), + exceptionHandlerEnd(oldHandler)); - intArrayBody(t, newIndex, (i * 3) + 1) - = c->machineIp(exceptionHandlerEnd(oldHandler))->value() - start; + if (LIKELY(handlerStart >= 0)) { + int handlerEnd = resolveIpBackwards + (context, exceptionHandlerEnd(oldHandler), + exceptionHandlerStart(oldHandler)); - intArrayBody(t, newIndex, (i * 3) + 2) - = c->machineIp(exceptionHandlerIp(oldHandler))->value() - start; + assert(t, handlerEnd >= 0); - object type; - if (exceptionHandlerCatchType(oldHandler)) { - type = resolveClassInPool - (t, context->method, exceptionHandlerCatchType(oldHandler) - 1); - } else { - type = 0; + intArrayBody(t, newIndex, ni * 3) + = c->machineIp(handlerStart)->value() - start; + + intArrayBody(t, newIndex, (ni * 3) + 1) + = c->machineIp(handlerEnd)->value() - start; + + intArrayBody(t, newIndex, (ni * 3) + 2) + = c->machineIp(exceptionHandlerIp(oldHandler))->value() - start; + + object type; + if (exceptionHandlerCatchType(oldHandler)) { + type = resolveClassInPool + (t, context->method, exceptionHandlerCatchType(oldHandler) - 1); + } else { + type = 0; + } + + set(t, newTable, ArrayBody + ((ni + 1) * BytesPerWord), type); + + ++ ni; } - - set(t, newTable, ArrayBody + ((i + 1) * BytesPerWord), type); } + if (UNLIKELY(ni < length)) { + newIndex = truncateIntArray(t, newIndex, ni * 3); + newTable = truncateArray(t, newTable, ni + 1); + } + + set(t, newTable, ArrayBody, newIndex); + return newTable; } else { return 0; @@ -5978,18 +6034,28 @@ translateLineNumberTable(MyThread* t, Context* context, intptr_t start) unsigned length = lineNumberTableLength(t, oldTable); object newTable = makeLineNumberTable(t, length); - for (unsigned i = 0; i < length; ++i) { - LineNumber* oldLine = lineNumberTableBody(t, oldTable, i); - LineNumber* newLine = lineNumberTableBody(t, newTable, i); + unsigned ni = 0; + for (unsigned oi = 0; oi < length; ++oi) { + LineNumber* oldLine = lineNumberTableBody(t, oldTable, oi); + LineNumber* newLine = lineNumberTableBody(t, newTable, ni); - lineNumberIp(newLine) - = context->compiler->machineIp - (resolveIp - (t, context, methodCode(t, context->method), lineNumberIp(oldLine))) - ->value() - - start; + int ip = resolveIpForwards + (context, lineNumberIp(oldLine), oi + 1 < length + ? lineNumberIp(lineNumberTableBody(t, oldTable, oi + 1)) - 1 + : lineNumberIp(oldLine) + 1); - lineNumberLine(newLine) = lineNumberLine(oldLine); + if (LIKELY(ip >= 0)) { + lineNumberIp(newLine) + = context->compiler->machineIp(ip)->value() - start; + + lineNumberLine(newLine) = lineNumberLine(oldLine); + + ++ ni; + } + } + + if (UNLIKELY(ni < length)) { + newTable = truncateLineNumberTable(t, newTable, ni); } return newTable; @@ -6881,55 +6947,56 @@ compile(MyThread* t, Context* context) THREAD_RUNTIME_ARRAY(t, bool, visited, visitCount); memset(RUNTIME_ARRAY_BODY(visited), 0, visitCount * sizeof(bool)); - while (visitCount) { - bool progress UNUSED = false; + bool progress = true; + while (progress) { + progress = false; for (unsigned i = 0; i < exceptionHandlerTableLength(t, eht); ++i) { c->restoreState(state); ExceptionHandler* eh = exceptionHandlerTableBody(t, eht, i); - unsigned start = resolveIp - (t, context, methodCode(t, context->method), - exceptionHandlerStart(eh)); + int start = resolveIpForwards + (context, exceptionHandlerStart(eh), exceptionHandlerEnd(eh)); if ((not RUNTIME_ARRAY_BODY(visited)[i]) + and start >= 0 and context->visitTable[start]) { - -- visitCount; RUNTIME_ARRAY_BODY(visited)[i] = true; progress = true; - THREAD_RUNTIME_ARRAY(t, uint8_t, stackMap, - codeMaxStack(t, methodCode(t, context->method))); - Frame frame2(&frame, RUNTIME_ARRAY_BODY(stackMap)); + if (context->visitTable[exceptionHandlerIp(eh)] == 0) { + THREAD_RUNTIME_ARRAY + (t, uint8_t, stackMap, + codeMaxStack(t, methodCode(t, context->method))); + Frame frame2(&frame, RUNTIME_ARRAY_BODY(stackMap)); - unsigned end = exceptionHandlerEnd(eh); - if (exceptionHandlerIp(eh) >= start - and exceptionHandlerIp(eh) < end) - { - end = exceptionHandlerIp(eh); + unsigned end = exceptionHandlerEnd(eh); + if (exceptionHandlerIp(eh) >= start + and exceptionHandlerIp(eh) < end) + { + end = exceptionHandlerIp(eh); + } + + context->eventLog.append(PushExceptionHandlerEvent); + context->eventLog.append2(start); + context->eventLog.append2(end); + + for (unsigned i = 1; + i < codeMaxStack(t, methodCode(t, context->method)); + ++i) + { + frame2.set(localSize(t, context->method) + i, Frame::Integer); + } + + compile(t, &frame2, exceptionHandlerIp(eh), start); + + context->eventLog.append(PopContextEvent); + + eventIndex = calculateFrameMaps(t, context, 0, eventIndex); } - - context->eventLog.append(PushExceptionHandlerEvent); - context->eventLog.append2(start); - context->eventLog.append2(end); - - for (unsigned i = 1; - i < codeMaxStack(t, methodCode(t, context->method)); - ++i) - { - frame2.set(localSize(t, context->method) + i, Frame::Integer); - } - - compile(t, &frame2, exceptionHandlerIp(eh), start); - - context->eventLog.append(PopContextEvent); - - eventIndex = calculateFrameMaps(t, context, 0, eventIndex); } } - - assert(t, progress); } } From 97aec1691ebea196186897670034f4994cad6df6 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 8 Apr 2011 20:15:36 -0600 Subject: [PATCH 075/117] fix jsr/ret stack mapping regression My last commit introduced a regression in JIT compilation of subroutines. This reverts the specific change which caused the regression. Further work will be needed to address the case which that change was intended to fix (namely, exception handlers which apply to multiple try/catch blocks). --- src/compile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compile.cpp b/src/compile.cpp index 8e06e89a01..6a53368436 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -6965,7 +6965,7 @@ compile(MyThread* t, Context* context) RUNTIME_ARRAY_BODY(visited)[i] = true; progress = true; - if (context->visitTable[exceptionHandlerIp(eh)] == 0) { + if (true) {//context->visitTable[exceptionHandlerIp(eh)] == 0) { THREAD_RUNTIME_ARRAY (t, uint8_t, stackMap, codeMaxStack(t, methodCode(t, context->method))); From 76fa43548d483be63b9aa6c9e31a1ea0d9ad645b Mon Sep 17 00:00:00 2001 From: Marcel van den Boer Date: Fri, 8 Apr 2011 20:31:33 -0600 Subject: [PATCH 076/117] Implementation of String.replace(CharSequence, CharSequence) --- classpath/java/lang/String.java | 36 +++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/classpath/java/lang/String.java b/classpath/java/lang/String.java index 788400dbac..7f6ff1edfc 100644 --- a/classpath/java/lang/String.java +++ b/classpath/java/lang/String.java @@ -494,6 +494,42 @@ public final class String public String replaceAll(String regex, String replacement) { return Pattern.compile(regex).matcher(this).replaceAll(replacement); } + + public String replace(CharSequence target, CharSequence replace) { + if (target.length() == 0) { + return this.infuse(replace.toString()); + } + + String targetString = target.toString(); + String replaceString = replace.toString(); + + int targetSize = target.length(); + + StringBuilder returnValue = new StringBuilder(); + String unhandled = this; + + int index = -1; + while ((index = unhandled.indexOf(targetString)) != -1) { + returnValue.append(unhandled.substring(0, index)).append(replaceString); + unhandled = unhandled.substring(index + targetSize, + unhandled.length()); + } + + returnValue.append(unhandled); + return returnValue.toString(); + } + + private String infuse(String infuseWith) { + StringBuilder retVal = new StringBuilder(); + + String me = this; + for (int i = 0; i < me.length(); i++) { + retVal.append(infuseWith).append(me.substring(i, i + 1)); + } + + retVal.append(infuseWith); + return retVal.toString(); + } public native String intern(); From c0f39fbe0c75e76dd8c98abfafd0db0e18ef199a Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 8 Apr 2011 20:32:33 -0600 Subject: [PATCH 077/117] implement System.nanoTime This is a quick and coarse, but servicable, implementation. --- classpath/java/lang/System.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/classpath/java/lang/System.java b/classpath/java/lang/System.java index 954c62d116..9506fb3457 100644 --- a/classpath/java/lang/System.java +++ b/classpath/java/lang/System.java @@ -20,6 +20,8 @@ import java.io.FileDescriptor; import java.util.Properties; public abstract class System { + private static final long NanoTimeBaseInMillis = currentTimeMillis(); + private static Property properties; private static SecurityManager securityManager; @@ -94,6 +96,10 @@ public abstract class System { public static native int identityHashCode(Object o); + public static long nanoTime() { + return (currentTimeMillis() - NanoTimeBaseInMillis) * 1000000; + } + public static String mapLibraryName(String name) { if (name != null) { return doMapLibraryName(name); From 239fd98781f319fe613abd5cd196ad7a545b09d4 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 9 Apr 2011 12:44:28 -0600 Subject: [PATCH 078/117] fix compilation of unusual exception handlers As described in commit 36aa0d6, apps such as jython which generate bytecode dynamically can produce patterns of bytecode for which the VM's compiler could not handle properly. However, that commit introduced a regression and had to be partially reverted. It turns out the real problem was the call to Compiler::restoreState which we made before checking whether we were actually ready to compile the exception handler (we delay compiling an exception handler until and unless the try/catch block it serves has been compiled so we can calculate the stack maps properly). That confused the compiler in rare cases, so we now only call restoreState once we're actually ready to compile the handler. --- src/compile.cpp | 56 ++++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index 6a53368436..369515b5d6 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -6952,8 +6952,6 @@ compile(MyThread* t, Context* context) progress = false; for (unsigned i = 0; i < exceptionHandlerTableLength(t, eht); ++i) { - c->restoreState(state); - ExceptionHandler* eh = exceptionHandlerTableBody(t, eht, i); int start = resolveIpForwards (context, exceptionHandlerStart(eh), exceptionHandlerEnd(eh)); @@ -6965,36 +6963,36 @@ compile(MyThread* t, Context* context) RUNTIME_ARRAY_BODY(visited)[i] = true; progress = true; - if (true) {//context->visitTable[exceptionHandlerIp(eh)] == 0) { - THREAD_RUNTIME_ARRAY - (t, uint8_t, stackMap, - codeMaxStack(t, methodCode(t, context->method))); - Frame frame2(&frame, RUNTIME_ARRAY_BODY(stackMap)); + c->restoreState(state); - unsigned end = exceptionHandlerEnd(eh); - if (exceptionHandlerIp(eh) >= start - and exceptionHandlerIp(eh) < end) - { - end = exceptionHandlerIp(eh); - } + THREAD_RUNTIME_ARRAY + (t, uint8_t, stackMap, + codeMaxStack(t, methodCode(t, context->method))); + Frame frame2(&frame, RUNTIME_ARRAY_BODY(stackMap)); - context->eventLog.append(PushExceptionHandlerEvent); - context->eventLog.append2(start); - context->eventLog.append2(end); - - for (unsigned i = 1; - i < codeMaxStack(t, methodCode(t, context->method)); - ++i) - { - frame2.set(localSize(t, context->method) + i, Frame::Integer); - } - - compile(t, &frame2, exceptionHandlerIp(eh), start); - - context->eventLog.append(PopContextEvent); - - eventIndex = calculateFrameMaps(t, context, 0, eventIndex); + unsigned end = exceptionHandlerEnd(eh); + if (exceptionHandlerIp(eh) >= start + and exceptionHandlerIp(eh) < end) + { + end = exceptionHandlerIp(eh); } + + context->eventLog.append(PushExceptionHandlerEvent); + context->eventLog.append2(start); + context->eventLog.append2(end); + + for (unsigned i = 1; + i < codeMaxStack(t, methodCode(t, context->method)); + ++i) + { + frame2.set(localSize(t, context->method) + i, Frame::Integer); + } + + compile(t, &frame2, exceptionHandlerIp(eh), start); + + context->eventLog.append(PopContextEvent); + + eventIndex = calculateFrameMaps(t, context, 0, eventIndex); } } } From 948a2523f1fce2a39b9305df6e10174440b022b7 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 9 Apr 2011 21:07:10 -0600 Subject: [PATCH 079/117] use vm::run to implement IsAssignableFrom and IsInstanceOf Under certain circumstances, the implementations of these functions may throw errors, so we need to wrap them using vm::run so we don't try to unwind past the JNI boundary. --- src/jnienv.cpp | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 9ed2ce4815..da86b870fe 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -460,22 +460,42 @@ GetSuperclass(Thread* t, jclass c) return reinterpret_cast(run(t, getSuperclass, arguments)); } -jboolean JNICALL -IsInstanceOf(Thread* t, jobject o, jclass c) +uint64_t +isInstanceOf(Thread* t, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + jobject o = reinterpret_cast(arguments[0]); + jclass c = reinterpret_cast(arguments[1]); return instanceOf(t, jclassVmClass(t, *c), *o); } jboolean JNICALL -IsAssignableFrom(Thread* t, jclass b, jclass a) +IsInstanceOf(Thread* t, jobject o, jclass c) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o), + reinterpret_cast(c) }; + + return run(t, isInstanceOf, arguments); +} + +uint64_t +isAssignableFrom(Thread* t, uintptr_t* arguments) +{ + jclass b = reinterpret_cast(arguments[0]); + jclass a = reinterpret_cast(arguments[1]); return isAssignableFrom(t, jclassVmClass(t, *a), jclassVmClass(t, *b)); } +jboolean JNICALL +IsAssignableFrom(Thread* t, jclass b, jclass a) +{ + uintptr_t arguments[] = { reinterpret_cast(b), + reinterpret_cast(a) }; + + return run(t, isAssignableFrom, arguments); +} + object findMethod(Thread* t, jclass c, const char* name, const char* spec) { From b3d65fab9b444ed6f97685d56a1a2462e3c07359 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 9 Apr 2011 21:09:59 -0600 Subject: [PATCH 080/117] fix handling of interfaces in isAssignableFrom The old version was both incorrect (in the case where both arguments are interfaces) and inefficient. --- src/machine.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/machine.cpp b/src/machine.cpp index bc6d1bdf63..2f7f896e2f 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -3176,13 +3176,12 @@ isAssignableFrom(Thread* t, object a, object b) } } - for (; b; b = classSuper(t, b)) { - object itable = classInterfaceTable(t, b); - if (itable) { - for (unsigned i = 0; i < arrayLength(t, itable); i += 2) { - if (arrayBody(t, itable, i) == a) { - return true; - } + object itable = classInterfaceTable(t, b); + if (itable) { + unsigned stride = (classFlags(t, b) & ACC_INTERFACE) ? 1 : 2; + for (unsigned i = 0; i < arrayLength(t, itable); i += stride) { + if (arrayBody(t, itable, i) == a) { + return true; } } } From e1d45cf7c8775cfeb3fda6ec7923fcb4f930e345 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 9 Apr 2011 21:17:15 -0600 Subject: [PATCH 081/117] add stub implementation of JVM_GetManagement This is the minimum needed to get Apache Geronimo running. --- src/classpath-openjdk.cpp | 277 +++++++++++++++++++++++++++++++++++++- 1 file changed, 276 insertions(+), 1 deletion(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 127565f2f4..1a2897c093 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -106,6 +106,185 @@ CREAT(string_t path, int mode) namespace local { +const int JMM_VERSION_1_0 = 0x20010000; + +struct jmmOptionalSupport { + unsigned isLowMemoryDetectionSupported : 1; + unsigned isCompilationTimeMonitoringSupported : 1; + unsigned isThreadContentionMonitoringSupported : 1; + unsigned isCurrentThreadCpuTimeSupported : 1; + unsigned isOtherThreadCpuTimeSupported : 1; + unsigned isBootClassPathSupported : 1; + unsigned isObjectMonitorUsageSupported : 1; + unsigned isSynchronizerUsageSupported : 1; +}; + +typedef unsigned jmmLongAttribute; +typedef unsigned jmmBoolAttribute; +typedef unsigned jmmStatisticType; +typedef unsigned jmmThresholdType; +typedef unsigned jmmVMGlobalType; +typedef unsigned jmmVMGlobalOrigin; + +struct jmmVMGlobal { + jstring name; + jvalue value; + jmmVMGlobalType type; + jmmVMGlobalOrigin origin; + unsigned writeable : 1; + unsigned external : 1; + unsigned reserved : 30; + void* reserved1; + void* reserved2; +}; + +struct jmmExtAttributeInfo { + const char* name; + char type; + const char* description; +}; + +struct jmmGCStat { + jlong gc_index; + jlong start_time; + jlong end_time; + jobjectArray usage_before_gc; + jobjectArray usage_after_gc; + jint gc_ext_attribute_values_size; + jvalue* gc_ext_attribute_values; + jint num_gc_ext_attributes; +}; + +struct JmmInterface { + void* reserved1; + void* reserved2; + + jint + (JNICALL *GetVersion) + (JNIEnv*); + + jint + (JNICALL *GetOptionalSupport) + (JNIEnv*, jmmOptionalSupport*); + + jobject + (JNICALL *GetInputArguments) + (JNIEnv*); + + jint + (JNICALL *GetThreadInfo) + (JNIEnv*, jlongArray, jint, jobjectArray); + + jobjectArray + (JNICALL *GetInputArgumentArray) + (JNIEnv*); + + jobjectArray + (JNICALL *GetMemoryPools) + (JNIEnv*, jobject); + + jobjectArray + (JNICALL *GetMemoryManagers) + (JNIEnv*, jobject); + + jobject + (JNICALL *GetMemoryPoolUsage) + (JNIEnv*, jobject); + + jobject + (JNICALL *GetPeakMemoryPoolUsage) + (JNIEnv*, jobject); + + void* reserved4; + + jobject + (JNICALL *GetMemoryUsage) + (JNIEnv*, jboolean); + + jlong + (JNICALL *GetLongAttribute) + (JNIEnv*, jobject, jmmLongAttribute); + + jboolean (JNICALL *GetBoolAttribute) + (JNIEnv*, jmmBoolAttribute); + + jboolean + (JNICALL *SetBoolAttribute) + (JNIEnv*, jmmBoolAttribute, jboolean); + + jint + (JNICALL *GetLongAttributes) + (JNIEnv*, jobject, jmmLongAttribute*, jint, jlong*); + + jobjectArray + (JNICALL *FindCircularBlockedThreads) + (JNIEnv*); + + jlong + (JNICALL *GetThreadCpuTime) + (JNIEnv*, jlong); + + jobjectArray + (JNICALL *GetVMGlobalNames) + (JNIEnv*); + + jint + (JNICALL *GetVMGlobals) + (JNIEnv*, jobjectArray, jmmVMGlobal*, jint); + + jint + (JNICALL *GetInternalThreadTimes) + (JNIEnv*, jobjectArray, jlongArray); + + jboolean + (JNICALL *ResetStatistic) + (JNIEnv*, jvalue, jmmStatisticType); + + void + (JNICALL *SetPoolSensor) + (JNIEnv*, jobject, jmmThresholdType, jobject); + + jlong + (JNICALL *SetPoolThreshold) + (JNIEnv*, jobject, jmmThresholdType, jlong); + + jobject + (JNICALL *GetPoolCollectionUsage) + (JNIEnv*, jobject); + + jint + (JNICALL *GetGCExtAttributeInfo) + (JNIEnv*, jobject, jmmExtAttributeInfo*, jint); + + void + (JNICALL *GetLastGCStat) + (JNIEnv*, jobject, jmmGCStat*); + + jlong + (JNICALL *GetThreadCpuTimeWithKind) + (JNIEnv*, jlong, jboolean); + + void* reserved5; + + jint + (JNICALL *DumpHeap0) + (JNIEnv*, jstring, jboolean); + + jobjectArray + (JNICALL *FindDeadlocks) + (JNIEnv*, jboolean); + + void + (JNICALL *SetVMGlobal) + (JNIEnv*, jstring, jvalue ); + + void* reserved6; + + jobjectArray + (JNICALL *DumpThreads) + (JNIEnv*, jlongArray, jboolean, jboolean); +}; + const unsigned InterfaceVersion = 4; const unsigned PageSize = 4 * 1024; const int VirtualFileBase = 1000000000; @@ -419,6 +598,7 @@ class MyClasspath : public Classpath { unsigned zipEntryMethodField; bool ranNetOnLoad; char buffer[BufferSize]; + JmmInterface jmmInterface; }; struct JVM_ExceptionTableEntryType { @@ -4825,8 +5005,103 @@ EXPORT(JVM_RawMonitorExit)(void* lock) (local::globalMachine->localThread->get())->systemThread); } +int JNICALL +GetVersion(Thread*) +{ + return JMM_VERSION_1_0; +} + +jint JNICALL +GetOptionalSupport(Thread*, jmmOptionalSupport* support) +{ + memset(support, 0, sizeof(jmmOptionalSupport)); + return 0; +} + +jlong JNICALL +GetLongAttribute(Thread* t, jobject, jmmLongAttribute attribute) +{ + const unsigned JMM_JVM_INIT_DONE_TIME_MS = 7; + + switch (attribute) { + case JMM_JVM_INIT_DONE_TIME_MS: + return 0; + + default: + abort(t); + } +} + +jboolean JNICALL +GetBoolAttribute(Thread* t, jmmBoolAttribute attribute) +{ + const unsigned JMM_THREAD_CPU_TIME = 24; + + switch (attribute) { + case JMM_THREAD_CPU_TIME: + return false; + + default: + abort(t); + } +} + +uint64_t +getMemoryManagers(Thread* t, uintptr_t*) +{ + return reinterpret_cast + (makeLocalReference + (t, makeObjectArray + (t, resolveClass + (t, root(t, Machine::BootLoader), + "java/lang/management/MemoryManagerMXBean"), 0))); +} + +jobjectArray JNICALL +GetMemoryManagers(Thread* t, jobject) +{ + return reinterpret_cast(run(t, getMemoryManagers, 0)); +} + +uint64_t +getMemoryPools(Thread* t, uintptr_t*) +{ + return reinterpret_cast + (makeLocalReference + (t, makeObjectArray + (t, resolveClass + (t, root(t, Machine::BootLoader), + "java/lang/management/MemoryPoolMXBean"), 0))); +} + +jobjectArray JNICALL +GetMemoryPools(Thread* t, jobject) +{ + return reinterpret_cast(run(t, getMemoryPools, 0)); +} + extern "C" JNIEXPORT void* JNICALL -EXPORT(JVM_GetManagement)(jint) { abort(); } +EXPORT(JVM_GetManagement)(jint version) +{ + if (version == JMM_VERSION_1_0) { + JmmInterface* interface + = &(static_cast + (local::globalMachine->classpath)->jmmInterface); + + memset(interface, 0, sizeof(JmmInterface)); + + interface->GetVersion = GetVersion; + interface->GetOptionalSupport = GetOptionalSupport; + interface->GetLongAttribute = GetLongAttribute; + interface->GetBoolAttribute = GetBoolAttribute; + interface->GetMemoryManagers = GetMemoryManagers; + interface->GetMemoryPools = GetMemoryPools; + + return interface; + } else { + return 0; + } +} extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_InitAgentProperties)(Thread*, jobject) { abort(); } From 6707116dd4af54adc9c3db880579d4a55d96735d Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 9 Apr 2011 21:19:49 -0600 Subject: [PATCH 082/117] implement sun.misc.Unsafe.addressSize --- src/classpath-openjdk.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 1a2897c093..d432c7f289 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -2179,6 +2179,13 @@ Avian_sun_misc_Unsafe_registerNatives // ignore } +extern "C" JNIEXPORT int64_t +Avian_sun_misc_Unsafe_addressSize +(Thread*, object, uintptr_t*) +{ + return BytesPerWord; +} + extern "C" JNIEXPORT int64_t Avian_sun_misc_Unsafe_defineClass__Ljava_lang_String_2_3BIILjava_lang_ClassLoader_2Ljava_security_ProtectionDomain_2 (Thread* t, object, uintptr_t* arguments) From 14762436626761bd48a5672047b782320aa3821f Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 9 Apr 2011 21:20:21 -0600 Subject: [PATCH 083/117] implement sun.misc.Unsafe.putShort --- src/classpath-openjdk.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index d432c7f289..569bf4693d 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -2394,6 +2394,17 @@ Avian_sun_misc_Unsafe_putByte__Ljava_lang_Object_2JB cast(o, offset) = value; } +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_putShort__Ljava_lang_Object_2JS +(Thread*, object, uintptr_t* arguments) +{ + object o = reinterpret_cast(arguments[1]); + int64_t offset; memcpy(&offset, arguments + 2, 8); + int16_t value = arguments[4]; + + cast(o, offset) = value; +} + extern "C" JNIEXPORT void JNICALL Avian_sun_misc_Unsafe_putInt__Ljava_lang_Object_2JI (Thread*, object, uintptr_t* arguments) From 00b829b8e8135fa0b62a04212b5fe67b9baf57e5 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 9 Apr 2011 21:20:56 -0600 Subject: [PATCH 084/117] fix Class.getDeclaredMethods Internally, the VM augments the method tables for abstract classes with any inherited abstract methods to make code simpler elsewhere, but that means we can't use that table to construct the result of Class.getDeclaredMethods since it would include methods not actually declared in the class. This commit ensures that we preserve and use the original, un-augmented table for that purpose. --- classpath/avian/ClassAddendum.java | 1 + src/classpath-openjdk.cpp | 21 ++++++++++++--- src/machine.cpp | 43 +++++++++++++++--------------- 3 files changed, 40 insertions(+), 25 deletions(-) diff --git a/classpath/avian/ClassAddendum.java b/classpath/avian/ClassAddendum.java index ff11591046..276be33fe9 100644 --- a/classpath/avian/ClassAddendum.java +++ b/classpath/avian/ClassAddendum.java @@ -13,4 +13,5 @@ package avian; public class ClassAddendum extends Addendum { public Object[] interfaceTable; public Object[] innerClassTable; + public Object[] methodTable; } diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 569bf4693d..89648f15de 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -1865,10 +1865,23 @@ interceptFileOperations(Thread* t) voidPointer(getBootstrapResources)); } +object +getClassMethodTable(Thread* t, object c) +{ + object addendum = classAddendum(t, c); + if (addendum) { + object table = classAddendumMethodTable(t, addendum); + if (table) { + return table; + } + } + return classMethodTable(t, c); +} + unsigned countMethods(Thread* t, object c, bool publicOnly) { - object table = classMethodTable(t, c); + object table = getClassMethodTable(t, c); unsigned count = 0; for (unsigned i = 0; i < arrayLength(t, table); ++i) { object vmMethod = arrayBody(t, table, i); @@ -1902,7 +1915,7 @@ countFields(Thread* t, object c, bool publicOnly) unsigned countConstructors(Thread* t, object c, bool publicOnly) { - object table = classMethodTable(t, c); + object table = getClassMethodTable(t, c); unsigned count = 0; for (unsigned i = 0; i < arrayLength(t, table); ++i) { object vmMethod = arrayBody(t, table, i); @@ -4054,7 +4067,7 @@ jvmGetClassDeclaredMethods(Thread* t, uintptr_t* arguments) jclass c = reinterpret_cast(arguments[0]); jboolean publicOnly = arguments[1]; - object table = classMethodTable(t, jclassVmClass(t, *c)); + object table = getClassMethodTable(t, jclassVmClass(t, *c)); if (table) { PROTECT(t, table); @@ -4249,7 +4262,7 @@ jvmGetClassDeclaredConstructors(Thread* t, uintptr_t* arguments) jclass c = reinterpret_cast(arguments[0]); jboolean publicOnly = arguments[1]; - object table = classMethodTable(t, jclassVmClass(t, *c)); + object table = getClassMethodTable(t, jclassVmClass(t, *c)); if (table) { PROTECT(t, table); diff --git a/src/machine.cpp b/src/machine.cpp index 2f7f896e2f..d01abec796 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -969,6 +969,17 @@ addInterfaces(Thread* t, object class_, object map) } } +object +getClassAddendum(Thread* t, object class_, object pool) +{ + object addendum = classAddendum(t, class_); + if (addendum == 0) { + addendum = makeClassAddendum(t, pool, 0, 0, 0, 0, 0); + set(t, class_, ClassAddendum, addendum); + } + return addendum; +} + void parseInterfaceTable(Thread* t, Stream& s, object class_, object pool, Machine::Type throwType) @@ -989,10 +1000,9 @@ parseInterfaceTable(Thread* t, Stream& s, object class_, object pool, if (count) { table = makeArray(t, count); - if (classAddendum(t, class_) == 0) { - object addendum = makeClassAddendum(t, pool, 0, 0, table, 0); - set(t, class_, ClassAddendum, addendum); - } + + object addendum = getClassAddendum(t, class_, pool); + set(t, addendum, ClassAddendumInterfaceTable, table); } for (unsigned i = 0; i < count; ++i) { @@ -1644,6 +1654,10 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool) if (abstractVirtuals) { PROTECT(t, vtable); + object addendum = getClassAddendum(t, class_, pool); + set(t, addendum, ClassAddendumMethodTable, + classMethodTable(t, class_)); + unsigned oldLength = arrayLength(t, classMethodTable(t, class_)); object newMethodTable = makeArray (t, oldLength + listSize(t, abstractVirtuals)); @@ -1707,9 +1721,6 @@ parseAttributeTable(Thread* t, Stream& s, object class_, object pool) PROTECT(t, class_); PROTECT(t, pool); - object addendum = classAddendum(t, class_); - PROTECT(t, addendum); - unsigned attributeCount = s.read2(); for (unsigned j = 0; j < attributeCount; ++j) { object name = singletonObject(t, pool, s.read2() - 1); @@ -1722,19 +1733,12 @@ parseAttributeTable(Thread* t, Stream& s, object class_, object pool) } else if (vm::strcmp(reinterpret_cast("Signature"), &byteArrayBody(t, name, 0)) == 0) { - if (addendum == 0) { - addendum = makeClassAddendum(t, pool, 0, 0, 0, 0); - } - + object addendum = getClassAddendum(t, class_, pool); set(t, addendum, AddendumSignature, singletonObject(t, pool, s.read2() - 1)); } else if (vm::strcmp(reinterpret_cast("InnerClasses"), &byteArrayBody(t, name, 0)) == 0) { - if (addendum == 0) { - addendum = makeClassAddendum(t, pool, 0, 0, 0, 0); - } - unsigned innerClassCount = s.read2(); object table = makeArray(t, innerClassCount); PROTECT(t, table); @@ -1754,25 +1758,22 @@ parseAttributeTable(Thread* t, Stream& s, object class_, object pool) set(t, table, ArrayBody + (i * BytesPerWord), reference); } + object addendum = getClassAddendum(t, class_, pool); set(t, addendum, ClassAddendumInnerClassTable, table); } else if (vm::strcmp(reinterpret_cast ("RuntimeVisibleAnnotations"), &byteArrayBody(t, name, 0)) == 0) { - if (addendum == 0) { - addendum = makeClassAddendum(t, pool, 0, 0, 0, 0); - } - object body = makeByteArray(t, length); + PROTECT(t, body); s.read(reinterpret_cast(&byteArrayBody(t, body, 0)), length); + object addendum = getClassAddendum(t, class_, pool); set(t, addendum, AddendumAnnotationTable, body); } else { s.skip(length); } } - - set(t, class_, ClassAddendum, addendum); } void From d5fb7f97b9ef03454cd063ae79cfceda5199a47d Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 10 Apr 2011 11:26:01 -0600 Subject: [PATCH 085/117] implement sun.misc.Unsafe.getFloat --- src/classpath-openjdk.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 89648f15de..83d85af556 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -2623,6 +2623,15 @@ Avian_sun_misc_Unsafe_getInt__J return *reinterpret_cast(p); } +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_getFloat__J +(Thread*, object, uintptr_t* arguments) +{ + int64_t p; memcpy(&p, arguments + 1, 8); + + return *reinterpret_cast(p); +} + extern "C" JNIEXPORT int64_t JNICALL Avian_sun_misc_Unsafe_pageSize (Thread*, object, uintptr_t*) From 3febd7cea7163115a3be13937deb8d5306ab5749 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 10 Apr 2011 11:26:44 -0600 Subject: [PATCH 086/117] load libfontmanager.so before trying to resolve FontManager.initIDs sun.font.FontManager.initIDs is a native method defined in libfontmanager.so, yet there seems to be no mechanism in OpenJDK's class library to actually load that library, so we lazily load it before trying to resolve the method. --- src/classpath-avian.cpp | 7 +++++++ src/classpath-openjdk.cpp | 26 +++++++++++++++++++++----- src/compile.cpp | 4 ++-- src/machine.h | 3 +++ 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/classpath-avian.cpp b/src/classpath-avian.cpp index af1e337fcc..89c6cdc13d 100644 --- a/src/classpath-avian.cpp +++ b/src/classpath-avian.cpp @@ -10,6 +10,7 @@ #include "machine.h" #include "classpath-common.h" +#include "process.h" using namespace vm; @@ -63,6 +64,12 @@ class MyClasspath : public Classpath { t->m->processor->invoke(t, method, 0, t->javaThread); } + virtual void + resolveNative(Thread* t, object method) + { + vm::resolveNative(t, method); + } + virtual void boot(Thread*) { diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 83d85af556..e130e93a16 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -11,6 +11,7 @@ #include "machine.h" #include "classpath-common.h" #include "util.h" +#include "process.h" #ifdef PLATFORM_WINDOWS @@ -517,6 +518,24 @@ class MyClasspath : public Classpath { release(t, t->javaThread); } + virtual void + resolveNative(Thread* t, object method) + { + if (strcmp(reinterpret_cast("sun/font/FontManager"), + &byteArrayBody(t, className(t, methodClass(t, method)), 0)) == 0 + and strcmp(reinterpret_cast("initIDs"), + &byteArrayBody(t, methodName(t, method), 0)) == 0 + and strcmp(reinterpret_cast("()V"), + &byteArrayBody(t, methodSpec(t, method), 0)) == 0) + { + PROTECT(t, method); + + expect(t, loadLibrary(t, libraryPath, "fontmanager", true, true)); + } + + vm::resolveNative(t, method); + } + virtual void boot(Thread* t) { @@ -528,11 +547,8 @@ class MyClasspath : public Classpath { #ifdef AVIAN_OPENJDK_SRC interceptFileOperations(t); #else // not AVIAN_OPENJDK_SRC - if (loadLibrary(t, libraryPath, "verify", true, true) == 0 - or loadLibrary(t, libraryPath, "java", true, true) == 0) - { - abort(t); - } + expect(t, loadLibrary(t, libraryPath, "verify", true, true)); + expect(t, loadLibrary(t, libraryPath, "java", true, true)); #endif // not AVIAN_OPENJDK_SRC object constructor = resolveMethod diff --git a/src/compile.cpp b/src/compile.cpp index 369515b5d6..de07ebd294 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -7334,7 +7334,7 @@ invokeNative(MyThread* t) static_cast(t)->trace->nativeMethod = 0; }); - resolveNative(t, t->trace->nativeMethod); + t->m->classpath->resolveNative(t, t->trace->nativeMethod); result = invokeNative2(t, t->trace->nativeMethod); @@ -8143,7 +8143,7 @@ class SignalHandler: public System::SignalHandler { t->exception = vm::root(t, root); } - // printTrace(t, t->exception); + printTrace(t, t->exception); object continuation; findUnwindTarget(t, ip, frame, stack, &continuation); diff --git a/src/machine.h b/src/machine.h index c73a11d0b3..488ed45563 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1567,6 +1567,9 @@ class Classpath { virtual void runThread(Thread* t) = 0; + virtual void + resolveNative(Thread* t, object method) = 0; + virtual void boot(Thread* t) = 0; From ed8a72af9eed9d41fcc6e283eaa2caee774a32e8 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 10 Apr 2011 12:55:12 -0600 Subject: [PATCH 087/117] fix MSVC build --- src/common.h | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/common.h b/src/common.h index 3f9860cc28..33e402579f 100644 --- a/src/common.h +++ b/src/common.h @@ -61,11 +61,7 @@ typedef uint64_t uintptr_t; namespace vm { -inline intptr_t& -alias(void* p, unsigned offset) -{ - return *reinterpret_cast(static_cast(p) + offset); -} +typedef intptr_t intptr_alias_t; } // namespace vm @@ -99,11 +95,6 @@ alias(void* p, unsigned offset) namespace vm { typedef intptr_t __attribute__((__may_alias__)) intptr_alias_t; -inline intptr_alias_t& -alias(void* p, unsigned offset) -{ - return *reinterpret_cast(static_cast(p) + offset); -} } // namespace vm @@ -178,6 +169,12 @@ inline void* operator new(size_t, void* p) throw() { return p; } namespace vm { +inline intptr_alias_t& +alias(void* p, unsigned offset) +{ + return *reinterpret_cast(static_cast(p) + offset); +} + #ifdef _MSC_VER template From 8091803b599d666d024e9e2ee72b2acedc2cddbd Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 10 Apr 2011 12:55:42 -0600 Subject: [PATCH 088/117] set MaxNativeCallFootprint to 5 on 32-bit systems Thunks such as divideLong now take a pointer and two int64_t arguments, which amounts to 5 words of stack space on a 32-bit system. --- src/compile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compile.cpp b/src/compile.cpp index de07ebd294..384c9e4c2e 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -52,7 +52,7 @@ const bool Continuations = true; const bool Continuations = false; #endif -const unsigned MaxNativeCallFootprint = 4; +const unsigned MaxNativeCallFootprint = BytesPerWord == 8 ? 4 : 5; const unsigned InitialZoneCapacityInBytes = 64 * 1024; From 88c95615c781a5dec1fa1c855607ae526f7b4271 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 10 Apr 2011 14:42:46 -0600 Subject: [PATCH 089/117] fix cut-and-paste error in ACQUIRE_FIELD_FOR_WRITE definition --- src/machine.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine.h b/src/machine.h index 488ed45563..152723071d 100644 --- a/src/machine.h +++ b/src/machine.h @@ -37,7 +37,7 @@ FieldReadResource MAKE_NAME(monitorResource_) (t, field) #define ACQUIRE_FIELD_FOR_WRITE(t, field) \ - FieldReadResource MAKE_NAME(monitorResource_) (t, field) + FieldWriteResource MAKE_NAME(monitorResource_) (t, field) #define ACQUIRE_RAW(t, x) RawMonitorResource MAKE_NAME(monitorResource_) (t, x) From 7c30e44601dfbe58bd544984d904e78f5b5c30a5 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 10 Apr 2011 14:46:53 -0600 Subject: [PATCH 090/117] add appropriate memory barriers to double-checked locking code --- src/classpath-openjdk.cpp | 9 ++++++++- src/compile.cpp | 14 ++++++-------- src/jnienv.cpp | 18 ++++++++++++++++-- src/machine.cpp | 6 +++++- src/machine.h | 13 ++++++++++++- 5 files changed, 47 insertions(+), 13 deletions(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index e130e93a16..beac1d639a 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -2120,13 +2120,20 @@ setProperty(Thread* t, object method, object properties, object interruptLock(Thread* t, object thread) { - if (threadInterruptLock(t, thread) == 0) { + object lock = threadInterruptLock(t, thread); + + loadMemoryBarrier(); + + if (lock == 0) { PROTECT(t, thread); ACQUIRE(t, t->m->referenceLock); if (threadInterruptLock(t, thread) == 0) { object head = makeMonitorNode(t, 0, 0); object lock = makeMonitor(t, 0, 0, 0, head, head, 0); + + storeStoreMemoryBarrier(); + set(t, thread, ThreadInterruptLock, lock); } } diff --git a/src/compile.cpp b/src/compile.cpp index 384c9e4c2e..29ac0aed24 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -9586,6 +9586,8 @@ compileVirtualThunk(MyThread* t, unsigned index, unsigned* size) uintptr_t virtualThunk(MyThread* t, unsigned index) { + ACQUIRE(t, t->m->classLock); + if (root(t, VirtualThunks) == 0 or wordArrayLength(t, root(t, VirtualThunks)) <= index * 2) { @@ -9599,14 +9601,10 @@ virtualThunk(MyThread* t, unsigned index) } if (wordArrayBody(t, root(t, VirtualThunks), index * 2) == 0) { - ACQUIRE(t, t->m->classLock); - - if (wordArrayBody(t, root(t, VirtualThunks), index * 2) == 0) { - unsigned size; - uintptr_t thunk = compileVirtualThunk(t, index, &size); - wordArrayBody(t, root(t, VirtualThunks), index * 2) = thunk; - wordArrayBody(t, root(t, VirtualThunks), (index * 2) + 1) = size; - } + unsigned size; + uintptr_t thunk = compileVirtualThunk(t, index, &size); + wordArrayBody(t, root(t, VirtualThunks), index * 2) = thunk; + wordArrayBody(t, root(t, VirtualThunks), (index * 2) + 1) = size; } return wordArrayBody(t, root(t, VirtualThunks), index * 2); diff --git a/src/jnienv.cpp b/src/jnienv.cpp index da86b870fe..fb3848cb08 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -509,7 +509,11 @@ findMethod(Thread* t, jclass c, const char* name, const char* spec) jint methodID(Thread* t, object method) { - if (methodNativeID(t, method) == 0) { + int id = methodNativeID(t, method); + + loadMemoryBarrier(); + + if (id == 0) { PROTECT(t, method); ACQUIRE(t, t->m->referenceLock); @@ -517,6 +521,9 @@ methodID(Thread* t, object method) if (methodNativeID(t, method) == 0) { setRoot(t, Machine::JNIMethodTable, vectorAppend (t, root(t, Machine::JNIMethodTable), method)); + + storeStoreMemoryBarrier(); + methodNativeID(t, method) = vectorSize (t, root(t, Machine::JNIMethodTable)); } @@ -1164,7 +1171,11 @@ CallStaticVoidMethod(Thread* t, jclass c, jmethodID m, ...) jint fieldID(Thread* t, object field) { - if (fieldNativeID(t, field) == 0) { + int id = fieldNativeID(t, field); + + loadMemoryBarrier(); + + if (id == 0) { PROTECT(t, field); ACQUIRE(t, t->m->referenceLock); @@ -1172,6 +1183,9 @@ fieldID(Thread* t, object field) if (fieldNativeID(t, field) == 0) { setRoot(t, Machine::JNIFieldTable, vectorAppend (t, root(t, Machine::JNIFieldTable), field)); + + storeStoreMemoryBarrier(); + fieldNativeID(t, field) = vectorSize(t, root(t, Machine::JNIFieldTable)); } } diff --git a/src/machine.cpp b/src/machine.cpp index d01abec796..0128558ce9 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -3677,7 +3677,11 @@ classNeedsInit(Thread* t, object c) bool preInitClass(Thread* t, object c) { - if (classVmFlags(t, c) & NeedInitFlag) { + int flags = classVmFlags(t, c); + + loadMemoryBarrier(); + + if (flags & NeedInitFlag) { PROTECT(t, c); ACQUIRE(t, t->m->classLock); diff --git a/src/machine.h b/src/machine.h index 152723071d..2a69b8e038 100644 --- a/src/machine.h +++ b/src/machine.h @@ -3619,7 +3619,11 @@ getClassRuntimeData(Thread* t, object c) inline object getMethodRuntimeData(Thread* t, object method) { - if (methodRuntimeDataIndex(t, method) == 0) { + int index = methodRuntimeDataIndex(t, method); + + loadMemoryBarrier(); + + if (index == 0) { PROTECT(t, method); ACQUIRE(t, t->m->classLock); @@ -3630,6 +3634,8 @@ getMethodRuntimeData(Thread* t, object method) setRoot(t, Machine::MethodRuntimeDataTable, vectorAppend (t, root(t, Machine::MethodRuntimeDataTable), runtimeData)); + storeStoreMemoryBarrier(); + methodRuntimeDataIndex(t, method) = vectorSize (t, root(t, Machine::MethodRuntimeDataTable)); } @@ -3645,12 +3651,17 @@ getJClass(Thread* t, object c) PROTECT(t, c); object jclass = classRuntimeDataJclass(t, getClassRuntimeData(t, c)); + + loadMemoryBarrier(); + if (jclass == 0) { ACQUIRE(t, t->m->classLock); jclass = classRuntimeDataJclass(t, getClassRuntimeData(t, c)); if (jclass == 0) { jclass = t->m->classpath->makeJclass(t, c); + + storeStoreMemoryBarrier(); set(t, getClassRuntimeData(t, c), ClassRuntimeDataJclass, jclass); } From 1d98d977ce5e5eeaed8a49581a0f9241998d2553 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 10 Apr 2011 15:51:17 -0600 Subject: [PATCH 091/117] only include security policy jars if they exist --- makefile | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/makefile b/makefile index 685a77956e..367311518f 100644 --- a/makefile +++ b/makefile @@ -91,8 +91,18 @@ ifneq ($(openjdk),) classpath-jar-dep = $(openjdk-jar-dep) javahome = $(embed-prefix)/javahomeJar javahome-files = lib/zi lib/currency.data lib/security/java.security \ - lib/security/java.policy lib/security/cacerts \ - lib/security/local_policy.jar lib/security/US_export_policy.jar + lib/security/java.policy lib/security/cacerts + + local-policy = lib/security/local_policy.jar + ifeq ($(shell test -e $(openjdk)/$(local-policy) && echo found),found) + javahome-files += $(local-policy) + endif + + export-policy = lib/security/US_export_policy.jar + ifeq ($(shell test -e $(openjdk)/$(export-policy) && echo found),found) + javahome-files += $(export-policy) + endif + ifeq ($(platform),windows) javahome-files += lib/tzmappings endif From 4d1711cd04154f14ba80ded9d9aa47dba04920b1 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 10 Apr 2011 15:57:03 -0600 Subject: [PATCH 092/117] add OpenJDK build examples to readme.txt --- readme.txt | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/readme.txt b/readme.txt index f4153af60d..4b13eea2db 100644 --- a/readme.txt +++ b/readme.txt @@ -262,6 +262,55 @@ You can reduce the size futher for embedded builds by using ProGuard and the supplied openjdk.pro configuration file (see "Embedding with ProGuard and a Boot Image" below). +Here are some examples of how to install OpenJDK and build Avian with +it on various OSes: + + Debian-based Linux: + # conventional build: + apt-get install openjdk-6-jdk + make openjdk=/usr/lib/jvm/java-6-openjdk test + + # stand-alone build: + apt-get install openjdk-6-jdk + apt-get source openjdk-6-jdk + apt-get build-dep openjdk-6-jdk + (cd openjdk-6-6b18-1.8.3 && ./debian/rules patch) + make openjdk=/usr/lib/jvm/java-6-openjdk \ + openjdk-src=$(pwd)/openjdk-6-6b18-1.8.3/build/openjdk/jdk/src \ + test + + Mac OS X: + # Prerequisite: install MacPorts (http://www.macports.org/) + sudo port selfupdate + + # conventional build: + sudo port install openjdk6 + make openjdk=/opt/local/share/java/openjdk6 test + + # stand-alone build: + sudo port fetch openjdk6 + sudo port patch openjdk6 + make openjdk=/opt/local/share/java/openjdk6 \ + openjdk-src=/opt/local/var/macports/build/_opt_local_var_macports_sources_rsync.macports.org_release_ports_java_openjdk6/work/jdk/src \ + test + + Windows (Cygwin): + # conventional build: + # Prerequisite: download and install the latest Windows OpenJDK + # build from http://www.openscg.com/se/openjdk/ + make openjdk=/cygdrive/c/OpenSCG/openjdk-6.21 test + + # stand-alone build: + # Prerequisite: install OpenSCG build as above, plus the + # corresponding source bundle from + # http://download.java.net/openjdk/jdk6/promoted/, e.g.: + wget http://download.java.net/openjdk/jdk6/promoted/b21/openjdk-6-src-b21-20_jan_2011.tar.gz + mkdir openjdk + (cd openjdk && tar xzf openjdk-6-src-b21-20_jan_2011.tar.gz) + make openjdk=/cygdrive/c/OpenSCG/openjdk-6.21 \ + openjdk-src=$(pwd)/openjdk/jdk/src \ + test + Installing ---------- From 09872555523588a5a8839682e091c717e1615a05 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 10 Apr 2011 17:01:38 -0600 Subject: [PATCH 093/117] tolerate missing classes in interceptFileOperations If we fail to resolve a given class (e.g. due to ProGuard obfuscating or eliminating it), just move on to the next one rather than return immediately. Otherwise, we may miss intercepting methods of classes we can resolve. --- src/classpath-openjdk.cpp | 225 +++++++++++++++++++++----------------- 1 file changed, 122 insertions(+), 103 deletions(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index beac1d639a..75a617fecb 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -1691,156 +1691,174 @@ interceptFileOperations(Thread* t) MyClasspath* cp = static_cast(t->m->classpath); { object fileClass = resolveClass - (t, root(t, Machine::BootLoader), "java/io/File"); - if (fileClass == 0) return; + (t, root(t, Machine::BootLoader), "java/io/File", false); - object filePathField = findFieldInClass2 - (t, fileClass, "path", "Ljava/lang/String;"); - if (filePathField == 0) return; - - cp->filePathField = fieldOffset(t, filePathField); + if (fileClass) { + object filePathField = findFieldInClass2 + (t, fileClass, "path", "Ljava/lang/String;"); + + if (filePathField) { + cp->filePathField = fieldOffset(t, filePathField); + } + } } { object fileDescriptorClass = resolveClass - (t, root(t, Machine::BootLoader), "java/io/FileDescriptor"); - if (fileDescriptorClass == 0) return; + (t, root(t, Machine::BootLoader), "java/io/FileDescriptor", false); - object fileDescriptorFdField = findFieldInClass2 - (t, fileDescriptorClass, "fd", "I"); - if (fileDescriptorFdField == 0) return; + if (fileDescriptorClass) { + object fileDescriptorFdField = findFieldInClass2 + (t, fileDescriptorClass, "fd", "I"); - cp->fileDescriptorFdField = fieldOffset(t, fileDescriptorFdField); + if (fileDescriptorFdField) { + cp->fileDescriptorFdField = fieldOffset(t, fileDescriptorFdField); + } + } } { object fileInputStreamClass = resolveClass - (t, root(t, Machine::BootLoader), "java/io/FileInputStream"); - if (fileInputStreamClass == 0) return; + (t, root(t, Machine::BootLoader), "java/io/FileInputStream", false); - PROTECT(t, fileInputStreamClass); + if (fileInputStreamClass) { + PROTECT(t, fileInputStreamClass); - object fileInputStreamFdField = findFieldInClass2 - (t, fileInputStreamClass, "fd", "Ljava/io/FileDescriptor;"); - if (fileInputStreamFdField == 0) return; + object fileInputStreamFdField = findFieldInClass2 + (t, fileInputStreamClass, "fd", "Ljava/io/FileDescriptor;"); - cp->fileInputStreamFdField = fieldOffset(t, fileInputStreamFdField); + if (fileInputStreamFdField) { + cp->fileInputStreamFdField = fieldOffset(t, fileInputStreamFdField); - intercept(t, fileInputStreamClass, "open", "(Ljava/lang/String;)V", - voidPointer(openFile)); + intercept(t, fileInputStreamClass, "open", "(Ljava/lang/String;)V", + voidPointer(openFile)); - intercept(t, fileInputStreamClass, "read", "()I", - voidPointer(readByteFromFile)); + intercept(t, fileInputStreamClass, "read", "()I", + voidPointer(readByteFromFile)); - intercept(t, fileInputStreamClass, "readBytes", "([BII)I", - voidPointer(readBytesFromFile)); + intercept(t, fileInputStreamClass, "readBytes", "([BII)I", + voidPointer(readBytesFromFile)); - intercept(t, fileInputStreamClass, "skip", "(J)J", - voidPointer(skipBytesInFile)); + intercept(t, fileInputStreamClass, "skip", "(J)J", + voidPointer(skipBytesInFile)); - intercept(t, fileInputStreamClass, "available", "()I", - voidPointer(availableBytesInFile)); + intercept(t, fileInputStreamClass, "available", "()I", + voidPointer(availableBytesInFile)); - intercept(t, fileInputStreamClass, "close0", "()V", - voidPointer(closeFile)); + intercept(t, fileInputStreamClass, "close0", "()V", + voidPointer(closeFile)); + } + } } { object zipEntryClass = resolveClass - (t, root(t, Machine::BootLoader), "java/util/zip/ZipEntry"); - if (zipEntryClass == 0) return; + (t, root(t, Machine::BootLoader), "java/util/zip/ZipEntry", false); - PROTECT(t, zipEntryClass); + if (zipEntryClass) { + PROTECT(t, zipEntryClass); - object zipEntryNameField = findFieldInClass2 - (t, zipEntryClass, "name", "Ljava/lang/String;"); - if (zipEntryNameField == 0) return; + object zipEntryNameField = findFieldInClass2 + (t, zipEntryClass, "name", "Ljava/lang/String;"); - cp->zipEntryNameField = fieldOffset(t, zipEntryNameField); + if (zipEntryNameField) { + cp->zipEntryNameField = fieldOffset(t, zipEntryNameField); - object zipEntryTimeField = findFieldInClass2 - (t, zipEntryClass, "time", "J"); - if (zipEntryTimeField == 0) return; + object zipEntryTimeField = findFieldInClass2 + (t, zipEntryClass, "time", "J"); - cp->zipEntryTimeField = fieldOffset(t, zipEntryTimeField); + if (zipEntryTimeField) { + cp->zipEntryTimeField = fieldOffset(t, zipEntryTimeField); - object zipEntryCrcField = findFieldInClass2 - (t, zipEntryClass, "crc", "J"); - if (zipEntryCrcField == 0) return; + object zipEntryCrcField = findFieldInClass2 + (t, zipEntryClass, "crc", "J"); - cp->zipEntryCrcField = fieldOffset(t, zipEntryCrcField); + if (zipEntryCrcField) { + cp->zipEntryCrcField = fieldOffset(t, zipEntryCrcField); - object zipEntrySizeField = findFieldInClass2 - (t, zipEntryClass, "size", "J"); - if (zipEntrySizeField == 0) return; + object zipEntrySizeField = findFieldInClass2 + (t, zipEntryClass, "size", "J"); - cp->zipEntrySizeField = fieldOffset(t, zipEntrySizeField); + if (zipEntrySizeField) { + cp->zipEntrySizeField = fieldOffset(t, zipEntrySizeField); - object zipEntryCsizeField = findFieldInClass2 - (t, zipEntryClass, "csize", "J"); - if (zipEntryCsizeField == 0) return; + object zipEntryCsizeField = findFieldInClass2 + (t, zipEntryClass, "csize", "J"); + + if (zipEntryCsizeField) { + cp->zipEntryCsizeField = fieldOffset(t, zipEntryCsizeField); - cp->zipEntryCsizeField = fieldOffset(t, zipEntryCsizeField); + object zipEntryMethodField = findFieldInClass2 + (t, zipEntryClass, "method", "I"); - object zipEntryMethodField = findFieldInClass2 - (t, zipEntryClass, "method", "I"); - if (zipEntryMethodField == 0) return; + if (zipEntryMethodField) { + cp->zipEntryMethodField = fieldOffset + (t, zipEntryMethodField); - cp->zipEntryMethodField = fieldOffset(t, zipEntryMethodField); - - intercept(t, zipEntryClass, "initFields", "(J)V", - voidPointer(initializeZipEntryFields)); + intercept(t, zipEntryClass, "initFields", "(J)V", + voidPointer(initializeZipEntryFields)); + } + } + } + } + } + } + } } { object zipFileClass = resolveClass - (t, root(t, Machine::BootLoader), "java/util/zip/ZipFile"); - if (zipFileClass == 0) return; + (t, root(t, Machine::BootLoader), "java/util/zip/ZipFile", false); - PROTECT(t, zipFileClass); + if (zipFileClass) { + PROTECT(t, zipFileClass); - object zipFileJzfileField = findFieldInClass2 - (t, zipFileClass, "jzfile", "J"); - if (zipFileJzfileField == 0) return; + object zipFileJzfileField = findFieldInClass2 + (t, zipFileClass, "jzfile", "J"); - cp->zipFileJzfileField = fieldOffset(t, zipFileJzfileField); + if (zipFileJzfileField) { + cp->zipFileJzfileField = fieldOffset(t, zipFileJzfileField); - intercept(t, zipFileClass, "open", "(Ljava/lang/String;IJ)J", - voidPointer(openZipFile)); + intercept(t, zipFileClass, "open", "(Ljava/lang/String;IJ)J", + voidPointer(openZipFile)); - intercept(t, zipFileClass, "getTotal", "(J)I", - voidPointer(getZipFileEntryCount)); + intercept(t, zipFileClass, "getTotal", "(J)I", + voidPointer(getZipFileEntryCount)); - intercept(t, zipFileClass, "getEntry", "(JLjava/lang/String;Z)J", - voidPointer(getZipFileEntry)); + intercept(t, zipFileClass, "getEntry", "(JLjava/lang/String;Z)J", + voidPointer(getZipFileEntry)); - intercept(t, zipFileClass, "getNextEntry", "(JI)J", - voidPointer(getNextZipFileEntry)); + intercept(t, zipFileClass, "getNextEntry", "(JI)J", + voidPointer(getNextZipFileEntry)); - intercept(t, zipFileClass, "getMethod", "(J)I", - voidPointer(getZipFileEntryMethod)); + intercept(t, zipFileClass, "getMethod", "(J)I", + voidPointer(getZipFileEntryMethod)); - intercept(t, zipFileClass, "freeEntry", "(JJ)V", - voidPointer(freeZipFileEntry)); + intercept(t, zipFileClass, "freeEntry", "(JJ)V", + voidPointer(freeZipFileEntry)); - intercept(t, zipFileClass, "read", "(JJJ[BII)I", - voidPointer(readZipFileEntry)); + intercept(t, zipFileClass, "read", "(JJJ[BII)I", + voidPointer(readZipFileEntry)); - intercept(t, zipFileClass, "getCSize", "(J)J", - voidPointer(getZipFileEntryCompressedSize)); + intercept(t, zipFileClass, "getCSize", "(J)J", + voidPointer(getZipFileEntryCompressedSize)); - intercept(t, zipFileClass, "getSize", "(J)J", - voidPointer(getZipFileEntryUncompressedSize)); + intercept(t, zipFileClass, "getSize", "(J)J", + voidPointer(getZipFileEntryUncompressedSize)); - intercept(t, zipFileClass, "getZipMessage", "(J)Ljava/lang/String;", - voidPointer(getZipMessage)); + intercept(t, zipFileClass, "getZipMessage", "(J)Ljava/lang/String;", + voidPointer(getZipMessage)); - intercept(t, zipFileClass, "close", "(J)V", - voidPointer(closeZipFile)); + intercept(t, zipFileClass, "close", "(J)V", + voidPointer(closeZipFile)); + } + } } { object jarFileClass = resolveClass - (t, root(t, Machine::BootLoader), "java/util/jar/JarFile"); - if (jarFileClass == 0) return; + (t, root(t, Machine::BootLoader), "java/util/jar/JarFile", false); - intercept(t, jarFileClass, "getMetaInfEntryNames", "()[Ljava/lang/String;", - voidPointer(getJarFileMetaInfEntryNames)); + if (jarFileClass) { + intercept(t, jarFileClass, "getMetaInfEntryNames", + "()[Ljava/lang/String;", + voidPointer(getJarFileMetaInfEntryNames)); + } } { @@ -1854,18 +1872,19 @@ interceptFileOperations(Thread* t) object fsClass = resolveClass (t, root(t, Machine::BootLoader), fsClassName, false); - if (fsClass == 0) return; - PROTECT(t, fsClass); + if (fsClass) { + PROTECT(t, fsClass); - intercept(t, fsClass, gbaMethodName, "(Ljava/io/File;)I", - voidPointer(getFileAttributes)); + intercept(t, fsClass, gbaMethodName, "(Ljava/io/File;)I", + voidPointer(getFileAttributes)); - intercept(t, fsClass, "checkAccess", "(Ljava/io/File;I)Z", - voidPointer(checkFileAccess)); + intercept(t, fsClass, "checkAccess", "(Ljava/io/File;I)Z", + voidPointer(checkFileAccess)); - intercept(t, fsClass, "getLength", "(Ljava/io/File;)J", - voidPointer(getFileLength)); + intercept(t, fsClass, "getLength", "(Ljava/io/File;)J", + voidPointer(getFileLength)); + } } intercept(t, type(t, Machine::ClassLoaderType), "loadLibrary", From cada2c6acc4626b21362619ea78c8657f29ee461 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 10 Apr 2011 17:04:58 -0600 Subject: [PATCH 094/117] add reference to avian-swt-examples.git in readme.txt --- readme.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/readme.txt b/readme.txt index 4b13eea2db..a17e553962 100644 --- a/readme.txt +++ b/readme.txt @@ -260,7 +260,9 @@ an LZMA-enabled version: You can reduce the size futher for embedded builds by using ProGuard and the supplied openjdk.pro configuration file (see "Embedding with -ProGuard and a Boot Image" below). +ProGuard and a Boot Image" below). Also see app.mk in +git://oss.readytalk.com/avian-swt-examples.git for an example of using +Avian, OpenJDK, ProGuard, and UPX in concert. Here are some examples of how to install OpenJDK and build Avian with it on various OSes: From a17045b02f894e2e4929a4ab42bb0c765883dc2f Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 14 Apr 2011 16:12:12 -0600 Subject: [PATCH 095/117] avoid naming conflicts in OpenJDK build of libavian.a OpenJDK's compile.c and Avian's compile.cpp were both being compiled to compile.o, which led to a conflict when building libavian.a. We now append "-openjdk" to the object file name for OpenJDK code to avoid such conflicts. --- makefile | 4 ++-- openjdk-src.mk | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/makefile b/makefile index 367311518f..7356792831 100644 --- a/makefile +++ b/makefile @@ -898,7 +898,7 @@ $(generator): $(generator-objects) @echo "linking $(@)" $(build-ld) $(^) $(build-lflags) -o $(@) -$(openjdk-objects): $(build)/openjdk/%.o: $(openjdk-src)/%.c \ +$(openjdk-objects): $(build)/openjdk/%-openjdk.o: $(openjdk-src)/%.c \ $(openjdk-headers-dep) @echo "compiling $(@)" @mkdir -p $(dir $(@)) @@ -907,7 +907,7 @@ $(openjdk-objects): $(build)/openjdk/%.o: $(openjdk-src)/%.c \ $(optimization-cflags) -w -c $(build)/openjdk/$(notdir $(<)) \ $(call output,$(@)) -$(openjdk-local-objects): $(build)/openjdk/%.o: $(src)/openjdk/%.c \ +$(openjdk-local-objects): $(build)/openjdk/%-openjdk.o: $(src)/openjdk/%.c \ $(openjdk-headers-dep) @echo "compiling $(@)" @mkdir -p $(dir $(@)) diff --git a/openjdk-src.mk b/openjdk-src.mk index 190c8622e9..b050f75c94 100644 --- a/openjdk-src.mk +++ b/openjdk-src.mk @@ -298,7 +298,7 @@ endif openjdk-local-sources = \ $(src)/openjdk/my_net_util.c -c-objects = $(foreach x,$(1),$(patsubst $(2)/%.c,$(3)/%.o,$(x))) +c-objects = $(foreach x,$(1),$(patsubst $(2)/%.c,$(3)/%-openjdk.o,$(x))) openjdk-objects = \ $(call c-objects,$(openjdk-sources),$(openjdk-src),$(build)/openjdk) From 195bafa9b38cb3727957700c432b69ab121eb7ff Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 14 Apr 2011 16:39:25 -0600 Subject: [PATCH 096/117] preserve Windows-specific OpenJDK entities from obfuscation --- openjdk.pro | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/openjdk.pro b/openjdk.pro index 81031f3bc9..dd9e07a910 100644 --- a/openjdk.pro +++ b/openjdk.pro @@ -104,7 +104,8 @@ } -keepclassmembers class java.io.FileDescriptor { - private int fd; + private int fd; + private long handle; } -keep class java.net.InetAddress { @@ -132,7 +133,8 @@ } -keepclassmembers class java.io.FileOutputStream { - private java.io.FileDescriptor fd; + private java.io.FileDescriptor fd; + private boolean append; } # changed in native code via sun.misc.Unsafe (todo: handle other @@ -174,6 +176,10 @@ public UnixFileSystem(); } +-keep class java.io.WinNTFileSystem { + public WinNTFileSystem(); + } + -keep class java.io.File { private java.lang.String path; } From b76cbbfa56ec2a0687e5c4065e82d70bf8e6d08b Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 11 May 2011 19:50:45 -0600 Subject: [PATCH 097/117] fix instruction offset calculation in powerpc.cpp The previous code did not take into account any padding embedded in a basic block due to inline jump tables, which led to invalid code generation in large methods --- src/powerpc.cpp | 76 ++++++++++++++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 30 deletions(-) diff --git a/src/powerpc.cpp b/src/powerpc.cpp index e7e247dacb..42a69fdcd6 100644 --- a/src/powerpc.cpp +++ b/src/powerpc.cpp @@ -196,7 +196,7 @@ class MyBlock: public Assembler::Block { MyBlock(Context* context, unsigned offset): context(context), next(0), jumpOffsetHead(0), jumpOffsetTail(0), lastJumpOffsetTail(0), jumpEventHead(0), jumpEventTail(0), - lastEventOffset(0), offset(offset), start(~0), size(0) + lastEventOffset(0), offset(offset), start(~0), size(0), resolved(false) { } virtual unsigned resolve(unsigned start, Assembler::Block* next) { @@ -205,6 +205,8 @@ class MyBlock: public Assembler::Block { ::resolve(this); + this->resolved = true; + return start + size + padding(this, size); } @@ -219,6 +221,7 @@ class MyBlock: public Assembler::Block { unsigned offset; unsigned start; unsigned size; + bool resolved; }; class Task; @@ -326,13 +329,14 @@ class Offset: public Promise { { } virtual bool resolved() { - return block->start != static_cast(~0); + return block->resolved; } virtual int64_t value() { assert(c, resolved()); - return block->start + (offset - block->offset); + unsigned o = offset - block->offset; + return block->start + padding(block, o) + o; } Context* c; @@ -495,38 +499,24 @@ appendJumpEvent(Context* c, MyBlock* b, unsigned offset, JumpOffset* head, b->jumpEventTail = e; } +bool +needJump(MyBlock* b) +{ + return b->next or (not bounded(2, 16, b->size)); +} + unsigned padding(MyBlock* b, unsigned offset) { unsigned total = 0; - for (JumpEvent** e = &(b->jumpEventHead); *e;) { - if ((*e)->offset <= offset) { - for (JumpOffset** o = &((*e)->jumpOffsetHead); *o;) { - if ((*o)->task->promise->resolved() - and (*o)->task->instructionOffset->resolved()) - { - int32_t v = reinterpret_cast((*o)->task->promise->value()) - - (b->context->result + (*o)->task->instructionOffset->value()); - - if (bounded(2, 16, v)) { - // this conditional jump needs no indirection -- a direct - // jump will suffice - *o = (*o)->next; - continue; - } - } - + for (JumpEvent* e = b->jumpEventHead; e; e = e->next) { + if (e->offset <= offset) { + for (JumpOffset* o = e->jumpOffsetHead; o; o = o->next) { total += BytesPerWord; - o = &((*o)->next); } - if ((*e)->jumpOffsetHead == 0) { - *e = (*e)->next; - } else { - if (b->next) { - total += BytesPerWord; - } - e = &((*e)->next); + if (needJump(b)) { + total += BytesPerWord; } } else { break; @@ -541,6 +531,32 @@ resolve(MyBlock* b) { Context* c = b->context; + for (JumpEvent** e = &(b->jumpEventHead); *e;) { + for (JumpOffset** o = &((*e)->jumpOffsetHead); *o;) { + if ((*o)->task->promise->resolved() + and (*o)->task->instructionOffset->resolved()) + { + int32_t v = reinterpret_cast((*o)->task->promise->value()) + - (c->result + (*o)->task->instructionOffset->value()); + + if (bounded(2, 16, v)) { + // this conditional jump needs no indirection -- a direct + // jump will suffice + *o = (*o)->next; + continue; + } + } + + o = &((*o)->next); + } + + if ((*e)->jumpOffsetHead == 0) { + *e = (*e)->next; + } else { + e = &((*e)->next); + } + } + if (b->jumpOffsetHead) { if (c->jumpOffsetTail) { c->jumpOffsetTail->next = b->jumpOffsetHead; @@ -2680,7 +2696,7 @@ class MyAssembler: public Assembler { uint8_t* address = dst + dstOffset + jumpTableSize; - if (b->next) { + if (needJump(b)) { address += BytesPerWord; } @@ -2691,7 +2707,7 @@ class MyAssembler: public Assembler { assert(&c, jumpTableSize); - if (b->next) { + if (needJump(b)) { write4(dst + dstOffset, ::b(jumpTableSize + BytesPerWord)); } From fa7d46c322ef90c220b0697ecb4f262bcd4a349d Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 11 May 2011 19:56:29 -0600 Subject: [PATCH 098/117] handle methods ending with large blocks properly when generating constant pools We can only omit the jump past a constant pool if it's placed at the end of a method, which is only true if the pool belongs to the last block of that method and that block is not so large that the pool must be placed inside the block instead of after it. --- src/arm.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/arm.cpp b/src/arm.cpp index 38ba3a6ce4..42cfcf724b 100644 --- a/src/arm.cpp +++ b/src/arm.cpp @@ -664,13 +664,19 @@ appendPoolEvent(Context* c, MyBlock* b, unsigned offset, PoolOffset* head, b->poolEventTail = e; } +bool +needJump(MyBlock* b) +{ + return b->next or b->size != (b->size & PoolOffsetMask); +} + unsigned padding(MyBlock* b, unsigned offset) { unsigned total = 0; for (PoolEvent* e = b->poolEventHead; e; e = e->next) { if (e->offset <= offset) { - if (b->next) { + if (needJump(b)) { total += BytesPerWord; } for (PoolOffset* o = e->poolOffsetHead; o; o = o->next) { @@ -2363,7 +2369,7 @@ class MyAssembler: public Assembler { unsigned entry = dstOffset + poolSize; - if (b->next) { + if (needJump(b)) { entry += BytesPerWord; } @@ -2381,7 +2387,7 @@ class MyAssembler: public Assembler { poolSize += BytesPerWord; } - if (b->next) { + if (needJump(b)) { write4(dst + dstOffset, ::b((poolSize + BytesPerWord - 8) >> 2)); } From 18a6393ecf2c58508eef44be6233796172cc19ec Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 16 May 2011 10:30:56 -0600 Subject: [PATCH 099/117] fix ClassCastException in ZipFile.getInputStream This was being thrown when the parameter passed was a JarFile.MyJarEntry, not a ZipFile.MyZipEntry, yet we cast it to the latter. --- classpath/java/util/jar/JarFile.java | 6 +++++- classpath/java/util/zip/ZipFile.java | 12 ++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/classpath/java/util/jar/JarFile.java b/classpath/java/util/jar/JarFile.java index af9e34f975..f86fd6ac36 100644 --- a/classpath/java/util/jar/JarFile.java +++ b/classpath/java/util/jar/JarFile.java @@ -33,7 +33,7 @@ public class JarFile extends ZipFile { return (JarEntry) getEntry(JarEntryFactory.Instance, name); } - private static class MyJarEntry extends JarEntry { + private static class MyJarEntry extends JarEntry implements MyEntry { public final Window window; public final int pointer; @@ -65,6 +65,10 @@ public class JarFile extends ZipFile { return 0; } } + + public int pointer() { + return pointer; + } } private static class JarEntryFactory implements EntryFactory { diff --git a/classpath/java/util/zip/ZipFile.java b/classpath/java/util/zip/ZipFile.java index 2bbb13c35a..c80e7104f2 100644 --- a/classpath/java/util/zip/ZipFile.java +++ b/classpath/java/util/zip/ZipFile.java @@ -83,7 +83,7 @@ public class ZipFile { } public InputStream getInputStream(ZipEntry entry) throws IOException { - int pointer = ((MyZipEntry) entry).pointer; + int pointer = ((MyEntry) entry).pointer(); int method = compressionMethod(window, pointer); int size = compressedSize(window, pointer); InputStream in = new MyInputStream(file, fileData(window, pointer), size); @@ -245,7 +245,11 @@ public class ZipFile { } } - private static class MyZipEntry extends ZipEntry { + protected interface MyEntry { + public int pointer(); + } + + private static class MyZipEntry extends ZipEntry implements MyEntry { public final Window window; public final int pointer; @@ -277,6 +281,10 @@ public class ZipFile { return 0; } } + + public int pointer() { + return pointer; + } } protected interface EntryFactory { From 2b229b4b6dc3ee6978227ded6af775e6b8636572 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 16 May 2011 10:33:46 -0600 Subject: [PATCH 100/117] add stub implementations of JVM_{Enable|Disable}Compiler --- src/classpath-openjdk.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 75a617fecb..25c0c7ff65 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -3160,10 +3160,16 @@ extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_CompilerCommand)(Thread*, jclass, jobject) { abort(); } extern "C" JNIEXPORT void JNICALL -EXPORT(JVM_EnableCompiler)(Thread*, jclass) { abort(); } +EXPORT(JVM_EnableCompiler)(Thread*, jclass) +{ + // ignore +} extern "C" JNIEXPORT void JNICALL -EXPORT(JVM_DisableCompiler)(Thread*, jclass) { abort(); } +EXPORT(JVM_DisableCompiler)(Thread*, jclass) +{ + // ignore +} extern "C" JNIEXPORT void JNICALL EXPORT(JVM_StartThread)(Thread* t, jobject thread) From bfe6934183ec0091cf32bf79cd442d62bd56e527 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 16 May 2011 10:34:10 -0600 Subject: [PATCH 101/117] support multiline Class-Path properties in JAR manifests --- src/finder.cpp | 94 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 77 insertions(+), 17 deletions(-) diff --git a/src/finder.cpp b/src/finder.cpp index 62474040d9..88006be320 100644 --- a/src/finder.cpp +++ b/src/finder.cpp @@ -629,6 +629,33 @@ void add(System* s, Element** first, Element** last, Allocator* allocator, const char* name, unsigned nameLength, const char* bootLibrary); +void +addTokens(System* s, Element** first, Element** last, Allocator* allocator, + const char* jarName, unsigned jarNameBase, const char* tokens, + unsigned tokensLength, const char* bootLibrary) +{ + for (Tokenizer t(tokens, tokensLength, ' '); t.hasMore();) { + Tokenizer::Token token(t.next()); + + RUNTIME_ARRAY(char, n, jarNameBase + token.length + 1); + memcpy(RUNTIME_ARRAY_BODY(n), jarName, jarNameBase); + memcpy(RUNTIME_ARRAY_BODY(n) + jarNameBase, token.s, token.length); + RUNTIME_ARRAY_BODY(n)[jarNameBase + token.length] = 0; + + add(s, first, last, allocator, RUNTIME_ARRAY_BODY(n), + jarNameBase + token.length, bootLibrary); + } +} + +bool +continuationLine(const uint8_t* base, unsigned total, unsigned* start, + unsigned* length) +{ + return readLine(base, total, start, length) + and *length > 0 + and base[*start] == ' '; +} + void addJar(System* s, Element** first, Element** last, Allocator* allocator, const char* name, const char* bootLibrary) @@ -640,6 +667,8 @@ addJar(System* s, Element** first, Element** last, Allocator* allocator, JarElement* e = new (allocator->allocate(sizeof(JarElement))) JarElement(s, allocator, name); + unsigned nameBase = baseName(name, s->fileSeparator()); + add(first, last, e); System::Region* region = e->find("META-INF/MANIFEST.MF"); @@ -647,29 +676,60 @@ addJar(System* s, Element** first, Element** last, Allocator* allocator, unsigned start = 0; unsigned length; while (readLine(region->start(), region->length(), &start, &length)) { + unsigned multilineTotal = 0; + const unsigned PrefixLength = 12; - if (strncmp("Class-Path: ", reinterpret_cast - (region->start() + start), PrefixLength) == 0) + if (length > PrefixLength + and strncmp("Class-Path: ", reinterpret_cast + (region->start() + start), PrefixLength) == 0) { - for (Tokenizer t(reinterpret_cast - (region->start() + start + PrefixLength), - length - PrefixLength, ' '); - t.hasMore();) - { - Tokenizer::Token token(t.next()); + { unsigned nextStart = start + length; + unsigned nextLength; + while (continuationLine + (region->start(), region->length(), &nextStart, &nextLength)) + { + multilineTotal += nextLength; + nextStart += nextLength; + } + } - unsigned base = baseName(name, s->fileSeparator()); + const char* line = reinterpret_cast + (region->start() + start + PrefixLength); - RUNTIME_ARRAY(char, n, base + token.length + 1); - memcpy(RUNTIME_ARRAY_BODY(n), name, base); - memcpy(RUNTIME_ARRAY_BODY(n) + base, token.s, token.length); - RUNTIME_ARRAY_BODY(n)[base + token.length] = 0; - - add(s, first, last, allocator, RUNTIME_ARRAY_BODY(n), - base + token.length, bootLibrary); + unsigned lineLength = length - PrefixLength; + + if (multilineTotal) { + RUNTIME_ARRAY + (char, n, (length - PrefixLength) + multilineTotal + 1); + + memcpy(RUNTIME_ARRAY_BODY(n), line, lineLength); + + unsigned offset = lineLength; + { unsigned nextStart = start + length; + unsigned nextLength; + while (continuationLine + (region->start(), region->length(), &nextStart, + &nextLength)) + { + unsigned continuationLength = nextLength - 1; + + memcpy(RUNTIME_ARRAY_BODY(n) + offset, + region->start() + nextStart + 1, continuationLength); + + offset += continuationLength; + nextStart += nextLength; + } + } + + addTokens(s, first, last, allocator, name, nameBase, + RUNTIME_ARRAY_BODY(n), offset, bootLibrary); + } else { + addTokens(s, first, last, allocator, name, nameBase, line, + lineLength, bootLibrary); } } - start += length; + + start += length + multilineTotal; } region->dispose(); From e788a18bc73774433f140039a9d4a63ed47245f5 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 16 May 2011 17:12:10 -0600 Subject: [PATCH 102/117] implement java.util.zip.CRC32 --- classpath/java/util/zip/CRC32.java | 69 ++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 classpath/java/util/zip/CRC32.java diff --git a/classpath/java/util/zip/CRC32.java b/classpath/java/util/zip/CRC32.java new file mode 100644 index 0000000000..047ee685af --- /dev/null +++ b/classpath/java/util/zip/CRC32.java @@ -0,0 +1,69 @@ +/* Copyright (c) 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. */ + +package java.util.zip; + +public class CRC32 { + private static final int Polynomial = 0x04C11DB7; + private static final int Width = 32; + private static final int Top = 1 << (Width - 1); + private static final int InitialRemainder = 0xFFFFFFFF; + private static final int ResultXor = 0xFFFFFFFF; + + private static final int[] table = new int[256]; + + static { + for (int dividend = 0; dividend < 256; ++ dividend) { + int remainder = dividend << (Width - 8); + for (int bit = 8; bit > 0; --bit) { + remainder = ((remainder & Top) != 0) + ? (remainder << 1) ^ Polynomial + : (remainder << 1); + } + table[dividend] = remainder; + } + } + + private int remainder = InitialRemainder; + + public void reset() { + remainder = InitialRemainder; + } + + public void update(int b) { + remainder = table[reflect(b, 8) ^ (remainder >>> (Width - 8))] + ^ (remainder << 8); + } + + public void update(byte[] array, int offset, int length) { + for (int i = 0; i < length; ++i) { + update(array[offset + i] & 0xFF); + } + } + + public void update(byte[] array) { + update(array, 0, array.length); + } + + public long getValue() { + return reflect(remainder, Width) ^ ResultXor; + } + + private static int reflect(int x, int n) { + int reflection = 0; + for (int i = 0; i < n; ++i) { + if ((x & 1) != 0) { + reflection |= (1 << ((n - 1) - i)); + } + x = (x >>> 1); + } + return reflection; + } +} From d4da92d300e4f7e6b45afa56eb6a1487e679256e Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 16 May 2011 17:12:41 -0600 Subject: [PATCH 103/117] fix bugs in Deflater and DeflaterOutputStream Previously, Deflater.deflate would pass Z_SYNC_FLUSH to zlib unconditionally, which caused the output to be enormous when setInput was called repeatedly with very small input buffers. In order to allow zlib to buffer output and thereby maximize compression, we must use Z_NO_FLUSH until Deflater.finish is called, at which point we switch to Z_FINISH. We also modify DeflaterOutputStream.close to call Deflater.finish and write any remaining output to the wrapped stream. --- classpath/java-util-zip.cpp | 4 +-- classpath/java/util/zip/Deflater.java | 27 ++++++++++++------ .../java/util/zip/DeflaterOutputStream.java | 28 ++++++++++--------- 3 files changed, 35 insertions(+), 24 deletions(-) diff --git a/classpath/java-util-zip.cpp b/classpath/java-util-zip.cpp index a7d969839a..f883e528bc 100644 --- a/classpath/java-util-zip.cpp +++ b/classpath/java-util-zip.cpp @@ -121,7 +121,7 @@ Java_java_util_zip_Deflater_deflate (JNIEnv* e, jclass, jlong peer, jbyteArray input, jint inputOffset, jint inputLength, jbyteArray output, jint outputOffset, jint outputLength, - jintArray results) + jboolean finish, jintArray results) { z_stream* s = reinterpret_cast(peer); @@ -145,7 +145,7 @@ Java_java_util_zip_Deflater_deflate s->next_out = reinterpret_cast(out); s->avail_out = outputLength; - int r = deflate(s, Z_SYNC_FLUSH); + int r = deflate(s, finish ? Z_FINISH : Z_NO_FLUSH); jint resultArray[3] = { r, inputLength - s->avail_in, outputLength - s->avail_out }; diff --git a/classpath/java/util/zip/Deflater.java b/classpath/java/util/zip/Deflater.java index d7bfc83b88..28df9754d2 100644 --- a/classpath/java/util/zip/Deflater.java +++ b/classpath/java/util/zip/Deflater.java @@ -27,14 +27,19 @@ public class Deflater { private boolean needDictionary; private boolean finished; private final boolean nowrap; + private boolean finish; - public Deflater(boolean nowrap) { + public Deflater(int level, boolean nowrap) { this.nowrap = nowrap; - peer = make(nowrap, DEFAULT_LEVEL); + peer = make(nowrap, level); + } + + public Deflater(int level) { + this(level, false); } public Deflater() { - this(false); + this(DEFAULT_LEVEL); } private void check() { @@ -85,16 +90,15 @@ public class Deflater { peer = make(nowrap, DEFAULT_LEVEL); input = null; offset = length = 0; + finish = false; needDictionary = finished = false; } - public int deflate(byte[] output) throws DataFormatException { + public int deflate(byte[] output) { return deflate(output, 0, output.length); } - public int deflate(byte[] output, int offset, int length) - throws DataFormatException - { + public int deflate(byte[] output, int offset, int length) { final int zlibResult = 0; final int inputCount = 1; final int outputCount = 2; @@ -110,10 +114,10 @@ public class Deflater { int[] results = new int[3]; deflate(peer, input, this.offset, this.length, - output, offset, length, results); + output, offset, length, finish, results); if (results[zlibResult] < 0) { - throw new DataFormatException(); + throw new AssertionError(); } switch (results[zlibResult]) { @@ -132,10 +136,15 @@ public class Deflater { return results[outputCount]; } + public void finish() { + finish = true; + } + private static native void deflate (long peer, byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset, int outputLength, + boolean finish, int[] results); public void dispose() { diff --git a/classpath/java/util/zip/DeflaterOutputStream.java b/classpath/java/util/zip/DeflaterOutputStream.java index e55668e53c..3ee3fcdbb8 100644 --- a/classpath/java/util/zip/DeflaterOutputStream.java +++ b/classpath/java/util/zip/DeflaterOutputStream.java @@ -52,23 +52,25 @@ public class DeflaterOutputStream extends OutputStream { } else if (length == 0) { return; } - - for (int i = 0; i < length; i+= buffer.length) { - deflater.setInput(b, offset + i, Math.min(buffer.length, length - i)); - while (deflater.getRemaining() > 0) { - try { - int len = deflater.deflate(buffer, 0, buffer.length); - if (len > 0) { - out.write(buffer, 0, len); - } - } catch (DataFormatException e) { - e.printStackTrace(); - } - } + + deflater.setInput(b, offset, length); + while (deflater.getRemaining() > 0) { + deflate(); + } + } + + private void deflate() throws IOException { + int len = deflater.deflate(buffer, 0, buffer.length); + if (len > 0) { + out.write(buffer, 0, len); } } public void close() throws IOException { + deflater.finish(); + while (! deflater.finished()) { + deflate(); + } out.close(); deflater.dispose(); } From 7bea2b6b7dc95f9239fd5e5bc50ab6e0287ae737 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 23 May 2011 12:35:01 -0600 Subject: [PATCH 104/117] fix putstatic/putfield for 64-bit volatiles We must call acquireMonitorForObject before popping the putstatic/pushfield operands off the stack to avoid clobbering said operands. --- src/compile.cpp | 24 ++++++++++++------------ test/Longs.java | 10 +++++++++- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index 29ac0aed24..58aa8f861c 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -5521,18 +5521,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, } } - Compiler::Operand* value = popField(t, frame, fieldCode); - - Compiler::Operand* table; - - if (instruction == putstatic) { - PROTECT(t, field); - - table = frame->append(staticTable); - } else { - table = frame->popObject(); - } - if (fieldFlags(t, field) & ACC_VOLATILE) { if (BytesPerWord == 4 and (fieldCode == DoubleField or fieldCode == LongField)) @@ -5550,6 +5538,18 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, } } + Compiler::Operand* value = popField(t, frame, fieldCode); + + Compiler::Operand* table; + + if (instruction == putstatic) { + PROTECT(t, field); + + table = frame->append(staticTable); + } else { + table = frame->popObject(); + } + switch (fieldCode) { case ByteField: case BooleanField: diff --git a/test/Longs.java b/test/Longs.java index 9beaf8a996..26f1e170b1 100644 --- a/test/Longs.java +++ b/test/Longs.java @@ -1,4 +1,10 @@ -public class Longs { +public class Longs { + private static volatile long volatileLong = getConstant(); + + private static long getConstant() { + return 0x123456789ABCDEFL; + } + private static void expect(boolean v) { if (! v) throw new RuntimeException(); } @@ -60,6 +66,8 @@ public class Longs { } public static void main(String[] args) throws Exception { + expect(volatileLong == getConstant()); + { long a = 0x1FFFFFFFFL; long b = -1; expect(a != b); From 24f7b42d451cb7c3d446e1a4c20d239667946204 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 26 May 2011 17:39:19 -0600 Subject: [PATCH 105/117] ensure class initialized in {Get|Set}Static*Field All static field accesses must trigger class initialization if it hasn't happened already, including JNI accesses. --- src/jnienv.cpp | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/jnienv.cpp b/src/jnienv.cpp index fb3848cb08..1772f7b39e 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -1667,6 +1667,9 @@ uint64_t getStaticObjectField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); + + initClass(t, jclassVmClass(t, *c)); + object field = getStaticField(t, arguments[1]); PROTECT(t, field); @@ -1691,6 +1694,9 @@ uint64_t getStaticBooleanField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); + + initClass(t, jclassVmClass(t, *c)); + object field = getStaticField(t, arguments[1]); PROTECT(t, field); @@ -1713,6 +1719,9 @@ uint64_t getStaticByteField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); + + initClass(t, jclassVmClass(t, *c)); + object field = getStaticField(t, arguments[1]); PROTECT(t, field); @@ -1735,6 +1744,9 @@ uint64_t getStaticCharField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); + + initClass(t, jclassVmClass(t, *c)); + object field = getStaticField(t, arguments[1]); PROTECT(t, field); @@ -1757,6 +1769,9 @@ uint64_t getStaticShortField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); + + initClass(t, jclassVmClass(t, *c)); + object field = getStaticField(t, arguments[1]); PROTECT(t, field); @@ -1779,6 +1794,9 @@ uint64_t getStaticIntField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); + + initClass(t, jclassVmClass(t, *c)); + object field = getStaticField(t, arguments[1]); PROTECT(t, field); @@ -1801,6 +1819,9 @@ uint64_t getStaticLongField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); + + initClass(t, jclassVmClass(t, *c)); + object field = getStaticField(t, arguments[1]); PROTECT(t, field); @@ -1823,6 +1844,9 @@ uint64_t getStaticFloatField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); + + initClass(t, jclassVmClass(t, *c)); + object field = getStaticField(t, arguments[1]); PROTECT(t, field); @@ -1846,6 +1870,9 @@ uint64_t getStaticDoubleField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); + + initClass(t, jclassVmClass(t, *c)); + object field = getStaticField(t, arguments[1]); PROTECT(t, field); @@ -1869,6 +1896,9 @@ uint64_t setStaticObjectField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); + + initClass(t, jclassVmClass(t, *c)); + object field = getStaticField(t, arguments[1]); jobject v = reinterpret_cast(arguments[2]); @@ -1895,6 +1925,9 @@ uint64_t setStaticBooleanField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); + + initClass(t, jclassVmClass(t, *c)); + object field = getStaticField(t, arguments[1]); jboolean v = arguments[2]; @@ -1921,6 +1954,9 @@ uint64_t setStaticByteField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); + + initClass(t, jclassVmClass(t, *c)); + object field = getStaticField(t, arguments[1]); jbyte v = arguments[2]; @@ -1947,6 +1983,9 @@ uint64_t setStaticCharField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); + + initClass(t, jclassVmClass(t, *c)); + object field = getStaticField(t, arguments[1]); jchar v = arguments[2]; @@ -1973,6 +2012,9 @@ uint64_t setStaticShortField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); + + initClass(t, jclassVmClass(t, *c)); + object field = getStaticField(t, arguments[1]); jshort v = arguments[2]; @@ -1999,6 +2041,9 @@ uint64_t setStaticIntField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); + + initClass(t, jclassVmClass(t, *c)); + object field = getStaticField(t, arguments[1]); jint v = arguments[2]; @@ -2025,6 +2070,9 @@ uint64_t setStaticLongField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); + + initClass(t, jclassVmClass(t, *c)); + object field = getStaticField(t, arguments[1]); jlong v; memcpy(&v, arguments + 2, sizeof(jlong)); @@ -2052,6 +2100,9 @@ uint64_t setStaticFloatField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); + + initClass(t, jclassVmClass(t, *c)); + object field = getStaticField(t, arguments[1]); jfloat v = bitsToFloat(arguments[2]); @@ -2078,6 +2129,9 @@ uint64_t setStaticDoubleField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); + + initClass(t, jclassVmClass(t, *c)); + object field = getStaticField(t, arguments[1]); jdouble v = bitsToDouble(arguments[2]); From 05f26983d083deef1c05ef88be329a0feb657542 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 26 May 2011 17:41:15 -0600 Subject: [PATCH 106/117] implement more sun.misc.Unsafe methods --- src/classpath-openjdk.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 25c0c7ff65..1b31b2ac8e 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -2627,6 +2627,16 @@ Avian_sun_misc_Unsafe_putByte__JB *reinterpret_cast(p) = v; } +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_putShort__JS +(Thread*, object, uintptr_t* arguments) +{ + int64_t p; memcpy(&p, arguments + 1, 8); + int16_t v = arguments[3]; + + *reinterpret_cast(p) = v; +} + extern "C" JNIEXPORT void JNICALL Avian_sun_misc_Unsafe_putLong__JJ (Thread*, object, uintptr_t* arguments) @@ -2665,6 +2675,15 @@ Avian_sun_misc_Unsafe_getInt__J return *reinterpret_cast(p); } +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_getLong__J +(Thread*, object, uintptr_t* arguments) +{ + int64_t p; memcpy(&p, arguments + 1, 8); + + return *reinterpret_cast(p); +} + extern "C" JNIEXPORT int64_t JNICALL Avian_sun_misc_Unsafe_getFloat__J (Thread*, object, uintptr_t* arguments) From 92adc83cafc7f5a605b627b7a1527388557999a1 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 29 May 2011 11:16:52 -0600 Subject: [PATCH 107/117] remove NPE debug logging --- src/compile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compile.cpp b/src/compile.cpp index 58aa8f861c..c29f403e61 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -8143,7 +8143,7 @@ class SignalHandler: public System::SignalHandler { t->exception = vm::root(t, root); } - printTrace(t, t->exception); + //printTrace(t, t->exception); object continuation; findUnwindTarget(t, ip, frame, stack, &continuation); From 6b4b4b0b8c4855d550a36be1410516e1a06b658d Mon Sep 17 00:00:00 2001 From: Mike Jensen Date: Mon, 23 May 2011 11:16:50 -0600 Subject: [PATCH 108/117] Changes to add end function to Inflater and Deflater per the java spec --- classpath/java/util/zip/Deflater.java | 4 ++++ classpath/java/util/zip/Inflater.java | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/classpath/java/util/zip/Deflater.java b/classpath/java/util/zip/Deflater.java index 28df9754d2..8368bb0817 100644 --- a/classpath/java/util/zip/Deflater.java +++ b/classpath/java/util/zip/Deflater.java @@ -147,6 +147,10 @@ public class Deflater { boolean finish, int[] results); + public void end() { + dispose(); + } + public void dispose() { if (peer != 0) { dispose(peer); diff --git a/classpath/java/util/zip/Inflater.java b/classpath/java/util/zip/Inflater.java index 6e04b87b92..9f44415194 100644 --- a/classpath/java/util/zip/Inflater.java +++ b/classpath/java/util/zip/Inflater.java @@ -127,6 +127,10 @@ public class Inflater { byte[] output, int outputOffset, int outputLength, int[] results); + public void end() { + dispose(); + } + public void dispose() { if (peer != 0) { dispose(peer); From 9356ade4fda3b7639a6336b8f5ff32852eda6799 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 3 Jun 2011 17:36:47 -0600 Subject: [PATCH 109/117] Revert "Updated powerpc build to disable stack overflow checks for now due to a problem we found with large enums." This reverts commit 8e736327d41ff7dc223b65b9b36e0addfb5f4a6d. --- src/powerpc.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/powerpc.cpp b/src/powerpc.cpp index 9205aa647d..42a69fdcd6 100644 --- a/src/powerpc.cpp +++ b/src/powerpc.cpp @@ -2439,16 +2439,16 @@ class MyAssembler: public Assembler { return arch_; } - virtual void checkStackOverflow(uintptr_t /*handler*/, - unsigned /*stackLimitOffsetFromThread*/) + virtual void checkStackOverflow(uintptr_t handler, + unsigned stackLimitOffsetFromThread) { - /*Register stack(StackRegister); + Register stack(StackRegister); Memory stackLimit(ThreadRegister, stackLimitOffsetFromThread); Constant handlerConstant (new (c.zone->allocate(sizeof(ResolvedPromise))) ResolvedPromise(handler)); branchRM(&c, JumpIfGreaterOrEqual, BytesPerWord, &stack, &stackLimit, - &handlerConstant);*/ + &handlerConstant); } virtual void saveFrame(unsigned stackOffset, unsigned) { From b891db43bc624d9b53d2a11b5260ca86a994ff3b Mon Sep 17 00:00:00 2001 From: Topher Lamey Date: Fri, 17 Jun 2011 10:55:13 -0600 Subject: [PATCH 110/117] Additions for Protobuf support --- classpath/java/util/RandomAccess.java | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 classpath/java/util/RandomAccess.java diff --git a/classpath/java/util/RandomAccess.java b/classpath/java/util/RandomAccess.java new file mode 100644 index 0000000000..619c1c9e88 --- /dev/null +++ b/classpath/java/util/RandomAccess.java @@ -0,0 +1,4 @@ +package java.util; + +public interface RandomAccess { +} From 9aae57ee03b58d093c0403cf064407cd0975773e Mon Sep 17 00:00:00 2001 From: Topher Lamey Date: Fri, 17 Jun 2011 10:57:44 -0600 Subject: [PATCH 111/117] Additions for Protobuf support --- classpath/java/util/Collections.java | 166 +++++++++++++++++++++++++- classpath/java/util/RandomAccess.java | 10 ++ 2 files changed, 173 insertions(+), 3 deletions(-) diff --git a/classpath/java/util/Collections.java b/classpath/java/util/Collections.java index 050c1ebb02..40c133f753 100644 --- a/classpath/java/util/Collections.java +++ b/classpath/java/util/Collections.java @@ -52,6 +52,23 @@ public class Collections { return array; } + public static final List EMPTY_LIST + = new UnmodifiableList(new ArrayList(0)); + + public static final List emptyList() { + return EMPTY_LIST; + } + + public static final Map emptyMap() { + return (Map) new UnmodifiableMap( + new HashMap(0)); + } + + public static final Set emptySet() { + return (Set) new UnmodifiableSet( + new HashSet(0)); + } + static String toString(Collection c) { StringBuilder sb = new StringBuilder(); sb.append("["); @@ -293,8 +310,153 @@ public class Collections { } } + public static List unmodifiableList(List list) { + return new UnmodifiableList(list); + } + + static class UnmodifiableList implements List { + + private List inner; + + UnmodifiableList(List l) { + this.inner = l; + } + + public T get(int index) { + return inner.get(index); + } + + public T set(int index, T value) { + throw new UnsupportedOperationException("not supported"); + } + + public T remove(int index) { + throw new UnsupportedOperationException("not supported"); + } + + public boolean remove(Object o) { + throw new UnsupportedOperationException("not supported"); + } + + public boolean add(T element) { + throw new UnsupportedOperationException("not supported"); + } + + public void add(int index, T element) { + throw new UnsupportedOperationException("not supported"); + } + + public Iterator iterator() { + return inner.iterator(); + } + + public int indexOf(Object value) { + return inner.indexOf(value); + } + + public int lastIndexOf(Object value) { + return inner.lastIndexOf(value); + } + + public boolean isEmpty() { + return inner.isEmpty(); + } + + public ListIterator listIterator(int index) { + return inner.listIterator(index); + } + + public ListIterator listIterator() { + return inner.listIterator(); + } + + public int size() { + return inner.size(); + } + + public boolean contains(Object element) { + return inner.contains(element); + } + + public boolean addAll(Collection collection) { + throw new UnsupportedOperationException("not supported"); + } + + public Object[] toArray() { + return inner.toArray(); + } + + public S[] toArray(S[] array) { + return inner.toArray(array); + } + + public void clear() { + throw new UnsupportedOperationException("not supported"); + } + } + + public static Map unmodifiableMap(Map m) { + return new UnmodifiableMap(m); + } + + static class UnmodifiableMap implements Map { + private Map inner; + + UnmodifiableMap(Map m) { + this.inner = m; + } + + public void clear() { + throw new UnsupportedOperationException("not supported"); + } + + public boolean containsKey(Object key) { + return inner.containsKey(key); + } + + public boolean containsValue(Object value) { + return inner.containsValue(value); + } + + public Set> entrySet() { + return unmodifiableSet(inner.entrySet()); + } + + public V get(Object key) { + return inner.get(key); + } + + public boolean isEmpty() { + return inner.isEmpty(); + } + + public Set keySet() { + return unmodifiableSet(inner.keySet()); + } + + public V put(K key, V value) { + throw new UnsupportedOperationException("not supported"); + } + + public void putAll(Map t) { + throw new UnsupportedOperationException("not supported"); + } + + public V remove(Object key) { + throw new UnsupportedOperationException("not supported"); + } + + public int size() { + return inner.size(); + } + + public Collection values() { + return unmodifiableSet((Set)inner.values()); + } + } + static class UnmodifiableSet implements Set { - Set inner; + private Set inner; UnmodifiableSet(Set inner) { this.inner = inner; @@ -396,7 +558,5 @@ public class Collections { public int compare(T o1, T o2) { return - cmp.compare(o1, o2); } - } - } diff --git a/classpath/java/util/RandomAccess.java b/classpath/java/util/RandomAccess.java index 619c1c9e88..9d8fd4691f 100644 --- a/classpath/java/util/RandomAccess.java +++ b/classpath/java/util/RandomAccess.java @@ -1,3 +1,13 @@ +/* Copyright (c) 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. */ + package java.util; public interface RandomAccess { From 6dc9c986049add78f85c46323da8367debcaa774 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 20 Jun 2011 14:24:11 -0600 Subject: [PATCH 112/117] fix Set[Static]DoubleField regression for 32-bit platforms We were truncating 64-bit doubles to 32-bit values with zany results. --- src/jnienv.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 1772f7b39e..d797b3092c 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -1631,7 +1631,7 @@ setDoubleField(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); object field = getField(t, arguments[1]); - jdouble v = bitsToDouble(arguments[2]); + jdouble v; memcpy(&v, arguments + 2, sizeof(jdouble)); PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); @@ -1644,9 +1644,10 @@ setDoubleField(Thread* t, uintptr_t* arguments) void JNICALL SetDoubleField(Thread* t, jobject o, jfieldID field, jdouble v) { - uintptr_t arguments[] = { reinterpret_cast(o), - field, - doubleToBits(v) }; + uintptr_t arguments[2 + (sizeof(jdouble) / BytesPerWord)]; + arguments[0] = reinterpret_cast(o); + arguments[1] = field; + memcpy(arguments + 2, &v, sizeof(jdouble)); run(t, setDoubleField, arguments); } @@ -2133,7 +2134,7 @@ setStaticDoubleField(Thread* t, uintptr_t* arguments) initClass(t, jclassVmClass(t, *c)); object field = getStaticField(t, arguments[1]); - jdouble v = bitsToDouble(arguments[2]); + jdouble v; memcpy(&v, arguments + 2, sizeof(jdouble)); PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); @@ -2147,9 +2148,10 @@ setStaticDoubleField(Thread* t, uintptr_t* arguments) void JNICALL SetStaticDoubleField(Thread* t, jobject c, jfieldID field, jdouble v) { - uintptr_t arguments[] = { reinterpret_cast(c), - field, - doubleToBits(v) }; + uintptr_t arguments[2 + (sizeof(jdouble) / BytesPerWord)]; + arguments[0] = reinterpret_cast(c); + arguments[1] = field; + memcpy(arguments + 2, &v, sizeof(jdouble)); run(t, setStaticDoubleField, arguments); } From 19856bc34600ce6ddb71bfceee428da45d658427 Mon Sep 17 00:00:00 2001 From: Topher Lamey Date: Tue, 21 Jun 2011 14:13:23 -0600 Subject: [PATCH 113/117] Changes for protobuf support --- classpath/java/io/FilterOutputStream.java | 36 +++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 classpath/java/io/FilterOutputStream.java diff --git a/classpath/java/io/FilterOutputStream.java b/classpath/java/io/FilterOutputStream.java new file mode 100644 index 0000000000..436bc42d3d --- /dev/null +++ b/classpath/java/io/FilterOutputStream.java @@ -0,0 +1,36 @@ +/* Copyright (c) 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. */ + +package java.io; + +public class FilterOutputStream extends OutputStream { + private OutputStream os; + + public void close() throws IOException { + os.close(); + } + + public void flush() throws IOException { + os.flush(); + } + + public void write(byte[] b) throws IOException { + os.write(b); + } + + public void write(byte[] b, int off, int len) throws IOException { + os.write(b, off, len); + } + + public void write(int b) throws IOException { + os.write(b); + } + +} From 9700b7def197b83e07791e885391d85a0bdb8abb Mon Sep 17 00:00:00 2001 From: Topher Lamey Date: Tue, 21 Jun 2011 14:13:54 -0600 Subject: [PATCH 114/117] Changes for protobuf support --- classpath/java/util/zip/CRC32.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/classpath/java/util/zip/CRC32.java b/classpath/java/util/zip/CRC32.java index 047ee685af..628167725b 100644 --- a/classpath/java/util/zip/CRC32.java +++ b/classpath/java/util/zip/CRC32.java @@ -15,7 +15,7 @@ public class CRC32 { private static final int Width = 32; private static final int Top = 1 << (Width - 1); private static final int InitialRemainder = 0xFFFFFFFF; - private static final int ResultXor = 0xFFFFFFFF; + private static final long ResultXor = 0xFFFFFFFFL; private static final int[] table = new int[256]; @@ -53,7 +53,7 @@ public class CRC32 { } public long getValue() { - return reflect(remainder, Width) ^ ResultXor; + return (reflect(remainder, Width) ^ ResultXor) & 0xFFFFFFFFL; } private static int reflect(int x, int n) { From 794a45cb7972449291a1487056dff153807ae139 Mon Sep 17 00:00:00 2001 From: Anonymous Date: Fri, 1 Jul 2011 08:43:43 -0600 Subject: [PATCH 115/117] fix various ObjectOutputStream/ObjectInputStream bugs --- classpath/java/io/ByteArrayOutputStream.java | 4 ++++ classpath/java/io/File.java | 2 +- classpath/java/io/FilterOutputStream.java | 16 +++++++++----- classpath/java/io/ObjectInputStream.java | 13 ++++++----- classpath/java/io/ObjectOutputStream.java | 16 +++++++------- classpath/java/lang/Class.java | 22 ++++++++++++++++++- classpath/java/lang/reflect/Field.java | 2 +- .../java/lang/reflect/InvocationHandler.java | 2 +- classpath/java/security/ProtectionDomain.java | 4 ++++ classpath/java/util/ArrayList.java | 2 +- classpath/java/util/Vector.java | 6 ++++- 11 files changed, 63 insertions(+), 26 deletions(-) diff --git a/classpath/java/io/ByteArrayOutputStream.java b/classpath/java/io/ByteArrayOutputStream.java index 61fb51759e..f0668da2da 100644 --- a/classpath/java/io/ByteArrayOutputStream.java +++ b/classpath/java/io/ByteArrayOutputStream.java @@ -98,6 +98,10 @@ public class ByteArrayOutputStream extends OutputStream { return array; } + public String toString(String encoding) throws UnsupportedEncodingException { + return new String(toByteArray(), encoding); + } + private static class Cell { public byte[] array; public int offset; diff --git a/classpath/java/io/File.java b/classpath/java/io/File.java index ec5338035e..3eb8ad2f03 100644 --- a/classpath/java/io/File.java +++ b/classpath/java/io/File.java @@ -10,7 +10,7 @@ package java.io; -public class File { +public class File implements Serializable { private static final String FileSeparator = System.getProperty("file.separator"); diff --git a/classpath/java/io/FilterOutputStream.java b/classpath/java/io/FilterOutputStream.java index 436bc42d3d..d22ff7b2ca 100644 --- a/classpath/java/io/FilterOutputStream.java +++ b/classpath/java/io/FilterOutputStream.java @@ -11,26 +11,30 @@ package java.io; public class FilterOutputStream extends OutputStream { - private OutputStream os; + protected OutputStream out; + + public FilterOutputStream(OutputStream out) { + this.out = out; + } public void close() throws IOException { - os.close(); + out.close(); } public void flush() throws IOException { - os.flush(); + out.flush(); } public void write(byte[] b) throws IOException { - os.write(b); + out.write(b); } public void write(byte[] b, int off, int len) throws IOException { - os.write(b, off, len); + out.write(b, off, len); } public void write(int b) throws IOException { - os.write(b); + out.write(b); } } diff --git a/classpath/java/io/ObjectInputStream.java b/classpath/java/io/ObjectInputStream.java index 20fa5cdfb8..a039046517 100644 --- a/classpath/java/io/ObjectInputStream.java +++ b/classpath/java/io/ObjectInputStream.java @@ -10,6 +10,8 @@ package java.io; +import avian.VMClass; + import java.util.HashMap; import java.lang.reflect.Array; import java.lang.reflect.Field; @@ -110,7 +112,7 @@ public class ObjectInputStream extends InputStream { StringBuilder sb = new StringBuilder(); int c; - while ((c = r.read()) != -1 && ! Character.isWhitespace((char) c)) { + while ((c = r.read()) != -1 && ! Character.isWhitespace((char) c) && c != ')') { sb.append((char) c); } if (c != -1) { @@ -149,7 +151,6 @@ public class ObjectInputStream extends InputStream { throws IOException, ClassNotFoundException { skipSpace(); - switch (r.read()) { case 'a': return deserializeArray(map); @@ -203,7 +204,7 @@ public class ObjectInputStream extends InputStream { return o; } - private static native Object makeInstance(Class c); + private static native Object makeInstance(VMClass c); private Object deserializeObject(HashMap map) throws IOException, ClassNotFoundException @@ -211,11 +212,11 @@ public class ObjectInputStream extends InputStream { read('('); int id = (int) readLongToken(); Class c = Class.forName(readStringToken()); - Object o = makeInstance(c); + Object o = makeInstance(c.vmClass); map.put(id, o); - - for (Field f: c.getFields()) { + + for (Field f: c.getAllFields()) { int modifiers = f.getModifiers(); if ((modifiers & (Modifier.TRANSIENT | Modifier.STATIC)) == 0) { try { diff --git a/classpath/java/io/ObjectOutputStream.java b/classpath/java/io/ObjectOutputStream.java index 80cac7857b..7e45f9d2cc 100644 --- a/classpath/java/io/ObjectOutputStream.java +++ b/classpath/java/io/ObjectOutputStream.java @@ -39,7 +39,7 @@ public class ObjectOutputStream extends OutputStream { } public void writeObject(Object o) throws IOException { - writeObject(o, new IdentityHashMap(), 0); + writeObject(o, new IdentityHashMap(), new int[] {0}); } public void writeBoolean(boolean v) { @@ -87,7 +87,7 @@ public class ObjectOutputStream extends OutputStream { } private void writeObject(Object o, IdentityHashMap map, - int nextId) + int[] nextId) throws IOException { if (o == null) { @@ -95,7 +95,7 @@ public class ObjectOutputStream extends OutputStream { } else { Integer id = map.get(o); if (id == null) { - map.put(o, nextId); + map.put(o, nextId[0]); Class c = o.getClass(); if (c.isArray()) { @@ -113,7 +113,7 @@ public class ObjectOutputStream extends OutputStream { } private void serializeArray(Object o, IdentityHashMap map, - int nextId) + int[] nextId) throws IOException { Class c = o.getClass(); @@ -121,7 +121,7 @@ public class ObjectOutputStream extends OutputStream { int length = Array.getLength(o); out.print("a("); - out.print(nextId++); + out.print(nextId[0]++); out.print(" "); out.print(c.getName()); out.print(" "); @@ -155,17 +155,17 @@ public class ObjectOutputStream extends OutputStream { } private void serializeObject(Object o, IdentityHashMap map, - int nextId) + int[] nextId) throws IOException { Class c = o.getClass(); out.print("l("); - out.print(nextId++); + out.print(nextId[0]++); out.print(" "); out.print(c.getName()); - for (Field f: c.getFields()) { + for (Field f: c.getAllFields()) { int modifiers = f.getModifiers(); if ((modifiers & (Modifier.TRANSIENT | Modifier.STATIC)) == 0) { out.print(" "); diff --git a/classpath/java/lang/Class.java b/classpath/java/lang/Class.java index b550ae5509..22b645793a 100644 --- a/classpath/java/lang/Class.java +++ b/classpath/java/lang/Class.java @@ -29,6 +29,7 @@ import java.lang.annotation.Annotation; import java.io.InputStream; import java.io.IOException; import java.net.URL; +import java.util.ArrayList; import java.util.Map; import java.util.HashMap; import java.security.ProtectionDomain; @@ -424,6 +425,25 @@ public final class Class implements Type, AnnotatedElement { return array; } + private static void getAllFields(VMClass vmClass, ArrayList fields) { + if (vmClass.super_ != null) { + getAllFields(vmClass.super_, fields); + } + if (vmClass.fieldTable != null) { + Classes.link(vmClass); + + for (int i = 0; i < vmClass.fieldTable.length; ++i) { + fields.add(new Field(vmClass.fieldTable[i])); + } + } + } + + public Field[] getAllFields() { + ArrayList fields = new ArrayList(); + getAllFields(vmClass, fields); + return fields.toArray(new Field[fields.size()]); + } + private int countMethods(boolean publicOnly) { int count = 0; if (vmClass.methodTable != null) { @@ -515,7 +535,7 @@ public final class Class implements Type, AnnotatedElement { } public Class getSuperclass() { - return SystemClassLoader.getClass(vmClass.super_); + return (vmClass.super_ == null ? null : SystemClassLoader.getClass(vmClass.super_)); } public boolean isArray() { diff --git a/classpath/java/lang/reflect/Field.java b/classpath/java/lang/reflect/Field.java index 4638c61990..524cb7613a 100644 --- a/classpath/java/lang/reflect/Field.java +++ b/classpath/java/lang/reflect/Field.java @@ -205,7 +205,7 @@ public class Field extends AccessibleObject { } else { throw new IllegalArgumentException ("needed " + getType() + ", got " - + Class.getName(Classes.vmClass(target)) + + + value.getClass().getName() + " when setting " + Class.getName(vmField.class_) + "." + getName()); } break; diff --git a/classpath/java/lang/reflect/InvocationHandler.java b/classpath/java/lang/reflect/InvocationHandler.java index 21932bae6e..9541797ad3 100644 --- a/classpath/java/lang/reflect/InvocationHandler.java +++ b/classpath/java/lang/reflect/InvocationHandler.java @@ -11,5 +11,5 @@ package java.lang.reflect; public interface InvocationHandler { - public Object invoke(Object proxy, Method method, Object[] arguments); + public Object invoke(Object proxy, Method method, Object[] arguments) throws Throwable; } diff --git a/classpath/java/security/ProtectionDomain.java b/classpath/java/security/ProtectionDomain.java index f7670e28a4..25673c8ee3 100644 --- a/classpath/java/security/ProtectionDomain.java +++ b/classpath/java/security/ProtectionDomain.java @@ -20,4 +20,8 @@ public class ProtectionDomain { this.codeSource = codeSource; this.permissions = permissions; } + + public CodeSource getCodeSource() { + return codeSource; + } } diff --git a/classpath/java/util/ArrayList.java b/classpath/java/util/ArrayList.java index e99c6ceade..698f3f79df 100644 --- a/classpath/java/util/ArrayList.java +++ b/classpath/java/util/ArrayList.java @@ -10,7 +10,7 @@ package java.util; -public class ArrayList extends AbstractList { +public class ArrayList extends AbstractList implements java.io.Serializable { private static final int MinimumCapacity = 16; private Object[] array; diff --git a/classpath/java/util/Vector.java b/classpath/java/util/Vector.java index 30ff6d9a9f..e95c8df414 100644 --- a/classpath/java/util/Vector.java +++ b/classpath/java/util/Vector.java @@ -10,7 +10,7 @@ package java.util; -public class Vector extends AbstractList { +public class Vector extends AbstractList implements java.io.Serializable { private final ArrayList list; public Vector(int capacity) { @@ -81,6 +81,10 @@ public class Vector extends AbstractList { remove(index); } + public synchronized void removeAllElements() { + list.clear(); + } + public synchronized boolean remove(Object element) { return list.remove(element); } From b4169ede914a236a0cf0a63b7a2062c546f57c34 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 6 Jul 2011 11:09:06 -0600 Subject: [PATCH 116/117] fix reversed arguments to maybeRex in sseMoveRR This was causing 8-byte SSE-to-SSE moves involving registers xmm8-xmm15 to be misencoded on x86_64, leading to incorrect code generation in methods with lots of local variables of type double. --- src/x86.cpp | 2 +- test/Floats.java | 84 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 1 deletion(-) diff --git a/src/x86.cpp b/src/x86.cpp index cf5bca82a0..e856a536c3 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -969,7 +969,7 @@ sseMoveRR(Context* c, unsigned aSize, Assembler::Register* a, modrm(c, 0xc0, a, b); } else { opcode(c, 0xf2); - maybeRex(c, 4, a, b); + maybeRex(c, 4, b, a); opcode(c, 0x0f, 0x10); modrm(c, 0xc0, a, b); } diff --git a/test/Floats.java b/test/Floats.java index 412bd5cd6c..38ae3121b1 100644 --- a/test/Floats.java +++ b/test/Floats.java @@ -33,7 +33,91 @@ public class Floats { return f.field * a; } + private static void subdivide(double src[], int srcoff, + double left[], int leftoff, + double right[], int rightoff) + { + double x1 = src[srcoff + 0]; + double y1 = src[srcoff + 1]; + double ctrlx1 = src[srcoff + 2]; + double ctrly1 = src[srcoff + 3]; + double ctrlx2 = src[srcoff + 4]; + double ctrly2 = src[srcoff + 5]; + double x2 = src[srcoff + 6]; + double y2 = src[srcoff + 7]; + if (left != null) { + left[leftoff + 0] = x1; + left[leftoff + 1] = y1; + } + if (right != null) { + right[rightoff + 6] = x2; + right[rightoff + 7] = y2; + } + x1 = (x1 + ctrlx1) / 2.0; + y1 = (y1 + ctrly1) / 2.0; + x2 = (x2 + ctrlx2) / 2.0; + y2 = (y2 + ctrly2) / 2.0; + double centerx = (ctrlx1 + ctrlx2) / 2.0; + double centery = (ctrly1 + ctrly2) / 2.0; + ctrlx1 = (x1 + centerx) / 2.0; + ctrly1 = (y1 + centery) / 2.0; + ctrlx2 = (x2 + centerx) / 2.0; + ctrly2 = (y2 + centery) / 2.0; + centerx = (ctrlx1 + ctrlx2) / 2.0; + centery = (ctrly1 + ctrly2) / 2.0; + if (left != null) { + left[leftoff + 2] = x1; + left[leftoff + 3] = y1; + left[leftoff + 4] = ctrlx1; + left[leftoff + 5] = ctrly1; + left[leftoff + 6] = centerx; + left[leftoff + 7] = centery; + } + if (right != null) { + right[rightoff + 0] = centerx; + right[rightoff + 1] = centery; + right[rightoff + 2] = ctrlx2; + right[rightoff + 3] = ctrly2; + right[rightoff + 4] = x2; + right[rightoff + 5] = y2; + } + } + public static void main(String[] args) { + { double input[] = new double[8]; + double left[] = new double[8]; + double right[] = new double[8]; + + input[0] = 732.0; + input[1] = 952.0; + input[2] = 761.0; + input[3] = 942.0; + input[4] = 786.0; + input[5] = 944.0; + input[6] = 813.0; + input[7] = 939.0; + + subdivide(input, 0, left, 0, right, 0); + + expect(left[0] == 732.0); + expect(left[1] == 952.0); + expect(left[2] == 746.5); + expect(left[3] == 947.0); + expect(left[4] == 760.0); + expect(left[5] == 945.0); + expect(left[6] == 773.25); + expect(left[7] == 943.625); + + expect(right[0] == 773.25); + expect(right[1] == 943.625); + expect(right[2] == 786.5); + expect(right[3] == 942.25); + expect(right[4] == 799.5); + expect(right[5] == 941.5); + expect(right[6] == 813.0); + expect(right[7] == 939.0); + } + expect(multiply(0.5d, 0.5d) == 0.25d); expect(multiply(0.5f, 0.5f) == 0.25f); From 506ec7838e47e35b133ab062f60f383c22260396 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 8 Jul 2011 11:45:23 -0600 Subject: [PATCH 117/117] remove unused Classes.vmClass method --- classpath/avian/Classes.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/classpath/avian/Classes.java b/classpath/avian/Classes.java index b2fc407d90..1d2ad9370e 100644 --- a/classpath/avian/Classes.java +++ b/classpath/avian/Classes.java @@ -26,8 +26,6 @@ public class Classes { public static native VMClass defineVMClass (ClassLoader loader, byte[] b, int offset, int length); - public static native VMClass vmClass(Object o); - public static native VMClass primitiveClass(char name); public static native void initialize(VMClass vmClass);