From 3862128a3ab443af0891c8035a39ce93441a5677 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 16 Nov 2009 17:23:09 -0700 Subject: [PATCH 01/16] 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 02/16] 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 03/16] 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 04/16] 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 05/16] 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 06/16] 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) From 5f5cc57d125e0b99f48f018821884ad0bdb65507 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 19 Nov 2009 19:32:54 -0700 Subject: [PATCH 07/16] only use atomic operations if the compiler supports them --- src/common.h | 9 ++++++++- src/heap.cpp | 14 ++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/common.h b/src/common.h index 535e231b6c..459cd0dcef 100644 --- a/src/common.h +++ b/src/common.h @@ -63,6 +63,11 @@ typedef uint64_t uintptr_t; # include "stdint.h" +# if (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 1) +# define USE_ATOMIC_OPERATIONS +# define COMPARE_AND_SWAP __sync_bool_compare_and_swap +# endif + # define LIKELY(v) __builtin_expect((v) != 0, true) # define UNLIKELY(v) __builtin_expect((v) != 0, false) @@ -325,13 +330,15 @@ markBit(uintptr_t* map, unsigned i) map[wordOf(i)] |= static_cast(1) << bitOf(i); } +#ifdef USE_ATOMIC_OPERATIONS 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)) { } + while (not COMPARE_AND_SWAP(p, *p, *p | v)) { } } +#endif inline void clearBit(uintptr_t* map, unsigned i) diff --git a/src/heap.cpp b/src/heap.cpp index 11c3c4ceda..b2bc515814 100644 --- a/src/heap.cpp +++ b/src/heap.cpp @@ -303,12 +303,14 @@ class Segment { if (child) child->set(p, v); } +#ifdef USE_ATOMIC_OPERATIONS 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); } +#endif unsigned get(void* p) { return getBits(data, bitsPerRecord, indexOf(p)); @@ -1816,6 +1818,10 @@ class MyHeap: public Heap { virtual void mark(void* p, unsigned offset, unsigned count) { if (needsMark(p)) { +#ifndef USE_ATOMIC_OPERATIONS + ACQUIRE(c.lock); +#endif + if (c.client->isFixed(p)) { Fixie* f = fixie(p); assert(&c, offset == 0 or f->hasMask); @@ -1830,7 +1836,11 @@ class MyHeap: public Heap { } dirty = true; +#ifdef USE_ATOMIC_OPERATIONS markBitAtomic(f->mask(), offset + i); +#else + markBit(f->mask(), offset + i); +#endif assert(&c, getBit(f->mask(), offset + i)); } } @@ -1848,7 +1858,11 @@ class MyHeap: public Heap { for (unsigned i = 0; i < count; ++i) { void** target = static_cast(p) + offset + i; if (targetNeedsMark(mask(*target))) { +#ifdef USE_ATOMIC_OPERATIONS map->markAtomic(target); +#else + map->set(target); +#endif } } } From e91157a3900eae192a9b76131b54c28f0b254599 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 19 Nov 2009 19:41:49 -0700 Subject: [PATCH 08/16] avoid acquiring a mutex recursively in markDirty --- src/heap.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/heap.cpp b/src/heap.cpp index b2bc515814..c2c4ec79c0 100644 --- a/src/heap.cpp +++ b/src/heap.cpp @@ -1022,7 +1022,9 @@ void markDirty(Context* c, Fixie* f) { if (not f->dirty) { +#ifdef USE_ATOMIC_OPERATIONS ACQUIRE(c->lock); +#endif if (not f->dirty) { f->dirty = true; From 15eada93ed09cf185c6f8572eeaa0ae44df0be4c Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 20 Nov 2009 10:40:01 -0700 Subject: [PATCH 09/16] implement atomicCompareAndSwap on x86_32 for GCC versions prior to 4.1 and for MSVC --- makefile | 2 +- src/common.h | 15 --------------- src/heap.cpp | 11 +++++++++++ src/powerpc.h | 13 +++++++++++++ src/x86.h | 34 ++++++++++++++++++++++++++++++++++ 5 files changed, 59 insertions(+), 16 deletions(-) diff --git a/makefile b/makefile index 7006194a35..4cb9d305b4 100644 --- a/makefile +++ b/makefile @@ -101,7 +101,7 @@ warnings = -Wall -Wextra -Werror -Wunused-parameter -Winit-self \ common-cflags = $(warnings) -fno-rtti -fno-exceptions -fno-omit-frame-pointer \ "-I$(JAVA_HOME)/include" -idirafter $(src) -I$(native-build) \ -D__STDC_LIMIT_MACROS -D_JNI_IMPLEMENTATION_ -DAVIAN_VERSION=\"$(version)\" \ - $(gnu-cflags) + -DUSE_ATOMIC_OPERATIONS $(gnu-cflags) build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \ "-I$(JAVA_HOME)/include/linux" -I$(src) -pthread diff --git a/src/common.h b/src/common.h index 459cd0dcef..b9990a674f 100644 --- a/src/common.h +++ b/src/common.h @@ -63,11 +63,6 @@ typedef uint64_t uintptr_t; # include "stdint.h" -# if (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 1) -# define USE_ATOMIC_OPERATIONS -# define COMPARE_AND_SWAP __sync_bool_compare_and_swap -# endif - # define LIKELY(v) __builtin_expect((v) != 0, true) # define UNLIKELY(v) __builtin_expect((v) != 0, false) @@ -330,16 +325,6 @@ markBit(uintptr_t* map, unsigned i) map[wordOf(i)] |= static_cast(1) << bitOf(i); } -#ifdef USE_ATOMIC_OPERATIONS -inline void -markBitAtomic(uintptr_t* map, unsigned i) -{ - uintptr_t* p = map + wordOf(i); - uintptr_t v = static_cast(1) << bitOf(i); - while (not COMPARE_AND_SWAP(p, *p, *p | v)) { } -} -#endif - inline void clearBit(uintptr_t* map, unsigned i) { diff --git a/src/heap.cpp b/src/heap.cpp index c2c4ec79c0..740b9985af 100644 --- a/src/heap.cpp +++ b/src/heap.cpp @@ -11,6 +11,7 @@ #include "heap.h" #include "system.h" #include "common.h" +#include "arch.h" using namespace vm; @@ -69,6 +70,16 @@ System* system(Context*); void* tryAllocate(Context* c, unsigned size); void free(Context* c, const void* p, unsigned size); +#ifdef USE_ATOMIC_OPERATIONS +inline void +markBitAtomic(uintptr_t* map, unsigned i) +{ + uintptr_t* p = map + wordOf(i); + uintptr_t v = static_cast(1) << bitOf(i); + while (not atomicCompareAndSwap(p, *p, *p | v)) { } +} +#endif // USE_ATOMIC_OPERATIONS + inline void* get(void* o, unsigned offsetInWords) { diff --git a/src/powerpc.h b/src/powerpc.h index e60d27bfe5..e66c826022 100644 --- a/src/powerpc.h +++ b/src/powerpc.h @@ -90,6 +90,19 @@ syncInstructionCache(const void* start, unsigned size) __asm__ __volatile__("isync"); } +#ifdef USE_ATOMIC_OPERATIONS +inline bool +atomicCompareAndSwap(uintptr_t* p, uintptr_t old, uintptr_t new_) +{ +#if (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 1) + return __sync_bool_compare_and_swap(p, old, new_); +#else // not GCC >= 4.1 + // todo: implement using inline assembly +# undef USE_ATOMIC_OPERATIONS +#endif // not GCC >= 4.1 +} +#endif // USE_ATOMIC_OPERATIONS + inline uint64_t dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes, unsigned argumentCount, unsigned argumentsSize, diff --git a/src/x86.h b/src/x86.h index 7dd86c482b..b195ed7725 100644 --- a/src/x86.h +++ b/src/x86.h @@ -188,6 +188,40 @@ syncInstructionCache(const void*, unsigned) // ignore } +#ifdef USE_ATOMIC_OPERATIONS +inline bool +atomicCompareAndSwap(uintptr_t* p, uintptr_t old, uintptr_t new_) +{ +#ifdef _MSC_VER +# ifdef ARCH_x86_32 + InterlockedCompareExchange(p, new_, old); +# elif defined ARCH_x86_64 + InterlockedCompareExchange64(p, new_, old); +# endif // ARCH_x86_64 +#elif (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 1) + return __sync_bool_compare_and_swap(p, old, new_); +#elif defined ARCH_x86_32 + uint8_t result; + + __asm__ __volatile__("lock; cmpxchgl %2, %0; setz %1" + : "=m"(*p), "=q"(result) + : "r"(new_), "a"(old), "m"(*p) + : "memory"); + + return result != 0; +#elif defined ARCH_x86_64 + uint8_t result; + + __asm__ __volatile__("lock; cmpxchg1 %2, %0; setz %1" + : "=m"(*p), "=q"(result) + : "r"(new_), "a"(old), "m"(*p) + : "memory"); + + return result != 0; +#endif // ARCH_x86_64 +} +#endif // USE_ATOMIC_OPERATIONS + } // namespace vm #endif//X86_H From b83314e884321d8656d62da3f1f67560d672455b Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 20 Nov 2009 10:42:02 -0700 Subject: [PATCH 10/16] fix powerpc build --- src/powerpc.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/powerpc.h b/src/powerpc.h index e66c826022..20b512c16e 100644 --- a/src/powerpc.h +++ b/src/powerpc.h @@ -91,16 +91,16 @@ syncInstructionCache(const void* start, unsigned size) } #ifdef USE_ATOMIC_OPERATIONS +# if (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 1) inline bool atomicCompareAndSwap(uintptr_t* p, uintptr_t old, uintptr_t new_) { -#if (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 1) return __sync_bool_compare_and_swap(p, old, new_); -#else // not GCC >= 4.1 - // todo: implement using inline assembly -# undef USE_ATOMIC_OPERATIONS -#endif // not GCC >= 4.1 } +# else // not GCC >= 4.1 +// todo: implement using inline assembly +# undef USE_ATOMIC_OPERATIONS +# endif // not GCC >= 4.1 #endif // USE_ATOMIC_OPERATIONS inline uint64_t From f75868b39416bad0095d79c00a07a4adda25cec1 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 20 Nov 2009 11:40:55 -0700 Subject: [PATCH 11/16] don't specify -march=i486 on Darwin because a later generation is assumed by default --- makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/makefile b/makefile index 4cb9d305b4..9376afadef 100644 --- a/makefile +++ b/makefile @@ -240,10 +240,12 @@ ifeq ($(mode),small) cflags += -Os -g3 -DNDEBUG endif +ifneq ($(platform),darwin) ifeq ($(arch),i386) # this is necessary to support __sync_bool_compare_and_swap: cflags += -march=i486 endif +endif output = -o $(1) as := $(cc) From 2276eece0ea2eb430118f9eb87e88e80c1c84aa3 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 20 Nov 2009 15:14:27 -0700 Subject: [PATCH 12/16] support atomicCompareAndSwap on powerpc for GCC versions prior to 4.1 --- src/powerpc.h | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/powerpc.h b/src/powerpc.h index 20b512c16e..1b906537cc 100644 --- a/src/powerpc.h +++ b/src/powerpc.h @@ -91,16 +91,33 @@ syncInstructionCache(const void* start, unsigned size) } #ifdef USE_ATOMIC_OPERATIONS -# if (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 1) inline bool atomicCompareAndSwap(uintptr_t* p, uintptr_t old, uintptr_t new_) { +#if (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 1) return __sync_bool_compare_and_swap(p, old, new_); +#else // not GCC >= 4.1 + bool result; + + __asm__ __volatile__(" sync\n" + "1:\n" + " lwarx %0,0,%2\n" + " cmpw %0,%3\n" + " bne- 2f\n" + " stwcx. %4,0,%2\n" + " bne- 1b\n" + " isync \n" + "2:\n" + " xor %0,%0,%3\n" + " cntlzw %0,%0\n" + " srwi %0,%0,5\n" + : "=&r"(result), "+m"(*p) + : "r"(p), "r"(old), "r"(new_) + : "cc", "memory"); + + return result; +#endif // not GCC >= 4.1 } -# else // not GCC >= 4.1 -// todo: implement using inline assembly -# undef USE_ATOMIC_OPERATIONS -# endif // not GCC >= 4.1 #endif // USE_ATOMIC_OPERATIONS inline uint64_t From a0d763d871d82a7a5df7ed749dc43a4dca94899b Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 20 Nov 2009 15:17:35 -0700 Subject: [PATCH 13/16] use cmpxchgq for 64-bit operands in atomicCompareAndSwap --- src/x86.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/x86.h b/src/x86.h index b195ed7725..f9f3c038a1 100644 --- a/src/x86.h +++ b/src/x86.h @@ -212,7 +212,7 @@ atomicCompareAndSwap(uintptr_t* p, uintptr_t old, uintptr_t new_) #elif defined ARCH_x86_64 uint8_t result; - __asm__ __volatile__("lock; cmpxchg1 %2, %0; setz %1" + __asm__ __volatile__("lock; cmpxchgq %2, %0; setz %1" : "=m"(*p), "=q"(result) : "r"(new_), "a"(old), "m"(*p) : "memory"); From 728a6ba7062835aec136da63cd996ee0d9117e84 Mon Sep 17 00:00:00 2001 From: Stan Date: Tue, 24 Nov 2009 08:24:37 -0700 Subject: [PATCH 14/16] use MapViewOfFile instead of mmap on Windows --- src/binaryToObject/main.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/binaryToObject/main.cpp b/src/binaryToObject/main.cpp index 0200dd4123..0e69698847 100644 --- a/src/binaryToObject/main.cpp +++ b/src/binaryToObject/main.cpp @@ -14,7 +14,11 @@ #include "string.h" #include "sys/stat.h" +#ifdef WIN32 +#include +#else #include "sys/mman.h" +#endif #include "fcntl.h" #include "unistd.h" @@ -152,8 +156,29 @@ main(int argc, const char** argv) struct stat s; int r = fstat(fd, &s); if (r != -1) { +#ifdef WIN32 + HANDLE fm; + HANDLE h = (HANDLE) _get_osfhandle (fd); + + fm = CreateFileMapping( + h, + NULL, + PAGE_READONLY, + 0, + 0, + NULL); + data = static_cast(MapViewOfFile( + fm, + FILE_MAP_READ, + 0, + 0, + s.st_size)); + + CloseHandle(fm); +#else data = static_cast (mmap(0, s.st_size, PROT_READ, MAP_PRIVATE, fd, 0)); +#endif size = s.st_size; } close(fd); @@ -173,7 +198,11 @@ main(int argc, const char** argv) fprintf(stderr, "unable to open %s\n", argv[2]); } +#ifdef WIN32 + UnmapViewOfFile(data); +#else munmap(data, size); +#endif } else { perror(argv[0]); } From 9f14d635922565b63ca7bb07af5cf39dc8c7f0f2 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 24 Nov 2009 19:15:27 -0700 Subject: [PATCH 15/16] initialize MyProcessor::getStackTrace::Visitor::trace in case visit is never called --- src/compile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compile.cpp b/src/compile.cpp index aeb5e3722b..bb9f699584 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -7260,7 +7260,7 @@ class MyProcessor: public Processor { class Visitor: public System::ThreadVisitor { public: Visitor(MyThread* t, MyProcessor* p, MyThread* target): - t(t), p(p), target(target) + t(t), p(p), target(target), trace(0) { } virtual void visit(void* ip, void* base, void* stack) { From f6a52e260b9d76074ea5c390f1b330619d6007e6 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 24 Nov 2009 19:16:22 -0700 Subject: [PATCH 16/16] specify CONTEXT::ContextFlags before calling GetThreadContext Previously, we assumed that the "context" parameter to GetThreadContext was only an output parameter, but it actually uses at the value of CONTEXT::ContextFlags on entry to decide what parts of the structure to fill in. We were getting lucking most of the time, because whatever garbage was on the stack at that location had the necessary bits set. When we weren't so lucky, we got all zeros for the register values which sometimes lead to a crash depending on the state of the thread being examined. --- src/windows.cpp | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/windows.cpp b/src/windows.cpp index f15c2996d2..4ac44e4d05 100644 --- a/src/windows.cpp +++ b/src/windows.cpp @@ -616,26 +616,32 @@ class MySystem: public System { ACQUIRE(this, mutex); + bool success = false; int rv = SuspendThread(target->thread); - expect(this, rv != -1); + if (rv != -1) { + CONTEXT context; + memset(&context, 0, sizeof(CONTEXT)); + context.ContextFlags = CONTEXT_CONTROL; + rv = GetThreadContext(target->thread, &context); - CONTEXT context; - rv = GetThreadContext(target->thread, &context); - expect(this, rv); + if (rv) { #ifdef ARCH_x86_32 - visitor->visit(reinterpret_cast(context.Eip), - reinterpret_cast(context.Ebp), - reinterpret_cast(context.Esp)); + visitor->visit(reinterpret_cast(context.Eip), + reinterpret_cast(context.Ebp), + reinterpret_cast(context.Esp)); #elif defined ARCH_x86_64 - visitor->visit(reinterpret_cast(context.Rip), - reinterpret_cast(context.Rbp), - reinterpret_cast(context.Rsp)); + visitor->visit(reinterpret_cast(context.Rip), + reinterpret_cast(context.Rbp), + reinterpret_cast(context.Rsp)); #endif + success = true; + } - rv = ResumeThread(target->thread); - expect(this, rv != -1); + rv = ResumeThread(target->thread); + expect(this, rv != -1); + } - return 0; + return (success ? 0 : 1); } virtual uint64_t call(void* function, uintptr_t* arguments, uint8_t* types,