diff --git a/classpath/java/util/HashMap.java b/classpath/java/util/HashMap.java index 0f00f920b2..e767b166d8 100644 --- a/classpath/java/util/HashMap.java +++ b/classpath/java/util/HashMap.java @@ -149,16 +149,17 @@ public class HashMap implements Map { } public boolean containsValue(Object value) { - if (array != null) { - int index = array.length - 1; - for (Cell c = array[index]; c != null; c = c.next()) { - if (helper.equal(value, c.getValue())) { - return true; + if (array != null) { + for (int i = 0; i < array.length; ++i) { + for (Cell c = array[i]; c != null; c = c.next()) { + if (helper.equal(value, c.getValue())) { + return true; + } } } } - return false; + return false; } public V get(Object key) { @@ -450,10 +451,12 @@ public class HashMap implements Map { public Entry next() { if (hasNext()) { - if (currentCell != null && currentCell.next() != null) { - previousCell = currentCell; - } else { - previousCell = null; + if (currentCell != null) { + if (currentCell.next() != null) { + previousCell = currentCell; + } else { + previousCell = null; + } } currentCell = nextCell; @@ -490,6 +493,7 @@ public class HashMap implements Map { } } currentCell = null; + -- size; } else { throw new IllegalStateException(); } diff --git a/makefile b/makefile index 10cc18eb47..6583457df3 100644 --- a/makefile +++ b/makefile @@ -159,6 +159,8 @@ common-cflags = $(warnings) -fno-rtti -fno-exceptions -fno-omit-frame-pointer \ build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \ "-I$(JAVA_HOME)/include/linux" -I$(src) -pthread +converter-cflags = -D__STDC_CONSTANT_MACROS + cflags = $(build-cflags) common-lflags = -lm -lz $(classpath-lflags) @@ -220,7 +222,7 @@ ifeq ($(platform),darwin) ifeq ($(arch),powerpc) ifneq (,$(filter i386 x86_64,$(build-arch))) - converter-cflags = -DOPPOSITE_ENDIAN + converter-cflags += -DOPPOSITE_ENDIAN endif openjdk-extra-cflags += -arch ppc cflags += -arch ppc @@ -230,7 +232,7 @@ ifeq ($(platform),darwin) ifeq ($(arch),i386) ifeq ($(build-arch),powerpc) - converter-cflags = -DOPPOSITE_ENDIAN + converter-cflags += -DOPPOSITE_ENDIAN endif openjdk-extra-cflags += -arch i386 cflags += -arch i386 @@ -240,7 +242,7 @@ ifeq ($(platform),darwin) ifeq ($(arch),x86_64) ifeq ($(build-arch),powerpc) - converter-cflags = -DOPPOSITE_ENDIAN + converter-cflags += -DOPPOSITE_ENDIAN endif openjdk-extra-cflags += -arch x86_64 cflags += -arch x86_64 diff --git a/src/heap.cpp b/src/heap.cpp index 718d2885a0..02211204b2 100644 --- a/src/heap.cpp +++ b/src/heap.cpp @@ -69,6 +69,7 @@ void assert(Context*, bool); System* system(Context*); void* tryAllocate(Context* c, unsigned size); void free(Context* c, const void* p, unsigned size); +void outOfMemory(Context*); #ifdef USE_ATOMIC_OPERATIONS inline void @@ -359,7 +360,7 @@ class Segment { break; } } else { - abort(context); + outOfMemory(context); } } } @@ -1708,7 +1709,8 @@ collect(Context* c) } } -void* tryAllocate(Context* c, unsigned size) +void* +tryAllocate(Context* c, unsigned size) { ACQUIRE(c->lock); @@ -1733,7 +1735,9 @@ void* tryAllocate(Context* c, unsigned size) return 0; } -void free(Context* c, const void* p, unsigned size) { +void +free(Context* c, const void* p, unsigned size) +{ ACQUIRE(c->lock); if (DebugAllocation) { @@ -1755,10 +1759,18 @@ void free(Context* c, const void* p, unsigned size) { c->count -= size; } -void free_(Context* c, const void* p, unsigned size) { +void +free_(Context* c, const void* p, unsigned size) +{ free(c, p, size); } +void +outOfMemory(Context* c) +{ + c->client->outOfMemory(); +} + class MyHeap: public Heap { public: MyHeap(System* system, unsigned limit): @@ -1781,7 +1793,9 @@ class MyHeap: public Heap { virtual void* allocate(unsigned size) { void* p = local::tryAllocate(&c, size); - expect(c.system, p); + if (p == 0) { + c.client->outOfMemory(); + } return p; } diff --git a/src/heap.h b/src/heap.h index 769bc1ec4b..6b392a1de6 100644 --- a/src/heap.h +++ b/src/heap.h @@ -49,6 +49,7 @@ class Heap: public Allocator { virtual unsigned copiedSizeInWords(void*) = 0; virtual void copy(void*, void*) = 0; virtual void walk(void*, Walker*) = 0; + virtual void outOfMemory() = 0; }; virtual void setClient(Client* client) = 0; diff --git a/src/machine.cpp b/src/machine.cpp index 89512b0b59..73ceca8032 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -2136,6 +2136,21 @@ class HeapClient: public Heap::Client { ::walk(m->rootThread, w, o, 0); } + virtual void outOfMemory() { +#ifdef AVIAN_HEAPDUMP + const char* path = findProperty(m->rootThread, "avian.heap.dump"); + if (path) { + FILE* out = vm::fopen(path, "wb"); + if (out) { + dumpHeap(m->rootThread, out); + fclose(out); + } + } +#endif//AVIAN_HEAPDUMP + + abort(m->system); + } + void dispose() { m->heap->free(this, sizeof(*this)); } diff --git a/src/posix.cpp b/src/posix.cpp index e72587eea6..2339b666dc 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -648,15 +648,22 @@ class MySystem: public System { int rv = pthread_kill(target->thread, VisitSignal); + int result; if (rv == 0) { while (visitTarget) visitLock->wait(t, 0); - threadVisitor = 0; - - return 0; + result = 0; } else { - return -1; + visitTarget = 0; + + result = -1; } + + threadVisitor = 0; + + system->visitLock->notifyAll(t); + + return result; } virtual uint64_t call(void* function, uintptr_t* arguments, uint8_t* types, @@ -876,7 +883,9 @@ handleSignal(int signal, siginfo_t* info, void* context) default: abort(); } - if (system->oldHandlers[index].sa_flags & SA_SIGINFO) { + 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); diff --git a/test/extra/DumpStats.java b/test/extra/DumpStats.java index c9e7774484..73b9170bed 100644 --- a/test/extra/DumpStats.java +++ b/test/extra/DumpStats.java @@ -16,8 +16,9 @@ import java.util.Arrays; * heap dump generated by Avian's heapdump.cpp. The output is a list * of classes (identified by number in the case of anonymous, * VM-internal classes), each followed by (1) the total memory - * footprint of all instances of the class, and (2) the number of - * instances. The output is ordered by instance memory footprint. + * footprint of all instances of the class in machine words, and (2) + * the number of instances. The output is ordered by instance memory + * footprint. */ public class DumpStats { private static final int Root = 0; @@ -107,8 +108,16 @@ public class DumpStats { return map; } + + private static void usageAndExit() { + System.err.println("usage: java DumpStats "); + } public static void main(String[] args) throws Exception { + if (args.length != 2) { + usageAndExit(); + } + Map map = read (new BufferedInputStream(new FileInputStream(args[0]))); @@ -119,19 +128,22 @@ public class DumpStats { } }); + int wordSize = Integer.parseInt(args[1]); + int footprint = 0; int count = 0; for (Record r: array) { if (r.name == null) { r.name = String.valueOf(r.key); } - System.out.println(r.name + ": " + r.footprint + " " + r.count); + System.out.println + (r.name + ": " + (r.footprint * wordSize) + " " + r.count); footprint += r.footprint; count += r.count; } System.out.println(); - System.out.println("total: " + footprint + " " + count); + System.out.println("total: " + (footprint * wordSize) + " " + count); } private static class Record { diff --git a/test/extra/QueryDump.java b/test/extra/QueryDump.java new file mode 100644 index 0000000000..156cd64d36 --- /dev/null +++ b/test/extra/QueryDump.java @@ -0,0 +1,358 @@ +package extra; + +import java.io.PrintStream; +import java.io.InputStream; +import java.io.FileInputStream; +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.EOFException; +import java.util.Set; +import java.util.HashSet; +import java.util.Map; +import java.util.HashMap; +import java.util.Comparator; +import java.util.Arrays; +import java.util.List; +import java.util.ArrayList; +import java.util.Iterator; + +public class QueryDump { + private static final int Root = 0; + private static final int Size = 1; + private static final int ClassName = 2; + private static final int Push = 3; + private static final int Pop = 4; + + private static int readInt(InputStream in) throws IOException { + int b1 = in.read(); + int b2 = in.read(); + int b3 = in.read(); + int b4 = in.read(); + if (b4 == -1) throw new EOFException(); + return (int) ((b1 << 24) | (b2 << 16) | (b3 << 8) | (b4)); + } + + private static String readString(InputStream in) throws IOException { + int count = readInt(in); + byte[] b = new byte[count]; + int offset = 0; + int c; + while ((c = in.read(b, offset, b.length - offset)) != -1 + && offset < b.length) + { + offset += c; + } + if (offset != b.length) throw new EOFException(); + return new String(b); + } + + private static Record record(Map map, int key) { + Record r = map.get(key); + if (r == null) { + map.put(key, r = new Record(key)); + } + return r; + } + + private static void push(List stack, T value) { + stack.add(value); + } + + private static T pop(List stack) { + return stack.remove(stack.size() - 1); + } + + private static T peek(List stack, int offset) { + return stack.get(stack.size() - 1 - offset); + } + + private static T peek(List stack) { + return peek(stack, 0); + } + + private static Set nodes(Record record) { + if (record.nodes == null) { + record.nodes = new HashSet(2); + } + return record.nodes; + } + + private static void query(Map nodes, Record[] query, + List stack, int index) + { + Node node = nodes.get(peek(stack, index).key); + if (node != null) { + int base = node.index(); + for (int i = base + 1; i < query.length; ++i) { + int peek = index + i - base; + if (peek < stack.size()) { + Instance instance = peek(stack, peek); + if (query[i] == instance.record) { + TreeNode next = (TreeNode) nodes.get(instance); + if (next == null) { + nodes.put(instance.key, next = new TreeNode(instance, i)); + } + next.children.add(node); + node = next; + } else { + return; + } + } else { + return; + } + } + + if (index + query.length - base < stack.size()) { + nodes(peek(stack, index + query.length - base).record).add(node); + } + } + } + + private static void query(Map nodes, Record[] query, + List stack) + { + if (stack.size() > 1) { + Instance instance = peek(stack, 1); + if (instance != null && instance.record == query[0]) { + Node node = nodes.get(instance.key); + if (node == null) { + nodes.put(instance.key, new LeafNode(instance)); + query(nodes, query, stack, 1); + } + return; + } + } + + query(nodes, query, stack, 0); + } + + private static Map read(InputStream in, + String[] queryClasses) + throws IOException + { + boolean done = false; + boolean popped = false; + Map records = new HashMap(); + Map nodes = new HashMap(); + List stack = new ArrayList(); + Record[] query = new Record[queryClasses.length]; + + Record roots = new Record(-1, ""); + records.put(roots.key, roots); + + while (! done) { + int flag = in.read(); + switch (flag) { + case Root: { + stack.clear(); + push(stack, new Instance(readInt(in))); + + query(nodes, query, stack); + + popped = false; + // System.out.println("root " + last); + } break; + + case ClassName: { + String name = readString(in); + Record r = record(records, peek(stack).key); + r.name = name; + + for (int i = 0; i < queryClasses.length; ++i) { + if (queryClasses[i].equals(name)) { + query[i] = r; + } + } + + query(nodes, query, stack); + } break; + + case Push: { + int key = readInt(in); + + if (! popped) { + peek(stack).record = record(records, key); + } + + push(stack, new Instance(key)); + + query(nodes, query, stack); + + popped = false; + } break; + + case Pop: { + pop(stack); + + popped = true; + } break; + + case Size: { + peek(stack).size = readInt(in); + } break; + + case -1: + done = true; + break; + + default: + throw new RuntimeException("bad flag: " + flag); + } + } + + return records; + } + + private static String[] copy(String[] array, int offset, int length) { + String[] copy = new String[length]; + if (length > 0) { + System.arraycopy(array, offset, copy, 0, length); + } + + return copy; + } + + private static void visitLeaves(Set nodes, LeafVisitor visitor) { + for (Node n: nodes) { + n.visitLeaves(visitor); + } + } + + private static void usageAndExit() { + System.err.println("usage: java QueryDump " + + " ..."); + } + + public static void main(String[] args) throws Exception { + if (args.length < 3) { + usageAndExit(); + } + + Map map = read + (new BufferedInputStream(new FileInputStream(args[0])), + copy(args, 2, args.length - 2)); + + for (Iterator it = map.values().iterator(); it.hasNext();) { + final Record r = it.next(); + if (r.nodes == null) { + it.remove(); + } else { + visitLeaves(r.nodes, new LeafVisitor() { + private Set set = new HashSet(); + + public void visit(LeafNode node) { + if (! set.contains(node.instance)) { + r.footprint += node.instance.size; + ++ r.count; + } + set.add(node.instance); + } + }); + } + } + + Record[] array = map.values().toArray(new Record[map.size()]); + Arrays.sort(array, new Comparator() { + public int compare(Record a, Record b) { + return b.footprint - a.footprint; + } + }); + + int wordSize = Integer.parseInt(args[1]); + + int footprint = 0; + int count = 0; + for (Record r: array) { + if (r.name == null) { + r.name = String.valueOf(r.key); + } + System.out.println + (r.name + ": " + (r.footprint * wordSize) + " " + r.count); + footprint += r.footprint; + count += r.count; + } + + System.out.println(); + System.out.println("total: " + (footprint * wordSize) + " " + count); + } + + private static class Record { + public final int key; + public String name; + public int footprint; + public int count; + public Set nodes; + + public Record(int key) { + this(key, null); + } + + public Record(int key, String name) { + this.key = key; + this.name = name; + } + + public String toString() { + return name; + } + } + + private static class Instance { + public final int key; + public int size; + public Record record; + + public Instance(int key) { + this.key = key; + } + + public String toString() { + return "[" + key + " " + record + "]"; + } + } + + public interface Node { + public void visitLeaves(LeafVisitor visitor); + public int index(); + } + + public static class LeafNode implements Node { + public final Instance instance; + + public LeafNode(Instance instance) { + this.instance = instance; + } + + public void visitLeaves(LeafVisitor visitor) { + visitor.visit(this); + } + + public int index() { + return 0; + } + } + + public static class TreeNode implements Node { + public final Instance instance; + public final int index; + + public final Set children = new HashSet(2); + + public TreeNode(Instance instance, int index) { + this.instance = instance; + this.index = index; + } + + public void visitLeaves(LeafVisitor visitor) { + QueryDump.visitLeaves(children, visitor); + } + + public int index() { + return index; + } + } + + public interface LeafVisitor { + public void visit(LeafNode node); + } +}