From 79119890553cc9cefc1cd4aa585fbaaf6932cef8 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 4 Aug 2009 17:24:29 -0600 Subject: [PATCH 01/13] add AbstractList and AbstractSequentialList classes to java.util and listIterator methods to java.util.List --- classpath/java/util/AbstractList.java | 15 +++ .../java/util/AbstractSequentialList.java | 15 +++ classpath/java/util/ArrayList.java | 4 +- classpath/java/util/Arrays.java | 10 +- classpath/java/util/Collections.java | 16 +-- classpath/java/util/LinkedList.java | 56 +++++++-- classpath/java/util/List.java | 4 + classpath/java/util/Vector.java | 12 +- test/List.java | 116 ++++++++++++++++++ 9 files changed, 223 insertions(+), 25 deletions(-) create mode 100644 classpath/java/util/AbstractList.java create mode 100644 classpath/java/util/AbstractSequentialList.java diff --git a/classpath/java/util/AbstractList.java b/classpath/java/util/AbstractList.java new file mode 100644 index 0000000000..fa1abbd65a --- /dev/null +++ b/classpath/java/util/AbstractList.java @@ -0,0 +1,15 @@ +/* Copyright (c) 2009, 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 abstract class AbstractList extends AbstractCollection + implements List +{ } diff --git a/classpath/java/util/AbstractSequentialList.java b/classpath/java/util/AbstractSequentialList.java new file mode 100644 index 0000000000..8af8938ba0 --- /dev/null +++ b/classpath/java/util/AbstractSequentialList.java @@ -0,0 +1,15 @@ +/* Copyright (c) 2009, 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 abstract class AbstractSequentialList extends AbstractList + implements List +{ } diff --git a/classpath/java/util/ArrayList.java b/classpath/java/util/ArrayList.java index e130c55c67..22726cb4fa 100644 --- a/classpath/java/util/ArrayList.java +++ b/classpath/java/util/ArrayList.java @@ -10,7 +10,7 @@ package java.util; -public class ArrayList implements List { +public class ArrayList extends AbstractList { private static final int MinimumCapacity = 16; private Object[] array; @@ -169,7 +169,7 @@ public class ArrayList implements List { } public Iterator iterator() { - return new Collections.ArrayListIterator(this); + return listIterator(); } public ListIterator listIterator(int index) { diff --git a/classpath/java/util/Arrays.java b/classpath/java/util/Arrays.java index db41e6bddc..219612f040 100644 --- a/classpath/java/util/Arrays.java +++ b/classpath/java/util/Arrays.java @@ -102,7 +102,15 @@ public class Arrays { } public Iterator iterator() { - return new Collections.ArrayListIterator(this); + return listIterator(); + } + + public ListIterator listIterator(int index) { + return new Collections.ArrayListIterator(this, index); + } + + public ListIterator listIterator() { + return listIterator(0); } }; } diff --git a/classpath/java/util/Collections.java b/classpath/java/util/Collections.java index 3b6ab87d87..70b6e03a48 100644 --- a/classpath/java/util/Collections.java +++ b/classpath/java/util/Collections.java @@ -198,7 +198,6 @@ public class Collections { return new SynchronizedMap (map); } - static class SynchronizedSet extends SynchronizedCollection implements Set @@ -232,7 +231,7 @@ public class Collections { static class ArrayListIterator implements ListIterator { private final List list; - private boolean canRemove = false; + private int toRemove = -1; private int index; public ArrayListIterator(List list) { @@ -250,7 +249,7 @@ public class Collections { public T previous() { if (hasPrevious()) { - canRemove = true; + toRemove = index; return list.get(index--); } else { throw new NoSuchElementException(); @@ -259,8 +258,8 @@ public class Collections { public T next() { if (hasNext()) { - canRemove = true; - return list.get(++index); + toRemove = ++index; + return list.get(index); } else { throw new NoSuchElementException(); } @@ -271,9 +270,10 @@ public class Collections { } public void remove() { - if (canRemove) { - canRemove = false; - list.remove(index--); + if (toRemove != -1) { + list.remove(toRemove); + index = toRemove - 1; + toRemove = -1; } else { throw new IllegalStateException(); } diff --git a/classpath/java/util/LinkedList.java b/classpath/java/util/LinkedList.java index 0fab004117..49164d87fe 100644 --- a/classpath/java/util/LinkedList.java +++ b/classpath/java/util/LinkedList.java @@ -10,7 +10,7 @@ package java.util; -public class LinkedList implements List { +public class LinkedList extends AbstractSequentialList { private Cell front; private Cell rear; private int size; @@ -198,7 +198,19 @@ public class LinkedList implements List { } public Iterator iterator() { - return new MyIterator(front); + return listIterator(); + } + + public ListIterator listIterator(int index) { + MyIterator it = new MyIterator(); + for (int i = 0; i < index; ++i) { + it.next(); + } + return it; + } + + public ListIterator listIterator() { + return listIterator(0); } public String toString() { @@ -217,18 +229,29 @@ public class LinkedList implements List { } } - private class MyIterator implements Iterator { + private class MyIterator implements ListIterator { + private Cell toRemove; private Cell current; - private Cell next; - public MyIterator(Cell start) { - next = start; + public T previous() { + if (hasPrevious()) { + T v = current.value; + toRemove = current; + current = current.prev; + return v; + } else { + throw new NoSuchElementException(); + } } public T next() { if (hasNext()) { - current = next; - next = next.next; + if (current == null) { + current = front; + } else { + current = current.next; + } + toRemove = current; return current.value; } else { throw new NoSuchElementException(); @@ -236,13 +259,22 @@ public class LinkedList implements List { } public boolean hasNext() { - return next != null; + if (current == null) { + return front != null; + } else { + return current.next != null; + } + } + + public boolean hasPrevious() { + return current != null; } public void remove() { - if (current != null) { - LinkedList.this.remove(current); - current = null; + if (toRemove != null) { + current = toRemove.prev; + LinkedList.this.remove(toRemove); + toRemove = null; } else { throw new IllegalStateException(); } diff --git a/classpath/java/util/List.java b/classpath/java/util/List.java index 0577e4b3e7..b9e5735edb 100644 --- a/classpath/java/util/List.java +++ b/classpath/java/util/List.java @@ -22,4 +22,8 @@ public interface List extends Collection { public void add(int index, T element); public boolean isEmpty(); + + public ListIterator listIterator(int index); + + public ListIterator listIterator(); } diff --git a/classpath/java/util/Vector.java b/classpath/java/util/Vector.java index f06f58ecbc..99b3dd7138 100644 --- a/classpath/java/util/Vector.java +++ b/classpath/java/util/Vector.java @@ -10,7 +10,7 @@ package java.util; -public class Vector implements List { +public class Vector extends AbstractList { private final ArrayList list; public Vector(int capacity) { @@ -112,7 +112,15 @@ public class Vector implements List { } public Iterator iterator() { - return new Collections.ArrayListIterator(this); + return listIterator(); + } + + public ListIterator listIterator(int index) { + return new Collections.ArrayListIterator(this, index); + } + + public ListIterator listIterator() { + return listIterator(0); } public Enumeration elements() { diff --git a/test/List.java b/test/List.java index ee3ffc0204..797aefbb7f 100644 --- a/test/List.java +++ b/test/List.java @@ -1,4 +1,6 @@ import java.util.ArrayList; +import java.util.LinkedList; +import java.util.ListIterator; public class List { private static void expect(boolean v) { @@ -21,6 +23,114 @@ public class List { expect(s1.equals(s2)); } + private static void testIterators(java.util.List l) { + l.add(1); + l.add(2); + l.add(3); + + ListIterator it = l.listIterator(); + expect(it.next().equals(Integer.valueOf(1))); + expect(it.next().equals(Integer.valueOf(2))); + expect(it.next().equals(Integer.valueOf(3))); + expect(! it.hasNext()); + + it = l.listIterator(1); + expect(it.next().equals(Integer.valueOf(2))); + expect(it.next().equals(Integer.valueOf(3))); + expect(! it.hasNext()); + + it = l.listIterator(2); + expect(it.next().equals(Integer.valueOf(3))); + expect(! it.hasNext()); + + it = l.listIterator(3); + expect(it.previous().equals(Integer.valueOf(3))); + expect(it.previous().equals(Integer.valueOf(2))); + expect(it.previous().equals(Integer.valueOf(1))); + expect(! it.hasPrevious()); + + it = l.listIterator(2); + expect(it.previous().equals(Integer.valueOf(2))); + expect(it.previous().equals(Integer.valueOf(1))); + expect(! it.hasPrevious()); + + it = l.listIterator(1); + expect(it.previous().equals(Integer.valueOf(1))); + expect(! it.hasPrevious()); + } + + private static void testIterators2(java.util.List l) { + l.add(1); + l.add(2); + l.add(3); + + ListIterator it = l.listIterator(); + expect(it.next().equals(Integer.valueOf(1))); + it.remove(); + expect(it.next().equals(Integer.valueOf(2))); + it.remove(); + expect(it.next().equals(Integer.valueOf(3))); + it.remove(); + expect(! it.hasNext()); + expect(l.isEmpty()); + + l.add(1); + l.add(2); + l.add(3); + + it = l.listIterator(1); + expect(it.next().equals(Integer.valueOf(2))); + it.remove(); + expect(it.next().equals(Integer.valueOf(3))); + it.remove(); + expect(! it.hasNext()); + expect(l.size() == 1); + + l.add(2); + l.add(3); + + it = l.listIterator(2); + expect(it.next().equals(Integer.valueOf(3))); + it.remove(); + expect(! it.hasNext()); + expect(l.size() == 2); + + l.add(3); + + it = l.listIterator(3); + expect(it.previous().equals(Integer.valueOf(3))); + it.remove(); + expect(it.previous().equals(Integer.valueOf(2))); + it.remove(); + expect(it.previous().equals(Integer.valueOf(1))); + it.remove(); + expect(! it.hasPrevious()); + expect(l.isEmpty()); + + l.add(1); + l.add(2); + l.add(3); + + it = l.listIterator(2); + expect(it.previous().equals(Integer.valueOf(2))); + it.remove(); + expect(it.previous().equals(Integer.valueOf(1))); + it.remove(); + expect(! it.hasPrevious()); + expect(l.size() == 1); + + l.clear(); + l.add(1); + l.add(2); + l.add(3); + + it = l.listIterator(1); + expect(it.previous().equals(Integer.valueOf(1))); + it.remove(); + expect(! it.hasPrevious()); + expect(l.size() == 2); + } + public static void main(String args[]) { ArrayList l = new ArrayList(); l.add(1); l.add(2); l.add(3); l.add(4); l.add(5); @@ -39,5 +149,11 @@ public class List { for (int i=0; i < z.length; i++) { System.out.println(z[i]); } + + testIterators(new ArrayList()); + testIterators(new LinkedList()); + + testIterators2(new ArrayList()); + testIterators2(new LinkedList()); } } From 0a7f94abfe62db3bddac869887bd6f200595a89f Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 4 Aug 2009 17:36:25 -0600 Subject: [PATCH 02/13] add java.util.Collection.toArray() --- classpath/java/util/AbstractCollection.java | 4 ++++ classpath/java/util/ArrayList.java | 4 ---- classpath/java/util/Arrays.java | 4 ++++ classpath/java/util/Collection.java | 2 ++ classpath/java/util/Collections.java | 11 +++++++++-- classpath/java/util/HashMap.java | 12 ++++++++++++ classpath/java/util/HashSet.java | 6 +----- classpath/java/util/LinkedList.java | 4 ---- classpath/java/util/TreeMap.java | 8 ++++++++ classpath/java/util/Vector.java | 4 ---- 10 files changed, 40 insertions(+), 19 deletions(-) diff --git a/classpath/java/util/AbstractCollection.java b/classpath/java/util/AbstractCollection.java index 5093b9a612..81500614ec 100644 --- a/classpath/java/util/AbstractCollection.java +++ b/classpath/java/util/AbstractCollection.java @@ -62,6 +62,10 @@ public abstract class AbstractCollection implements Collection { public abstract int size(); + public Object[] toArray() { + return toArray(new Object[size()]); + } + public S[] toArray(S[] array) { return Collections.toArray(this, array); } diff --git a/classpath/java/util/ArrayList.java b/classpath/java/util/ArrayList.java index 22726cb4fa..31e3dd5f58 100644 --- a/classpath/java/util/ArrayList.java +++ b/classpath/java/util/ArrayList.java @@ -159,10 +159,6 @@ public class ArrayList extends AbstractList { return size() == 0; } - public S[] toArray(S[] a) { - return Collections.toArray(this, a); - } - public void clear() { array = null; size = 0; diff --git a/classpath/java/util/Arrays.java b/classpath/java/util/Arrays.java index 219612f040..129b5f5528 100644 --- a/classpath/java/util/Arrays.java +++ b/classpath/java/util/Arrays.java @@ -81,6 +81,10 @@ public class Arrays { throw new UnsupportedOperationException(); } + public Object[] toArray() { + return toArray(new Object[size()]); + } + public S[] toArray(S[] a) { return (S[])array; } diff --git a/classpath/java/util/Collection.java b/classpath/java/util/Collection.java index aa8eee6d89..77fb9c8d3e 100644 --- a/classpath/java/util/Collection.java +++ b/classpath/java/util/Collection.java @@ -23,6 +23,8 @@ public interface Collection extends Iterable { public boolean remove(Object element); + public Object[] toArray(); + public S[] toArray(S[] array); public void clear(); diff --git a/classpath/java/util/Collections.java b/classpath/java/util/Collections.java index 70b6e03a48..00facfaa0e 100644 --- a/classpath/java/util/Collections.java +++ b/classpath/java/util/Collections.java @@ -129,6 +129,10 @@ public class Collections { synchronized (lock) { return collection.remove((T)e); } } + public Object[] toArray() { + return toArray(new Object[size()]); + } + public T[] toArray(T[] array) { synchronized (lock) { return collection.toArray(array); } } @@ -319,10 +323,13 @@ public class Collections { return inner.size(); } + public Object[] toArray() { + return toArray(new Object[size()]); + } + public S[] toArray(S[] array) { return inner.toArray(array); - } - + } } public static Set unmodifiableSet(Set hs) { diff --git a/classpath/java/util/HashMap.java b/classpath/java/util/HashMap.java index 2bc46b5e9d..ecae9a01f1 100644 --- a/classpath/java/util/HashMap.java +++ b/classpath/java/util/HashMap.java @@ -334,6 +334,10 @@ public class HashMap implements Map { return removeCell(e.getKey()) != null; } + public Object[] toArray() { + return toArray(new Object[size()]); + } + public T[] toArray(T[] array) { return Collections.toArray(this, array); } @@ -374,6 +378,10 @@ public class HashMap implements Map { return removeCell(key) != null; } + public Object[] toArray() { + return toArray(new Object[size()]); + } + public T[] toArray(T[] array) { return Collections.toArray(this, array); } @@ -412,6 +420,10 @@ public class HashMap implements Map { throw new UnsupportedOperationException(); } + public Object[] toArray() { + return toArray(new Object[size()]); + } + public T[] toArray(T[] array) { return Collections.toArray(this, array); } diff --git a/classpath/java/util/HashSet.java b/classpath/java/util/HashSet.java index b89c317a35..aa86f47df5 100644 --- a/classpath/java/util/HashSet.java +++ b/classpath/java/util/HashSet.java @@ -10,7 +10,7 @@ package java.util; -public class HashSet implements Set { +public class HashSet extends AbstractSet implements Set { private static final Object Value = new Object(); private final HashMap map; @@ -54,10 +54,6 @@ public class HashSet implements Set { return map.remove(element) != Value; } - public T[] toArray(T[] array) { - return Collections.toArray(this, array); - } - public void clear() { map.clear(); } diff --git a/classpath/java/util/LinkedList.java b/classpath/java/util/LinkedList.java index 49164d87fe..a437534363 100644 --- a/classpath/java/util/LinkedList.java +++ b/classpath/java/util/LinkedList.java @@ -85,10 +85,6 @@ public class LinkedList extends AbstractSequentialList { } } - public S[] toArray(S[] a) { - return Collections.toArray(this, a); - } - public int size() { return size; } diff --git a/classpath/java/util/TreeMap.java b/classpath/java/util/TreeMap.java index 99a7860e17..686e9ffda3 100644 --- a/classpath/java/util/TreeMap.java +++ b/classpath/java/util/TreeMap.java @@ -144,6 +144,10 @@ public class TreeMap implements Map { return set.removeAndReturn(new MyEntry(key, null)) != null; } + public Object[] toArray() { + return toArray(new Object[size()]); + } + public T[] toArray(T[] array) { return Collections.toArray(this, array); } @@ -182,6 +186,10 @@ public class TreeMap implements Map { throw new UnsupportedOperationException(); } + public Object[] toArray() { + return toArray(new Object[size()]); + } + public T[] toArray(T[] array) { return Collections.toArray(this, array); } diff --git a/classpath/java/util/Vector.java b/classpath/java/util/Vector.java index 99b3dd7138..4364c58281 100644 --- a/classpath/java/util/Vector.java +++ b/classpath/java/util/Vector.java @@ -77,10 +77,6 @@ public class Vector extends AbstractList { return list.isEmpty(); } - public synchronized S[] toArray(S[] a) { - return list.toArray(a); - } - public void removeElementAt(int index) { remove(index); } From 590238bbfcd02d5b298ed6fab45946a54a22589a Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 4 Aug 2009 17:58:31 -0600 Subject: [PATCH 03/13] add indexOf and lastIndexOf methods to java.util.List --- classpath/java/util/ArrayList.java | 6 +++--- classpath/java/util/Arrays.java | 18 ++++++++++++++++++ classpath/java/util/LinkedList.java | 22 ++++++++++++++++++++++ classpath/java/util/List.java | 4 ++++ classpath/java/util/Vector.java | 4 ++-- 5 files changed, 49 insertions(+), 5 deletions(-) diff --git a/classpath/java/util/ArrayList.java b/classpath/java/util/ArrayList.java index 31e3dd5f58..faabdebb5c 100644 --- a/classpath/java/util/ArrayList.java +++ b/classpath/java/util/ArrayList.java @@ -94,7 +94,7 @@ public class ArrayList extends AbstractList { return true; } - public int indexOf(T element) { + public int indexOf(Object element) { for (int i = 0; i < size; ++i) { if (equal(element, array[i])) { return i; @@ -103,8 +103,8 @@ public class ArrayList extends AbstractList { return -1; } - public int lastIndexOf(T element) { - for (int i = size; i >= 0; --i) { + public int lastIndexOf(Object element) { + for (int i = size - 1; i >= 0; --i) { if (equal(element, array[i])) { return i; } diff --git a/classpath/java/util/Arrays.java b/classpath/java/util/Arrays.java index 129b5f5528..2fe49fbc67 100644 --- a/classpath/java/util/Arrays.java +++ b/classpath/java/util/Arrays.java @@ -73,6 +73,24 @@ public class Arrays { return false; } + public int indexOf(Object element) { + for (int i = 0; i < array.length; ++i) { + if (equal(element, array[i])) { + return i; + } + } + return -1; + } + + public int lastIndexOf(Object element) { + for (int i = array.length - 1; i >= 0; --i) { + if (equal(element, array[i])) { + return i; + } + } + return -1; + } + public T get(int index) { return array[index]; } diff --git a/classpath/java/util/LinkedList.java b/classpath/java/util/LinkedList.java index a437534363..55bc80fed9 100644 --- a/classpath/java/util/LinkedList.java +++ b/classpath/java/util/LinkedList.java @@ -93,6 +93,28 @@ public class LinkedList extends AbstractSequentialList { return find(element) != null; } + public int indexOf(Object element) { + int i = 0; + for (Cell c = front; c != null; c = c.next) { + if (equal(c.value, element)) { + return i; + } + ++ i; + } + return -1; + } + + public int lastIndexOf(Object element) { + int i = size; + for (Cell c = rear; c != null; c = c.prev) { + -- i; + if (equal(c.value, element)) { + return i; + } + } + return -1; + } + public boolean add(T element) { addLast(element); return true; diff --git a/classpath/java/util/List.java b/classpath/java/util/List.java index b9e5735edb..487ebc18d1 100644 --- a/classpath/java/util/List.java +++ b/classpath/java/util/List.java @@ -21,6 +21,10 @@ public interface List extends Collection { public void add(int index, T element); + public int indexOf(Object value); + + public int lastIndexOf(Object value); + public boolean isEmpty(); public ListIterator listIterator(int index); diff --git a/classpath/java/util/Vector.java b/classpath/java/util/Vector.java index 4364c58281..c23a4d59fd 100644 --- a/classpath/java/util/Vector.java +++ b/classpath/java/util/Vector.java @@ -93,11 +93,11 @@ public class Vector extends AbstractList { list.clear(); } - public synchronized int indexOf(T element) { + public synchronized int indexOf(Object element) { return list.indexOf(element); } - public synchronized int lastIndexOf(T element) { + public synchronized int lastIndexOf(Object element) { return list.lastIndexOf(element); } From 626c5143737cdb6d4d1b932e86be9ad26a916f4d Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 4 Aug 2009 17:59:07 -0600 Subject: [PATCH 04/13] add listFiles and isFile methods to java.io.File --- classpath/java-io.cpp | 15 +++++++++++++++ classpath/java/io/File.java | 19 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/classpath/java-io.cpp b/classpath/java-io.cpp index 1bf1a04fec..9fbf2087bb 100644 --- a/classpath/java-io.cpp +++ b/classpath/java-io.cpp @@ -305,6 +305,21 @@ Java_java_io_File_isDirectory(JNIEnv* e, jclass, jstring path) } } +extern "C" JNIEXPORT jboolean JNICALL +Java_java_io_File_isFile(JNIEnv* e, jclass, jstring path) +{ + const char* chars = e->GetStringUTFChars(path, 0); + if (chars) { + STRUCT_STAT s; + int r = STAT(chars, &s); + bool v = (r == 0 and S_ISREG(s.st_mode)); + e->ReleaseStringUTFChars(path, chars); + return v; + } else { + return false; + } +} + extern "C" JNIEXPORT jboolean JNICALL Java_java_io_File_exists(JNIEnv* e, jclass, jstring path) { diff --git a/classpath/java/io/File.java b/classpath/java/io/File.java index 7308eb4872..48c8078aed 100644 --- a/classpath/java/io/File.java +++ b/classpath/java/io/File.java @@ -41,6 +41,12 @@ public class File { return isDirectory(path); } + private static native boolean isFile(String path); + + public boolean isFile() { + return isFile(path); + } + public String getName() { int index = path.lastIndexOf(FileSeparator); if (index >= 0) { @@ -141,6 +147,19 @@ public class File { return mkdir(); } + public File[] listFiles() { + return listFiles(null); + } + + public File[] listFiles(FilenameFilter filter) { + String[] list = list(filter); + File[] result = new File[list.length]; + for (int i = 0; i < list.length; ++i) { + result[i] = new File(this, list[i]); + } + return result; + } + public String[] list() { return list(null); } From 2de750768b072d965b21a94a51ad6da866d2d5a5 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 5 Aug 2009 14:14:45 +0000 Subject: [PATCH 05/13] add java.lang.reflect.Modifier.isInterface --- classpath/java/lang/reflect/Modifier.java | 1 + 1 file changed, 1 insertion(+) diff --git a/classpath/java/lang/reflect/Modifier.java b/classpath/java/lang/reflect/Modifier.java index a2671ad4d3..042554f298 100644 --- a/classpath/java/lang/reflect/Modifier.java +++ b/classpath/java/lang/reflect/Modifier.java @@ -35,4 +35,5 @@ public final class Modifier { public static boolean isSuper (int v) { return (v & SUPER) != 0; } public static boolean isNative (int v) { return (v & NATIVE) != 0; } public static boolean isAbstract (int v) { return (v & ABSTRACT) != 0; } + public static boolean isInterface(int v) { return (v & INTERFACE) != 0; } } From 6d27274aea57d5580edd9ca7f4192e5a49f2227f Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 5 Aug 2009 15:57:51 +0000 Subject: [PATCH 06/13] update Class.PrimitiveFlag value to reflect change in machine.h; make Class.getName work for primitive types --- classpath/java/lang/Class.java | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/classpath/java/lang/Class.java b/classpath/java/lang/Class.java index 551bd710d8..f439ba3521 100644 --- a/classpath/java/lang/Class.java +++ b/classpath/java/lang/Class.java @@ -27,7 +27,7 @@ import java.security.Permissions; import java.security.AllPermission; public final class Class implements Type, GenericDeclaration { - private static final int PrimitiveFlag = 1 << 4; + private static final int PrimitiveFlag = 1 << 5; private short flags; private byte vmFlags; @@ -62,6 +62,34 @@ public final class Class implements Type, GenericDeclaration { } public String getName() { + if (name == null) { + if ((vmFlags & PrimitiveFlag) != 0) { + if (this == primitiveClass('V')) { + name = "void".getBytes(); + } else if (this == primitiveClass('Z')) { + name = "boolean".getBytes(); + } else if (this == primitiveClass('B')) { + name = "byte".getBytes(); + } else if (this == primitiveClass('C')) { + name = "char".getBytes(); + } else if (this == primitiveClass('S')) { + name = "short".getBytes(); + } else if (this == primitiveClass('I')) { + name = "int".getBytes(); + } else if (this == primitiveClass('F')) { + name = "float".getBytes(); + } else if (this == primitiveClass('J')) { + name = "long".getBytes(); + } else if (this == primitiveClass('D')) { + name = "double".getBytes(); + } else { + throw new AssertionError(); + } + } else { + throw new AssertionError(); + } + } + return new String (replace('/', '.', name, 0, name.length - 1), 0, name.length - 1, false); } From 0c36b7b3b609fb3a01a19b44604c757e3ac73549 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 5 Aug 2009 15:00:27 -0600 Subject: [PATCH 07/13] change popDouble return type to double --- src/interpret.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/interpret.cpp b/src/interpret.cpp index 7a51fc997a..b1d533eb1a 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -167,7 +167,7 @@ popLong(Thread* t) return (b << 32) | a; } -inline float +inline double popDouble(Thread* t) { return bitsToDouble(popLong(t)); From 1ffe46a545635f71d5f1f1adc80a2776a533ab78 Mon Sep 17 00:00:00 2001 From: jet Date: Thu, 6 Aug 2009 11:52:36 -0600 Subject: [PATCH 08/13] added ARM interpreted mode supported --- classpath/java-nio.cpp | 1 + makefile | 163 +--- src/arch.h | 2 + src/arm.S | 56 ++ src/arm.cpp | 2043 ++++++++++++++++++++++++++++++++++++++++ src/arm.h | 119 +++ src/common.h | 2 +- src/interpret.cpp | 38 +- 8 files changed, 2300 insertions(+), 124 deletions(-) create mode 100644 src/arm.S create mode 100644 src/arm.cpp create mode 100644 src/arm.h diff --git a/classpath/java-nio.cpp b/classpath/java-nio.cpp index 899982a472..84810c8000 100644 --- a/classpath/java-nio.cpp +++ b/classpath/java-nio.cpp @@ -27,6 +27,7 @@ # include # include # include +# include #endif #define java_nio_channels_SelectionKey_OP_READ 1L diff --git a/makefile b/makefile index 21b007dd13..59d1c11b29 100644 --- a/makefile +++ b/makefile @@ -18,6 +18,10 @@ bootimage-platform = \ $(subst cygwin,windows,$(subst mingw32,windows,$(build-platform))) platform = $(bootimage-platform) +ifeq ($(platform),windows) + arch = i386 +endif + mode = fast process = compile @@ -39,23 +43,6 @@ endif ifeq ($(continuations),true) options := $(options)-continuations endif -ifdef gnu - options := $(options)-gnu - gnu-sources = $(src)/gnu.cpp - gnu-jar = $(gnu)/share/classpath/glibj.zip - gnu-libraries = \ - $(gnu)/lib/classpath/libjavaio.a \ - $(gnu)/lib/classpath/libjavalang.a \ - $(gnu)/lib/classpath/libjavalangreflect.a \ - $(gnu)/lib/classpath/libjavamath.a \ - $(gnu)/lib/classpath/libjavanet.a \ - $(gnu)/lib/classpath/libjavanio.a \ - $(gnu)/lib/classpath/libjavautil.a - gnu-object-dep = $(build)/gnu-object.dep - gnu-cflags = -DBOOT_BUILTINS=\"javaio,javalang,javalangreflect,javamath,javanet,javanio,javautil\" -DAVIAN_GNU - gnu-lflags = -lgmp - gnu-objects = $(shell find $(build)/gnu-objects -name "*.o") -endif root = $(shell (cd .. && pwd)) build = build @@ -66,12 +53,6 @@ src = src classpath = classpath test = test -ifdef gnu - avian-classpath-build = $(build)/avian-classpath -else - avian-classpath-build = $(classpath-build) -endif - input = List build-cxx = g++ @@ -102,14 +83,13 @@ 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) build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \ "-I$(JAVA_HOME)/include/linux" -I$(src) -pthread cflags = $(build-cflags) -common-lflags = -lm -lz $(gnu-lflags) +common-lflags = -lm -lz build-lflags = @@ -140,6 +120,21 @@ ifeq ($(arch),powerpc) object-format = elf32-powerpc pointer-size = 4 endif +ifeq ($(arch),arm) + lflags := -L/opt/crosstool/gcc-4.1.0-glibc-2.3.2/arm-unknown-linux-gnu/arm-unknown-linux-gnu/lib -L$(root)/arm/lib $(lflags) + cflags := -I/opt/crosstool/gcc-4.1.0-glibc-2.3.2/arm-unknown-linux-gnu/arm-unknown-linux-gnu/include -I$(root)/arm/include $(cflags) + + asm = arm + object-arch = arm + object-format = elf32-littlearm + pointer-size = 4 + cxx = arm-unknown-linux-gnu-g++ + cc = arm-unknown-linux-gnu-gcc + ar = arm-unknown-linux-gnu-ar + ranlib = arm-unknown-linux-gnu-ranlib + objcopy = arm-unknown-linux-gnu-objcopy + strip = arm-unknown-linux-gnu-strip +endif ifeq ($(platform),darwin) build-cflags = $(common-cflags) -fPIC -fvisibility=hidden -I$(src) @@ -187,21 +182,6 @@ ifeq ($(platform),windows) native-path = cygpath -m endif endif - - ifeq ($(arch),x86_64) - cxx = x86_64-pc-mingw32-g++ - cc = x86_64-pc-mingw32-gcc - dlltool = x86_64-pc-mingw32-dlltool - ar = x86_64-pc-mingw32-ar - ranlib = x86_64-pc-mingw32-ranlib - objcopy = x86_64-pc-mingw32-objcopy - strip = : - inc = "$(root)/win64/include" - lib = "$(root)/win64/lib" - pointer-size = 8 - object-format = pe-x86-64 - endif - endif ifeq ($(mode),debug) @@ -267,8 +247,7 @@ vm-sources = \ $(src)/$(process).cpp \ $(src)/builtin.cpp \ $(src)/jnienv.cpp \ - $(src)/process.cpp \ - $(gnu-sources) + $(src)/process.cpp vm-asm-sources = $(src)/$(asm).S @@ -350,43 +329,16 @@ classpath-sources = $(shell find $(classpath) -name '*.java') classpath-classes = \ $(call java-classes,$(classpath-sources),$(classpath),$(classpath-build)) classpath-object = $(native-build)/classpath-jar.o -classpath-dep = $(classpath-build).dep - -gnu-blacklist = \ - java/lang/AbstractStringBuffer.class \ - java/lang/reflect/Proxy.class - -gnu-overrides = \ - avian/*.class \ - avian/resource/*.class \ - java/lang/Class.class \ - java/lang/Enum.class \ - java/lang/InheritableThreadLocal.class \ - java/lang/Object.class \ - java/lang/StackTraceElement.class \ - java/lang/String*.class \ - java/lang/StringBuffer.class \ - java/lang/StringBuilder.class \ - java/lang/Thread.class \ - java/lang/ThreadLocal.class \ - java/lang/Throwable.class \ - java/lang/ref/PhantomReference.class \ - java/lang/ref/Reference.class \ - java/lang/ref/ReferenceQueue.class \ - java/lang/ref/WeakReference.class \ - java/lang/reflect/AccessibleObject.class \ - java/lang/reflect/Constructor.class \ - java/lang/reflect/Field.class \ - java/lang/reflect/Method.class +classpath-dep = $(classpath-build)/dep test-sources = $(wildcard $(test)/*.java) test-classes = $(call java-classes,$(test-sources),$(test),$(test-build)) -test-dep = $(test-build).dep +test-dep = $(test-build)/dep test-extra-sources = $(wildcard $(test)/extra/*.java) test-extra-classes = \ $(call java-classes,$(test-extra-sources),$(test),$(test-build)) -test-extra-dep = $(test-build)-extra.dep +test-extra-dep = $(test-build)/extra/dep class-name = $(patsubst $(1)/%.class,%,$(2)) class-names = $(foreach x,$(2),$(call class-name,$(1),$(x))) @@ -456,24 +408,11 @@ $(native-build)/type-generator.o: \ $(classpath-build)/%.class: $(classpath)/%.java @echo $(<) -$(classpath-dep): $(classpath-sources) $(gnu-jar) +$(classpath-dep): $(classpath-sources) @echo "compiling classpath classes" - @mkdir -p $(avian-classpath-build) - $(javac) -d $(avian-classpath-build) \ - -bootclasspath $(avian-classpath-build) \ + @mkdir -p $(dir $(@)) + $(javac) -d $(dir $(@)) -bootclasspath $(classpath-build) \ $(shell $(MAKE) -s --no-print-directory $(classpath-classes)) -ifdef gnu - (wd=$$(pwd) && \ - cd $(avian-classpath-build) && \ - $(jar) c0f "$$($(native-path) "$${wd}/$(build)/overrides.jar")" \ - $(gnu-overrides)) - @mkdir -p $(classpath-build) - (wd=$$(pwd) && \ - cd $(classpath-build) && \ - $(jar) xf $(gnu-jar) && \ - rm $(gnu-blacklist) && \ - jar xf "$$($(native-path) "$${wd}/$(build)/overrides.jar")") -endif @touch $(@) $(test-build)/%.class: $(test)/%.java @@ -481,16 +420,16 @@ $(test-build)/%.class: $(test)/%.java $(test-dep): $(test-sources) @echo "compiling test classes" - @mkdir -p $(test-build) - $(javac) -d $(test-build) -bootclasspath $(classpath-build) \ + @mkdir -p $(dir $(@)) + $(javac) -d $(dir $(@)) -bootclasspath $(classpath-build) \ $(shell $(MAKE) -s --no-print-directory $(test-classes)) - $(javac) -source 1.2 -target 1.1 -XDjsrlimit=0 -d $(test-build) \ + $(javac) -source 1.2 -target 1.1 -XDjsrlimit=0 -d $(dir $(@)) \ test/Subroutine.java @touch $(@) $(test-extra-dep): $(test-extra-sources) @echo "compiling extra test classes" - @mkdir -p $(test-build) + @mkdir -p $(dir $(@)) $(javac) -d $(test-build) -bootclasspath $(classpath-build) \ $(shell $(MAKE) -s --no-print-directory $(test-extra-classes)) @touch $(@) @@ -532,9 +471,9 @@ $(boot-object): $(boot-source) $(compile-object) $(build)/classpath.jar: $(classpath-dep) - (wd=$$(pwd) && \ - cd $(classpath-build) && \ - $(jar) c0f "$$($(native-path) "$${wd}/$(@)")" .) + (wd=$$(pwd); \ + cd $(classpath-build); \ + $(jar) c0f "$$($(native-path) "$${wd}/$(@)")" $$(find . -name '*.class')) $(binaryToMacho): $(src)/binaryToMacho.cpp $(cxx) $(^) -o $(@) @@ -545,8 +484,8 @@ ifeq ($(platform),darwin) $(binaryToMacho) $(asm) $(build)/classpath.jar __TEXT __text \ __binary_classpath_jar_start __binary_classpath_jar_end > $(@) else - (wd=$$(pwd) && \ - cd $(build) && \ + (wd=$$(pwd); \ + cd $(build); \ $(objcopy) -I binary classpath.jar \ -O $(object-format) -B $(object-arch) "$${wd}/$(@)") endif @@ -560,11 +499,10 @@ $(generator-objects): $(native-build)/%.o: $(src)/%.cpp $(jni-objects): $(native-build)/%.o: $(classpath)/%.cpp $(compile-object) -$(static-library): $(gnu-object-dep) $(static-library): $(vm-objects) $(jni-objects) $(vm-heapwalk-objects) @echo "creating $(@)" rm -rf $(@) - $(ar) cru $(@) $(^) $(call gnu-objects) + $(ar) cru $(@) $(^) $(ranlib) $(@) $(bootimage-bin): $(bootimage-generator) @@ -576,32 +514,24 @@ ifeq ($(platform),darwin) $(binaryToMacho) $(asm) $(<) __BOOT __boot \ __binary_bootimage_bin_start __binary_bootimage_bin_end > $(@) else - (wd=$$(pwd) && \ - cd $(native-build) && \ + (wd=$$(pwd); \ + cd $(native-build); \ $(objcopy) --rename-section=.data=.boot -I binary bootimage.bin \ - -O $(object-format) -B $(object-arch) "$${wd}/$(@).tmp" && \ + -O $(object-format) -B $(object-arch) "$${wd}/$(@).tmp"; \ $(objcopy) --set-section-flags .boot=alloc,load,code "$${wd}/$(@).tmp" \ "$${wd}/$(@)") endif -$(gnu-object-dep): $(gnu-libraries) - @mkdir -p $(build)/gnu-objects - (cd $(build)/gnu-objects && \ - for x in $(gnu-libraries); do ar x $${x}; done) - @touch $(@) - -$(executable): $(gnu-object-dep) $(executable): \ $(vm-objects) $(jni-objects) $(driver-object) $(vm-heapwalk-objects) \ $(boot-object) $(vm-classpath-object) @echo "linking $(@)" ifeq ($(platform),windows) - $(dlltool) -z $(@).def $(^) $(call gnu-objects) + $(dlltool) -z $(@).def $(^) $(dlltool) -d $(@).def -e $(@).exp - $(cc) $(@).exp $(^) $(call gnu-objects) $(lflags) -o $(@) + $(cc) $(@).exp $(^) $(lflags) -o $(@) else - $(cc) $(^) $(call gnu-objects) $(rdynamic) $(lflags) $(bootimage-lflags) \ - -o $(@) + $(cc) $(^) $(rdynamic) $(lflags) $(bootimage-lflags) -o $(@) endif $(strip) $(strip-all) $(@) @@ -630,13 +560,11 @@ else $(cc) $(^) $(rdynamic) $(lflags) -o $(@) endif -$(dynamic-library): $(gnu-object-dep) $(dynamic-library): \ $(vm-objects) $(dynamic-object) $(jni-objects) $(vm-heapwalk-objects) \ - $(boot-object) $(vm-classpath-object) $(gnu-libraries) + $(boot-object) $(vm-classpath-object) @echo "linking $(@)" - $(cc) $(^) $(call gnu-objects) $(shared) $(lflags) $(bootimage-lflags) \ - -o $(@) + $(cc) $(^) $(shared) $(lflags) $(bootimage-lflags) -o $(@) $(strip) $(strip-all) $(@) $(executable-dynamic): $(driver-dynamic-object) $(dynamic-library) @@ -647,3 +575,4 @@ $(executable-dynamic): $(driver-dynamic-object) $(dynamic-library) $(generator): $(generator-objects) @echo "linking $(@)" $(build-cc) $(^) $(build-lflags) -o $(@) + diff --git a/src/arch.h b/src/arch.h index ae2039296f..a6fc2af570 100644 --- a/src/arch.h +++ b/src/arch.h @@ -21,6 +21,8 @@ vmJump(void* address, void* base, void* stack, void* thread, # include "x86.h" #elif defined __POWERPC__ # include "powerpc.h" +#elif defined __arm__ +# include "arm.h" #else # error unsupported architecture #endif diff --git a/src/arm.S b/src/arm.S new file mode 100644 index 0000000000..f3dd2b146f --- /dev/null +++ b/src/arm.S @@ -0,0 +1,56 @@ +/* arm.S: JNI gluecode for ARM/Linux + Copyright (c) 2008-2009, 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. */ + +.text + +.globl vmNativeCall +vmNativeCall: + /* + arguments: + r0 -> r4 : function + r1 -> r5 : stackTotal + r2 : memoryTable + r3 : memoryCount + [sp, #0] -> r6 : gprTable + */ + mov ip, sp // save stack frame + stmfd sp!, {r4-r6, lr} // save clobbered non-volatile regs + + // mv args into non-volatile regs + mov r4, r0 + mov r5, r1 + ldr r6, [ip] + + // setup stack arguments if necessary + sub sp, sp, r5 // allocate stack + mov ip, sp +.Lloop: + tst r3, r3 + ldrne r0, [r2], #4 + strne r0, [ip], #4 + subne r3, r3, #4 + bne .Lloop + + // setup argument registers if necessary + tst r6, r6 + ldmneia r6, {r0-r3} + + blx r4 // call function + add sp, sp, r5 // deallocate stack + + ldmfd sp!, {r4-r6, pc} // restore non-volatile regs and return + +.globl vmJump +vmJump: + mov sp, r2 + mov r4, r3 + ldmia sp, {r0,r1} + mov pc, lr diff --git a/src/arm.cpp b/src/arm.cpp new file mode 100644 index 0000000000..99e175abb1 --- /dev/null +++ b/src/arm.cpp @@ -0,0 +1,2043 @@ +/* Copyright (c) 2009, 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. */ + +#include "assembler.h" +#include "vector.h" + +#define CAST1(x) reinterpret_cast(x) +#define CAST2(x) reinterpret_cast(x) +#define CAST3(x) reinterpret_cast(x) + +using namespace vm; + +namespace { + +namespace field { +// BITFIELD MASKS +const int64_t MASK_LO32 = 0x0ffffffff; +const int MASK_LO16 = 0x0ffff; +const int MASK_LO8 = 0x0ff; +// BITFIELD EXTRACTORS +inline int lo32(int64_t i) { return (int)(i & MASK_LO32); } +inline int hi32(int64_t i) { return lo32(i >> 32); } +inline int lo16(int64_t i) { return (int)(i & MASK_LO16); } +inline int hi16(int64_t i) { return lo16(i >> 16); } +inline int lo8(int64_t i) { return (int)(i & MASK_LO8); } +inline int hi8(int64_t i) { return lo8(i >> 8); } +} + +namespace isa { +// INSTRUCTION OPTIONS +enum COND { EQ, NE, CS, CC, MI, PL, VS, VC, HI, LS, GE, LT, GT, LE, AL, NV }; +enum SHIFT { LSL, LSR, ASR, ROR }; +// INSTRUCTION FORMATS +inline int DATA(int cond, int opcode, int S, int Rn, int Rd, int shift, int Sh, int Rm) +{ return cond<<28 | opcode<<21 | S<<20 | Rn<<16 | Rd<<12 | shift<<7 | Sh<<5 | Rm; } +inline int DATAS(int cond, int opcode, int S, int Rn, int Rd, int Rs, int Sh, int Rm) +{ return cond<<28 | opcode<<21 | S<<20 | Rn<<16 | Rd<<12 | Rs<<8 | Sh<<5 | 1<<4 | Rm; } +inline int DATAI(int cond, int opcode, int S, int Rn, int Rd, int rot, int imm) +{ return cond<<28 | 1<<25 | opcode<<21 | S<<20 | Rn<<16 | Rd<<12 | rot<<8 | imm; } +inline int BRANCH(int cond, int L, int offset) +{ return cond<<28 | 5<<25 | L<<24 | offset; } +inline int BRANCHX(int cond, int L, int Rm) +{ return cond<<28 | 0x4bffc<<6 | L<<5 | 1<<4 | Rm; } +inline int MULTIPLY(int cond, int mul, int S, int Rd, int Rn, int Rs, int Rm) +{ return cond<<28 | mul<<21 | S<<20 | Rd<<16 | Rn<<12 | Rs<<8 | 9<<4 | Rm; } +inline int XFER(int cond, int P, int U, int B, int W, int L, int Rn, int Rd, int shift, int Sh, int Rm) +{ return cond<<28 | 3<<25 | P<<24 | U<<23 | B<<22 | W<<21 | L<<20 | Rn<<16 | Rd<<12 | shift<<7 | Sh<<5 | Rm; } +inline int XFERI(int cond, int P, int U, int B, int W, int L, int Rn, int Rd, int offset) +{ return cond<<28 | 2<<25 | P<<24 | U<<23 | B<<22 | W<<21 | L<<20 | Rn<<16 | Rd<<12 | offset; } +inline int XFER2(int cond, int P, int U, int W, int L, int Rn, int Rd, int S, int H, int Rm) +{ return cond<<28 | P<<24 | U<<23 | W<<21 | L<<20 | Rn<<16 | Rd<<12 | 1<<7 | S<<6 | H<<5 | 1<<4 | Rm; } +inline int XFER2I(int cond, int P, int U, int W, int L, int Rn, int Rd, int offsetH, int S, int H, int offsetL) +{ return cond<<28 | P<<24 | U<<23 | 1<<22 | W<<21 | L<<20 | Rn<<16 | Rd<<12 | offsetH<<8 | 1<<7 | S<<6 | H<<5 | 1<<4 | offsetL; } +inline int BLOCKXFER(int cond, int P, int U, int S, int W, int L, int Rn, int rlist) +{ return cond<<28 | 4<<25 | P<<24 | U<<23 | S<<22 | W<<21 | L<<20 | Rn<<16 | rlist; } +inline int SWI_(int cond, int imm) +{ return cond<<28 | 0x0f<<24 | imm; } +inline int SWAP(int cond, int B, int Rn, int Rd, int Rm) +{ return cond<<28 | 1<<24 | B<<22 | Rn<<16 | Rd<<12 | 9<<4 | Rm; } +// INSTRUCTIONS +// For easier coding, some features (conditions, shifts, etc.) are left out of the instruction compilers. +// They may be enabled using the helper functions included in this namespace. +inline int B(int offset) { return BRANCH(AL, 0, offset); } +inline int BL(int offset) { return BRANCH(AL, 1, offset); } +inline int BX(int Rm) { return BRANCHX(AL, 0, Rm); } +inline int BLX(int Rm) { return BRANCHX(AL, 1, Rm); } +inline int SWI(int imm) { return SWI_(AL, imm); } +inline int AND(int Rd, int Rn, int Rm) { return DATA(AL, 0x0, 0, Rn, Rd, 0, 0, Rm); } +inline int EOR(int Rd, int Rn, int Rm) { return DATA(AL, 0x1, 0, Rn, Rd, 0, 0, Rm); } +inline int SUB(int Rd, int Rn, int Rm) { return DATA(AL, 0x2, 0, Rn, Rd, 0, 0, Rm); } +inline int RSB(int Rd, int Rn, int Rm) { return DATA(AL, 0x3, 0, Rn, Rd, 0, 0, Rm); } +inline int ADD(int Rd, int Rn, int Rm) { return DATA(AL, 0x4, 0, Rn, Rd, 0, 0, Rm); } +inline int ADC(int Rd, int Rn, int Rm) { return DATA(AL, 0x5, 0, Rn, Rd, 0, 0, Rm); } +inline int SBC(int Rd, int Rn, int Rm) { return DATA(AL, 0x6, 0, Rn, Rd, 0, 0, Rm); } +inline int RSC(int Rd, int Rn, int Rm) { return DATA(AL, 0x7, 0, Rn, Rd, 0, 0, Rm); } +inline int TST(int Rn, int Rm) { return DATA(AL, 0x8, 0, Rn, 0, 0, 0, Rm); } +inline int TEQ(int Rn, int Rm) { return DATA(AL, 0x9, 0, Rn, 0, 0, 0, Rm); } +inline int CMP(int Rn, int Rm) { return DATA(AL, 0xa, 0, Rn, 0, 0, 0, Rm); } +inline int CMN(int Rn, int Rm) { return DATA(AL, 0xb, 0, Rn, 0, 0, 0, Rm); } +inline int ORR(int Rd, int Rn, int Rm) { return DATA(AL, 0xc, 0, Rn, Rd, 0, 0, Rm); } +inline int MOV(int Rd, int Rm) { return DATA(AL, 0xd, 0, 0, Rd, 0, 0, Rm); } +inline int BIC(int Rd, int Rn, int Rm) { return DATA(AL, 0xe, 0, Rn, Rd, 0, 0, Rm); } +inline int MVN(int Rd, int Rm) { return DATA(AL, 0xf, 0, 0, Rd, 0, 0, Rm); } +inline int ANDi(int Rd, int Rn, int imm) { return DATAI(AL, 0x0, 0, Rn, Rd, 0, imm); } +inline int SUBi(int Rd, int Rn, int imm) { return DATAI(AL, 0x2, 0, Rn, Rd, 0, imm); } +inline int ADDi(int Rd, int Rn, int imm) { return DATAI(AL, 0x4, 0, Rn, Rd, 0, imm); } +inline int ORRi(int Rd, int Rn, int imm) { return DATAI(AL, 0xc, 0, Rn, Rd, 0, imm); } +inline int MOVs(int Rd, int Rm, int Rs, int Sh) { return DATAS(AL, 0xd, 0, 0, Rd, Rs, Sh, Rm); } +inline int MUL(int Rd, int Rm, int Rs) { return MULTIPLY(AL, 0, 0, Rd, 0, Rs, Rm); } +inline int UMULL(int RdLo, int RdHi, int Rm, int Rs) { return MULTIPLY(AL, 4, 0, RdHi, RdLo, Rs, Rm); } // only avail. on ARM7M series and above +inline int SMULL(int RdLo, int RdHi, int Rm, int Rs) { return MULTIPLY(AL, 6, 0, RdHi, RdLo, Rs, Rm); } // '' +inline int LDR(int Rd, int Rn, int Rm) { return XFER(AL, 1, 1, 0, 0, 1, Rn, Rd, 0, 0, Rm); } +inline int LDRi(int Rd, int Rn, int imm) { return XFERI(AL, 1, 1, 0, 0, 1, Rn, Rd, imm); } +inline int LDRB(int Rd, int Rn, int Rm) { return XFER(AL, 1, 1, 1, 0, 1, Rn, Rd, 0, 0, Rm); } +inline int LDRBi(int Rd, int Rn, int imm) { return XFERI(AL, 1, 1, 1, 0, 1, Rn, Rd, imm); } +inline int STR(int Rd, int Rn, int Rm) { return XFER(AL, 1, 1, 0, 0, 0, Rn, Rd, 0, 0, Rm); } +inline int STRi(int Rd, int Rn, int imm) { return XFERI(AL, 1, 1, 0, 0, 0, Rn, Rd, imm); } +inline int STRB(int Rd, int Rn, int Rm) { return XFER(AL, 1, 1, 1, 0, 0, Rn, Rd, 0, 0, Rm); } +inline int STRBi(int Rd, int Rn, int imm) { return XFERI(AL, 1, 1, 1, 0, 0, Rn, Rd, imm); } +inline int LDRH(int Rd, int Rn, int Rm) { return XFER2(AL, 1, 1, 0, 1, Rn, Rd, 0, 1, Rm); } +inline int LDRHi(int Rd, int Rn, int imm) { return XFER2I(AL, 1, 1, 0, 1, Rn, Rd, imm>>4 & 0xf, 0, 1, imm&0xf); } +inline int STRH(int Rd, int Rn, int Rm) { return XFER2(AL, 1, 1, 0, 0, Rn, Rd, 0, 1, Rm); } +inline int STRHi(int Rd, int Rn, int imm) { return XFER2I(AL, 1, 1, 0, 0, Rn, Rd, imm>>4 & 0xf, 0, 1, imm&0xf); } +inline int LDRSH(int Rd, int Rn, int Rm) { return XFER2(AL, 1, 1, 0, 1, Rn, Rd, 1, 1, Rm); } +inline int LDRSHi(int Rd, int Rn, int imm) { return XFER2I(AL, 1, 1, 0, 1, Rn, Rd, imm>>4 & 0xf, 1, 1, imm&0xf); } +inline int LDRSB(int Rd, int Rn, int Rm) { return XFER2(AL, 1, 1, 0, 1, Rn, Rd, 1, 0, Rm); } +inline int LDRSBi(int Rd, int Rn, int imm) { return XFER2I(AL, 1, 1, 0, 1, Rn, Rd, imm>>4 & 0xf, 1, 0, imm&0xf); } +inline int LDMIB(int Rn, int rlist) { return BLOCKXFER(AL, 1, 1, 0, 0, 1, Rn, rlist); } +inline int LDMIA(int Rn, int rlist) { return BLOCKXFER(AL, 0, 1, 0, 0, 1, Rn, rlist); } +inline int STMIB(int Rn, int rlist) { return BLOCKXFER(AL, 1, 1, 0, 0, 0, Rn, rlist); } +inline int STMDB(int Rn, int rlist) { return BLOCKXFER(AL, 1, 0, 0, 0, 0, Rn, rlist); } +inline int SWP(int Rd, int Rm, int Rn) { return SWAP(AL, 0, Rn, Rd, Rm); } +inline int SWPB(int Rd, int Rm, int Rn) { return SWAP(AL, 1, Rn, Rd, Rm); } +// HELPER FUNCTIONS +inline int setCond(int ins, int cond) { return ins&0x0fffffff | cond<<28; } +inline int setResult(int ins) { return ins | 1<<20; } +inline int setShift(int ins, int Sh, int shift) { return ins | shift<<7 | Sh<<5; } +inline int setRot(int ins, int rot) { return ins | rot<<8; } +// PSEUDO-INSTRUCTIONS +inline int NOP() { return MOV(0, 0); } +inline int LSL_(int Rd, int Rm, int Rs) { return MOVs(Rd, Rm, Rs, LSL); } +inline int LSLi(int Rd, int Rm, int imm) { return setShift(MOV(Rd, Rm), LSL, imm); } +inline int LSR_(int Rd, int Rm, int Rs) { return MOVs(Rd, Rm, Rs, LSR); } +inline int LSRi(int Rd, int Rm, int imm) { return setShift(MOV(Rd, Rm), LSR, imm); } +inline int ASR_(int Rd, int Rm, int Rs) { return MOVs(Rd, Rm, Rs, ASR); } +inline int ASRi(int Rd, int Rm, int imm) { return setShift(MOV(Rd, Rm), ASR, imm); } +inline int ROR_(int Rd, int Rm, int Rs) { return MOVs(Rd, Rm, Rs, ROR); } +} + +inline bool +isInt16(intptr_t v) +{ + return v == static_cast(v); +} + +inline int +carry16(intptr_t v) +{ + return static_cast(v) < 0 ? 1 : 0; +} + +const unsigned FrameFooterSize = 6; + +const int StackRegister = 1; +const int ThreadRegister = 13; + +class MyBlock: public Assembler::Block { + public: + MyBlock(unsigned offset): + next(0), offset(offset), start(~0), size(0) + { } + + virtual unsigned resolve(unsigned start, Assembler::Block* next) { + this->start = start; + this->next = static_cast(next); + + return start + size; + } + + MyBlock* next; + unsigned offset; + unsigned start; + unsigned size; +}; + +class Task; + +class Context { + public: + Context(System* s, Allocator* a, Zone* zone): + s(s), zone(zone), client(0), code(s, a, 1024), tasks(0), result(0), + firstBlock(new (zone->allocate(sizeof(MyBlock))) MyBlock(0)), + lastBlock(firstBlock) + { } + + System* s; + Zone* zone; + Assembler::Client* client; + Vector code; + Task* tasks; + uint8_t* result; + MyBlock* firstBlock; + MyBlock* lastBlock; +}; + +class Task { + public: + Task(Task* next): next(next) { } + + virtual void run(Context* c) = 0; + + Task* next; +}; + +typedef void (*OperationType)(Context*); + +typedef void (*UnaryOperationType)(Context*, unsigned, Assembler::Operand*); + +typedef void (*BinaryOperationType) +(Context*, unsigned, Assembler::Operand*, unsigned, Assembler::Operand*); + +typedef void (*TernaryOperationType) +(Context*, unsigned, Assembler::Operand*, Assembler::Operand*, + Assembler::Operand*); + +class ArchitectureContext { + public: + ArchitectureContext(System* s): s(s) { } + + System* s; + OperationType operations[OperationCount]; + UnaryOperationType unaryOperations[UnaryOperationCount + * OperandTypeCount]; + BinaryOperationType binaryOperations + [BinaryOperationCount * OperandTypeCount * OperandTypeCount]; + TernaryOperationType ternaryOperations + [TernaryOperationCount * OperandTypeCount]; +}; + +inline void NO_RETURN +abort(Context* c) +{ + abort(c->s); +} + +inline void NO_RETURN +abort(ArchitectureContext* c) +{ + abort(c->s); +} + +#ifndef NDEBUG +inline void +assert(Context* c, bool v) +{ + assert(c->s, v); +} + +inline void +assert(ArchitectureContext* c, bool v) +{ + assert(c->s, v); +} +#endif // not NDEBUG + +inline void +expect(Context* c, bool v) +{ + expect(c->s, v); +} + +class Offset: public Promise { + public: + Offset(Context* c, MyBlock* block, unsigned offset): + c(c), block(block), offset(offset) + { } + + virtual bool resolved() { + return block->start != static_cast(~0); + } + + virtual int64_t value() { + assert(c, resolved()); + + return block->start + (offset - block->offset); + } + + Context* c; + MyBlock* block; + unsigned offset; +}; + +Promise* +offset(Context* c) +{ + return new (c->zone->allocate(sizeof(Offset))) + Offset(c, c->lastBlock, c->code.length()); +} + +bool +bounded(int right, int left, int32_t v) +{ + return ((v << left) >> left) == v and ((v >> right) << right) == v; +} + +void* +updateOffset(System* s, uint8_t* instruction, bool conditional, int64_t value) +{ + int32_t v = reinterpret_cast(value) - instruction; + + int32_t mask; + if (conditional) { + expect(s, bounded(2, 16, v)); + mask = 0xFFFC; + } else { + expect(s, bounded(2, 6, v)); + mask = 0x3FFFFFC; + } + + int32_t* p = reinterpret_cast(instruction); + *p = (v & mask) | ((~mask) & *p); + + return instruction + 4; +} + +class OffsetListener: public Promise::Listener { + public: + OffsetListener(System* s, uint8_t* instruction, bool conditional): + s(s), + instruction(instruction), + conditional(conditional) + { } + + virtual bool resolve(int64_t value, void** location) { + void* p = updateOffset(s, instruction, conditional, value); + if (location) *location = p; + return false; + } + + System* s; + uint8_t* instruction; + bool conditional; +}; + +class OffsetTask: public Task { + public: + OffsetTask(Task* next, Promise* promise, Promise* instructionOffset, + bool conditional): + Task(next), + promise(promise), + instructionOffset(instructionOffset), + conditional(conditional) + { } + + virtual void run(Context* c) { + if (promise->resolved()) { + updateOffset + (c->s, c->result + instructionOffset->value(), conditional, + promise->value()); + } else { + new (promise->listen(sizeof(OffsetListener))) + OffsetListener(c->s, c->result + instructionOffset->value(), + conditional); + } + } + + Promise* promise; + Promise* instructionOffset; + bool conditional; +}; + +void +appendOffsetTask(Context* c, Promise* promise, Promise* instructionOffset, + bool conditional) +{ + c->tasks = new (c->zone->allocate(sizeof(OffsetTask))) OffsetTask + (c->tasks, promise, instructionOffset, conditional); +} + +inline unsigned +index(UnaryOperation operation, OperandType operand) +{ + return operation + (UnaryOperationCount * operand); +} + +inline unsigned +index(BinaryOperation operation, + OperandType operand1, + OperandType operand2) +{ + return operation + + (BinaryOperationCount * operand1) + + (BinaryOperationCount * OperandTypeCount * operand2); +} + +inline unsigned +index(TernaryOperation operation, + OperandType operand1) +{ + return operation + (TernaryOperationCount * operand1); +} + + +// BEGIN OPERATION COMPILERS + +using namespace field; + +typedef Assembler::Register Reg; +typedef Assembler::Constant Const; + +inline void issue(Context* con, int code) { con->code.append4(code); } +inline int getTemp(Context* con) { return con->client->acquireTemporary(); } +inline void freeTemp(Context* con, int r) { con->client->releaseTemporary(r); } +inline int64_t getVal(Const* c) { return c->value->value(); } +inline int R(Reg* r) { return r->low; } +inline int H(Reg* r) { return r->high; } + + +void shiftLeftR(Context* con, unsigned size, Reg* a, Reg* b, Reg* t) +{ + if(size == 8) { + Reg Tmp(getTemp(con), getTemp(con)); Reg* tmp = &Tmp; + issue(con, subfic(H(tmp), R(a), 32)); + issue(con, slw(H(t), H(b), R(a))); + issue(con, srw(R(tmp), R(b), H(tmp))); + issue(con, or_(H(t), H(t), R(tmp))); + issue(con, addi(H(tmp), R(a), -32)); + issue(con, slw(R(tmp), R(b), H(tmp))); + issue(con, or_(H(t), H(t), R(tmp))); + freeTemp(con, H(tmp)); freeTemp(con, R(tmp)); + } + issue(con, slw(R(t), R(b), R(a))); +} + +void shiftLeftC(Context* con, unsigned size, Const* a, Reg* b, Reg* t) +{ + int sh = getVal(a); + if (size == 8) { + if (sh < 32) { + issue(con, rlwinm(H(t),H(b),sh,0,31-sh)); + issue(con, rlwimi(H(t),R(b),sh,32-sh,31)); + } else { + issue(con, rlwinm(H(t),R(b),sh-32,0,63-sh)); + issue(con, li(R(t),0)); + } + } + issue(con, slwi(R(t), R(b), sh)); +} + +void shiftRightR(Context* con, unsigned size, Reg* a, Reg* b, Reg* t) +{ + if(size == 8) { + Reg Tmp(getTemp(con), getTemp(con)); Reg* tmp = &Tmp; + issue(con, subfic(H(tmp), R(a), 32)); + issue(con, srw(R(t), R(b), R(a))); + issue(con, slw(R(tmp), H(b), H(tmp))); + issue(con, or_(R(t), R(t), R(tmp))); + issue(con, addic(H(tmp), R(a), -32)); + issue(con, sraw(R(tmp), H(b), H(tmp))); + issue(con, ble(8)); + issue(con, ori(R(t), R(tmp), 0)); + issue(con, sraw(H(t), H(b), R(a))); + freeTemp(con, H(tmp)); freeTemp(con, R(tmp)); + } else { + issue(con, sraw(R(t), R(b), R(a))); + } +} + +void shiftRightC(Context* con, unsigned size, Const* a, Reg* b, Reg* t) +{ + int sh = getVal(a); + if(size == 8) { + if (sh < 32) { + issue(con, rlwinm(R(t),R(b),32-sh,sh,31)); + issue(con, rlwimi(R(t),H(b),32-sh,0,sh-1)); + issue(con, srawi(H(t),H(b),sh)); + } else { + issue(con, srawi(H(t),H(b),31)); + issue(con, srawi(R(t),H(b),sh-32)); + } + } else { + issue(con, srawi(R(t), R(b), sh)); + } +} + +void unsignedShiftRightR(Context* con, unsigned size, Reg* a, Reg* b, Reg* t) +{ + issue(con, srw(R(t), R(b), R(a))); + if(size == 8) { + Reg Tmp(getTemp(con), getTemp(con)); Reg* tmp = &Tmp; + issue(con, subfic(H(tmp), R(a), 32)); + issue(con, slw(R(tmp), H(b), H(tmp))); + issue(con, or_(R(t), R(t), R(tmp))); + issue(con, addi(H(tmp), R(a), -32)); + issue(con, srw(R(tmp), H(b), H(tmp))); + issue(con, or_(R(t), R(t), R(tmp))); + issue(con, srw(H(t), H(b), R(a))); + freeTemp(con, H(tmp)); freeTemp(con, R(tmp)); + } +} + +void unsignedShiftRightC(Context* con, unsigned size, Const* a, Reg* b, Reg* t) +{ + int sh = getVal(a); + if (size == 8) { + if (sh < 32) { + issue(con, srwi(R(t), R(b), sh)); + issue(con, rlwimi(R(t),H(b),32-sh,0,sh-1)); + issue(con, rlwinm(H(t),H(b),32-sh,sh,31)); + } else { + issue(con, rlwinm(R(t),H(b),64-sh,sh-32,31)); + issue(con, li(H(t),0)); + } + } else { + issue(con, srwi(R(t), R(b), sh)); + } +} + +void +updateImmediate(System* s, void* dst, int64_t src, unsigned size) +{ + switch (size) { + case 4: { + int32_t* p = static_cast(dst); + int r = (p[1] >> 21) & 31; + + p[0] = lis(r, src >> 16); + p[1] = ori(r, r, src); + } break; + + default: abort(s); + } +} + +class ImmediateListener: public Promise::Listener { + public: + ImmediateListener(System* s, void* dst, unsigned size, unsigned offset): + s(s), dst(dst), size(size), offset(offset) + { } + + virtual bool resolve(int64_t value, void** location) { + updateImmediate(s, dst, value, size); + if (location) *location = static_cast(dst) + offset; + return false; + } + + System* s; + void* dst; + unsigned size; + unsigned offset; +}; + +class ImmediateTask: public Task { + public: + ImmediateTask(Task* next, Promise* promise, Promise* offset, unsigned size, + unsigned promiseOffset): + Task(next), + promise(promise), + offset(offset), + size(size), + promiseOffset(promiseOffset) + { } + + virtual void run(Context* c) { + if (promise->resolved()) { + updateImmediate + (c->s, c->result + offset->value(), promise->value(), size); + } else { + new (promise->listen(sizeof(ImmediateListener))) ImmediateListener + (c->s, c->result + offset->value(), size, promiseOffset); + } + } + + Promise* promise; + Promise* offset; + unsigned size; + unsigned promiseOffset; +}; + +void +appendImmediateTask(Context* c, Promise* promise, Promise* offset, + unsigned size, unsigned promiseOffset = 0) +{ + c->tasks = new (c->zone->allocate(sizeof(ImmediateTask))) ImmediateTask + (c->tasks, promise, offset, size, promiseOffset); +} + +void +jumpR(Context* c, unsigned size UNUSED, Assembler::Register* target) +{ + assert(c, size == BytesPerWord); + + issue(c, mtctr(target->low)); + issue(c, bctr()); +} + +void +moveRR(Context* c, unsigned srcSize, Assembler::Register* src, + unsigned dstSize, Assembler::Register* dst); + +void +swapRR(Context* c, unsigned aSize, Assembler::Register* a, + unsigned bSize, Assembler::Register* b) +{ + assert(c, aSize == BytesPerWord); + assert(c, bSize == BytesPerWord); + + Assembler::Register tmp(c->client->acquireTemporary()); + moveRR(c, aSize, a, bSize, &tmp); + moveRR(c, bSize, b, aSize, a); + moveRR(c, bSize, &tmp, bSize, b); + c->client->releaseTemporary(tmp.low); +} + +void +moveRR(Context* c, unsigned srcSize, Assembler::Register* src, + unsigned dstSize, Assembler::Register* dst) +{ + switch (srcSize) { + case 1: + issue(c, extsb(dst->low, src->low)); + break; + + case 2: + issue(c, extsh(dst->low, src->low)); + break; + + case 4: + case 8: + if (srcSize == 4 and dstSize == 8) { + moveRR(c, 4, src, 4, dst); + issue(c, srawi(dst->high, src->low, 31)); + } else if (srcSize == 8 and dstSize == 8) { + Assembler::Register srcHigh(src->high); + Assembler::Register dstHigh(dst->high); + + if (src->high == dst->low) { + if (src->low == dst->high) { + swapRR(c, 4, src, 4, dst); + } else { + moveRR(c, 4, &srcHigh, 4, &dstHigh); + moveRR(c, 4, src, 4, dst); + } + } else { + moveRR(c, 4, src, 4, dst); + moveRR(c, 4, &srcHigh, 4, &dstHigh); + } + } else if (src->low != dst->low) { + issue(c, mr(dst->low, src->low)); + } + break; + + default: abort(c); + } +} + +void +moveZRR(Context* c, unsigned srcSize, Assembler::Register* src, + unsigned, Assembler::Register* dst) +{ + switch (srcSize) { + case 2: + issue(c, andi(dst->low, src->low, 0xFFFF)); + break; + + default: abort(c); + } +} + +void +moveCR2(Context* c, unsigned, Assembler::Constant* src, + unsigned dstSize, Assembler::Register* dst, unsigned promiseOffset) +{ + if (dstSize <= 4) { + if (src->value->resolved()) { + int32_t v = src->value->value(); + if (isInt16(v)) { + issue(c, li(dst->low, v)); + } else { + issue(c, lis(dst->low, v >> 16)); + issue(c, ori(dst->low, dst->low, v)); + } + } else { + appendImmediateTask + (c, src->value, offset(c), BytesPerWord, promiseOffset); + issue(c, lis(dst->low, 0)); + issue(c, ori(dst->low, dst->low, 0)); + } + } else { + abort(c); // todo + } +} + +void +moveCR(Context* c, unsigned srcSize, Assembler::Constant* src, + unsigned dstSize, Assembler::Register* dst) +{ + moveCR2(c, srcSize, src, dstSize, dst, 0); +} + +void addR(Context* con, unsigned size, Reg* a, Reg* b, Reg* t) { + if(size == 8) { + issue(con, addc(R(t), R(a), R(b))); + issue(con, adde(H(t), H(a), H(b))); + } else { + issue(con, add(R(t), R(a), R(b))); + } +} + +void addC(Context* con, unsigned size, Const* a, Reg* b, Reg* t) { + assert(con, size == BytesPerWord); + + int32_t i = getVal(a); + if(i) { + issue(con, addi(R(t), R(b), lo16(i))); + if(not isInt16(i)) + issue(con, addis(R(t), R(t), hi16(i) + carry16(i))); + } else { + moveRR(con, size, b, size, t); + } +} + +void subR(Context* con, unsigned size, Reg* a, Reg* b, Reg* t) { + if(size == 8) { + issue(con, subfc(R(t), R(a), R(b))); + issue(con, subfe(H(t), H(a), H(b))); + } else { + issue(con, subf(R(t), R(a), R(b))); + } +} + +void subC(Context* c, unsigned size, Const* a, Reg* b, Reg* t) { + assert(c, size == BytesPerWord); + + ResolvedPromise promise(- a->value->value()); + Assembler::Constant constant(&promise); + addC(c, size, &constant, b, t); +} + +void multiplyR(Context* con, unsigned size, Reg* a, Reg* b, Reg* t) { + if(size == 8) { + bool useTemporaries = b->low == t->low; + int tmpLow; + int tmpHigh; + if (useTemporaries) { + tmpLow = con->client->acquireTemporary(); + tmpHigh = con->client->acquireTemporary(); + } else { + tmpLow = t->low; + tmpHigh = t->high; + } + + issue(con, mullw(tmpHigh, H(a), R(b))); + issue(con, mullw(tmpLow, R(a), H(b))); + issue(con, add(H(t), tmpHigh, tmpLow)); + issue(con, mulhwu(tmpLow, R(a), R(b))); + issue(con, add(H(t), H(t), tmpLow)); + issue(con, mullw(R(t), R(a), R(b))); + + if (useTemporaries) { + con->client->releaseTemporary(tmpLow); + con->client->releaseTemporary(tmpHigh); + } + } else { + issue(con, mullw(R(t), R(a), R(b))); + } +} + +void divideR(Context* con, unsigned size UNUSED, Reg* a, Reg* b, Reg* t) { + assert(con, size == 4); + issue(con, divw(R(t), R(b), R(a))); +} + +void remainderR(Context* con, unsigned size, Reg* a, Reg* b, Reg* t) { + bool useTemporary = b->low == t->low; + Assembler::Register tmp(t->low); + if (useTemporary) { + tmp.low = con->client->acquireTemporary(); + } + + divideR(con, size, a, b, &tmp); + multiplyR(con, size, a, &tmp, &tmp); + subR(con, size, &tmp, b, t); + + if (useTemporary) { + con->client->releaseTemporary(tmp.low); + } +} + +int +normalize(Context* c, int offset, int index, unsigned scale, + bool* preserveIndex, bool* release) +{ + if (offset != 0 or scale != 1) { + Assembler::Register normalizedIndex + (*preserveIndex ? c->client->acquireTemporary() : index); + + if (*preserveIndex) { + *release = true; + *preserveIndex = false; + } else { + *release = false; + } + + int scaled; + + if (scale != 1) { + Assembler::Register unscaledIndex(index); + + ResolvedPromise scalePromise(log(scale)); + Assembler::Constant scaleConstant(&scalePromise); + + shiftLeftC(c, BytesPerWord, &scaleConstant, + &unscaledIndex, &normalizedIndex); + + scaled = normalizedIndex.low; + } else { + scaled = index; + } + + if (offset != 0) { + Assembler::Register untranslatedIndex(scaled); + + ResolvedPromise offsetPromise(offset); + Assembler::Constant offsetConstant(&offsetPromise); + + addC(c, BytesPerWord, &offsetConstant, + &untranslatedIndex, &normalizedIndex); + } + + return normalizedIndex.low; + } else { + *release = false; + return index; + } +} + +void +store(Context* c, unsigned size, Assembler::Register* src, + int base, int offset, int index, unsigned scale, bool preserveIndex) +{ + if (index != NoRegister) { + bool release; + int normalized = normalize + (c, offset, index, scale, &preserveIndex, &release); + + switch (size) { + case 1: + issue(c, stbx(src->low, base, normalized)); + break; + + case 2: + issue(c, sthx(src->low, base, normalized)); + break; + + case 4: + issue(c, stwx(src->low, base, normalized)); + break; + + case 8: { + Assembler::Register srcHigh(src->high); + store(c, 4, &srcHigh, base, 0, normalized, 1, preserveIndex); + store(c, 4, src, base, 4, normalized, 1, preserveIndex); + } break; + + default: abort(c); + } + + if (release) c->client->releaseTemporary(normalized); + } else { + switch (size) { + case 1: + issue(c, stb(src->low, base, offset)); + break; + + case 2: + issue(c, sth(src->low, base, offset)); + break; + + case 4: + issue(c, stw(src->low, base, offset)); + break; + + case 8: { + Assembler::Register srcHigh(src->high); + store(c, 4, &srcHigh, base, offset, NoRegister, 1, false); + store(c, 4, src, base, offset + 4, NoRegister, 1, false); + } break; + + default: abort(c); + } + } +} + +void +moveRM(Context* c, unsigned srcSize, Assembler::Register* src, + unsigned dstSize UNUSED, Assembler::Memory* dst) +{ + assert(c, srcSize == dstSize); + + store(c, srcSize, src, dst->base, dst->offset, dst->index, dst->scale, true); +} + +void +moveAndUpdateRM(Context* c, unsigned srcSize UNUSED, Assembler::Register* src, + unsigned dstSize UNUSED, Assembler::Memory* dst) +{ + assert(c, srcSize == BytesPerWord); + assert(c, dstSize == BytesPerWord); + assert(c, dst->index == NoRegister); + + issue(c, stwu(src->low, dst->base, dst->offset)); +} + +void +load(Context* c, unsigned srcSize, int base, int offset, int index, + unsigned scale, unsigned dstSize, Assembler::Register* dst, + bool preserveIndex, bool signExtend) +{ + if (index != NoRegister) { + bool release; + int normalized = normalize + (c, offset, index, scale, &preserveIndex, &release); + + switch (srcSize) { + case 1: + issue(c, lbzx(dst->low, base, normalized)); + if (signExtend) { + issue(c, extsb(dst->low, dst->low)); + } + break; + + case 2: + if (signExtend) { + issue(c, lhax(dst->low, base, normalized)); + } else { + issue(c, lhzx(dst->low, base, normalized)); + } + break; + + case 4: + case 8: { + if (srcSize == 4 and dstSize == 8) { + load(c, 4, base, 0, normalized, 1, 4, dst, preserveIndex, false); + moveRR(c, 4, dst, 8, dst); + } else if (srcSize == 8 and dstSize == 8) { + Assembler::Register dstHigh(dst->high); + load(c, 4, base, 0, normalized, 1, 4, &dstHigh, preserveIndex, false); + load(c, 4, base, 4, normalized, 1, 4, dst, preserveIndex, false); + } else { + issue(c, lwzx(dst->low, base, normalized)); + } + } break; + + default: abort(c); + } + + if (release) c->client->releaseTemporary(normalized); + } else { + switch (srcSize) { + case 1: + issue(c, lbz(dst->low, base, offset)); + if (signExtend) { + issue(c, extsb(dst->low, dst->low)); + } + break; + + case 2: + if (signExtend) { + issue(c, lha(dst->low, base, offset)); + } else { + issue(c, lha(dst->low, base, offset)); + } + break; + + case 4: + issue(c, lwz(dst->low, base, offset)); + break; + + case 8: { + if (srcSize == 4 and dstSize == 8) { + load(c, 4, base, offset, NoRegister, 1, 4, dst, false, false); + moveRR(c, 4, dst, 8, dst); + } else if (srcSize == 8 and dstSize == 8) { + Assembler::Register dstHigh(dst->high); + load(c, 4, base, offset, NoRegister, 1, 4, &dstHigh, false, false); + load(c, 4, base, offset + 4, NoRegister, 1, 4, dst, false, false); + } else { + issue(c, lwzx(dst->low, base, offset)); + } + } break; + + default: abort(c); + } + } +} + +void +moveMR(Context* c, unsigned srcSize, Assembler::Memory* src, + unsigned dstSize, Assembler::Register* dst) +{ + load(c, srcSize, src->base, src->offset, src->index, src->scale, + dstSize, dst, true, true); +} + +void +moveZMR(Context* c, unsigned srcSize, Assembler::Memory* src, + unsigned dstSize, Assembler::Register* dst) +{ + load(c, srcSize, src->base, src->offset, src->index, src->scale, + dstSize, dst, true, false); +} + +// void moveCR3(Context* con, unsigned aSize, Const* a, unsigned tSize, Reg* t) { +// int64_t i = getVal(a); +// if(tSize == 8) { +// int64_t j; +// if(aSize == 8) j = i; // 64-bit const -> load high bits into high register +// else j = 0; // 32-bit const -> clear high register +// issue(con, lis(H(t), hi16(hi32(j)))); +// issue(con, ori(H(t), H(t), lo16(hi32(j)))); +// } +// issue(con, lis(R(t), hi16(i))); +// issue(con, ori(R(t), R(t), lo16(i))); +// } + +void +andR(Context* c, unsigned size, Assembler::Register* a, + Assembler::Register* b, Assembler::Register* dst) +{ + if (size == 8) { + Assembler::Register ah(a->high); + Assembler::Register bh(b->high); + Assembler::Register dh(dst->high); + + andR(c, 4, a, b, dst); + andR(c, 4, &ah, &bh, &dh); + } else { + issue(c, and_(dst->low, a->low, b->low)); + } +} + +void +andC(Context* c, unsigned size, Assembler::Constant* a, + Assembler::Register* b, Assembler::Register* dst) +{ + int64_t v = a->value->value(); + + if (size == 8) { + ResolvedPromise high((v >> 32) & 0xFFFFFFFF); + Assembler::Constant ah(&high); + + ResolvedPromise low(v & 0xFFFFFFFF); + Assembler::Constant al(&low); + + Assembler::Register bh(b->high); + Assembler::Register dh(dst->high); + + andC(c, 4, &al, b, dst); + andC(c, 4, &ah, &bh, &dh); + } else { + // bitmasks of the form regex 0*1*0* can be handled in a single + // rlwinm instruction, hence the following: + + uint32_t v32 = static_cast(v); + unsigned state = 0; + unsigned start = 0; + unsigned end = 31; + for (unsigned i = 0; i < 32; ++i) { + unsigned bit = (v32 >> i) & 1; + switch (state) { + case 0: + if (bit) { + start = i; + state = 1; + } + break; + + case 1: + if (bit == 0) { + end = i - 1; + state = 2; + } + break; + + case 2: + if (bit) { + // not in 0*1*0* form. We can only use andi(s) if either + // the topmost or bottommost 16 bits are zero. + + if ((v32 >> 16) == 0) { + issue(c, andi(dst->low, b->low, v32)); + } else if ((v32 & 0xFFFF) == 0) { + issue(c, andis(dst->low, b->low, v32 >> 16)); + } else { + bool useTemporary = b->low == dst->low; + Assembler::Register tmp(dst->low); + if (useTemporary) { + tmp.low = c->client->acquireTemporary(); + } + + moveCR(c, 4, a, 4, &tmp); + andR(c, 4, b, &tmp, dst); + + if (useTemporary) { + c->client->releaseTemporary(tmp.low); + } + } + return; + } + break; + } + } + + if (state) { + if (start != 0 or end != 31) { + issue(c, rlwinm(dst->low, b->low, 0, 31 - end, 31 - start)); + } else { + moveRR(c, 4, b, 4, dst); + } + } else { + issue(c, li(dst->low, 0)); + } + } +} + +void +orR(Context* c, unsigned size, Assembler::Register* a, + Assembler::Register* b, Assembler::Register* dst) +{ + if (size == 8) { + Assembler::Register ah(a->high); + Assembler::Register bh(b->high); + Assembler::Register dh(dst->high); + + orR(c, 4, a, b, dst); + orR(c, 4, &ah, &bh, &dh); + } else { + issue(c, or_(dst->low, a->low, b->low)); + } +} + +void +orC(Context* c, unsigned size, Assembler::Constant* a, + Assembler::Register* b, Assembler::Register* dst) +{ + int64_t v = a->value->value(); + + if (size == 8) { + ResolvedPromise high((v >> 32) & 0xFFFFFFFF); + Assembler::Constant ah(&high); + + ResolvedPromise low(v & 0xFFFFFFFF); + Assembler::Constant al(&low); + + Assembler::Register bh(b->high); + Assembler::Register dh(dst->high); + + orC(c, 4, &al, b, dst); + orC(c, 4, &ah, &bh, &dh); + } else { + issue(c, ori(b->low, dst->low, v)); + if (v >> 16) { + issue(c, oris(dst->low, dst->low, v >> 16)); + } + } +} + +void +xorR(Context* c, unsigned size, Assembler::Register* a, + Assembler::Register* b, Assembler::Register* dst) +{ + if (size == 8) { + Assembler::Register ah(a->high); + Assembler::Register bh(b->high); + Assembler::Register dh(dst->high); + + xorR(c, 4, a, b, dst); + xorR(c, 4, &ah, &bh, &dh); + } else { + issue(c, xor_(dst->low, a->low, b->low)); + } +} + +void +xorC(Context* c, unsigned size, Assembler::Constant* a, + Assembler::Register* b, Assembler::Register* dst) +{ + uint64_t v = a->value->value(); + + if (size == 8) { + ResolvedPromise high((v >> 32) & 0xFFFFFFFF); + Assembler::Constant ah(&high); + + ResolvedPromise low(v & 0xFFFFFFFF); + Assembler::Constant al(&low); + + Assembler::Register bh(b->high); + Assembler::Register dh(dst->high); + + xorC(c, 4, &al, b, dst); + xorC(c, 4, &ah, &bh, &dh); + } else { + if (v >> 16) { + issue(c, xoris(b->low, dst->low, v >> 16)); + issue(c, xori(dst->low, dst->low, v)); + } else { + issue(c, xori(b->low, dst->low, v)); + } + } +} + +void +moveAR(Context* c, unsigned srcSize, Assembler::Address* src, + unsigned dstSize, Assembler::Register* dst) +{ + assert(c, srcSize == 4 and dstSize == 4); + + Assembler::Constant constant(src->address); + Assembler::Memory memory(dst->low, 0, -1, 0); + + moveCR(c, srcSize, &constant, dstSize, dst); + moveMR(c, dstSize, &memory, dstSize, dst); +} + +void +compareRR(Context* c, unsigned aSize UNUSED, Assembler::Register* a, + unsigned bSize UNUSED, Assembler::Register* b) +{ + assert(c, aSize == 4 and bSize == 4); + + issue(c, cmpw(b->low, a->low)); +} + +void +compareCR(Context* c, unsigned aSize, Assembler::Constant* a, + unsigned bSize, Assembler::Register* b) +{ + assert(c, aSize == 4 and bSize == 4); + + if (a->value->resolved() and isInt16(a->value->value())) { + issue(c, cmpwi(b->low, a->value->value())); + } else { + Assembler::Register tmp(c->client->acquireTemporary()); + moveCR(c, aSize, a, bSize, &tmp); + compareRR(c, bSize, &tmp, bSize, b); + c->client->releaseTemporary(tmp.low); + } +} + +void +compareCM(Context* c, unsigned aSize, Assembler::Constant* a, + unsigned bSize, Assembler::Memory* b) +{ + assert(c, aSize == 4 and bSize == 4); + + Assembler::Register tmp(c->client->acquireTemporary()); + moveMR(c, bSize, b, bSize, &tmp); + compareCR(c, aSize, a, bSize, &tmp); + c->client->releaseTemporary(tmp.low); +} + +void +compareRM(Context* c, unsigned aSize, Assembler::Register* a, + unsigned bSize, Assembler::Memory* b) +{ + assert(c, aSize == 4 and bSize == 4); + + Assembler::Register tmp(c->client->acquireTemporary()); + moveMR(c, bSize, b, bSize, &tmp); + compareRR(c, aSize, a, bSize, &tmp); + c->client->releaseTemporary(tmp.low); +} + +void +compareUnsignedRR(Context* c, unsigned aSize UNUSED, Assembler::Register* a, + unsigned bSize UNUSED, Assembler::Register* b) +{ + assert(c, aSize == 4 and bSize == 4); + + issue(c, cmplw(b->low, a->low)); +} + +void +compareUnsignedCR(Context* c, unsigned aSize, Assembler::Constant* a, + unsigned bSize, Assembler::Register* b) +{ + assert(c, aSize == 4 and bSize == 4); + + if (a->value->resolved() and (a->value->value() >> 16) == 0) { + issue(c, cmplwi(b->low, a->value->value())); + } else { + Assembler::Register tmp(c->client->acquireTemporary()); + moveCR(c, aSize, a, bSize, &tmp); + compareUnsignedRR(c, bSize, &tmp, bSize, b); + c->client->releaseTemporary(tmp.low); + } +} + +void +longCompare(Context* c, Assembler::Operand* al, Assembler::Operand* ah, + Assembler::Operand* bl, Assembler::Operand* bh, + Assembler::Register* dst, BinaryOperationType compareSigned, + BinaryOperationType compareUnsigned) +{ + ResolvedPromise negativePromise(-1); + Assembler::Constant negative(&negativePromise); + + ResolvedPromise zeroPromise(0); + Assembler::Constant zero(&zeroPromise); + + ResolvedPromise positivePromise(1); + Assembler::Constant positive(&positivePromise); + + compareSigned(c, 4, ah, 4, bh); + + unsigned less = c->code.length(); + issue(c, blt(0)); + + unsigned greater = c->code.length(); + issue(c, bgt(0)); + + compareUnsigned(c, 4, al, 4, bl); + + unsigned above = c->code.length(); + issue(c, bgt(0)); + + unsigned below = c->code.length(); + issue(c, blt(0)); + + moveCR(c, 4, &zero, 4, dst); + + unsigned nextFirst = c->code.length(); + issue(c, b(0)); + + updateOffset + (c->s, c->code.data + less, true, reinterpret_cast + (c->code.data + c->code.length())); + + updateOffset + (c->s, c->code.data + below, true, reinterpret_cast + (c->code.data + c->code.length())); + + moveCR(c, 4, &negative, 4, dst); + + unsigned nextSecond = c->code.length(); + issue(c, b(0)); + + updateOffset + (c->s, c->code.data + greater, true, reinterpret_cast + (c->code.data + c->code.length())); + + updateOffset + (c->s, c->code.data + above, true, reinterpret_cast + (c->code.data + c->code.length())); + + moveCR(c, 4, &positive, 4, dst); + + updateOffset + (c->s, c->code.data + nextFirst, false, reinterpret_cast + (c->code.data + c->code.length())); + + updateOffset + (c->s, c->code.data + nextSecond, false, reinterpret_cast + (c->code.data + c->code.length())); +} + +void +longCompareR(Context* c, unsigned size UNUSED, Assembler::Register* a, + Assembler::Register* b, Assembler::Register* dst) +{ + assert(c, size == 8); + + Assembler::Register ah(a->high); + Assembler::Register bh(b->high); + + longCompare(c, a, &ah, b, &bh, dst, CAST2(compareRR), + CAST2(compareUnsignedRR)); +} + +void +longCompareC(Context* c, unsigned size UNUSED, Assembler::Constant* a, + Assembler::Register* b, Assembler::Register* dst) +{ + assert(c, size == 8); + + int64_t v = a->value->value(); + + ResolvedPromise low(v & ~static_cast(0)); + Assembler::Constant al(&low); + + ResolvedPromise high((v >> 32) & ~static_cast(0)); + Assembler::Constant ah(&high); + + Assembler::Register bh(b->high); + + longCompare(c, &al, &ah, b, &bh, dst, CAST2(compareCR), + CAST2(compareUnsignedCR)); +} + +ShiftMaskPromise* +shiftMaskPromise(Context* c, Promise* base, unsigned shift, int64_t mask) +{ + return new (c->zone->allocate(sizeof(ShiftMaskPromise))) + ShiftMaskPromise(base, shift, mask); +} + +void +moveCM(Context* c, unsigned srcSize, Assembler::Constant* src, + unsigned dstSize, Assembler::Memory* dst) +{ + switch (dstSize) { + case 8: { + Assembler::Constant srcHigh + (shiftMaskPromise(c, src->value, 32, 0xFFFFFFFF)); + Assembler::Constant srcLow + (shiftMaskPromise(c, src->value, 0, 0xFFFFFFFF)); + + Assembler::Memory dstLow + (dst->base, dst->offset + 4, dst->index, dst->scale); + + moveCM(c, 4, &srcLow, 4, &dstLow); + moveCM(c, 4, &srcHigh, 4, dst); + } break; + + default: + Assembler::Register tmp(c->client->acquireTemporary()); + moveCR(c, srcSize, src, dstSize, &tmp); + moveRM(c, dstSize, &tmp, dstSize, dst); + c->client->releaseTemporary(tmp.low); + } +} + +void +negateRR(Context* c, unsigned srcSize, Assembler::Register* src, + unsigned dstSize UNUSED, Assembler::Register* dst) +{ + assert(c, srcSize == dstSize); + + if (srcSize == 8) { + Assembler::Register dstHigh(dst->high); + + issue(c, subfic(dst->low, src->low, 0)); + issue(c, subfze(dst->high, src->high)); + } else { + issue(c, neg(dst->low, src->low)); + } +} + +void +callR(Context* c, unsigned size UNUSED, Assembler::Register* target) +{ + assert(c, size == BytesPerWord); + + issue(c, mtctr(target->low)); + issue(c, bctrl()); +} + +void +callC(Context* c, unsigned size UNUSED, Assembler::Constant* target) +{ + assert(c, size == BytesPerWord); + + appendOffsetTask(c, target->value, offset(c), false); + issue(c, bl(0)); +} + +void +longCallC(Context* c, unsigned size UNUSED, Assembler::Constant* target) +{ + assert(c, size == BytesPerWord); + + Assembler::Register tmp(0); + moveCR2(c, BytesPerWord, target, BytesPerWord, &tmp, 12); + callR(c, BytesPerWord, &tmp); +} + +void +longJumpC(Context* c, unsigned size UNUSED, Assembler::Constant* target) +{ + assert(c, size == BytesPerWord); + + Assembler::Register tmp(0); + moveCR2(c, BytesPerWord, target, BytesPerWord, &tmp, 12); + jumpR(c, BytesPerWord, &tmp); +} + +void +jumpC(Context* c, unsigned size UNUSED, Assembler::Constant* target) +{ + assert(c, size == BytesPerWord); + + appendOffsetTask(c, target->value, offset(c), false); + issue(c, b(0)); +} + +void +jumpIfEqualC(Context* c, unsigned size UNUSED, Assembler::Constant* target) +{ + assert(c, size == BytesPerWord); + + appendOffsetTask(c, target->value, offset(c), true); + issue(c, be(0)); +} + +void +jumpIfNotEqualC(Context* c, unsigned size UNUSED, Assembler::Constant* target) +{ + assert(c, size == BytesPerWord); + + appendOffsetTask(c, target->value, offset(c), true); + issue(c, bne(0)); +} + +void +jumpIfGreaterC(Context* c, unsigned size UNUSED, Assembler::Constant* target) +{ + assert(c, size == BytesPerWord); + + appendOffsetTask(c, target->value, offset(c), true); + issue(c, bgt(0)); +} + +void +jumpIfGreaterOrEqualC(Context* c, unsigned size UNUSED, + Assembler::Constant* target) +{ + assert(c, size == BytesPerWord); + + appendOffsetTask(c, target->value, offset(c), true); + issue(c, bge(0)); +} + +void +jumpIfLessC(Context* c, unsigned size UNUSED, Assembler::Constant* target) +{ + assert(c, size == BytesPerWord); + + appendOffsetTask(c, target->value, offset(c), true); + issue(c, blt(0)); +} + +void +jumpIfLessOrEqualC(Context* c, unsigned size UNUSED, + Assembler::Constant* target) +{ + assert(c, size == BytesPerWord); + + appendOffsetTask(c, target->value, offset(c), true); + issue(c, ble(0)); +} + +void +return_(Context* c) +{ + issue(c, blr()); +} + +void +memoryBarrier(Context* c) +{ + issue(c, sync(0)); +} + +// END OPERATION COMPILERS + + +void +populateTables(ArchitectureContext* c) +{ + const OperandType C = ConstantOperand; + const OperandType A = AddressOperand; + const OperandType R = RegisterOperand; + const OperandType M = MemoryOperand; + + OperationType* zo = c->operations; + UnaryOperationType* uo = c->unaryOperations; + BinaryOperationType* bo = c->binaryOperations; + TernaryOperationType* to = c->ternaryOperations; + + zo[Return] = return_; + zo[LoadBarrier] = memoryBarrier; + zo[StoreStoreBarrier] = memoryBarrier; + zo[StoreLoadBarrier] = memoryBarrier; + + uo[index(LongCall, C)] = CAST1(longCallC); + + uo[index(LongJump, C)] = CAST1(longJumpC); + + uo[index(Jump, R)] = CAST1(jumpR); + uo[index(Jump, C)] = CAST1(jumpC); + + uo[index(JumpIfEqual, C)] = CAST1(jumpIfEqualC); + uo[index(JumpIfNotEqual, C)] = CAST1(jumpIfNotEqualC); + uo[index(JumpIfGreater, C)] = CAST1(jumpIfGreaterC); + uo[index(JumpIfGreaterOrEqual, C)] = CAST1(jumpIfGreaterOrEqualC); + uo[index(JumpIfLess, C)] = CAST1(jumpIfLessC); + uo[index(JumpIfLessOrEqual, C)] = CAST1(jumpIfLessOrEqualC); + + uo[index(Call, C)] = CAST1(callC); + uo[index(Call, R)] = CAST1(callR); + + uo[index(AlignedCall, C)] = CAST1(callC); + uo[index(AlignedCall, R)] = CAST1(callR); + + bo[index(Move, R, R)] = CAST2(moveRR); + bo[index(Move, C, R)] = CAST2(moveCR); + bo[index(Move, C, M)] = CAST2(moveCM); + bo[index(Move, M, R)] = CAST2(moveMR); + bo[index(Move, R, M)] = CAST2(moveRM); + bo[index(Move, A, R)] = CAST2(moveAR); + + bo[index(MoveZ, R, R)] = CAST2(moveZRR); + bo[index(MoveZ, M, R)] = CAST2(moveZMR); + bo[index(MoveZ, C, R)] = CAST2(moveCR); + + bo[index(Compare, R, R)] = CAST2(compareRR); + bo[index(Compare, C, R)] = CAST2(compareCR); + bo[index(Compare, R, M)] = CAST2(compareRM); + bo[index(Compare, C, M)] = CAST2(compareCM); + + bo[index(Negate, R, R)] = CAST2(negateRR); + + to[index(Add, R)] = CAST3(addR); + to[index(Add, C)] = CAST3(addC); + + to[index(Subtract, R)] = CAST3(subR); + to[index(Subtract, C)] = CAST3(subC); + + to[index(Multiply, R)] = CAST3(multiplyR); + + to[index(Divide, R)] = CAST3(divideR); + + to[index(Remainder, R)] = CAST3(remainderR); + + to[index(ShiftLeft, R)] = CAST3(shiftLeftR); + to[index(ShiftLeft, C)] = CAST3(shiftLeftC); + + to[index(ShiftRight, R)] = CAST3(shiftRightR); + to[index(ShiftRight, C)] = CAST3(shiftRightC); + + to[index(UnsignedShiftRight, R)] = CAST3(unsignedShiftRightR); + to[index(UnsignedShiftRight, C)] = CAST3(unsignedShiftRightC); + + to[index(And, C)] = CAST3(andC); + to[index(And, R)] = CAST3(andR); + + to[index(Or, C)] = CAST3(orC); + to[index(Or, R)] = CAST3(orR); + + to[index(Xor, C)] = CAST3(xorC); + to[index(Xor, R)] = CAST3(xorR); + + to[index(LongCompare, R)] = CAST3(longCompareR); + to[index(LongCompare, C)] = CAST3(longCompareC); +} + +class MyArchitecture: public Assembler::Architecture { + public: + MyArchitecture(System* system): c(system), referenceCount(0) { + populateTables(&c); + } + + virtual unsigned registerCount() { + return 32; + } + + virtual int stack() { + return StackRegister; + } + + virtual int thread() { + return ThreadRegister; + } + + virtual int returnLow() { + return 4; + } + + virtual int returnHigh() { + return (BytesPerWord == 4 ? 3 : NoRegister); + } + + virtual bool condensedAddressing() { + return false; + } + + virtual bool bigEndian() { + return true; + } + + virtual bool reserved(int register_) { + switch (register_) { + case 0: // r0 has special meaning in addi and other instructions + case StackRegister: + case ThreadRegister: + return true; + + default: + return false; + } + } + + virtual unsigned argumentFootprint(unsigned footprint) { + return footprint; + } + + virtual unsigned argumentRegisterCount() { + return 8; + } + + virtual int argumentRegister(unsigned index) { + assert(&c, index < argumentRegisterCount()); + + return index + 3; + } + + virtual void updateCall(UnaryOperation op UNUSED, + bool assertAlignment UNUSED, void* returnAddress, + void* newTarget) + { + switch (op) { + case Call: + case Jump: { + updateOffset(c.s, static_cast(returnAddress) - 4, false, + reinterpret_cast(newTarget)); + } break; + + case LongCall: + case LongJump: { + updateImmediate(c.s, static_cast(returnAddress) - 12, + reinterpret_cast(newTarget), BytesPerWord); + } break; + + default: abort(&c); + } + } + + virtual uintptr_t getConstant(const void* src) { + const int32_t* p = static_cast(src); + return (p[0] << 16) | (p[1] & 0xFFFF); + } + + virtual void setConstant(void* dst, uintptr_t constant) { + updateImmediate(c.s, dst, constant, BytesPerWord); + } + + virtual unsigned alignFrameSize(unsigned sizeInWords) { + const unsigned alignment = 16 / BytesPerWord; + return (ceiling(sizeInWords + FrameFooterSize, alignment) * alignment); + } + + virtual void* frameIp(void* stack) { + return stack ? static_cast(stack)[2] : 0; + } + + virtual unsigned frameHeaderSize() { + return 0; + } + + virtual unsigned frameReturnAddressSize() { + return 0; + } + + virtual unsigned frameFooterSize() { + return FrameFooterSize; + } + + virtual void nextFrame(void** stack, void**) { + assert(&c, *static_cast(*stack) != *stack); + + *stack = *static_cast(*stack); + } + + virtual void plan + (UnaryOperation, + unsigned, uint8_t* aTypeMask, uint64_t* aRegisterMask, + bool* thunk) + { + *aTypeMask = (1 << RegisterOperand) | (1 << ConstantOperand); + *aRegisterMask = ~static_cast(0); + *thunk = false; + } + + virtual void plan + (BinaryOperation op, + unsigned, uint8_t* aTypeMask, uint64_t* aRegisterMask, + unsigned, uint8_t* bTypeMask, uint64_t* bRegisterMask, + bool* thunk) + { + *aTypeMask = ~0; + *aRegisterMask = ~static_cast(0); + + *bTypeMask = (1 << RegisterOperand) | (1 << MemoryOperand); + *bRegisterMask = ~static_cast(0); + + *thunk = false; + + switch (op) { + case Compare: + *aTypeMask = (1 << RegisterOperand) | (1 << ConstantOperand); + *bTypeMask = (1 << RegisterOperand); + break; + + case Negate: + *aTypeMask = (1 << RegisterOperand); + *bTypeMask = (1 << RegisterOperand); + break; + + default: + break; + } + } + + virtual void plan + (TernaryOperation op, + unsigned aSize, uint8_t* aTypeMask, uint64_t* aRegisterMask, + unsigned, uint8_t* bTypeMask, uint64_t* bRegisterMask, + unsigned, uint8_t* cTypeMask, uint64_t* cRegisterMask, + bool* thunk) + { + *aTypeMask = (1 << RegisterOperand) | (1 << ConstantOperand); + *aRegisterMask = ~static_cast(0); + + *bTypeMask = (1 << RegisterOperand); + *bRegisterMask = ~static_cast(0); + + *thunk = false; + + switch (op) { + case Add: + case Subtract: + if (aSize == 8) { + *aTypeMask = *bTypeMask = (1 << RegisterOperand); + } + break; + + case Multiply: + *aTypeMask = *bTypeMask = (1 << RegisterOperand); + break; + + case LongCompare: + *bTypeMask = (1 << RegisterOperand); + break; + + case Divide: + case Remainder: + if (BytesPerWord == 4 and aSize == 8) { + *bTypeMask = ~0; + *thunk = true; + } else { + *aTypeMask = (1 << RegisterOperand); + } + break; + + default: + break; + } + + *cTypeMask = *bTypeMask; + *cRegisterMask = *bRegisterMask; + } + + virtual void acquire() { + ++ referenceCount; + } + + virtual void release() { + if (-- referenceCount == 0) { + c.s->free(this); + } + } + + ArchitectureContext c; + unsigned referenceCount; +}; + +class MyAssembler: public Assembler { + public: + MyAssembler(System* s, Allocator* a, Zone* zone, MyArchitecture* arch): + c(s, a, zone), arch_(arch) + { } + + virtual void setClient(Client* client) { + assert(&c, c.client == 0); + c.client = client; + } + + virtual Architecture* arch() { + return arch_; + } + + virtual void saveFrame(unsigned stackOffset, unsigned) { + Register stack(StackRegister); + Memory stackDst(ThreadRegister, stackOffset); + moveRM(&c, BytesPerWord, &stack, BytesPerWord, &stackDst); + } + + virtual void pushFrame(unsigned argumentCount, ...) { + struct { + unsigned size; + OperandType type; + Operand* operand; + } arguments[argumentCount]; + + va_list a; va_start(a, argumentCount); + unsigned footprint = 0; + for (unsigned i = 0; i < argumentCount; ++i) { + arguments[i].size = va_arg(a, unsigned); + arguments[i].type = static_cast(va_arg(a, int)); + arguments[i].operand = va_arg(a, Operand*); + footprint += ceiling(arguments[i].size, BytesPerWord); + } + va_end(a); + + allocateFrame(arch_->alignFrameSize(footprint)); + + unsigned offset = 0; + for (unsigned i = 0; i < argumentCount; ++i) { + if (i < arch_->argumentRegisterCount()) { + Register dst(arch_->argumentRegister(i)); + + apply(Move, + arguments[i].size, arguments[i].type, arguments[i].operand, + pad(arguments[i].size), RegisterOperand, &dst); + + offset += ceiling(arguments[i].size, BytesPerWord); + } else { + Memory dst(ThreadRegister, (offset + FrameFooterSize) * BytesPerWord); + + apply(Move, + arguments[i].size, arguments[i].type, arguments[i].operand, + pad(arguments[i].size), MemoryOperand, &dst); + + offset += ceiling(arguments[i].size, BytesPerWord); + } + } + } + + virtual void allocateFrame(unsigned footprint) { + Register returnAddress(0); + issue(&c, mflr(returnAddress.low)); + + Memory returnAddressDst(StackRegister, 8); + moveRM(&c, BytesPerWord, &returnAddress, BytesPerWord, &returnAddressDst); + + Register stack(StackRegister); + Memory stackDst(StackRegister, -footprint * BytesPerWord); + moveAndUpdateRM(&c, BytesPerWord, &stack, BytesPerWord, &stackDst); + } + + virtual void popFrame() { + Register stack(StackRegister); + Memory stackSrc(StackRegister, 0); + moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &stack); + + Assembler::Register returnAddress(0); + Assembler::Memory returnAddressSrc(StackRegister, 8); + moveMR(&c, BytesPerWord, &returnAddressSrc, BytesPerWord, &returnAddress); + + issue(&c, mtlr(returnAddress.low)); + } + + virtual void apply(Operation op) { + arch_->c.operations[op](&c); + } + + virtual void apply(UnaryOperation op, + unsigned aSize, OperandType aType, Operand* aOperand) + { + arch_->c.unaryOperations[index(op, aType)](&c, aSize, aOperand); + } + + virtual void apply(BinaryOperation op, + unsigned aSize, OperandType aType, Operand* aOperand, + unsigned bSize, OperandType bType, Operand* bOperand) + { + arch_->c.binaryOperations[index(op, aType, bType)] + (&c, aSize, aOperand, bSize, bOperand); + } + + virtual void apply(TernaryOperation op, + unsigned, OperandType aType, Operand* aOperand, + unsigned bSize, OperandType bType UNUSED, + Operand* bOperand, + unsigned cSize UNUSED, OperandType cType UNUSED, + Operand* cOperand) + { + assert(&c, bSize == cSize); + assert(&c, bType == RegisterOperand); + assert(&c, cType == RegisterOperand); + + arch_->c.ternaryOperations[index(op, aType)] + (&c, bSize, aOperand, bOperand, cOperand); + } + + virtual void writeTo(uint8_t* dst) { + c.result = dst; + + for (MyBlock* b = c.firstBlock; b; b = b->next) { + memcpy(dst + b->start, c.code.data + b->offset, b->size); + } + + for (Task* t = c.tasks; t; t = t->next) { + t->run(&c); + } + } + + virtual Promise* offset() { + return ::offset(&c); + } + + virtual Block* endBlock(bool startNew) { + MyBlock* b = c.lastBlock; + b->size = c.code.length() - b->offset; + if (startNew) { + c.lastBlock = new (c.zone->allocate(sizeof(MyBlock))) + MyBlock(c.code.length()); + } else { + c.lastBlock = 0; + } + return b; + } + + virtual unsigned length() { + return c.code.length(); + } + + virtual void dispose() { + c.code.dispose(); + } + + Context c; + MyArchitecture* arch_; +}; + +} // namespace + +namespace vm { + +Assembler::Architecture* +makeArchitecture(System* system) +{ + return new (allocate(system, sizeof(MyArchitecture))) MyArchitecture(system); +} + +Assembler* +makeAssembler(System* system, Allocator* allocator, Zone* zone, + Assembler::Architecture* architecture) +{ + return new (zone->allocate(sizeof(MyAssembler))) + MyAssembler(system, allocator, zone, + static_cast(architecture)); +} + +} // namespace vm diff --git a/src/arm.h b/src/arm.h new file mode 100644 index 0000000000..f17fa596be --- /dev/null +++ b/src/arm.h @@ -0,0 +1,119 @@ +/* Copyright (c) 2008-2009, 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. */ + +#ifndef ARM_H +#define ARM_H + +#include "types.h" +#include "common.h" + +#define IP_REGISTER(context) (context->uc_mcontext.gregs[15]) +#define STACK_REGISTER(context) (context->uc_mcontext.gregs[13]) +#define THREAD_REGISTER(context) (context->uc_mcontext.gregs[12]) + +extern "C" uint64_t +vmNativeCall(void* function, unsigned stackTotal, void* memoryTable, + unsigned memoryCount, void* gprTable); + +namespace vm { + +inline void +trap() +{ + asm("nop"); +} + +inline void +memoryBarrier() +{ + asm("nop"); +} + +inline void +storeStoreMemoryBarrier() +{ + memoryBarrier(); +} + +inline void +storeLoadMemoryBarrier() +{ + memoryBarrier(); +} + +inline void +loadMemoryBarrier() +{ + memoryBarrier(); +} + +inline void +syncInstructionCache(const void* start UNUSED, unsigned size UNUSED) +{ + asm("nop"); +} + +inline uint64_t +dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes, + unsigned argumentCount, unsigned argumentsSize, + unsigned returnType UNUSED) +{ + const unsigned GprCount = 4; + uintptr_t gprTable[GprCount]; + unsigned gprIndex = 0; + + uintptr_t stack[argumentsSize / BytesPerWord]; + unsigned stackIndex = 0; + + unsigned ai = 0; + for (unsigned ati = 0; ati < argumentCount; ++ ati) { + switch (argumentTypes[ati]) { + case DOUBLE_TYPE: + case INT64_TYPE: { + if (gprIndex + (8 / BytesPerWord) <= GprCount) { + memcpy(gprTable + gprIndex, arguments + ai, 8); + gprIndex += 8 / BytesPerWord; + } else if (gprIndex == GprCount-1) { // split between last GPR and stack + memcpy(gprTable + gprIndex, arguments + ai, 4); + ++gprIndex; + memcpy(stack + stackIndex, arguments + ai + 4, 4); + ++stackIndex; + } else { + memcpy(stack + stackIndex, arguments + ai, 8); + stackIndex += 8 / BytesPerWord; + } + ai += 8 / BytesPerWord; + } break; + + default: { + if (gprIndex < GprCount) { + gprTable[gprIndex++] = arguments[ai]; + } else { + stack[stackIndex++] = arguments[ai]; + } + ++ ai; + } break; + } + } + + if (gprIndex < GprCount) { // pad since assembly loads all GPRs + memset(gprTable + gprIndex, 0, (GprCount-gprIndex)*4); + gprIndex = GprCount; + } + + unsigned stackSize = stackIndex*BytesPerWord + ((stackIndex & 1) << 2); + return vmNativeCall + (function, stackSize, stack, stackIndex * BytesPerWord, + (gprIndex ? gprTable : 0)); +} + +} // namespace vm + +#endif // ARM_H diff --git a/src/common.h b/src/common.h index c9964b7b7d..7e1f94e93b 100644 --- a/src/common.h +++ b/src/common.h @@ -29,7 +29,7 @@ # define PATH_SEPARATOR ':' #endif -#if (defined __i386__) || (defined __POWERPC__) +#if (defined __i386__) || (defined __POWERPC__) || (defined __arm__) # define LD "ld" # define LLD "lld" #ifdef __APPLE__ diff --git a/src/interpret.cpp b/src/interpret.cpp index 7a51fc997a..614a24d60c 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -117,7 +117,11 @@ pushLong(Thread* t, uint64_t v) inline void pushDouble(Thread* t, double v) { - pushLong(t, doubleToBits(v)); + uint64_t w = doubleToBits(v); +#ifdef __arm__ + w = w << 32 | w >> 32; +#endif + pushLong(t, w); } inline object @@ -167,10 +171,14 @@ popLong(Thread* t) return (b << 32) | a; } -inline float +inline double popDouble(Thread* t) { - return bitsToDouble(popLong(t)); + uint64_t v = popLong(t); +#ifdef __arm__ + v = v << 32 | v >> 32; +#endif + return bitsToDouble(v); } inline object @@ -560,8 +568,17 @@ pushResult(Thread* t, unsigned returnCode, uint64_t result, bool indirect) pushInt(t, result); break; - case LongField: case DoubleField: +#ifdef __arm__ + result = result << 32 | result >> 32; + if (DebugRun) { + fprintf(stderr, "result: %"LLD"\n", result); + } + pushLong(t, result); + break; +#endif + + case LongField: if (DebugRun) { fprintf(stderr, "result: %"LLD"\n", result); } @@ -611,8 +628,17 @@ marshalArguments(Thread* t, uintptr_t* args, unsigned i, unsigned count, args[offset++] = peekInt(t, sp++); break; - case INT64_TYPE: - case DOUBLE_TYPE: { + case DOUBLE_TYPE: +#ifdef __arm__ + { + uint64_t v = peekLong(t, sp); + v = v << 32 | v >> 32; + memcpy(args + offset, &v, 8); + offset += (8 / BytesPerWord); + sp += 2; + } break; +#endif + case INT64_TYPE: { uint64_t v = peekLong(t, sp); memcpy(args + offset, &v, 8); offset += (8 / BytesPerWord); From 3e0c0c8116e0e7d8f8d2f7465b0dfcda2df15483 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 6 Aug 2009 12:10:44 -0600 Subject: [PATCH 09/13] revert recent accidental makefile changes --- makefile | 163 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 117 insertions(+), 46 deletions(-) diff --git a/makefile b/makefile index 59d1c11b29..21b007dd13 100644 --- a/makefile +++ b/makefile @@ -18,10 +18,6 @@ bootimage-platform = \ $(subst cygwin,windows,$(subst mingw32,windows,$(build-platform))) platform = $(bootimage-platform) -ifeq ($(platform),windows) - arch = i386 -endif - mode = fast process = compile @@ -43,6 +39,23 @@ endif ifeq ($(continuations),true) options := $(options)-continuations endif +ifdef gnu + options := $(options)-gnu + gnu-sources = $(src)/gnu.cpp + gnu-jar = $(gnu)/share/classpath/glibj.zip + gnu-libraries = \ + $(gnu)/lib/classpath/libjavaio.a \ + $(gnu)/lib/classpath/libjavalang.a \ + $(gnu)/lib/classpath/libjavalangreflect.a \ + $(gnu)/lib/classpath/libjavamath.a \ + $(gnu)/lib/classpath/libjavanet.a \ + $(gnu)/lib/classpath/libjavanio.a \ + $(gnu)/lib/classpath/libjavautil.a + gnu-object-dep = $(build)/gnu-object.dep + gnu-cflags = -DBOOT_BUILTINS=\"javaio,javalang,javalangreflect,javamath,javanet,javanio,javautil\" -DAVIAN_GNU + gnu-lflags = -lgmp + gnu-objects = $(shell find $(build)/gnu-objects -name "*.o") +endif root = $(shell (cd .. && pwd)) build = build @@ -53,6 +66,12 @@ src = src classpath = classpath test = test +ifdef gnu + avian-classpath-build = $(build)/avian-classpath +else + avian-classpath-build = $(classpath-build) +endif + input = List build-cxx = g++ @@ -83,13 +102,14 @@ 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) build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \ "-I$(JAVA_HOME)/include/linux" -I$(src) -pthread cflags = $(build-cflags) -common-lflags = -lm -lz +common-lflags = -lm -lz $(gnu-lflags) build-lflags = @@ -120,21 +140,6 @@ ifeq ($(arch),powerpc) object-format = elf32-powerpc pointer-size = 4 endif -ifeq ($(arch),arm) - lflags := -L/opt/crosstool/gcc-4.1.0-glibc-2.3.2/arm-unknown-linux-gnu/arm-unknown-linux-gnu/lib -L$(root)/arm/lib $(lflags) - cflags := -I/opt/crosstool/gcc-4.1.0-glibc-2.3.2/arm-unknown-linux-gnu/arm-unknown-linux-gnu/include -I$(root)/arm/include $(cflags) - - asm = arm - object-arch = arm - object-format = elf32-littlearm - pointer-size = 4 - cxx = arm-unknown-linux-gnu-g++ - cc = arm-unknown-linux-gnu-gcc - ar = arm-unknown-linux-gnu-ar - ranlib = arm-unknown-linux-gnu-ranlib - objcopy = arm-unknown-linux-gnu-objcopy - strip = arm-unknown-linux-gnu-strip -endif ifeq ($(platform),darwin) build-cflags = $(common-cflags) -fPIC -fvisibility=hidden -I$(src) @@ -182,6 +187,21 @@ ifeq ($(platform),windows) native-path = cygpath -m endif endif + + ifeq ($(arch),x86_64) + cxx = x86_64-pc-mingw32-g++ + cc = x86_64-pc-mingw32-gcc + dlltool = x86_64-pc-mingw32-dlltool + ar = x86_64-pc-mingw32-ar + ranlib = x86_64-pc-mingw32-ranlib + objcopy = x86_64-pc-mingw32-objcopy + strip = : + inc = "$(root)/win64/include" + lib = "$(root)/win64/lib" + pointer-size = 8 + object-format = pe-x86-64 + endif + endif ifeq ($(mode),debug) @@ -247,7 +267,8 @@ vm-sources = \ $(src)/$(process).cpp \ $(src)/builtin.cpp \ $(src)/jnienv.cpp \ - $(src)/process.cpp + $(src)/process.cpp \ + $(gnu-sources) vm-asm-sources = $(src)/$(asm).S @@ -329,16 +350,43 @@ classpath-sources = $(shell find $(classpath) -name '*.java') classpath-classes = \ $(call java-classes,$(classpath-sources),$(classpath),$(classpath-build)) classpath-object = $(native-build)/classpath-jar.o -classpath-dep = $(classpath-build)/dep +classpath-dep = $(classpath-build).dep + +gnu-blacklist = \ + java/lang/AbstractStringBuffer.class \ + java/lang/reflect/Proxy.class + +gnu-overrides = \ + avian/*.class \ + avian/resource/*.class \ + java/lang/Class.class \ + java/lang/Enum.class \ + java/lang/InheritableThreadLocal.class \ + java/lang/Object.class \ + java/lang/StackTraceElement.class \ + java/lang/String*.class \ + java/lang/StringBuffer.class \ + java/lang/StringBuilder.class \ + java/lang/Thread.class \ + java/lang/ThreadLocal.class \ + java/lang/Throwable.class \ + java/lang/ref/PhantomReference.class \ + java/lang/ref/Reference.class \ + java/lang/ref/ReferenceQueue.class \ + java/lang/ref/WeakReference.class \ + java/lang/reflect/AccessibleObject.class \ + java/lang/reflect/Constructor.class \ + java/lang/reflect/Field.class \ + java/lang/reflect/Method.class test-sources = $(wildcard $(test)/*.java) test-classes = $(call java-classes,$(test-sources),$(test),$(test-build)) -test-dep = $(test-build)/dep +test-dep = $(test-build).dep test-extra-sources = $(wildcard $(test)/extra/*.java) test-extra-classes = \ $(call java-classes,$(test-extra-sources),$(test),$(test-build)) -test-extra-dep = $(test-build)/extra/dep +test-extra-dep = $(test-build)-extra.dep class-name = $(patsubst $(1)/%.class,%,$(2)) class-names = $(foreach x,$(2),$(call class-name,$(1),$(x))) @@ -408,11 +456,24 @@ $(native-build)/type-generator.o: \ $(classpath-build)/%.class: $(classpath)/%.java @echo $(<) -$(classpath-dep): $(classpath-sources) +$(classpath-dep): $(classpath-sources) $(gnu-jar) @echo "compiling classpath classes" - @mkdir -p $(dir $(@)) - $(javac) -d $(dir $(@)) -bootclasspath $(classpath-build) \ + @mkdir -p $(avian-classpath-build) + $(javac) -d $(avian-classpath-build) \ + -bootclasspath $(avian-classpath-build) \ $(shell $(MAKE) -s --no-print-directory $(classpath-classes)) +ifdef gnu + (wd=$$(pwd) && \ + cd $(avian-classpath-build) && \ + $(jar) c0f "$$($(native-path) "$${wd}/$(build)/overrides.jar")" \ + $(gnu-overrides)) + @mkdir -p $(classpath-build) + (wd=$$(pwd) && \ + cd $(classpath-build) && \ + $(jar) xf $(gnu-jar) && \ + rm $(gnu-blacklist) && \ + jar xf "$$($(native-path) "$${wd}/$(build)/overrides.jar")") +endif @touch $(@) $(test-build)/%.class: $(test)/%.java @@ -420,16 +481,16 @@ $(test-build)/%.class: $(test)/%.java $(test-dep): $(test-sources) @echo "compiling test classes" - @mkdir -p $(dir $(@)) - $(javac) -d $(dir $(@)) -bootclasspath $(classpath-build) \ + @mkdir -p $(test-build) + $(javac) -d $(test-build) -bootclasspath $(classpath-build) \ $(shell $(MAKE) -s --no-print-directory $(test-classes)) - $(javac) -source 1.2 -target 1.1 -XDjsrlimit=0 -d $(dir $(@)) \ + $(javac) -source 1.2 -target 1.1 -XDjsrlimit=0 -d $(test-build) \ test/Subroutine.java @touch $(@) $(test-extra-dep): $(test-extra-sources) @echo "compiling extra test classes" - @mkdir -p $(dir $(@)) + @mkdir -p $(test-build) $(javac) -d $(test-build) -bootclasspath $(classpath-build) \ $(shell $(MAKE) -s --no-print-directory $(test-extra-classes)) @touch $(@) @@ -471,9 +532,9 @@ $(boot-object): $(boot-source) $(compile-object) $(build)/classpath.jar: $(classpath-dep) - (wd=$$(pwd); \ - cd $(classpath-build); \ - $(jar) c0f "$$($(native-path) "$${wd}/$(@)")" $$(find . -name '*.class')) + (wd=$$(pwd) && \ + cd $(classpath-build) && \ + $(jar) c0f "$$($(native-path) "$${wd}/$(@)")" .) $(binaryToMacho): $(src)/binaryToMacho.cpp $(cxx) $(^) -o $(@) @@ -484,8 +545,8 @@ ifeq ($(platform),darwin) $(binaryToMacho) $(asm) $(build)/classpath.jar __TEXT __text \ __binary_classpath_jar_start __binary_classpath_jar_end > $(@) else - (wd=$$(pwd); \ - cd $(build); \ + (wd=$$(pwd) && \ + cd $(build) && \ $(objcopy) -I binary classpath.jar \ -O $(object-format) -B $(object-arch) "$${wd}/$(@)") endif @@ -499,10 +560,11 @@ $(generator-objects): $(native-build)/%.o: $(src)/%.cpp $(jni-objects): $(native-build)/%.o: $(classpath)/%.cpp $(compile-object) +$(static-library): $(gnu-object-dep) $(static-library): $(vm-objects) $(jni-objects) $(vm-heapwalk-objects) @echo "creating $(@)" rm -rf $(@) - $(ar) cru $(@) $(^) + $(ar) cru $(@) $(^) $(call gnu-objects) $(ranlib) $(@) $(bootimage-bin): $(bootimage-generator) @@ -514,24 +576,32 @@ ifeq ($(platform),darwin) $(binaryToMacho) $(asm) $(<) __BOOT __boot \ __binary_bootimage_bin_start __binary_bootimage_bin_end > $(@) else - (wd=$$(pwd); \ - cd $(native-build); \ + (wd=$$(pwd) && \ + cd $(native-build) && \ $(objcopy) --rename-section=.data=.boot -I binary bootimage.bin \ - -O $(object-format) -B $(object-arch) "$${wd}/$(@).tmp"; \ + -O $(object-format) -B $(object-arch) "$${wd}/$(@).tmp" && \ $(objcopy) --set-section-flags .boot=alloc,load,code "$${wd}/$(@).tmp" \ "$${wd}/$(@)") endif +$(gnu-object-dep): $(gnu-libraries) + @mkdir -p $(build)/gnu-objects + (cd $(build)/gnu-objects && \ + for x in $(gnu-libraries); do ar x $${x}; done) + @touch $(@) + +$(executable): $(gnu-object-dep) $(executable): \ $(vm-objects) $(jni-objects) $(driver-object) $(vm-heapwalk-objects) \ $(boot-object) $(vm-classpath-object) @echo "linking $(@)" ifeq ($(platform),windows) - $(dlltool) -z $(@).def $(^) + $(dlltool) -z $(@).def $(^) $(call gnu-objects) $(dlltool) -d $(@).def -e $(@).exp - $(cc) $(@).exp $(^) $(lflags) -o $(@) + $(cc) $(@).exp $(^) $(call gnu-objects) $(lflags) -o $(@) else - $(cc) $(^) $(rdynamic) $(lflags) $(bootimage-lflags) -o $(@) + $(cc) $(^) $(call gnu-objects) $(rdynamic) $(lflags) $(bootimage-lflags) \ + -o $(@) endif $(strip) $(strip-all) $(@) @@ -560,11 +630,13 @@ else $(cc) $(^) $(rdynamic) $(lflags) -o $(@) endif +$(dynamic-library): $(gnu-object-dep) $(dynamic-library): \ $(vm-objects) $(dynamic-object) $(jni-objects) $(vm-heapwalk-objects) \ - $(boot-object) $(vm-classpath-object) + $(boot-object) $(vm-classpath-object) $(gnu-libraries) @echo "linking $(@)" - $(cc) $(^) $(shared) $(lflags) $(bootimage-lflags) -o $(@) + $(cc) $(^) $(call gnu-objects) $(shared) $(lflags) $(bootimage-lflags) \ + -o $(@) $(strip) $(strip-all) $(@) $(executable-dynamic): $(driver-dynamic-object) $(dynamic-library) @@ -575,4 +647,3 @@ $(executable-dynamic): $(driver-dynamic-object) $(dynamic-library) $(generator): $(generator-objects) @echo "linking $(@)" $(build-cc) $(^) $(build-lflags) -o $(@) - From e5947b5ec0c3dbd2573ed47277223bd3479dea7c Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 6 Aug 2009 15:58:26 -0600 Subject: [PATCH 10/13] remove bashism from test.sh --- test/test.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test.sh b/test/test.sh index fd028e39f0..55b4ff54a6 100644 --- a/test/test.sh +++ b/test/test.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh log=build/log.txt vg="nice valgrind --leak-check=full --num-callers=32 \ @@ -28,7 +28,7 @@ for test in ${tests}; do exit 1;; esac - if (( ${?} == 0 )); then + if [ "${?}" = "0" ]; then echo "success" else echo "fail" From 012d548bbb185c715a71080770c6066863c71e25 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 7 Aug 2009 14:48:30 -0600 Subject: [PATCH 11/13] fix sign extension from int to long on x86_64 --- src/x86.cpp | 2 +- test/Longs.java | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/x86.cpp b/src/x86.cpp index 59959a2ce9..1854a01427 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -895,7 +895,7 @@ moveRR(Context* c, unsigned aSize, Assembler::Register* a, case 4: if (bSize == 8) { if (BytesPerWord == 8) { - alwaysRex(c, aSize, b, a); + alwaysRex(c, bSize, b, a); opcode(c, 0x63); modrm(c, 0xc0, a, b); } else { diff --git a/test/Longs.java b/test/Longs.java index daa6966677..51fad92969 100644 --- a/test/Longs.java +++ b/test/Longs.java @@ -35,7 +35,13 @@ public class Longs { return a - (a % b); } + private static int negativeOne() { + return -1; + } + public static void main(String[] args) { + expect(((long) negativeOne()) == -1); + { long foo = 25214903884L; int radix = 10; expect(foo > 0); From 2da6980eb5098eedbe20badfac3886d6db7ab369 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 7 Aug 2009 16:27:24 -0600 Subject: [PATCH 12/13] print intptr_t's as pointers in compareIpToMethodBounds to avoid printf compatibility issues --- src/compile.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index ff6f15a5a6..add06d4845 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -189,8 +189,10 @@ compareIpToMethodBounds(Thread* t, intptr_t ip, object method) intptr_t start = methodCompiled(t, method); if (DebugMethodTree) { - fprintf(stderr, "find 0x%"LX" in (0x%"LX",0x%"LX")\n", ip, start, - start + compiledSize(start)); + fprintf(stderr, "find %p in (%p,%p)\n", + reinterpret_cast(ip), + reinterpret_cast(start), + reinterpret_cast(start + compiledSize(start))); } if (ip < start) { From 2f864ebea5fda6401c07cefaacf143c6ad9f5f16 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 7 Aug 2009 16:28:47 -0600 Subject: [PATCH 13/13] fix LLD definition for MinGW 4.4 --- src/common.h | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/common.h b/src/common.h index 7e1f94e93b..10690c6046 100644 --- a/src/common.h +++ b/src/common.h @@ -31,14 +31,18 @@ #if (defined __i386__) || (defined __POWERPC__) || (defined __arm__) # define LD "ld" -# define LLD "lld" -#ifdef __APPLE__ -# define ULD "lu" -# define LX "lx" -#else -# define LX "x" -# define ULD "u" -#endif +# ifdef __MINGW32__ +# define LLD "I64d" +# else +# define LLD "lld" +# endif +# ifdef __APPLE__ +# define ULD "lu" +# define LX "lx" +# else +# define LX "x" +# define ULD "u" +# endif #elif defined __x86_64__ # ifdef __MINGW32__ # define LD "I64d"