From ef9c1ee32c0dfe26a50d20acf420d41564a64e0d Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 3 Nov 2009 16:07:13 -0700 Subject: [PATCH 1/9] specify -arch explicitly to compiler and liner on OS X On 10.6 the compiler generates x86_64 code by default, even though uname -m reports "i386", so we have to be explicit --- makefile | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/makefile b/makefile index b6ce200fba..29840c8529 100644 --- a/makefile +++ b/makefile @@ -159,6 +159,18 @@ ifeq ($(platform),darwin) strip-all = -S -x so-suffix = .jnilib shared = -dynamiclib + + ifeq ($(arch),powerpc) + cflags += -arch ppc + asmflags += -arch ppc + lflags += -arch ppc + endif + + ifeq ($(arch),i386) + cflags += -arch i386 + asmflags += -arch i386 + lflags += -arch i386 + endif endif ifeq ($(platform),windows) From fb5796b740097c2968dd8bfbda0d541843b17002 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 4 Nov 2009 00:02:38 +0000 Subject: [PATCH 2/9] don't use SSE for long-to-double conversion on 32-bit systems --- src/x86.cpp | 2 +- test/Floats.java | 22 +++++++++++++++------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/x86.cpp b/src/x86.cpp index 97e85dfb41..310aa8350f 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -2931,7 +2931,7 @@ class MyArchitecture: public Assembler::Architecture { break; case Int2Float: - if (useSSE(&c)) { + if (useSSE(&c) and (aSize <= BytesPerWord)) { *aTypeMask = (1 << RegisterOperand) | (1 << MemoryOperand); *aRegisterMask = GeneralRegisterMask | (static_cast(GeneralRegisterMask) << 32); diff --git a/test/Floats.java b/test/Floats.java index 33c30145fd..bd85a74d10 100644 --- a/test/Floats.java +++ b/test/Floats.java @@ -46,11 +46,13 @@ public class Floats { expect(subtract(0.5d, 0.1d) == 0.4d); - double d = 1d; - expect(((int) d) == 1); + { double d = 1d; + expect(((int) d) == 1); + } - float f = 1f; - expect(((int) f) == 1); + { float f = 1f; + expect(((int) f) == 1); + } expect(Math.round(0.4f) == 0); expect(Math.round(0.5f) == 1); @@ -62,8 +64,14 @@ public class Floats { expect(Math.round(1.0d) == 1); expect(Math.round(1.9d) == 2); - float b = 1.0f; - int blue = (int)(b * 255 + 0.5); - expect(blue == 255); + { float b = 1.0f; + int blue = (int)(b * 255 + 0.5); + expect(blue == 255); + } + + { long z = 6553311036568663L; + double d = (double) z; + expect(d == 6553311036568663.0); + } } } From 5b8a7ca566a4dd175cdc096bcbb84254fe31d451 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 4 Nov 2009 15:16:06 +0000 Subject: [PATCH 3/9] temporarily disable use of SSE on 32-bit systems until a bug involving memory<->SSE-register moves is fixed --- src/jnienv.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 391938180a..533039b066 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -2169,7 +2169,10 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args) System* s = makeSystem(crashDumpDirectory); Heap* h = makeHeap(s, heapLimit); Finder* f = makeFinder(s, RUNTIME_ARRAY_BODY(classpathBuffer), bootLibrary); - Processor* p = makeProcessor(s, h, true); + Processor* p = makeProcessor(s, h, false); // change back to true + // once use of SSE is + // fixed on 32-bit + // systems const char** properties = static_cast (h->allocate(sizeof(const char*) * propertyCount)); From 3862128a3ab443af0891c8035a39ce93441a5677 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 16 Nov 2009 17:23:09 -0700 Subject: [PATCH 4/9] tolerate EINTR in ServerSocketChannel.accept implementation On POSIX systems, Avian sends a special signal to a thread to implement Thread.getStackTrace() when called from a different thread. If the target thread is blocked on a call to accept when this happens, it will return -1, with errno set to EINTR. Instead of treating this as an error, we now just loop and call accept again. --- classpath/java-nio.cpp | 2 +- classpath/java/nio/channels/ServerSocketChannel.java | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/classpath/java-nio.cpp b/classpath/java-nio.cpp index 66904a26ca..0419877acc 100644 --- a/classpath/java-nio.cpp +++ b/classpath/java-nio.cpp @@ -266,7 +266,7 @@ doAccept(JNIEnv* e, int s) int r = ::accept(s, &address, &length); if (r >= 0) { return r; - } else { + } else if (errno != EINTR) { throwIOException(e); } return -1; diff --git a/classpath/java/nio/channels/ServerSocketChannel.java b/classpath/java/nio/channels/ServerSocketChannel.java index 178e0bbed1..0410d47e44 100644 --- a/classpath/java/nio/channels/ServerSocketChannel.java +++ b/classpath/java/nio/channels/ServerSocketChannel.java @@ -47,7 +47,14 @@ public class ServerSocketChannel extends SelectableChannel { } private int doAccept() throws IOException { - return natDoAccept(channel.socket); + while (true) { + int s = natDoAccept(channel.socket); + if (s != -1) { + return s; + } + // todo: throw ClosedByInterruptException if this thread was + // interrupted during the accept call + } } private int doListen(String host, int port) throws IOException { From c711ac570181aa753525903c4daf28d2887c1153 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 18 Nov 2009 11:01:47 -0700 Subject: [PATCH 5/9] return null from NewString[UTF] if the char* parameter is null --- src/jnienv.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 533039b066..d0e7aebaa5 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -195,6 +195,8 @@ GetArrayLength(Thread* t, jarray array) jstring JNICALL NewString(Thread* t, const jchar* chars, jsize size) { + if (chars == 0) return 0; + ENTER(t, Thread::ActiveState); object a = 0; @@ -210,6 +212,8 @@ NewString(Thread* t, const jchar* chars, jsize size) jstring JNICALL NewStringUTF(Thread* t, const char* chars) { + if (chars == 0) return 0; + ENTER(t, Thread::ActiveState); object a = 0; From adcac443e4dff6c5f0ee4c4da3af9e712a02073a Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 19 Nov 2009 11:43:11 -0700 Subject: [PATCH 6/9] don't null out array in ArrayList when size goes to zero This avoids thrashing in the case of a list which is frequently emptied and refilled with a small number of elements. --- classpath/java/util/ArrayList.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/classpath/java/util/ArrayList.java b/classpath/java/util/ArrayList.java index faabdebb5c..4ab5603bec 100644 --- a/classpath/java/util/ArrayList.java +++ b/classpath/java/util/ArrayList.java @@ -38,8 +38,6 @@ public class ArrayList extends AbstractList { private void shrink() { if (array.length / 2 >= MinimumCapacity && size <= array.length / 3) { resize(array.length / 2); - } else if (size == 0) { - resize(0); } } From 6475beda83962b83ef99ca2231e405d90fcabedf Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 19 Nov 2009 12:55:53 -0700 Subject: [PATCH 7/9] don't null out array in HashMap when size drops to zero As in ArrayList, we want to avoid thrashing in cases where the map is frequently emptied and refilled. --- classpath/java/util/HashMap.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/classpath/java/util/HashMap.java b/classpath/java/util/HashMap.java index ecae9a01f1..2f707ba489 100644 --- a/classpath/java/util/HashMap.java +++ b/classpath/java/util/HashMap.java @@ -66,8 +66,6 @@ public class HashMap implements Map { private void shrink() { if (array.length / 2 >= MinimumCapacity && size <= array.length / 3) { resize(array.length / 2); - } else if (size == 0) { - resize(0); } } From fdde34694c0e697fba89f63b30e800cb7f6f38c2 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 19 Nov 2009 18:13:00 -0700 Subject: [PATCH 8/9] use atomic operations in MyHeap::mark to avoid need for mutex --- src/common.h | 8 ++++++ src/heap.cpp | 77 ++++++++++++++++++++++++++++----------------------- src/heap.h | 2 -- src/machine.h | 10 ++----- 4 files changed, 53 insertions(+), 44 deletions(-) diff --git a/src/common.h b/src/common.h index b9990a674f..535e231b6c 100644 --- a/src/common.h +++ b/src/common.h @@ -325,6 +325,14 @@ markBit(uintptr_t* map, unsigned i) map[wordOf(i)] |= static_cast(1) << bitOf(i); } +inline void +markBitAtomic(uintptr_t* map, unsigned i) +{ + uintptr_t* p = map + wordOf(i); + uintptr_t v = static_cast(1) << bitOf(i); + while (not __sync_bool_compare_and_swap(p, *p, *p | v)) { } +} + inline void clearBit(uintptr_t* map, unsigned i) { diff --git a/src/heap.cpp b/src/heap.cpp index 5067909498..11c3c4ceda 100644 --- a/src/heap.cpp +++ b/src/heap.cpp @@ -303,6 +303,13 @@ class Segment { if (child) child->set(p, v); } + void markAtomic(void* p) { + assert(segment->context, bitsPerRecord == 1); + markBitAtomic(data, indexOf(p)); + assert(segment->context, getBit(data, indexOf(p))); + if (child) child->markAtomic(p); + } + unsigned get(void* p) { return getBits(data, bitsPerRecord, indexOf(p)); } @@ -1013,8 +1020,12 @@ void markDirty(Context* c, Fixie* f) { if (not f->dirty) { - f->dirty = true; - f->move(c, &(c->dirtyTenuredFixies)); + ACQUIRE(c->lock); + + if (not f->dirty) { + f->dirty = true; + f->move(c, &(c->dirtyTenuredFixies)); + } } } @@ -1784,7 +1795,7 @@ class MyHeap: public Heap { Fixie(&c, sizeInWords, objectMask, 0, true))->body(); } - virtual bool needsMark(void* p) { + bool needsMark(void* p) { assert(&c, c.client->isFixed(p) or (not immortalHeapContains(&c, p))); if (c.client->isFixed(p)) { @@ -1794,11 +1805,6 @@ class MyHeap: public Heap { } } - virtual bool needsMark(void* p, unsigned offset) { - return needsMark(p) and targetNeedsMark - (mask(*(static_cast(p) + offset))); - } - bool targetNeedsMark(void* target) { return target and not c.gen2.contains(target) @@ -1809,38 +1815,41 @@ class MyHeap: public Heap { } virtual void mark(void* p, unsigned offset, unsigned count) { - if (c.client->isFixed(p)) { - Fixie* f = fixie(p); - assert(&c, offset == 0 or f->hasMask); + if (needsMark(p)) { + if (c.client->isFixed(p)) { + Fixie* f = fixie(p); + assert(&c, offset == 0 or f->hasMask); - bool dirty = false; - for (unsigned i = 0; i < count; ++i) { - void** target = static_cast(p) + offset + i; - if (targetNeedsMark(mask(*target))) { - if (DebugFixies) { - fprintf(stderr, "dirty fixie %p at %d (%p): %p\n", - f, offset, f->body() + offset, mask(*target)); + bool dirty = false; + for (unsigned i = 0; i < count; ++i) { + void** target = static_cast(p) + offset + i; + if (targetNeedsMark(mask(*target))) { + if (DebugFixies) { + fprintf(stderr, "dirty fixie %p at %d (%p): %p\n", + f, offset, f->body() + offset, mask(*target)); + } + + dirty = true; + markBitAtomic(f->mask(), offset + i); + assert(&c, getBit(f->mask(), offset + i)); } - - dirty = true; - markBit(f->mask(), offset + i); } - } - if (dirty) markDirty(&c, f); - } else { - Segment::Map* map; - if (c.gen2.contains(p)) { - map = &(c.heapMap); + if (dirty) markDirty(&c, f); } else { - assert(&c, c.nextGen2.contains(p)); - map = &(c.nextHeapMap); - } + Segment::Map* map; + if (c.gen2.contains(p)) { + map = &(c.heapMap); + } else { + assert(&c, c.nextGen2.contains(p)); + map = &(c.nextHeapMap); + } - for (unsigned i = 0; i < count; ++i) { - void** target = static_cast(p) + offset + i; - if (targetNeedsMark(mask(*target))) { - map->set(target); + for (unsigned i = 0; i < count; ++i) { + void** target = static_cast(p) + offset + i; + if (targetNeedsMark(mask(*target))) { + map->markAtomic(target); + } } } } diff --git a/src/heap.h b/src/heap.h index 28f1533d8f..769bc1ec4b 100644 --- a/src/heap.h +++ b/src/heap.h @@ -59,8 +59,6 @@ class Heap: public Allocator { virtual void* allocateImmortalFixed(Allocator* allocator, unsigned sizeInWords, bool objectMask, unsigned* totalInBytes) = 0; - virtual bool needsMark(void* p) = 0; - virtual bool needsMark(void* p, unsigned offset) = 0; virtual void mark(void* p, unsigned offset, unsigned count) = 0; virtual void pad(void* p) = 0; virtual void* follow(void* p) = 0; diff --git a/src/machine.h b/src/machine.h index 1bc04a9e9e..598a72e424 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1584,19 +1584,13 @@ allocate(Thread* t, unsigned sizeInBytes, bool objectMask) inline void mark(Thread* t, object o, unsigned offset, unsigned count) { - if (t->m->heap->needsMark(o)) { - ACQUIRE_RAW(t, t->m->heapLock); - t->m->heap->mark(o, offset / BytesPerWord, count); - } + t->m->heap->mark(o, offset / BytesPerWord, count); } inline void mark(Thread* t, object o, unsigned offset) { - if (t->m->heap->needsMark(o, offset / BytesPerWord)) { - ACQUIRE_RAW(t, t->m->heapLock); - t->m->heap->mark(o, offset / BytesPerWord, 1); - } + t->m->heap->mark(o, offset / BytesPerWord, 1); } inline void From 07f40a07e19a58c559ed47abaa0e989ba75c9517 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 19 Nov 2009 18:51:43 -0700 Subject: [PATCH 9/9] specify -march=i486 for x86_32 to support __sync_bool_compare_and_swap --- makefile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/makefile b/makefile index 29840c8529..7006194a35 100644 --- a/makefile +++ b/makefile @@ -240,6 +240,11 @@ ifeq ($(mode),small) cflags += -Os -g3 -DNDEBUG endif +ifeq ($(arch),i386) +# this is necessary to support __sync_bool_compare_and_swap: + cflags += -march=i486 +endif + output = -o $(1) as := $(cc) ld := $(cc)