Merge branch 'gnu'

This commit is contained in:
Joel Dice 2009-08-03 09:01:16 -06:00
commit 08dd7d0a5a
69 changed files with 3828 additions and 1060 deletions

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2008, Avian Contributors /* Copyright (c) 2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided for any purpose with or without fee is hereby granted, provided
@ -8,7 +8,7 @@
There is NO WARRANTY for this software. See license.txt for There is NO WARRANTY for this software. See license.txt for
details. */ details. */
package java.util; package avian;
public class Cell <T> { public class Cell <T> {
public T value; public T value;

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2008, Avian Contributors /* Copyright (c) 2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided for any purpose with or without fee is hereby granted, provided
@ -8,7 +8,9 @@
There is NO WARRANTY for this software. See license.txt for There is NO WARRANTY for this software. See license.txt for
details. */ details. */
package java.util; package avian;
import java.util.Comparator;
public class PersistentSet <T> implements Iterable <T> { public class PersistentSet <T> implements Iterable <T> {
private static final Node NullNode = new Node(null); private static final Node NullNode = new Node(null);

View File

@ -0,0 +1,101 @@
/* 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. */
package avian.resource;
import java.net.URL;
import java.net.URLStreamHandler;
import java.net.URLConnection;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.io.InputStream;
public class Handler extends URLStreamHandler {
protected URLConnection openConnection(URL url) {
return new ResourceConnection(url);
}
private static class ResourceConnection extends URLConnection {
public ResourceConnection(URL url) {
super(url);
}
public int getContentLength() {
return ResourceInputStream.getContentLength(url.getFile());
}
public InputStream getInputStream() throws IOException {
return new ResourceInputStream(url.getFile());
}
}
private static class ResourceInputStream extends InputStream {
private long peer;
private int position;
public ResourceInputStream(String path) throws IOException {
peer = open(path);
if (peer == 0) {
throw new FileNotFoundException(path);
}
}
private static native int getContentLength(String path);
private static native long open(String path) throws IOException;
private static native int read(long peer, int position) throws IOException;
private static native int read(long peer, int position,
byte[] b, int offset, int length)
throws IOException;
public static native void close(long peer) throws IOException;
public int read() throws IOException {
if (peer != 0) {
int c = read(peer, position);
if (c >= 0) {
++ position;
}
return c;
} else {
throw new IOException();
}
}
public int read(byte[] b, int offset, int length) throws IOException {
if (peer != 0) {
if (b == null) {
throw new NullPointerException();
}
if (offset < 0 || offset + length > b.length) {
throw new ArrayIndexOutOfBoundsException();
}
int c = read(peer, position, b, offset, length);
if (c >= 0) {
position += c;
}
return c;
} else {
throw new IOException();
}
}
public void close() throws IOException {
if (peer != 0) {
close(peer);
peer = 0;
}
}
}
}

View File

@ -23,6 +23,7 @@
#ifdef WIN32 #ifdef WIN32
# include <windows.h> # include <windows.h>
# include <io.h> # include <io.h>
# include <direct.h>
# define OPEN _open # define OPEN _open
# define CLOSE _close # define CLOSE _close

View File

@ -82,7 +82,7 @@ namespace {
int descriptor(JNIEnv* e, HANDLE h) int descriptor(JNIEnv* e, HANDLE h)
{ {
int fd = _open_osfhandle(reinterpret_cast<long>(h), 0); int fd = _open_osfhandle(reinterpret_cast<intptr_t>(h), 0);
if (fd == -1) { if (fd == -1) {
throwNew(e, "java/io/IOException", strerror(errno)); throwNew(e, "java/io/IOException", strerror(errno));
} }

View File

@ -0,0 +1,22 @@
/* 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.lang;
import java.io.IOException;
public interface Appendable {
public Appendable append(char c) throws IOException;
public Appendable append(CharSequence sequence) throws IOException;
public Appendable append(CharSequence sequence, int start, int end)
throws IOException;
}

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2008, Avian Contributors /* Copyright (c) 2008-2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided for any purpose with or without fee is hereby granted, provided
@ -10,7 +10,7 @@
package java.lang; package java.lang;
public class ArrayIndexOutOfBoundsException extends RuntimeException { public class ArrayIndexOutOfBoundsException extends IndexOutOfBoundsException {
public ArrayIndexOutOfBoundsException(String message, Throwable cause) { public ArrayIndexOutOfBoundsException(String message, Throwable cause) {
super(message, cause); super(message, cause);
} }

View File

@ -187,4 +187,40 @@ public final class Character implements Comparable<Character> {
return isHighSurrogate(high) && isLowSurrogate(low); return isHighSurrogate(high) && isLowSurrogate(low);
} }
public static int codePointAt(CharSequence sequence, int offset) {
int length = sequence.length();
if (offset < 0 || offset >= length) {
throw new IndexOutOfBoundsException();
}
char high = sequence.charAt(offset);
if (! isHighSurrogate(high) || offset >= length) {
return high;
}
char low = sequence.charAt(offset + 1);
if (! isLowSurrogate(low)) {
return high;
}
return toCodePoint(high, low);
}
public static int codePointCount(CharSequence sequence, int start, int end) {
int length = sequence.length();
if (start < 0 || start > end || end >= length) {
throw new IndexOutOfBoundsException();
}
int count = 0;
for (int i = start; i < end; ++i) {
if (isHighSurrogate(sequence.charAt(i))
&& (i + 1) < end
&& isLowSurrogate(sequence.charAt(i + 1)))
{
++ i;
}
++ count;
}
return count;
}
} }

View File

@ -14,12 +14,19 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.GenericDeclaration;
import java.lang.annotation.Annotation;
import java.io.InputStream; import java.io.InputStream;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.security.ProtectionDomain;
import java.security.Permissions;
import java.security.AllPermission;
public final class Class <T> { public final class Class <T> implements Type, GenericDeclaration {
private static final int PrimitiveFlag = 1 << 4; private static final int PrimitiveFlag = 1 << 4;
private short flags; private short flags;
@ -84,6 +91,9 @@ public final class Class <T> {
ClassLoader loader) ClassLoader loader)
throws ClassNotFoundException throws ClassNotFoundException
{ {
if (loader == null) {
loader = Class.class.loader;
}
Class c = loader.loadClass(name); Class c = loader.loadClass(name);
if (initialize) { if (initialize) {
c.initialize(); c.initialize();
@ -168,6 +178,8 @@ public final class Class <T> {
private Method findMethod(String name, Class[] parameterTypes) { private Method findMethod(String name, Class[] parameterTypes) {
if (methodTable != null) { if (methodTable != null) {
if (parameterTypes == null)
parameterTypes = new Class[0];
for (int i = 0; i < methodTable.length; ++i) { for (int i = 0; i < methodTable.length; ++i) {
if (methodTable[i].getName().equals(name) if (methodTable[i].getName().equals(name)
&& match(parameterTypes, methodTable[i].getParameterTypes())) && match(parameterTypes, methodTable[i].getParameterTypes()))
@ -438,4 +450,59 @@ public final class Class <T> {
public boolean desiredAssertionStatus() { public boolean desiredAssertionStatus() {
return false; return false;
} }
public T cast(Object o) {
return (T) o;
}
public Object[] getSigners() {
throw new UnsupportedOperationException();
}
public Annotation[] getDeclaredAnnotations() {
throw new UnsupportedOperationException();
}
public boolean isEnum() {
throw new UnsupportedOperationException();
}
public TypeVariable<Class<T>>[] getTypeParameters() {
throw new UnsupportedOperationException();
}
public String getSimpleName() {
throw new UnsupportedOperationException();
}
public Method getEnclosingMethod() {
throw new UnsupportedOperationException();
}
public Constructor getEnclosingConstructor() {
throw new UnsupportedOperationException();
}
public Class getEnclosingClass() {
throw new UnsupportedOperationException();
}
public Class[] getDeclaredClasses() {
throw new UnsupportedOperationException();
}
public <A extends Annotation> A getAnnotation(Class<A> c) {
throw new UnsupportedOperationException();
}
public ProtectionDomain getProtectionDomain() {
Permissions p = new Permissions();
p.add(new AllPermission());
return new ProtectionDomain(null, p);
}
// for GNU Classpath compatibility:
void setSigners(Object[] signers) {
throw new UnsupportedOperationException();
}
} }

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2008, Avian Contributors /* Copyright (c) 2008-2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided for any purpose with or without fee is hereby granted, provided
@ -11,8 +11,11 @@
package java.lang; package java.lang;
public class ClassNotFoundException extends Exception { public class ClassNotFoundException extends Exception {
private final Throwable cause2;
public ClassNotFoundException(String message, Throwable cause) { public ClassNotFoundException(String message, Throwable cause) {
super(message, cause); super(message, cause);
cause2 = cause;
} }
public ClassNotFoundException(String message) { public ClassNotFoundException(String message) {

View File

@ -53,4 +53,12 @@ public abstract class Enum<E extends Enum<E>> implements Comparable<E> {
public String toString() { public String toString() {
return name; return name;
} }
public Class<E> getDeclaringClass() {
Class c = getClass();
while (c.getSuperclass() != Enum.class) {
c = c.getSuperclass();
}
return c;
}
} }

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2008, Avian Contributors /* Copyright (c) 2008-2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided for any purpose with or without fee is hereby granted, provided
@ -11,11 +11,14 @@
package java.lang; package java.lang;
public class ExceptionInInitializerError extends Error { public class ExceptionInInitializerError extends Error {
private final Throwable cause2;
public ExceptionInInitializerError(String message) { public ExceptionInInitializerError(String message) {
super(message); super(message);
cause2 = null;
} }
public ExceptionInInitializerError() { public ExceptionInInitializerError() {
super(); this(null);
} }
} }

View File

@ -25,7 +25,7 @@ public class Object {
return this == o; return this == o;
} }
protected void finalize() { } protected void finalize() throws Throwable { }
public native final Class<? extends Object> getClass(); public native final Class<? extends Object> getClass();
@ -41,5 +41,14 @@ public class Object {
wait(0); wait(0);
} }
public native final void wait(long timeout) throws InterruptedException; public native final void wait(long milliseconds) throws InterruptedException;
public final void wait(long milliseconds, int nanoseconds)
throws InterruptedException
{
if (nanoseconds != 0) {
++ milliseconds;
}
wait(milliseconds);
}
} }

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2008, Avian Contributors /* Copyright (c) 2008-2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided for any purpose with or without fee is hereby granted, provided
@ -10,9 +10,9 @@
package java.lang; package java.lang;
public class StackOverflowError extends Error { public class StackOverflowError extends VirtualMachineError {
public StackOverflowError(String message) { public StackOverflowError(String message) {
super(message, null); super(message);
} }
public StackOverflowError() { public StackOverflowError() {

View File

@ -18,7 +18,7 @@ public class StackTraceElement {
private String file; private String file;
private int line; private int line;
private StackTraceElement(String class_, String method, String file, public StackTraceElement(String class_, String method, String file,
int line) int line)
{ {
this.class_ = class_; this.class_ = class_;
@ -56,7 +56,7 @@ public class StackTraceElement {
} }
public String getClassName() { public String getClassName() {
return class_; return class_.replace('/', '.');
} }
public String getMethodName() { public String getMethodName() {

View File

@ -12,14 +12,30 @@ package java.lang;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.Comparator;
import java.util.Locale;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.Serializable;
public final class String
implements Comparable<String>, CharSequence, Serializable
{
public static Comparator<String> CASE_INSENSITIVE_ORDER
= new Comparator<String>() {
public int compare(String a, String b) {
return a.compareToIgnoreCase(b);
}
};
public final class String implements Comparable<String>, CharSequence {
private final Object data; private final Object data;
private final int offset; private final int offset;
private final int length; private final int length;
private int hashCode; private int hashCode;
public String() {
this(new char[0], 0, 0);
}
public String(char[] data, int offset, int length, boolean copy) { public String(char[] data, int offset, int length, boolean copy) {
this((Object) data, offset, length, copy); this((Object) data, offset, length, copy);
} }
@ -32,9 +48,11 @@ public final class String implements Comparable<String>, CharSequence {
this(data, 0, data.length); this(data, 0, data.length);
} }
public String(byte bytes[], int offset, int length, String charsetName) throws UnsupportedEncodingException { public String(byte bytes[], int offset, int length, String charsetName)
throws UnsupportedEncodingException
{
this(bytes, offset, length); this(bytes, offset, length);
if (!charsetName.equals("UTF-8")) { if (! charsetName.equalsIgnoreCase("UTF-8")) {
throw new UnsupportedEncodingException(charsetName); throw new UnsupportedEncodingException(charsetName);
} }
} }
@ -64,6 +82,23 @@ public final class String implements Comparable<String>, CharSequence {
} }
} }
public String(byte bytes[], int highByte, int offset, int length) {
if (offset < 0 || offset + length > bytes.length) {
throw new IndexOutOfBoundsException
(offset + " < 0 or " + offset + " + " + length + " > " + bytes.length);
}
char[] c = new char[length];
int mask = highByte << 8;
for (int i = 0; i < length; ++i) {
c[i] = (char) ((bytes[offset + i] & 0xFF) | mask);
}
this.data = c;
this.offset = 0;
this.length = length;
}
private String(Object data, int offset, int length, boolean copy) { private String(Object data, int offset, int length, boolean copy) {
int l; int l;
if (data instanceof char[]) { if (data instanceof char[]) {
@ -200,7 +235,7 @@ public final class String implements Comparable<String>, CharSequence {
} }
public boolean equalsIgnoreCase(String s) { public boolean equalsIgnoreCase(String s) {
return this == s || compareToIgnoreCase(s) == 0; return this == s || (s != null && compareToIgnoreCase(s) == 0);
} }
public int compareTo(String s) { public int compareTo(String s) {
@ -381,7 +416,7 @@ public final class String implements Comparable<String>, CharSequence {
} }
} else { } else {
throw new IndexOutOfBoundsException throw new IndexOutOfBoundsException
(start + " not in (0, " + end + ") or " + end + " > " + length); (start + " not in [0, " + end + ") or " + end + " > " + length);
} }
} }
@ -534,6 +569,10 @@ public final class String implements Comparable<String>, CharSequence {
return Pattern.matches(regex, this); return Pattern.matches(regex, this);
} }
public String replaceAll(String regex, String replacement) {
return Pattern.compile(regex).matcher(this).replaceAll(replacement);
}
public native String intern(); public native String intern();
public static String valueOf(Object s) { public static String valueOf(Object s) {
@ -557,7 +596,9 @@ public final class String implements Comparable<String>, CharSequence {
} }
public static String valueOf(int v) { public static String valueOf(int v) {
return Integer.toString(v); // use Integer.toString(int, int), because GNU Classpath's
// Integer.toString(int) just calls String.valueOf(int):
return Integer.toString(v, 10);
} }
public static String valueOf(long v) { public static String valueOf(long v) {
@ -572,6 +613,14 @@ public final class String implements Comparable<String>, CharSequence {
return Double.toString(v); return Double.toString(v);
} }
public static String valueOf(char[] data, int offset, int length) {
return new String(data, offset, length);
}
public static String valueOf(char[] data) {
return valueOf(data, 0, data.length);
}
public int lastIndexOf(int ch, int lastIndex) { public int lastIndexOf(int ch, int lastIndex) {
for (int i = lastIndex ; i >= 0; --i) { for (int i = lastIndex ; i >= 0; --i) {
if (charAt(i) == ch) { if (charAt(i) == ch) {
@ -581,4 +630,63 @@ public final class String implements Comparable<String>, CharSequence {
return -1; return -1;
} }
public boolean regionMatches(int thisOffset, String match, int matchOffset,
int length)
{
return regionMatches(false, thisOffset, match, matchOffset, length);
}
public boolean regionMatches(boolean ignoreCase, int thisOffset,
String match, int matchOffset, int length)
{
String a = substring(thisOffset, thisOffset + length);
String b = match.substring(matchOffset, matchOffset + length);
if (ignoreCase) {
return a.equalsIgnoreCase(b);
} else {
return a.equals(b);
}
}
public boolean isEmpty() {
return length == 0;
}
public boolean contains(String match) {
return indexOf(match) != -1;
}
public int codePointAt(int offset) {
return Character.codePointAt(this, offset);
}
public int codePointCount(int start, int end) {
return Character.codePointCount(this, start, end);
}
public String replace(CharSequence match, CharSequence replacement) {
throw new UnsupportedOperationException();
}
public String toUpperCase(Locale locale) {
throw new UnsupportedOperationException();
}
public String toLowerCase(Locale locale) {
throw new UnsupportedOperationException();
}
// for GNU Classpath compatibility:
static char[] zeroBasedStringValue(String s) {
if (s.offset == 0) {
if (s.data instanceof char[]) {
char[] data = (char[]) s.data;
if (data.length == s.length) {
return data;
}
}
}
return s.toCharArray();
}
} }

View File

@ -10,7 +10,7 @@
package java.lang; package java.lang;
public class StringBuilder implements CharSequence { public class StringBuilder implements CharSequence, Appendable {
private static final int BufferSize = 32; private static final int BufferSize = 32;
private Cell chain; private Cell chain;
@ -54,6 +54,14 @@ public class StringBuilder implements CharSequence {
} }
} }
public StringBuilder append(CharSequence sequence) {
return append(sequence.toString());
}
public Appendable append(CharSequence sequence, int start, int end) {
return append(sequence.subSequence(start, end));
}
public StringBuilder append(char[] b, int offset, int length) { public StringBuilder append(char[] b, int offset, int length) {
return append(new String(b, offset, length)); return append(new String(b, offset, length));
} }
@ -150,6 +158,10 @@ public class StringBuilder implements CharSequence {
return this; return this;
} }
public StringBuilder insert(int i, CharSequence s) {
return insert(i, s.toString());
}
public StringBuilder insert(int i, char c) { public StringBuilder insert(int i, char c) {
return insert(i, new String(new char[] { c }, 0, 1, false)); return insert(i, new String(new char[] { c }, 0, 1, false));
} }
@ -332,4 +344,8 @@ public class StringBuilder implements CharSequence {
deleteCharAt(index); deleteCharAt(index);
insert(index, ch); insert(index, ch);
} }
public void ensureCapacity(int capacity) {
// ignore
}
} }

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2008, Avian Contributors /* Copyright (c) 2008-2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided for any purpose with or without fee is hereby granted, provided
@ -15,14 +15,30 @@ import java.util.WeakHashMap;
public class Thread implements Runnable { public class Thread implements Runnable {
private long peer; private long peer;
private boolean interrupted;
private boolean daemon;
private byte state;
private byte priority;
private final Runnable task; private final Runnable task;
private Map<ThreadLocal, Object> locals; private Map<ThreadLocal, Object> locals;
private boolean interrupted;
private Object sleepLock; private Object sleepLock;
private ClassLoader classLoader; private ClassLoader classLoader;
private String name; private UncaughtExceptionHandler exceptionHandler;
public Thread(Runnable task, String name) { // package private for GNU Classpath, which inexplicably bypasses
// the accessor methods:
String name;
ThreadGroup group;
private static UncaughtExceptionHandler defaultExceptionHandler;
public static final int MIN_PRIORITY = 1;
public static final int NORM_PRIORITY = 5;
public static final int MAX_PRIORITY = 10;
public Thread(ThreadGroup group, Runnable task, String name, long stackSize)
{
this.group = group;
this.task = task; this.task = task;
this.name = name; this.name = name;
@ -41,8 +57,28 @@ public class Thread implements Runnable {
classLoader = current.classLoader; classLoader = current.classLoader;
} }
public Thread(ThreadGroup group, Runnable task, String name) {
this(group, task, name, 0);
}
public Thread(ThreadGroup group, String name) {
this(null, null, name);
}
public Thread(Runnable task, String name) {
this(null, task, name);
}
public Thread(Runnable task) { public Thread(Runnable task) {
this(task, "Thread["+task+"]"); this(null, task, "Thread["+task+"]");
}
public Thread(String name) {
this(null, null, name);
}
public Thread() {
this((Runnable) null);
} }
public synchronized void start() { public synchronized void start() {
@ -58,6 +94,28 @@ public class Thread implements Runnable {
private native long doStart(); private native long doStart();
private static void run(Thread t) throws Throwable {
t.state = (byte) State.RUNNABLE.ordinal();
try {
t.run();
} catch (Throwable e) {
UncaughtExceptionHandler eh = t.exceptionHandler;
UncaughtExceptionHandler deh = defaultExceptionHandler;
if (eh != null) {
eh.uncaughtException(t, e);
} else if (deh != null) {
deh.uncaughtException(t, e);
} else {
throw e;
}
} finally {
synchronized (t) {
t.state = (byte) State.TERMINATED.ordinal();
t.notifyAll();
}
}
}
public void run() { public void run() {
if (task != null) { if (task != null) {
task.run(); task.run();
@ -101,6 +159,10 @@ public class Thread implements Runnable {
} }
} }
public static boolean isInterrupted() {
return currentThread().interrupted;
}
public static void sleep(long milliseconds) throws InterruptedException { public static void sleep(long milliseconds) throws InterruptedException {
Thread t = currentThread(); Thread t = currentThread();
if (t.sleepLock == null) { if (t.sleepLock == null) {
@ -111,6 +173,16 @@ public class Thread implements Runnable {
} }
} }
public static void sleep(long milliseconds, int nanoseconds)
throws InterruptedException
{
if (nanoseconds > 0) {
++ milliseconds;
}
sleep(milliseconds);
}
public StackTraceElement[] getStackTrace() { public StackTraceElement[] getStackTrace() {
return Throwable.resolveTrace(getStackTrace(peer)); return Throwable.resolveTrace(getStackTrace(peer));
} }
@ -125,4 +197,124 @@ public class Thread implements Runnable {
return name; return name;
} }
public void setName(String name) {
this.name = name;
}
public UncaughtExceptionHandler getUncaughtExceptionHandler() {
UncaughtExceptionHandler eh = exceptionHandler;
return (eh == null ? group : eh);
}
public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler() {
return defaultExceptionHandler;
}
public void setUncaughtExceptionHandler(UncaughtExceptionHandler h) {
exceptionHandler = h;
}
public static void setDefaultUncaughtExceptionHandler
(UncaughtExceptionHandler h)
{
defaultExceptionHandler = h;
}
public State getState() {
return State.values()[state];
}
public boolean isAlive() {
switch (getState()) {
case NEW:
case TERMINATED:
return false;
default:
return true;
}
}
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
if (priority < MIN_PRIORITY || priority > MAX_PRIORITY) {
throw new IllegalArgumentException();
}
this.priority = (byte) priority;
}
public boolean isDaemon() {
return daemon;
}
public void setDaemon(boolean v) {
daemon = v;
}
public static native void yield();
public synchronized void join() throws InterruptedException {
while (getState() != State.TERMINATED) {
wait();
}
}
public synchronized void join(long milliseconds) throws InterruptedException
{
long then = System.currentTimeMillis();
long remaining = milliseconds;
while (remaining > 0 && getState() != State.TERMINATED) {
wait(remaining);
remaining = milliseconds - (System.currentTimeMillis() - then);
}
}
public void join(long milliseconds, int nanoseconds)
throws InterruptedException
{
if (nanoseconds > 0) {
++ milliseconds;
}
join(milliseconds);
}
public ThreadGroup getThreadGroup() {
return group;
}
public static native boolean holdsLock(Object o);
public long getId() {
return peer;
}
public void stop() {
throw new UnsupportedOperationException();
}
public void stop(Throwable t) {
throw new UnsupportedOperationException();
}
public void suspend() {
throw new UnsupportedOperationException();
}
public void resume() {
throw new UnsupportedOperationException();
}
public interface UncaughtExceptionHandler {
public void uncaughtException(Thread t, Throwable e);
}
public enum State {
NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED
}
} }

View File

@ -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.lang;
public class ThreadDeath extends Error {
public ThreadDeath() { }
}

View File

@ -0,0 +1,35 @@
/* 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.lang;
public class ThreadGroup implements Thread.UncaughtExceptionHandler {
private final ThreadGroup parent;
private final String name;
public ThreadGroup(ThreadGroup parent, String name) {
this.parent = parent;
this.name = name;
}
public void uncaughtException(Thread t, Throwable e) {
if (parent != null) {
parent.uncaughtException(t, e);
} else {
Thread.UncaughtExceptionHandler deh
= Thread.getDefaultUncaughtExceptionHandler();
if (deh != null) {
deh.uncaughtException(t, e);
} else if (! (e instanceof ThreadDeath)) {
e.printStackTrace();
}
}
}
}

View File

@ -13,8 +13,9 @@ package java.lang;
import java.io.PrintStream; import java.io.PrintStream;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.IOException; import java.io.IOException;
import java.io.Serializable;
public class Throwable { public class Throwable implements Serializable {
private String message; private String message;
private Object trace; private Object trace;
private Throwable cause; private Throwable cause;
@ -109,4 +110,9 @@ public class Throwable {
cause.printStackTrace(sb, nl); cause.printStackTrace(sb, nl);
} }
} }
public Throwable fillInStackTrace() {
trace = trace(0);
return this;
}
} }

View File

@ -0,0 +1,21 @@
/* 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.lang;
public class VirtualMachineError extends Error {
public VirtualMachineError(String message) {
super(message);
}
public VirtualMachineError() {
this(null);
}
}

View File

@ -22,6 +22,10 @@ public abstract class Reference<T> {
this.queue = queue; this.queue = queue;
} }
protected Reference(T target) {
this(target, null);
}
public T get() { public T get() {
return target; return target;
} }

View File

@ -10,7 +10,9 @@
package java.lang.reflect; package java.lang.reflect;
public class Constructor<T> extends AccessibleObject implements Member { public class Constructor<T> extends AccessibleObject
implements Member, GenericDeclaration
{
private Method<T> method; private Method<T> method;
public Constructor(Method<T> method) { public Constructor(Method<T> method) {
@ -46,6 +48,18 @@ public class Constructor<T> extends AccessibleObject implements Member {
return method.getName(); return method.getName();
} }
public boolean isSynthetic() {
return method.isSynthetic();
}
public TypeVariable<Constructor<T>>[] getTypeParameters() {
throw new UnsupportedOperationException();
}
public Type[] getGenericParameterTypes() {
return method.getGenericParameterTypes();
}
private static native <T> T make(Class<T> c); private static native <T> T make(Class<T> c);
public T newInstance(Object ... arguments) public T newInstance(Object ... arguments)

View File

@ -101,6 +101,38 @@ public class Field<T> extends AccessibleObject {
} }
} }
public boolean getBoolean(Object instance) throws IllegalAccessException {
return ((Boolean) get(instance)).booleanValue();
}
public byte getByte(Object instance) throws IllegalAccessException {
return ((Byte) get(instance)).byteValue();
}
public short getShort(Object instance) throws IllegalAccessException {
return ((Short) get(instance)).shortValue();
}
public char getChar(Object instance) throws IllegalAccessException {
return ((Character) get(instance)).charValue();
}
public int getInt(Object instance) throws IllegalAccessException {
return ((Integer) get(instance)).intValue();
}
public float getFloat(Object instance) throws IllegalAccessException {
return ((Float) get(instance)).floatValue();
}
public long getLong(Object instance) throws IllegalAccessException {
return ((Long) get(instance)).longValue();
}
public double getDouble(Object instance) throws IllegalAccessException {
return ((Double) get(instance)).doubleValue();
}
public void set(Object instance, Object value) public void set(Object instance, Object value)
throws IllegalAccessException throws IllegalAccessException
{ {
@ -162,6 +194,10 @@ public class Field<T> extends AccessibleObject {
} }
} }
public boolean isEnumConstant() {
throw new UnsupportedOperationException();
}
private static native long getPrimitive private static native long getPrimitive
(Object instance, int code, int offset); (Object instance, int code, int offset);

View File

@ -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.lang.reflect;
public interface GenericDeclaration {
public TypeVariable<?>[] getTypeParameters();
}

View File

@ -19,4 +19,6 @@ public interface Member {
public int getModifiers(); public int getModifiers();
public String getName(); public String getName();
public boolean isSynthetic();
} }

View File

@ -10,7 +10,9 @@
package java.lang.reflect; package java.lang.reflect;
public class Method<T> extends AccessibleObject implements Member { public class Method<T> extends AccessibleObject
implements Member, GenericDeclaration
{
private byte vmFlags; private byte vmFlags;
private byte returnCode; private byte returnCode;
private byte parameterCount; private byte parameterCount;
@ -124,4 +126,28 @@ public class Method<T> extends AccessibleObject implements Member {
} }
throw new RuntimeException(); throw new RuntimeException();
} }
public boolean isSynthetic() {
throw new UnsupportedOperationException();
}
public Object getDefaultValue() {
throw new UnsupportedOperationException();
}
public Type[] getGenericParameterTypes() {
throw new UnsupportedOperationException();
}
public Type getGenericReturnType() {
throw new UnsupportedOperationException();
}
public Class[] getExceptionTypes() {
throw new UnsupportedOperationException();
}
public TypeVariable<Method<T>>[] getTypeParameters() {
throw new UnsupportedOperationException();
}
} }

View File

@ -0,0 +1,13 @@
/* 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.lang.reflect;
public interface Type { }

View File

@ -0,0 +1,19 @@
/* 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.lang.reflect;
public interface TypeVariable<T extends GenericDeclaration>
extends Type
{
public Type[] getBounds();
public T getGenericDeclaration();
public String getName();
}

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2008, Avian Contributors /* Copyright (c) 2008-2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided for any purpose with or without fee is hereby granted, provided
@ -11,7 +11,6 @@
package java.net; package java.net;
import java.io.IOException; import java.io.IOException;
import java.io.FileNotFoundException;
import java.io.InputStream; import java.io.InputStream;
public final class URL { public final class URL {
@ -73,7 +72,7 @@ public final class URL {
throws MalformedURLException throws MalformedURLException
{ {
if ("resource".equals(protocol)) { if ("resource".equals(protocol)) {
return new ResourceHandler(); return new avian.resource.Handler();
} else { } else {
throw new MalformedURLException("unknown protocol: " + protocol); throw new MalformedURLException("unknown protocol: " + protocol);
} }
@ -88,87 +87,4 @@ public final class URL {
this.file = file; this.file = file;
this.ref = ref; this.ref = ref;
} }
private static class ResourceHandler extends URLStreamHandler {
protected URLConnection openConnection(URL url) {
return new ResourceConnection(url);
}
}
private static class ResourceConnection extends URLConnection {
public ResourceConnection(URL url) {
super(url);
}
public int getContentLength() {
return ResourceInputStream.getContentLength(url.getFile());
}
public InputStream getInputStream() throws IOException {
return new ResourceInputStream(url.getFile());
}
}
private static class ResourceInputStream extends InputStream {
private long peer;
private int position;
public ResourceInputStream(String path) throws IOException {
peer = open(path);
if (peer == 0) {
throw new FileNotFoundException(path);
}
}
private static native int getContentLength(String path);
private static native long open(String path) throws IOException;
private static native int read(long peer, int position) throws IOException;
private static native int read(long peer, int position,
byte[] b, int offset, int length)
throws IOException;
public static native void close(long peer) throws IOException;
public int read() throws IOException {
if (peer != 0) {
int c = read(peer, position);
if (c >= 0) {
++ position;
}
return c;
} else {
throw new IOException();
}
}
public int read(byte[] b, int offset, int length) throws IOException {
if (peer != 0) {
if (b == null) {
throw new NullPointerException();
}
if (offset < 0 || offset + length > b.length) {
throw new ArrayIndexOutOfBoundsException();
}
int c = read(peer, position, b, offset, length);
if (c >= 0) {
position += c;
}
return c;
} else {
throw new IOException();
}
}
public void close() throws IOException {
if (peer != 0) {
close(peer);
peer = 0;
}
}
}
} }

View File

@ -0,0 +1,13 @@
/* 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.security;
public class AllPermission extends Permission { }

View File

@ -0,0 +1,13 @@
/* 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.security;
public class CodeSource { }

View File

@ -0,0 +1,17 @@
/* 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.security;
public abstract class Permission {
public PermissionCollection newPermissionCollection() {
return null;
}
}

View File

@ -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.security;
public abstract class PermissionCollection {
public abstract void add(Permission p);
}

View File

@ -0,0 +1,41 @@
/* 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.security;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.HashSet;
public class Permissions extends PermissionCollection {
private final Map<Class,PermissionCollection> collections = new HashMap();
public void add(Permission p) {
Class c = p.getClass();
PermissionCollection pc = collections.get(c);
if (pc == null) {
pc = p.newPermissionCollection();
if (pc == null) {
pc = new MyPermissionCollection();
}
collections.put(c, pc);
}
pc.add(p);
}
private static class MyPermissionCollection extends PermissionCollection {
private final Set<Permission> permissions = new HashSet();
public void add(Permission p) {
permissions.add(p);
}
}
}

View File

@ -0,0 +1,23 @@
/* 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.security;
public class ProtectionDomain {
private final CodeSource codeSource;
private final PermissionCollection permissions;
public ProtectionDomain(CodeSource codeSource,
PermissionCollection permissions)
{
this.codeSource = codeSource;
this.permissions = permissions;
}
}

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2008, Avian Contributors /* Copyright (c) 2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided for any purpose with or without fee is hereby granted, provided
@ -10,6 +10,9 @@
package java.util; package java.util;
import avian.PersistentSet;
import avian.Cell;
public class TreeSet<T> extends AbstractSet<T> implements Collection<T> { public class TreeSet<T> extends AbstractSet<T> implements Collection<T> {
private PersistentSet<Cell<T>> set; private PersistentSet<Cell<T>> set;
private int size; private int size;

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2008, Avian Contributors /* Copyright (c) 2008-2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided for any purpose with or without fee is hereby granted, provided
@ -63,7 +63,7 @@ public class ZipFile {
return index.size(); return index.size();
} }
public Enumeration<ZipEntry> entries() { public Enumeration<? extends ZipEntry> entries() {
return new MyEnumeration(window, index.values().iterator()); return new MyEnumeration(window, index.values().iterator());
} }

148
makefile
View File

@ -18,10 +18,6 @@ bootimage-platform = \
$(subst cygwin,windows,$(subst mingw32,windows,$(build-platform))) $(subst cygwin,windows,$(subst mingw32,windows,$(build-platform)))
platform = $(bootimage-platform) platform = $(bootimage-platform)
ifeq ($(platform),windows)
arch = i386
endif
mode = fast mode = fast
process = compile process = compile
@ -43,6 +39,23 @@ endif
ifeq ($(continuations),true) ifeq ($(continuations),true)
options := $(options)-continuations options := $(options)-continuations
endif 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)) root = $(shell (cd .. && pwd))
build = build build = build
@ -53,6 +66,12 @@ src = src
classpath = classpath classpath = classpath
test = test test = test
ifdef gnu
avian-classpath-build = $(build)/avian-classpath
else
avian-classpath-build = $(classpath-build)
endif
input = List input = List
build-cxx = g++ 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 \ common-cflags = $(warnings) -fno-rtti -fno-exceptions -fno-omit-frame-pointer \
"-I$(JAVA_HOME)/include" -idirafter $(src) -I$(native-build) \ "-I$(JAVA_HOME)/include" -idirafter $(src) -I$(native-build) \
-D__STDC_LIMIT_MACROS -D_JNI_IMPLEMENTATION_ -DAVIAN_VERSION=\"$(version)\" \ -D__STDC_LIMIT_MACROS -D_JNI_IMPLEMENTATION_ -DAVIAN_VERSION=\"$(version)\" \
$(gnu-cflags)
build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \ build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \
"-I$(JAVA_HOME)/include/linux" -I$(src) -pthread "-I$(JAVA_HOME)/include/linux" -I$(src) -pthread
cflags = $(build-cflags) cflags = $(build-cflags)
common-lflags = -lm -lz common-lflags = -lm -lz $(gnu-lflags)
build-lflags = build-lflags =
@ -167,6 +187,21 @@ ifeq ($(platform),windows)
native-path = cygpath -m native-path = cygpath -m
endif endif
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 endif
ifeq ($(mode),debug) ifeq ($(mode),debug)
@ -232,7 +267,8 @@ vm-sources = \
$(src)/$(process).cpp \ $(src)/$(process).cpp \
$(src)/builtin.cpp \ $(src)/builtin.cpp \
$(src)/jnienv.cpp \ $(src)/jnienv.cpp \
$(src)/process.cpp $(src)/process.cpp \
$(gnu-sources)
vm-asm-sources = $(src)/$(asm).S vm-asm-sources = $(src)/$(asm).S
@ -314,16 +350,43 @@ classpath-sources = $(shell find $(classpath) -name '*.java')
classpath-classes = \ classpath-classes = \
$(call java-classes,$(classpath-sources),$(classpath),$(classpath-build)) $(call java-classes,$(classpath-sources),$(classpath),$(classpath-build))
classpath-object = $(native-build)/classpath-jar.o 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-sources = $(wildcard $(test)/*.java)
test-classes = $(call java-classes,$(test-sources),$(test),$(test-build)) 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-sources = $(wildcard $(test)/extra/*.java)
test-extra-classes = \ test-extra-classes = \
$(call java-classes,$(test-extra-sources),$(test),$(test-build)) $(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-name = $(patsubst $(1)/%.class,%,$(2))
class-names = $(foreach x,$(2),$(call class-name,$(1),$(x))) class-names = $(foreach x,$(2),$(call class-name,$(1),$(x)))
@ -393,11 +456,24 @@ $(native-build)/type-generator.o: \
$(classpath-build)/%.class: $(classpath)/%.java $(classpath-build)/%.class: $(classpath)/%.java
@echo $(<) @echo $(<)
$(classpath-dep): $(classpath-sources) $(classpath-dep): $(classpath-sources) $(gnu-jar)
@echo "compiling classpath classes" @echo "compiling classpath classes"
@mkdir -p $(dir $(@)) @mkdir -p $(avian-classpath-build)
$(javac) -d $(dir $(@)) -bootclasspath $(classpath-build) \ $(javac) -d $(avian-classpath-build) \
-bootclasspath $(avian-classpath-build) \
$(shell $(MAKE) -s --no-print-directory $(classpath-classes)) $(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 $(@) @touch $(@)
$(test-build)/%.class: $(test)/%.java $(test-build)/%.class: $(test)/%.java
@ -405,16 +481,16 @@ $(test-build)/%.class: $(test)/%.java
$(test-dep): $(test-sources) $(test-dep): $(test-sources)
@echo "compiling test classes" @echo "compiling test classes"
@mkdir -p $(dir $(@)) @mkdir -p $(test-build)
$(javac) -d $(dir $(@)) -bootclasspath $(classpath-build) \ $(javac) -d $(test-build) -bootclasspath $(classpath-build) \
$(shell $(MAKE) -s --no-print-directory $(test-classes)) $(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 test/Subroutine.java
@touch $(@) @touch $(@)
$(test-extra-dep): $(test-extra-sources) $(test-extra-dep): $(test-extra-sources)
@echo "compiling extra test classes" @echo "compiling extra test classes"
@mkdir -p $(dir $(@)) @mkdir -p $(test-build)
$(javac) -d $(test-build) -bootclasspath $(classpath-build) \ $(javac) -d $(test-build) -bootclasspath $(classpath-build) \
$(shell $(MAKE) -s --no-print-directory $(test-extra-classes)) $(shell $(MAKE) -s --no-print-directory $(test-extra-classes))
@touch $(@) @touch $(@)
@ -456,9 +532,9 @@ $(boot-object): $(boot-source)
$(compile-object) $(compile-object)
$(build)/classpath.jar: $(classpath-dep) $(build)/classpath.jar: $(classpath-dep)
(wd=$$(pwd); \ (wd=$$(pwd) && \
cd $(classpath-build); \ cd $(classpath-build) && \
$(jar) c0f "$$($(native-path) "$${wd}/$(@)")" $$(find . -name '*.class')) $(jar) c0f "$$($(native-path) "$${wd}/$(@)")" .)
$(binaryToMacho): $(src)/binaryToMacho.cpp $(binaryToMacho): $(src)/binaryToMacho.cpp
$(cxx) $(^) -o $(@) $(cxx) $(^) -o $(@)
@ -469,8 +545,8 @@ ifeq ($(platform),darwin)
$(binaryToMacho) $(asm) $(build)/classpath.jar __TEXT __text \ $(binaryToMacho) $(asm) $(build)/classpath.jar __TEXT __text \
__binary_classpath_jar_start __binary_classpath_jar_end > $(@) __binary_classpath_jar_start __binary_classpath_jar_end > $(@)
else else
(wd=$$(pwd); \ (wd=$$(pwd) && \
cd $(build); \ cd $(build) && \
$(objcopy) -I binary classpath.jar \ $(objcopy) -I binary classpath.jar \
-O $(object-format) -B $(object-arch) "$${wd}/$(@)") -O $(object-format) -B $(object-arch) "$${wd}/$(@)")
endif endif
@ -484,10 +560,11 @@ $(generator-objects): $(native-build)/%.o: $(src)/%.cpp
$(jni-objects): $(native-build)/%.o: $(classpath)/%.cpp $(jni-objects): $(native-build)/%.o: $(classpath)/%.cpp
$(compile-object) $(compile-object)
$(static-library): $(gnu-object-dep)
$(static-library): $(vm-objects) $(jni-objects) $(vm-heapwalk-objects) $(static-library): $(vm-objects) $(jni-objects) $(vm-heapwalk-objects)
@echo "creating $(@)" @echo "creating $(@)"
rm -rf $(@) rm -rf $(@)
$(ar) cru $(@) $(^) $(ar) cru $(@) $(^) $(call gnu-objects)
$(ranlib) $(@) $(ranlib) $(@)
$(bootimage-bin): $(bootimage-generator) $(bootimage-bin): $(bootimage-generator)
@ -499,24 +576,32 @@ ifeq ($(platform),darwin)
$(binaryToMacho) $(asm) $(<) __BOOT __boot \ $(binaryToMacho) $(asm) $(<) __BOOT __boot \
__binary_bootimage_bin_start __binary_bootimage_bin_end > $(@) __binary_bootimage_bin_start __binary_bootimage_bin_end > $(@)
else else
(wd=$$(pwd); \ (wd=$$(pwd) && \
cd $(native-build); \ cd $(native-build) && \
$(objcopy) --rename-section=.data=.boot -I binary bootimage.bin \ $(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" \ $(objcopy) --set-section-flags .boot=alloc,load,code "$${wd}/$(@).tmp" \
"$${wd}/$(@)") "$${wd}/$(@)")
endif 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): \ $(executable): \
$(vm-objects) $(jni-objects) $(driver-object) $(vm-heapwalk-objects) \ $(vm-objects) $(jni-objects) $(driver-object) $(vm-heapwalk-objects) \
$(boot-object) $(vm-classpath-object) $(boot-object) $(vm-classpath-object)
@echo "linking $(@)" @echo "linking $(@)"
ifeq ($(platform),windows) ifeq ($(platform),windows)
$(dlltool) -z $(@).def $(^) $(dlltool) -z $(@).def $(^) $(call gnu-objects)
$(dlltool) -d $(@).def -e $(@).exp $(dlltool) -d $(@).def -e $(@).exp
$(cc) $(@).exp $(^) $(lflags) -o $(@) $(cc) $(@).exp $(^) $(call gnu-objects) $(lflags) -o $(@)
else else
$(cc) $(^) $(rdynamic) $(lflags) $(bootimage-lflags) -o $(@) $(cc) $(^) $(call gnu-objects) $(rdynamic) $(lflags) $(bootimage-lflags) \
-o $(@)
endif endif
$(strip) $(strip-all) $(@) $(strip) $(strip-all) $(@)
@ -545,11 +630,13 @@ else
$(cc) $(^) $(rdynamic) $(lflags) -o $(@) $(cc) $(^) $(rdynamic) $(lflags) -o $(@)
endif endif
$(dynamic-library): $(gnu-object-dep)
$(dynamic-library): \ $(dynamic-library): \
$(vm-objects) $(dynamic-object) $(jni-objects) $(vm-heapwalk-objects) \ $(vm-objects) $(dynamic-object) $(jni-objects) $(vm-heapwalk-objects) \
$(boot-object) $(vm-classpath-object) $(boot-object) $(vm-classpath-object) $(gnu-libraries)
@echo "linking $(@)" @echo "linking $(@)"
$(cc) $(^) $(shared) $(lflags) $(bootimage-lflags) -o $(@) $(cc) $(^) $(call gnu-objects) $(shared) $(lflags) $(bootimage-lflags) \
-o $(@)
$(strip) $(strip-all) $(@) $(strip) $(strip-all) $(@)
$(executable-dynamic): $(driver-dynamic-object) $(dynamic-library) $(executable-dynamic): $(driver-dynamic-object) $(dynamic-library)
@ -560,4 +647,3 @@ $(executable-dynamic): $(driver-dynamic-object) $(dynamic-library)
$(generator): $(generator-objects) $(generator): $(generator-objects)
@echo "linking $(@)" @echo "linking $(@)"
$(build-cc) $(^) $(build-lflags) -o $(@) $(build-cc) $(^) $(build-lflags) -o $(@)

View File

@ -303,6 +303,10 @@ writeBootImage(Thread* t, FILE* out, BootImage* image, uint8_t* code,
(t->m->heap->allocate(heapMapSize(HeapCapacity))); (t->m->heap->allocate(heapMapSize(HeapCapacity)));
memset(heapMap, 0, heapMapSize(HeapCapacity)); memset(heapMap, 0, heapMapSize(HeapCapacity));
// this map will not be used when the bootimage is loaded, so
// there's no need to preserve it:
t->m->byteArrayMap = makeWeakHashMap(t, 0, 0);
collect(t, Heap::MajorCollection); collect(t, Heap::MajorCollection);
HeapWalker* heapWalker = makeHeapImage HeapWalker* heapWalker = makeHeapImage

View File

@ -63,6 +63,25 @@ enumerateThreads(Thread* t, Thread* x, object array, unsigned* index,
} }
} }
bool
compatibleArrayTypes(Thread* t, object a, object b)
{
return classArrayElementSize(t, a)
and classArrayElementSize(t, b)
and (a == b
or (not ((classVmFlags(t, a) & PrimitiveFlag)
or (classVmFlags(t, b) & PrimitiveFlag))));
}
void
runOnLoadIfFound(Thread* t, System::Library* library)
{
void* p = library->resolve("JNI_OnLoad");
if (p) {
reinterpret_cast<jint (JNICALL *)(Machine*, void*)>(p)(t->m, 0);
}
}
} // namespace } // namespace
extern "C" JNIEXPORT int64_t JNICALL extern "C" JNIEXPORT int64_t JNICALL
@ -530,7 +549,9 @@ Avian_java_lang_System_arraycopy
int32_t length = arguments[4]; int32_t length = arguments[4];
if (LIKELY(src and dst)) { if (LIKELY(src and dst)) {
if (LIKELY(objectClass(t, src) == objectClass(t, dst))) { if (LIKELY(compatibleArrayTypes
(t, objectClass(t, src), objectClass(t, dst))))
{
unsigned elementSize = classArrayElementSize(t, objectClass(t, src)); unsigned elementSize = classArrayElementSize(t, objectClass(t, src));
if (LIKELY(elementSize)) { if (LIKELY(elementSize)) {
@ -602,6 +623,10 @@ Avian_java_lang_Runtime_load
and (s[length] == ',' or s[length] == 0)) and (s[length] == ',' or s[length] == 0))
{ {
// library is built in to this executable // library is built in to this executable
if (not t->m->triedBuiltinOnLoad) {
t->m->triedBuiltinOnLoad = true;
runOnLoadIfFound(t, t->m->libraries);
}
return; return;
} else { } else {
while (*s and *s != ',') ++ s; while (*s and *s != ',') ++ s;
@ -625,6 +650,7 @@ Avian_java_lang_Runtime_load
System::Library* lib; System::Library* lib;
if (LIKELY(t->m->system->success(t->m->system->load(&lib, n, mapName)))) { if (LIKELY(t->m->system->success(t->m->system->load(&lib, n, mapName)))) {
last->setNext(lib); last->setNext(lib);
runOnLoadIfFound(t, lib);
} else { } else {
object message = makeString(t, "library not found: %s", n); object message = makeString(t, "library not found: %s", n);
t->exception = makeUnsatisfiedLinkError(t, message); t->exception = makeUnsatisfiedLinkError(t, message);
@ -836,7 +862,7 @@ Avian_java_lang_Thread_enumerate
} }
extern "C" JNIEXPORT int64_t JNICALL extern "C" JNIEXPORT int64_t JNICALL
Avian_java_net_URL_00024ResourceInputStream_getContentLength Avian_avian_resource_Handler_00024ResourceInputStream_getContentLength
(Thread* t, object, uintptr_t* arguments) (Thread* t, object, uintptr_t* arguments)
{ {
object path = reinterpret_cast<object>(*arguments); object path = reinterpret_cast<object>(*arguments);
@ -856,7 +882,7 @@ Avian_java_net_URL_00024ResourceInputStream_getContentLength
} }
extern "C" JNIEXPORT int64_t JNICALL extern "C" JNIEXPORT int64_t JNICALL
Avian_java_net_URL_00024ResourceInputStream_open Avian_avian_resource_Handler_00024ResourceInputStream_open
(Thread* t, object, uintptr_t* arguments) (Thread* t, object, uintptr_t* arguments)
{ {
object path = reinterpret_cast<object>(*arguments); object path = reinterpret_cast<object>(*arguments);
@ -873,7 +899,7 @@ Avian_java_net_URL_00024ResourceInputStream_open
} }
extern "C" JNIEXPORT int64_t JNICALL extern "C" JNIEXPORT int64_t JNICALL
Avian_java_net_URL_00024ResourceInputStream_read__JI Avian_avian_resource_Handler_00024ResourceInputStream_read__JI
(Thread*, object, uintptr_t* arguments) (Thread*, object, uintptr_t* arguments)
{ {
int64_t peer; memcpy(&peer, arguments, 8); int64_t peer; memcpy(&peer, arguments, 8);
@ -888,7 +914,7 @@ Avian_java_net_URL_00024ResourceInputStream_read__JI
} }
extern "C" JNIEXPORT int64_t JNICALL extern "C" JNIEXPORT int64_t JNICALL
Avian_java_net_URL_00024ResourceInputStream_read__JI_3BII Avian_avian_resource_Handler_00024ResourceInputStream_read__JI_3BII
(Thread* t, object, uintptr_t* arguments) (Thread* t, object, uintptr_t* arguments)
{ {
int64_t peer; memcpy(&peer, arguments, 8); int64_t peer; memcpy(&peer, arguments, 8);
@ -913,7 +939,7 @@ Avian_java_net_URL_00024ResourceInputStream_read__JI_3BII
} }
extern "C" JNIEXPORT void JNICALL extern "C" JNIEXPORT void JNICALL
Avian_java_net_URL_00024ResourceInputStream_close Avian_avian_resource_Handler_00024ResourceInputStream_close
(Thread*, object, uintptr_t* arguments) (Thread*, object, uintptr_t* arguments)
{ {
int64_t peer; memcpy(&peer, arguments, 8); int64_t peer; memcpy(&peer, arguments, 8);

View File

@ -40,10 +40,17 @@
# define ULD "u" # define ULD "u"
#endif #endif
#elif defined __x86_64__ #elif defined __x86_64__
# ifdef __MINGW32__
# define LD "I64d"
# define LX "I64x"
# define LLD "I64d"
# define ULD "I64x"
# else
# define LD "ld" # define LD "ld"
# define LX "lx" # define LX "lx"
# define LLD "ld" # define LLD "ld"
# define ULD "lu" # define ULD "lu"
# endif
#else #else
# error "Unsupported architecture" # error "Unsupported architecture"
#endif #endif
@ -115,7 +122,6 @@ pad(unsigned n)
return pad(n, BytesPerWord); return pad(n, BytesPerWord);
} }
inline unsigned inline unsigned
ceiling(unsigned n, unsigned d) ceiling(unsigned n, unsigned d)
{ {

View File

@ -22,18 +22,139 @@
#ifdef __x86_64__ #ifdef __x86_64__
#define THREAD_CONTINUATION 168 #ifdef __MINGW32__
#define THREAD_EXCEPTION 64
#define THREAD_EXCEPTION_STACK_ADJUSTMENT 176
#define THREAD_EXCEPTION_OFFSET 184
#define THREAD_EXCEPTION_HANDLER 192
#define CONTINUATION_NEXT 8 #define CALLEE_SAVED_REGISTER_FOOTPRINT 64
#define CONTINUATION_ADDRESS 32
#define CONTINUATION_RETURN_ADDRESS_OFFSET 40 .globl GLOBAL(vmInvoke)
#define CONTINUATION_FRAME_POINTER_OFFSET 48 GLOBAL(vmInvoke):
#define CONTINUATION_LENGTH 56 pushq %rbp
#define CONTINUATION_BODY 64 movq %rsp,%rbp
// %rcx: thread
// %rdx: function
// %r8 : arguments
// %r9 : argumentsFootprint
// 48(%rbp) : frameSize
// 56(%rbp) : returnType (ignored)
// allocate stack space, adding room for callee-saved registers
movl 48(%rbp),%eax
subq %rax,%rsp
subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%rsp
// save callee-saved registers
movq %rsp,%r11
addq %rax,%r11
movq %rbx,0(%r11)
movq %r12,8(%r11)
movq %r13,16(%r11)
movq %r14,24(%r11)
movq %r15,32(%r11)
movq %rsi,40(%r11)
movq %rdi,48(%r11)
// we use rbx to hold the thread pointer, by convention
mov %rcx,%rbx
// copy arguments into place
movq $0,%r11
jmp LOCAL(vmInvoke_argumentTest)
LOCAL(vmInvoke_argumentLoop):
movq (%r8,%r11,1),%rsi
movq %rsi,(%rsp,%r11,1)
addq $8,%r11
LOCAL(vmInvoke_argumentTest):
cmpq %r9,%r11
jb LOCAL(vmInvoke_argumentLoop)
// call function
call *%rdx
.globl GLOBAL(vmInvoke_returnAddress)
GLOBAL(vmInvoke_returnAddress):
// restore stack pointer
movq %rbp,%rsp
#ifdef AVIAN_CONTINUATIONS
# include "continuations-x86.S"
#endif // AVIAN_CONTINUATIONS
// restore callee-saved registers (below the stack pointer, but in
// the red zone)
movq %rsp,%r11
subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%r11
movq 0(%r11),%rbx
movq 8(%r11),%r12
movq 16(%r11),%r13
movq 24(%r11),%r14
movq 32(%r11),%r15
movq 40(%r11),%rsi
movq 48(%r11),%rdi
// return
popq %rbp
ret
.globl GLOBAL(vmJumpAndInvoke)
GLOBAL(vmJumpAndInvoke):
#ifdef AVIAN_CONTINUATIONS
// %rcx: thread
// %rdx: address
// %r8 : base
// %r9 : (unused)
// 8(%rsp): argumentFootprint
// 16(%rsp): arguments
// 24(%rsp): frameSize
movq %r8,%rbp
// restore (pseudo)-stack pointer (we don't want to touch the real
// stack pointer, since we haven't copied the arguments yet)
movq %rbp,%r9
// allocate new frame, adding room for callee-saved registers
movl 24(%rsp),%eax
subq %rax,%r9
subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%r9
movq %rcx,%rbx
// set return address
movq vmInvoke_returnAddress@GOTPCREL(%rip),%r10
movq %r10,(%r9)
// copy arguments into place
movq $0,%r11
movq 16(%rsp),%r8
movq 8(%rsp),%rax
jmp LOCAL(vmJumpAndInvoke_argumentTest)
LOCAL(vmJumpAndInvoke_argumentLoop):
movq (%r8,%r11,1),%r10
movq %r10,8(%r9,%r11,1)
addq $8,%r11
LOCAL(vmJumpAndInvoke_argumentTest):
cmpq %rax,%r11
jb LOCAL(vmJumpAndInvoke_argumentLoop)
// the arguments have been copied, so we can set the real stack
// pointer now
movq %r9,%rsp
jmp *%rdx
#else // not AVIAN_CONTINUATIONS
// vmJumpAndInvoke should only be called when continuations are
// enabled
int3
#endif // not AVIAN_CONTINUATIONS
#else // not __MINGW32__
#define CALLEE_SAVED_REGISTER_FOOTPRINT 48 #define CALLEE_SAVED_REGISTER_FOOTPRINT 48
@ -88,65 +209,7 @@ GLOBAL(vmInvoke_returnAddress):
movq %rbp,%rsp movq %rbp,%rsp
#ifdef AVIAN_CONTINUATIONS #ifdef AVIAN_CONTINUATIONS
// call the next continuation, if any # include "continuations-x86.S"
movq THREAD_CONTINUATION(%rbx),%rcx
cmpq $0,%rcx
je LOCAL(vmInvoke_exit)
// allocate a frame of size (continuation.length * BYTES_PER_WORD)
// + CALLEE_SAVED_REGISTER_FOOTPRINT
movq CONTINUATION_LENGTH(%rcx),%rsi
shlq $3,%rsi
subq %rsi,%rsp
subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%rsp
// copy the continuation body into the frame
leaq CONTINUATION_BODY(%rcx),%rdi
movq $0,%r9
jmp LOCAL(vmInvoke_continuationTest)
LOCAL(vmInvoke_continuationLoop):
movq (%rdi,%r9,1),%r8
movq %r8,(%rsp,%r9,1)
addq $8,%r9
LOCAL(vmInvoke_continuationTest):
cmpq %rsi,%r9
jb LOCAL(vmInvoke_continuationLoop)
// set the return address to vmInvoke_returnAddress
movq CONTINUATION_RETURN_ADDRESS_OFFSET(%rcx),%rdi
movq vmInvoke_returnAddress@GOTPCREL(%rip),%r10
movq %r10,(%rsp,%rdi,1)
// save the current base pointer in the frame and update it
movq CONTINUATION_FRAME_POINTER_OFFSET(%rcx),%rdi
movq %rbp,(%rsp,%rdi,1)
addq %rsp,%rdi
movq %rdi,%rbp
// consume the continuation
movq CONTINUATION_NEXT(%rcx),%rdi
movq %rdi,THREAD_CONTINUATION(%rbx)
// call the continuation unless we're handling an exception
movq THREAD_EXCEPTION(%rbx),%rsi
cmpq $0,%rsi
jne LOCAL(vmInvoke_handleException)
jmp *CONTINUATION_ADDRESS(%rcx)
LOCAL(vmInvoke_handleException):
// we're handling an exception - call the exception handler instead
movq $0,THREAD_EXCEPTION(%rbx)
movq THREAD_EXCEPTION_STACK_ADJUSTMENT(%rbx),%rdi
subq %rdi,%rsp
movq THREAD_EXCEPTION_OFFSET(%rbx),%rdi
movq %rsi,(%rsp,%rdi,1)
jmp *THREAD_EXCEPTION_HANDLER(%rbx)
LOCAL(vmInvoke_exit):
#endif // AVIAN_CONTINUATIONS #endif // AVIAN_CONTINUATIONS
// restore callee-saved registers (below the stack pointer, but in // restore callee-saved registers (below the stack pointer, but in
@ -216,21 +279,10 @@ LOCAL(vmJumpAndInvoke_argumentTest):
int3 int3
#endif // not AVIAN_CONTINUATIONS #endif // not AVIAN_CONTINUATIONS
#endif // not __MINGW32__
#elif defined __i386__ #elif defined __i386__
#define THREAD_CONTINUATION 96
#define THREAD_EXCEPTION 36
#define THREAD_EXCEPTION_STACK_ADJUSTMENT 100
#define THREAD_EXCEPTION_OFFSET 104
#define THREAD_EXCEPTION_HANDLER 108
#define CONTINUATION_NEXT 4
#define CONTINUATION_ADDRESS 16
#define CONTINUATION_RETURN_ADDRESS_OFFSET 20
#define CONTINUATION_FRAME_POINTER_OFFSET 24
#define CONTINUATION_LENGTH 28
#define CONTINUATION_BODY 32
#define CALLEE_SAVED_REGISTER_FOOTPRINT 16 #define CALLEE_SAVED_REGISTER_FOOTPRINT 16
.globl GLOBAL(vmInvoke) .globl GLOBAL(vmInvoke)
@ -286,72 +338,7 @@ vmInvoke_returnAddress:
movl %ecx,%esp movl %ecx,%esp
#ifdef AVIAN_CONTINUATIONS #ifdef AVIAN_CONTINUATIONS
// call the next continuation, if any # include "continuations-x86.S"
movl THREAD_CONTINUATION(%ebx),%ecx
cmpl $0,%ecx
je LOCAL(vmInvoke_exit)
// allocate a frame of size (continuation.length * BYTES_PER_WORD)
movl CONTINUATION_LENGTH(%ecx),%esi
shll $2,%esi
subl %esi,%esp
// copy the continuation body into the frame
leal CONTINUATION_BODY(%ecx),%edi
push %eax
push %edx
movl $0,%edx
jmp LOCAL(vmInvoke_continuationTest)
LOCAL(vmInvoke_continuationLoop):
movl (%edi,%edx,1),%eax
movl %eax,8(%esp,%edx,1)
addl $4,%edx
LOCAL(vmInvoke_continuationTest):
cmpl %esi,%edx
jb LOCAL(vmInvoke_continuationLoop)
pop %edx
pop %eax
// set the return address to vmInvoke_returnAddress
movl CONTINUATION_RETURN_ADDRESS_OFFSET(%ecx),%edi
call LOCAL(getPC)
addl $_GLOBAL_OFFSET_TABLE_,%esi
movl vmInvoke_returnAddress@GOT(%esi),%esi
movl %esi,(%esp,%edi,1)
// save the current base pointer in the frame and update it
movl CONTINUATION_FRAME_POINTER_OFFSET(%ecx),%edi
movl %ebp,(%esp,%edi,1)
addl %esp,%edi
movl %edi,%ebp
// consume the continuation
movl CONTINUATION_NEXT(%ecx),%edi
movl %edi,THREAD_CONTINUATION(%ebx)
// call the continuation unless we're handling an exception
movl THREAD_EXCEPTION(%ebx),%esi
cmpl $0,%esi
jne LOCAL(vmInvoke_handleException)
jmp *CONTINUATION_ADDRESS(%ecx)
LOCAL(vmInvoke_handleException):
// we're handling an exception - call the exception handler instead
movl $0,THREAD_EXCEPTION(%ebx)
movl THREAD_EXCEPTION_STACK_ADJUSTMENT(%ebx),%edi
subl %edi,%esp
movl THREAD_EXCEPTION_OFFSET(%ebx),%edi
movl %esi,(%esp,%edi,1)
jmp *THREAD_EXCEPTION_HANDLER(%ebx)
LOCAL(vmInvoke_exit):
#endif // AVIAN_CONTINUATIONS #endif // AVIAN_CONTINUATIONS
// restore callee-saved registers // restore callee-saved registers
@ -443,5 +430,5 @@ LOCAL(vmJumpAndInvoke_argumentTest):
#endif // AVIAN_CONTINUATIONS #endif // AVIAN_CONTINUATIONS
#else #else
# error unsupported platform #error unsupported architecture
#endif #endif //def __x86_64__

File diff suppressed because it is too large Load Diff

View File

@ -4016,6 +4016,31 @@ appendSaveLocals(Context* c)
SaveLocalsEvent(c)); SaveLocalsEvent(c));
} }
class CleanLocalsEvent: public Event {
public:
CleanLocalsEvent(Context* c):
Event(c)
{ }
virtual const char* name() {
return "CleanLocalsEvent";
}
virtual void compile(Context* c) {
for (FrameIterator it(c, 0, c->locals); it.hasMore();) {
FrameIterator::Element e = it.next(c);
clean(c, e.value, 0);
}
}
};
void
appendCleanLocals(Context* c)
{
append(c, new (c->zone->allocate(sizeof(CleanLocalsEvent)))
CleanLocalsEvent(c));
}
class DummyEvent: public Event { class DummyEvent: public Event {
public: public:
DummyEvent(Context* c): DummyEvent(Context* c):
@ -4927,11 +4952,12 @@ class MyCompiler: public Compiler {
} }
virtual void endSubroutine(Subroutine* subroutine) { virtual void endSubroutine(Subroutine* subroutine) {
appendCleanLocals(&c);
static_cast<MySubroutine*>(subroutine)->forkState = ::saveState(&c); static_cast<MySubroutine*>(subroutine)->forkState = ::saveState(&c);
} }
virtual void restoreFromSubroutine(Subroutine* subroutine) { virtual void linkSubroutine(Subroutine* subroutine) {
::restoreState(&c, static_cast<MySubroutine*>(subroutine)->forkState); restoreState(static_cast<MySubroutine*>(subroutine)->forkState);
} }
virtual void init(unsigned logicalCodeLength, unsigned parameterFootprint, virtual void init(unsigned logicalCodeLength, unsigned parameterFootprint,
@ -5032,12 +5058,30 @@ class MyCompiler: public Compiler {
(c.zone->allocate(sizeof(LogicalInstruction))) (c.zone->allocate(sizeof(LogicalInstruction)))
LogicalInstruction(logicalIp, c.stack, c.locals); LogicalInstruction(logicalIp, c.stack, c.locals);
if (c.subroutine) { bool startSubroutine = c.subroutine != 0;
if (startSubroutine) {
c.logicalCode[logicalIp]->subroutine = c.subroutine; c.logicalCode[logicalIp]->subroutine = c.subroutine;
c.subroutine = 0; c.subroutine = 0;
} }
c.logicalIp = logicalIp; c.logicalIp = logicalIp;
if (startSubroutine) {
// assume all local variables are initialized on entry to a
// subroutine, since other calls to the subroutine may
// initialize them:
unsigned sizeInBytes = sizeof(Local) * c.localFootprint;
Local* newLocals = static_cast<Local*>(c.zone->allocate(sizeInBytes));
memcpy(newLocals, c.locals, sizeInBytes);
c.locals = newLocals;
for (unsigned li = 0; li < c.localFootprint; ++li) {
Local* local = c.locals + li;
if (local->value == 0) {
initLocal(1, li);
}
}
}
} }
virtual Promise* machineIp(unsigned logicalIp) { virtual Promise* machineIp(unsigned logicalIp) {

View File

@ -43,7 +43,7 @@ class Compiler {
virtual Subroutine* startSubroutine() = 0; virtual Subroutine* startSubroutine() = 0;
virtual void endSubroutine(Subroutine* subroutine) = 0; virtual void endSubroutine(Subroutine* subroutine) = 0;
virtual void restoreFromSubroutine(Subroutine* subroutine) = 0; virtual void linkSubroutine(Subroutine* subroutine) = 0;
virtual void init(unsigned logicalCodeSize, unsigned parameterFootprint, virtual void init(unsigned logicalCodeSize, unsigned parameterFootprint,
unsigned localFootprint, unsigned alignedFrameSize) = 0; unsigned localFootprint, unsigned alignedFrameSize) = 0;

161
src/continuations-x86.S Normal file
View File

@ -0,0 +1,161 @@
#ifdef __x86_64__
#define THREAD_CONTINUATION 168
#define THREAD_EXCEPTION 64
#define THREAD_EXCEPTION_STACK_ADJUSTMENT 176
#define THREAD_EXCEPTION_OFFSET 184
#define THREAD_EXCEPTION_HANDLER 192
#define CONTINUATION_NEXT 8
#define CONTINUATION_ADDRESS 32
#define CONTINUATION_RETURN_ADDRESS_OFFSET 40
#define CONTINUATION_FRAME_POINTER_OFFSET 48
#define CONTINUATION_LENGTH 56
#define CONTINUATION_BODY 64
// call the next continuation, if any
movq THREAD_CONTINUATION(%rbx),%rcx
cmpq $0,%rcx
je LOCAL(vmInvoke_exit)
// allocate a frame of size (continuation.length * BYTES_PER_WORD)
// + CALLEE_SAVED_REGISTER_FOOTPRINT
movq CONTINUATION_LENGTH(%rcx),%rsi
shlq $3,%rsi
subq %rsi,%rsp
subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%rsp
// copy the continuation body into the frame
leaq CONTINUATION_BODY(%rcx),%rdi
movq $0,%r9
jmp LOCAL(vmInvoke_continuationTest)
LOCAL(vmInvoke_continuationLoop):
movq (%rdi,%r9,1),%r8
movq %r8,(%rsp,%r9,1)
addq $8,%r9
LOCAL(vmInvoke_continuationTest):
cmpq %rsi,%r9
jb LOCAL(vmInvoke_continuationLoop)
// set the return address to vmInvoke_returnAddress
movq CONTINUATION_RETURN_ADDRESS_OFFSET(%rcx),%rdi
movq vmInvoke_returnAddress@GOTPCREL(%rip),%r10
movq %r10,(%rsp,%rdi,1)
// save the current base pointer in the frame and update it
movq CONTINUATION_FRAME_POINTER_OFFSET(%rcx),%rdi
movq %rbp,(%rsp,%rdi,1)
addq %rsp,%rdi
movq %rdi,%rbp
// consume the continuation
movq CONTINUATION_NEXT(%rcx),%rdi
movq %rdi,THREAD_CONTINUATION(%rbx)
// call the continuation unless we're handling an exception
movq THREAD_EXCEPTION(%rbx),%rsi
cmpq $0,%rsi
jne LOCAL(vmInvoke_handleException)
jmp *CONTINUATION_ADDRESS(%rcx)
LOCAL(vmInvoke_handleException):
// we're handling an exception - call the exception handler instead
movq $0,THREAD_EXCEPTION(%rbx)
movq THREAD_EXCEPTION_STACK_ADJUSTMENT(%rbx),%rdi
subq %rdi,%rsp
movq THREAD_EXCEPTION_OFFSET(%rbx),%rdi
movq %rsi,(%rsp,%rdi,1)
jmp *THREAD_EXCEPTION_HANDLER(%rbx)
LOCAL(vmInvoke_exit):
#elif defined __i386__
#define THREAD_CONTINUATION 96
#define THREAD_EXCEPTION 36
#define THREAD_EXCEPTION_STACK_ADJUSTMENT 100
#define THREAD_EXCEPTION_OFFSET 104
#define THREAD_EXCEPTION_HANDLER 108
#define CONTINUATION_NEXT 4
#define CONTINUATION_ADDRESS 16
#define CONTINUATION_RETURN_ADDRESS_OFFSET 20
#define CONTINUATION_FRAME_POINTER_OFFSET 24
#define CONTINUATION_LENGTH 28
#define CONTINUATION_BODY 32
// call the next continuation, if any
movl THREAD_CONTINUATION(%ebx),%ecx
cmpl $0,%ecx
je LOCAL(vmInvoke_exit)
// allocate a frame of size (continuation.length * BYTES_PER_WORD)
movl CONTINUATION_LENGTH(%ecx),%esi
shll $2,%esi
subl %esi,%esp
// copy the continuation body into the frame
leal CONTINUATION_BODY(%ecx),%edi
push %eax
push %edx
movl $0,%edx
jmp LOCAL(vmInvoke_continuationTest)
LOCAL(vmInvoke_continuationLoop):
movl (%edi,%edx,1),%eax
movl %eax,8(%esp,%edx,1)
addl $4,%edx
LOCAL(vmInvoke_continuationTest):
cmpl %esi,%edx
jb LOCAL(vmInvoke_continuationLoop)
pop %edx
pop %eax
// set the return address to vmInvoke_returnAddress
movl CONTINUATION_RETURN_ADDRESS_OFFSET(%ecx),%edi
call LOCAL(getPC)
addl $_GLOBAL_OFFSET_TABLE_,%esi
movl vmInvoke_returnAddress@GOT(%esi),%esi
movl %esi,(%esp,%edi,1)
// save the current base pointer in the frame and update it
movl CONTINUATION_FRAME_POINTER_OFFSET(%ecx),%edi
movl %ebp,(%esp,%edi,1)
addl %esp,%edi
movl %edi,%ebp
// consume the continuation
movl CONTINUATION_NEXT(%ecx),%edi
movl %edi,THREAD_CONTINUATION(%ebx)
// call the continuation unless we're handling an exception
movl THREAD_EXCEPTION(%ebx),%esi
cmpl $0,%esi
jne LOCAL(vmInvoke_handleException)
jmp *CONTINUATION_ADDRESS(%ecx)
LOCAL(vmInvoke_handleException):
// we're handling an exception - call the exception handler instead
movl $0,THREAD_EXCEPTION(%ebx)
movl THREAD_EXCEPTION_STACK_ADJUSTMENT(%ebx),%edi
subl %edi,%esp
movl THREAD_EXCEPTION_OFFSET(%ebx),%edi
movl %esi,(%esp,%edi,1)
jmp *THREAD_EXCEPTION_HANDLER(%ebx)
LOCAL(vmInvoke_exit):
#else
# error unsupported architecture
#endif

394
src/gnu.cpp Normal file
View File

@ -0,0 +1,394 @@
/* 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 "machine.h"
#include "constants.h"
#include "processor.h"
using namespace vm;
namespace {
void
setProperty(Thread* t, object method, object properties,
const char* name, const void* value, const char* format = "%s")
{
PROTECT(t, method);
PROTECT(t, properties);
object n = makeString(t, "%s", name);
PROTECT(t, n);
object v = makeString(t, format, value);
t->m->processor->invoke(t, method, properties, n, v);
}
} // namespace
namespace vm {
jobject JNICALL
NewDirectByteBuffer(Thread* t, void* address, jlong capacity)
{
const char* pointerClassName;
const char* initSpec;
if (BytesPerWord == 8) {
pointerClassName = "gnu/classpath/Pointer64";
initSpec = "(J)V";
} else {
pointerClassName = "gnu/classpath/Pointer32";
initSpec = "(I)V";
}
object pointerClass = resolveClass(t, pointerClassName);
if (UNLIKELY(pointerClass == 0)) return 0;
PROTECT(t, pointerClass);
object pointerConstructor = resolveMethod
(t, pointerClass, "<init>", initSpec);
if (UNLIKELY(pointerConstructor == 0)) return 0;
object pointer = make(t, pointerClass);
PROTECT(t, pointer);
t->m->processor->invoke(t, pointerConstructor, pointer, address);
if (UNLIKELY(t->exception)) return 0;
object bufferClass = resolveClass
(t, "java/nio/DirectByteBufferImpl$ReadWrite");
if (UNLIKELY(bufferClass == 0)) return 0;
PROTECT(t, bufferClass);
object bufferConstructor = resolveMethod
(t, bufferClass, "<init>", "(Lgnu/classpath/Pointer;int)V");
if (UNLIKELY(bufferConstructor == 0)) return 0;
object buffer = make(t, bufferClass);
PROTECT(t, buffer);
t->m->processor->invoke
(t, bufferConstructor, buffer, &pointer, static_cast<jint>(capacity));
if (UNLIKELY(t->exception)) return 0;
return makeLocalReference(t, buffer);
}
void* JNICALL
GetDirectBufferAddress(Thread* t, jobject buffer)
{
object addressField = resolveField
(t, objectClass(t, *buffer), "address", "Lgnu/classpath/Pointer;");
if (UNLIKELY(addressField == 0)) return 0;
object address = cast<object>(*buffer, fieldOffset(t, addressField));
if (address == 0) return 0;
const char* dataSpec;
if (BytesPerWord == 8) {
dataSpec = "J";
} else {
dataSpec = "I";
}
object dataField = resolveField
(t, objectClass(t, address), "data", dataSpec);
if (UNLIKELY(dataField == 0)) return 0;
return cast<void*>(address, fieldOffset(t, dataField));
}
jlong JNICALL
GetDirectBufferCapacity(Thread* t, jobject buffer)
{
object capField = resolveField(t, objectClass(t, *buffer), "cap", "I");
if (UNLIKELY(capField == 0)) return 0;
return cast<jint>(*buffer, fieldOffset(t, capField));
}
} // namespace vm
extern "C" JNIEXPORT void JNICALL
Avian_gnu_classpath_VMSystemProperties_preInit
(Thread* t, object, uintptr_t* arguments)
{
object properties = reinterpret_cast<object>(arguments[0]);
PROTECT(t, properties);
object method = resolveMethod
(t, "java/util/Properties", "setProperty",
"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;");
if (UNLIKELY(t->exception)) {
return;
}
PROTECT(t, method);
setProperty(t, method, properties, "java.vm.name", "Avian");
setProperty(t, method, properties, "java.protocol.handler.pkgs", "avian");
setProperty(t, method, properties, "file.encoding", "ASCII");
// specify a bogus library path so we can do our own search in
// VMRuntime.nativeLoad:
#define LIBRARY_PATH_SENTINAL "*"
setProperty(t, method, properties, "java.library.path",
LIBRARY_PATH_SENTINAL);
#ifdef WIN32
# define FILE_SEPARATOR "\\"
setProperty(t, method, properties, "line.separator", "\r\n");
setProperty(t, method, properties, "file.separator", FILE_SEPARATOR);
setProperty(t, method, properties, "path.separator", ";");
setProperty(t, method, properties, "os.name", "Windows");
TCHAR buffer[MAX_PATH];
GetTempPath(MAX_PATH, buffer);
setProperty(t, method, properties, "java.io.tmpdir", buffer);
setProperty(t, method, properties, "user.home",
_wgetenv(L"USERPROFILE"), "%ls");
GetCurrentDirectory(MAX_PATH, buffer);
setProperty(t, method, properties, "user.dir", buffer);
#else
# define FILE_SEPARATOR "/"
setProperty(t, method, properties, "line.separator", "\n");
setProperty(t, method, properties, "file.separator", FILE_SEPARATOR);
setProperty(t, method, properties, "path.separator", ":");
# ifdef __APPLE__
setProperty(t, method, properties, "os.name", "Mac OS X");
# else
setProperty(t, method, properties, "os.name", "Linux");
# endif
setProperty(t, method, properties, "java.io.tmpdir", "/tmp");
setProperty(t, method, properties, "user.home", getenv("HOME"));
setProperty(t, method, properties, "user.dir", getenv("PWD"));
#endif
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_gnu_classpath_VMStackWalker_getClassContext
(Thread* t, object, uintptr_t*)
{
class Visitor: public Processor::StackVisitor {
public:
Visitor(Thread* t):
t(t), skipCount(1), trace(0), index(0), protector(t, &trace)
{ }
virtual bool visit(Processor::StackWalker* walker) {
if (skipCount == 0) {
if (trace == 0) {
trace = makeObjectArray
(t, arrayBody(t, t->m->types, Machine::ClassType),
walker->count());
}
assert(t, index < objectArrayLength(t, trace));
set(t, trace, ArrayBody + (index * BytesPerWord),
methodClass(t, walker->method()));
++ index;
return true;
} else {
-- skipCount;
return true;
}
}
Thread* t;
unsigned skipCount;
object trace;
unsigned index;
Thread::SingleProtector protector;
} v(t);
t->m->processor->walkStack(t, &v);
if (v.trace == 0) {
v.trace = makeObjectArray
(t, arrayBody(t, t->m->types, Machine::ClassType), 0);
}
return reinterpret_cast<int64_t>(v.trace);
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_gnu_classpath_VMStackWalker_getClassLoader
(Thread* t, object, uintptr_t* arguments)
{
return reinterpret_cast<int64_t>
(classLoader(t, reinterpret_cast<object>(arguments[0])));
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_java_lang_VMRuntime_mapLibraryName
(Thread* t, object, uintptr_t* arguments)
{
object name = reinterpret_cast<object>(arguments[0]);
PROTECT(t, name);
const unsigned soPrefixLength = sizeof(SO_PREFIX) - 1;
const unsigned nameLength = stringLength(t, name);
const unsigned soSuffixLength = sizeof(SO_SUFFIX) - 1;
const unsigned total = soPrefixLength + nameLength + soSuffixLength;
object s = makeByteArray(t, total + 1);
char* p = reinterpret_cast<char*>(&byteArrayBody(t, s, 0));
memcpy(p, SO_PREFIX, soPrefixLength);
stringChars(t, name, p + soPrefixLength);
memcpy(p + soPrefixLength + nameLength, SO_SUFFIX, soSuffixLength);
p[total] = 0;
return reinterpret_cast<int64_t>(makeString(t, s, 0, total, 0));
}
extern "C" JNIEXPORT void JNICALL
Avian_java_lang_System_arraycopy
(Thread*, object, uintptr_t*);
extern "C" JNIEXPORT void JNICALL
Avian_java_lang_VMSystem_arraycopy
(Thread* t, object, uintptr_t* arguments)
{
Avian_java_lang_System_arraycopy(t, 0, arguments);
}
extern "C" JNIEXPORT void JNICALL
Avian_java_lang_Runtime_load
(Thread* t, object, uintptr_t*);
extern "C" JNIEXPORT int64_t JNICALL
Avian_java_lang_VMRuntime_nativeLoad
(Thread* t, object, uintptr_t* arguments)
{
object name = reinterpret_cast<object>(arguments[0]);
// given that we set java.library.path to LIBRARY_PATH_SENTINAL, we
// can determine which names are filenames and which are library
// names by looking for the prefix LIBRARY_PATH_SENTINAL
// FILE_SEPARATOR
unsigned length = stringLength(t, name);
char n[length + 1];
stringChars(t, name, n);
const unsigned pathPrefixLength
= sizeof(LIBRARY_PATH_SENTINAL) - 1
+ sizeof(FILE_SEPARATOR) - 1;
bool mapName = (strncmp(n, LIBRARY_PATH_SENTINAL FILE_SEPARATOR,
pathPrefixLength) == 0);
if (mapName) {
// strip the path prefix, SO prefix, and SO suffix before passing
// the name to Runtime.load
const unsigned soPrefixLength = sizeof(SO_PREFIX) - 1;
const unsigned soSuffixLength = sizeof(SO_SUFFIX) - 1;
const unsigned newOffset
= stringOffset(t, name) + pathPrefixLength + soPrefixLength;
const unsigned newLength
= length - pathPrefixLength - soPrefixLength - soSuffixLength;
name = makeString(t, stringData(t, name), newOffset, newLength, 0);
}
uintptr_t args[] = { reinterpret_cast<uintptr_t>(name), mapName };
Avian_java_lang_Runtime_load(t, 0, args);
if (t->exception) {
t->exception = 0;
return 0;
} else {
return 1;
}
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_java_lang_Class_primitiveClass
(Thread* t, object, uintptr_t*);
extern "C" JNIEXPORT int64_t JNICALL
Avian_java_lang_VMClassLoader_getPrimitiveClass
(Thread* t, object, uintptr_t* arguments)
{
return Avian_java_lang_Class_primitiveClass(t, 0, arguments);
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_java_lang_System_identityHashCode
(Thread*, object, uintptr_t*);
extern "C" JNIEXPORT int64_t JNICALL
Avian_java_lang_VMSystem_identityHashCode
(Thread* t, object, uintptr_t* arguments)
{
return Avian_java_lang_System_identityHashCode(t, 0, arguments);
}
extern "C" JNIEXPORT void JNICALL
Avian_java_lang_Runtime_gc
(Thread*, object, uintptr_t*);
extern "C" JNIEXPORT void JNICALL
Avian_java_lang_VMRuntime_gc
(Thread* t, object, uintptr_t*)
{
Avian_java_lang_Runtime_gc(t, 0, 0);
}
extern "C" JNIEXPORT void JNICALL
Avian_java_lang_VMRuntime_runFinalizationForExit
(Thread*, object, uintptr_t*)
{
// ignore
}
extern "C" JNIEXPORT void JNICALL
Avian_java_lang_VMRuntime_exit
(Thread*, object, uintptr_t* arguments)
{
exit(arguments[0]);
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_avian_SystemClassLoader_findClass
(Thread*, object, uintptr_t*);
extern "C" JNIEXPORT int64_t JNICALL
Avian_java_lang_VMClassLoader_loadClass
(Thread* t, object, uintptr_t* arguments)
{
uintptr_t args[] = { 0, arguments[0] };
return Avian_avian_SystemClassLoader_findClass(t, 0, args);
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_avian_SystemClassLoader_findLoadedClass
(Thread*, object, uintptr_t*);
extern "C" JNIEXPORT int64_t JNICALL
Avian_java_lang_VMClassLoader_findLoadedClass
(Thread* t, object, uintptr_t* arguments)
{
uintptr_t args[] = { 0, arguments[1] };
return Avian_avian_SystemClassLoader_findLoadedClass(t, 0, args);
}

View File

@ -88,7 +88,7 @@ class Context {
while (stack) { while (stack) {
Stack* dead = stack; Stack* dead = stack;
stack = dead->next; stack = dead->next;
thread->m->heap->free(stack, sizeof(Stack)); thread->m->heap->free(dead, sizeof(Stack));
} }
} }

View File

@ -26,6 +26,8 @@ const unsigned FrameMethodOffset = 2;
const unsigned FrameIpOffset = 3; const unsigned FrameIpOffset = 3;
const unsigned FrameFootprint = 4; const unsigned FrameFootprint = 4;
class ClassInitList;
class Thread: public vm::Thread { class Thread: public vm::Thread {
public: public:
static const unsigned StackSizeInBytes = 64 * 1024; static const unsigned StackSizeInBytes = 64 * 1024;
@ -36,16 +38,39 @@ class Thread: public vm::Thread {
ip(0), ip(0),
sp(0), sp(0),
frame(-1), frame(-1),
code(0) code(0),
classInitList(0)
{ } { }
unsigned ip; unsigned ip;
unsigned sp; unsigned sp;
int frame; int frame;
object code; object code;
ClassInitList* classInitList;
uintptr_t stack[StackSizeInWords]; uintptr_t stack[StackSizeInWords];
}; };
class ClassInitList {
public:
ClassInitList(Thread* t, object class_, ClassInitList* next):
t(t), class_(class_), next(next)
{ }
static void push(Thread* t, object class_) {
t->classInitList = new (t->m->heap->allocate(sizeof(ClassInitList)))
ClassInitList(t, class_, t->classInitList);
}
void pop() {
t->classInitList = next;
t->m->heap->free(this, sizeof(ClassInitList));
}
Thread* t;
object class_;
ClassInitList* next;
};
inline void inline void
pushObject(Thread* t, object o) pushObject(Thread* t, object o)
{ {
@ -348,12 +373,14 @@ popFrame(Thread* t)
} }
} }
if (UNLIKELY(methodVmFlags(t, method) & ClassInitFlag)) { if (UNLIKELY(methodVmFlags(t, method) & ClassInitFlag)
if (t->exception) { and t->classInitList)
t->exception = makeExceptionInInitializerError(t, t->exception); {
} assert(t, t->classInitList->class_ == methodClass(t, method));
classVmFlags(t, methodClass(t, method)) &= ~(NeedInitFlag | InitFlag);
release(t, t->m->classLock); t->classInitList->pop();
postInitClass(t, methodClass(t, method));
} }
t->sp = frameBase(t, t->frame); t->sp = frameBase(t, t->frame);
@ -732,17 +759,21 @@ invokeNative(Thread* t, object method)
bool bool
classInit2(Thread* t, object class_, unsigned ipOffset) classInit2(Thread* t, object class_, unsigned ipOffset)
{ {
for (ClassInitList* list = t->classInitList; list; list = list->next) {
if (list->class_ == class_) {
return false;
}
}
PROTECT(t, class_); PROTECT(t, class_);
acquire(t, t->m->classLock);
if (classVmFlags(t, class_) & NeedInitFlag if (preInitClass(t, class_)) {
and (classVmFlags(t, class_) & InitFlag) == 0) ClassInitList::push(t, class_);
{
classVmFlags(t, class_) |= InitFlag;
t->code = classInitializer(t, class_); t->code = classInitializer(t, class_);
t->ip -= ipOffset; t->ip -= ipOffset;
return true; return true;
} else { } else {
release(t, t->m->classLock);
return false; return false;
} }
} }
@ -3070,22 +3101,6 @@ class MyProcessor: public Processor {
// ignore // ignore
} }
virtual void
initClass(vm::Thread* t, object c)
{
PROTECT(t, c);
acquire(t, t->m->classLock);
if (classVmFlags(t, c) & NeedInitFlag
and (classVmFlags(t, c) & InitFlag) == 0)
{
classVmFlags(t, c) |= InitFlag;
invoke(t, classInitializer(t, c), 0);
} else {
release(t, t->m->classLock);
}
}
virtual void virtual void
visitObjects(vm::Thread* vmt, Heap::Visitor* v) visitObjects(vm::Thread* vmt, Heap::Visitor* v)
{ {
@ -3098,6 +3113,10 @@ class MyProcessor: public Processor {
v->visit(reinterpret_cast<object*>(t->stack + (i * 2) + 1)); v->visit(reinterpret_cast<object*>(t->stack + (i * 2) + 1));
} }
} }
for (ClassInitList* list = t->classInitList; list; list = list->next) {
v->visit(reinterpret_cast<object*>(&(list->class_)));
}
} }
virtual void virtual void

View File

@ -62,8 +62,10 @@ AttachCurrentThread(Machine* m, Thread** t, void*)
*t = static_cast<Thread*>(m->localThread->get()); *t = static_cast<Thread*>(m->localThread->get());
if (*t == 0) { if (*t == 0) {
*t = m->processor->makeThread(m, 0, m->rootThread); *t = m->processor->makeThread(m, 0, m->rootThread);
m->system->attach(&((*t)->runnable));
enter(*t, Thread::ActiveState); enter(*t, Thread::ActiveState);
enter(*t, Thread::IdleState);
m->localThread->set(*t); m->localThread->set(*t);
} }
@ -264,6 +266,26 @@ ExceptionCheck(Thread* t)
return t->exception != 0; return t->exception != 0;
} }
#ifndef AVIAN_GNU
jobject JNICALL
NewDirectByteBuffer(Thread*, void*, jlong)
{
return 0;
}
void* JNICALL
GetDirectBufferAddress(Thread*, jobject)
{
return 0;
}
jlong JNICALL
GetDirectBufferCapacity(Thread*, jobject)
{
return -1;
}
#endif// not AVIAN_GNU
jclass JNICALL jclass JNICALL
GetObjectClass(Thread* t, jobject o) GetObjectClass(Thread* t, jobject o)
{ {
@ -823,22 +845,12 @@ CallStaticVoidMethod(Thread* t, jclass c, jmethodID m, ...)
va_end(a); va_end(a);
} }
object
findField(Thread* t, jclass c, const char* name, const char* spec)
{
object n = makeByteArray(t, "%s", name);
PROTECT(t, n);
object s = makeByteArray(t, "%s", spec);
return vm::findField(t, *c, n, s);
}
jfieldID JNICALL jfieldID JNICALL
GetFieldID(Thread* t, jclass c, const char* name, const char* spec) GetFieldID(Thread* t, jclass c, const char* name, const char* spec)
{ {
ENTER(t, Thread::ActiveState); ENTER(t, Thread::ActiveState);
object field = findField(t, c, name, spec); object field = resolveField(t, *c, name, spec);
if (UNLIKELY(t->exception)) return 0; if (UNLIKELY(t->exception)) return 0;
return fieldOffset(t, field); return fieldOffset(t, field);
@ -849,7 +861,7 @@ GetStaticFieldID(Thread* t, jclass c, const char* name, const char* spec)
{ {
ENTER(t, Thread::ActiveState); ENTER(t, Thread::ActiveState);
object field = findField(t, c, name, spec); object field = resolveField(t, *c, name, spec);
if (UNLIKELY(t->exception)) return 0; if (UNLIKELY(t->exception)) return 0;
return fieldOffset(t, field); return fieldOffset(t, field);
@ -1889,6 +1901,17 @@ append(char** p, const char* value, unsigned length, char tail)
namespace vm { namespace vm {
#ifdef AVIAN_GNU
jobject JNICALL
NewDirectByteBuffer(Thread*, void*, jlong);
void* JNICALL
GetDirectBufferAddress(Thread*, jobject);
jlong JNICALL
GetDirectBufferCapacity(Thread*, jobject);
#endif//AVIAN_GNU
void void
populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable) populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable)
{ {
@ -1914,6 +1937,9 @@ populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable)
envTable->FindClass = ::FindClass; envTable->FindClass = ::FindClass;
envTable->ThrowNew = ::ThrowNew; envTable->ThrowNew = ::ThrowNew;
envTable->ExceptionCheck = ::ExceptionCheck; envTable->ExceptionCheck = ::ExceptionCheck;
envTable->NewDirectByteBuffer = ::NewDirectByteBuffer;
envTable->GetDirectBufferAddress = ::GetDirectBufferAddress;
envTable->GetDirectBufferCapacity = ::GetDirectBufferCapacity;
envTable->DeleteLocalRef = ::DeleteLocalRef; envTable->DeleteLocalRef = ::DeleteLocalRef;
envTable->GetObjectClass = ::GetObjectClass; envTable->GetObjectClass = ::GetObjectClass;
envTable->IsInstanceOf = ::IsInstanceOf; envTable->IsInstanceOf = ::IsInstanceOf;

View File

@ -481,6 +481,33 @@ postCollect(Thread* t)
} }
} }
void
finalizeObject(Thread* t, object o)
{
if (t->state == Thread::ExitState) {
// don't waste time running Java finalizers if we're exiting the
// VM
return;
}
for (object c = objectClass(t, o); c; c = classSuper(t, c)) {
for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, c)); ++i) {
object m = arrayBody(t, classMethodTable(t, c), i);
if (strcmp(reinterpret_cast<const int8_t*>("finalize"),
&byteArrayBody(t, methodName(t, m), 0)) == 0
and strcmp(reinterpret_cast<const int8_t*>("()V"),
&byteArrayBody(t, methodSpec(t, m), 0)) == 0)
{
t->m->processor->invoke(t, m, o);
t->exception = 0;
return;
}
}
}
abort(t);
}
object object
makeByteArray(Thread* t, const char* format, va_list a) makeByteArray(Thread* t, const char* format, va_list a)
{ {
@ -497,21 +524,31 @@ makeByteArray(Thread* t, const char* format, va_list a)
} }
object object
parseUtf8(Thread* t, Stream& s, unsigned length) parseUtf8NonAscii(Thread* t, Stream& s, object bytesSoFar, unsigned byteCount,
unsigned sourceIndex, unsigned lastByteRead)
{ {
object value = makeByteArray(t, length + 1); PROTECT(t, bytesSoFar);
unsigned length = byteArrayLength(t, bytesSoFar) - 1;
object value = makeCharArray(t, length + 1);
unsigned vi = 0; unsigned vi = 0;
for (unsigned si = 0; si < length; ++si) { for (; vi < byteCount; ++vi) {
unsigned a = s.read1(); charArrayBody(t, value, vi) = byteArrayBody(t, bytesSoFar, vi);
}
unsigned a = lastByteRead;
unsigned si = sourceIndex;
while (true) {
if (a & 0x80) { if (a & 0x80) {
// todo: handle non-ASCII characters properly
if (a & 0x20) { if (a & 0x20) {
// 3 bytes // 3 bytes
si += 2; si += 2;
assert(t, si < length); assert(t, si < length);
/*unsigned b = */s.read1(); unsigned b = s.read1();
/*unsigned c = */s.read1(); unsigned c = s.read1();
byteArrayBody(t, value, vi++) = '_'; charArrayBody(t, value, vi++)
= ((a & 0xf) << 12) | ((b & 0x3f) << 6) | (c & 0x3f);
} else { } else {
// 2 bytes // 2 bytes
++ si; ++ si;
@ -519,9 +556,55 @@ parseUtf8(Thread* t, Stream& s, unsigned length)
unsigned b = s.read1(); unsigned b = s.read1();
if (a == 0xC0 and b == 0x80) { if (a == 0xC0 and b == 0x80) {
charArrayBody(t, value, vi++) = 0;
} else {
charArrayBody(t, value, vi++) = ((a & 0x1f) << 6) | (b & 0x3f);
}
}
} else {
charArrayBody(t, value, vi++) = a;
}
if (++si < length) {
a = s.read1();
} else {
break;
}
}
if (vi < length) {
PROTECT(t, value);
object v = makeCharArray(t, vi + 1);
memcpy(&charArrayBody(t, v, 0), &charArrayBody(t, value, 0), vi * 2);
value = v;
}
charArrayBody(t, value, vi) = 0;
return value;
}
object
parseUtf8(Thread* t, Stream& s, unsigned length)
{
object value = makeByteArray(t, length + 1);
unsigned vi = 0;
for (unsigned si = 0; si < length; ++si) {
unsigned a = s.read1();
if (a & 0x80) {
if (a & 0x20) {
// 3 bytes
return parseUtf8NonAscii(t, s, value, vi, si, a);
} else {
// 2 bytes
unsigned b = s.read1();
if (a == 0xC0 and b == 0x80) {
++ si;
assert(t, si < length);
byteArrayBody(t, value, vi++) = 0; byteArrayBody(t, value, vi++) = 0;
} else { } else {
byteArrayBody(t, value, vi++) = '_'; return parseUtf8NonAscii(t, s, value, vi, si, a);
} }
} }
} else { } else {
@ -541,6 +624,28 @@ parseUtf8(Thread* t, Stream& s, unsigned length)
return value; return value;
} }
void
removeByteArray(Thread* t, object o)
{
hashMapRemove(t, t->m->byteArrayMap, o, byteArrayHash, objectEqual);
}
object
internByteArray(Thread* t, object array)
{
PROTECT(t, array);
object n = hashMapFindNode
(t, t->m->byteArrayMap, array, byteArrayHash, byteArrayEqual);
if (n) {
return jreferenceTarget(t, tripleFirst(t, n));
} else {
hashMapInsert(t, t->m->byteArrayMap, array, 0, byteArrayHash);
addFinalizer(t, array, removeByteArray);
return array;
}
}
unsigned unsigned
parsePoolEntry(Thread* t, Stream& s, uint32_t* index, object pool, unsigned i) parsePoolEntry(Thread* t, Stream& s, uint32_t* index, object pool, unsigned i)
{ {
@ -563,6 +668,11 @@ parsePoolEntry(Thread* t, Stream& s, uint32_t* index, object pool, unsigned i)
case CONSTANT_Utf8: { case CONSTANT_Utf8: {
if (singletonObject(t, pool, i) == 0) { if (singletonObject(t, pool, i) == 0) {
object value = parseUtf8(t, s, s.read2()); object value = parseUtf8(t, s, s.read2());
if (objectClass(t, value)
== arrayBody(t, t->m->types, Machine::ByteArrayType))
{
value = internByteArray(t, value);
}
set(t, pool, SingletonBody + (i * BytesPerWord), value); set(t, pool, SingletonBody + (i * BytesPerWord), value);
} }
} return 1; } return 1;
@ -583,7 +693,8 @@ parsePoolEntry(Thread* t, Stream& s, uint32_t* index, object pool, unsigned i)
parsePoolEntry(t, s, index, pool, si); parsePoolEntry(t, s, index, pool, si);
object value = singletonObject(t, pool, si); object value = singletonObject(t, pool, si);
value = makeString(t, value, 0, byteArrayLength(t, value) - 1, 0); value = makeString
(t, value, 0, cast<uintptr_t>(value, BytesPerWord) - 1, 0);
value = intern(t, value); value = intern(t, value);
set(t, pool, SingletonBody + (i * BytesPerWord), value); set(t, pool, SingletonBody + (i * BytesPerWord), value);
} }
@ -1163,6 +1274,17 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
hashMapInsert(t, virtualMap, method, method, methodHash); hashMapInsert(t, virtualMap, method, method, methodHash);
} }
if (UNLIKELY(strcmp
(reinterpret_cast<const int8_t*>("finalize"),
&byteArrayBody(t, methodName(t, method), 0)) == 0
and strcmp
(reinterpret_cast<const int8_t*>("()V"),
&byteArrayBody(t, methodSpec(t, method), 0)) == 0
and (not emptyMethod(t, method))))
{
classVmFlags(t, class_) |= HasFinalizerFlag;
}
} else { } else {
methodOffset(t, method) = i; methodOffset(t, method) = i;
@ -1317,6 +1439,8 @@ updateBootstrapClass(Thread* t, object bootstrapClass, object class_)
expect(t, bootstrapClass == arrayBody(t, t->m->types, Machine::ClassType) expect(t, bootstrapClass == arrayBody(t, t->m->types, Machine::ClassType)
or classFixedSize(t, bootstrapClass) >= classFixedSize(t, class_)); or classFixedSize(t, bootstrapClass) >= classFixedSize(t, class_));
expect(t, (classVmFlags(t, class_) & HasFinalizerFlag) == 0);
PROTECT(t, bootstrapClass); PROTECT(t, bootstrapClass);
PROTECT(t, class_); PROTECT(t, class_);
@ -1513,7 +1637,7 @@ boot(Thread* t)
m->unsafe = true; m->unsafe = true;
m->loader = allocate(t, sizeof(void*) * 3, true); m->loader = allocate(t, FixedSizeOfSystemClassLoader, true);
m->types = allocate(t, pad((TypeCount + 2) * BytesPerWord), true); m->types = allocate(t, pad((TypeCount + 2) * BytesPerWord), true);
arrayLength(t, m->types) = TypeCount; arrayLength(t, m->types) = TypeCount;
@ -1707,6 +1831,7 @@ Machine::Machine(System* system, Heap* heap, Finder* finder,
bootstrapClassMap(0), bootstrapClassMap(0),
monitorMap(0), monitorMap(0),
stringMap(0), stringMap(0),
byteArrayMap(0),
types(0), types(0),
jniMethodTable(0), jniMethodTable(0),
finalizers(0), finalizers(0),
@ -1715,6 +1840,7 @@ Machine::Machine(System* system, Heap* heap, Finder* finder,
weakReferences(0), weakReferences(0),
tenuredWeakReferences(0), tenuredWeakReferences(0),
unsafe(false), unsafe(false),
triedBuiltinOnLoad(false),
heapPoolIndex(0) heapPoolIndex(0)
{ {
heap->setClient(heapClient); heap->setClient(heapClient);
@ -1777,6 +1903,7 @@ Thread::Thread(Machine* m, object javaThread, Thread* parent):
heapIndex(0), heapIndex(0),
heapOffset(0), heapOffset(0),
protector(0), protector(0),
classInitStack(0),
runnable(this), runnable(this),
defaultHeap(static_cast<uintptr_t*> defaultHeap(static_cast<uintptr_t*>
(m->heap->allocate(ThreadHeapSizeInBytes))), (m->heap->allocate(ThreadHeapSizeInBytes))),
@ -1827,6 +1954,7 @@ Thread::init()
boot(this); boot(this);
} }
m->byteArrayMap = makeWeakHashMap(this, 0, 0);
m->monitorMap = makeWeakHashMap(this, 0, 0); m->monitorMap = makeWeakHashMap(this, 0, 0);
m->jniMethodTable = makeVector(this, 0, 0); m->jniMethodTable = makeVector(this, 0, 0);
@ -1840,8 +1968,12 @@ Thread::init()
if (javaThread) { if (javaThread) {
threadPeer(this, javaThread) = reinterpret_cast<jlong>(this); threadPeer(this, javaThread) = reinterpret_cast<jlong>(this);
} else { } else {
const unsigned NewState = 0;
const unsigned NormalPriority = 5;
this->javaThread = makeThread this->javaThread = makeThread
(this, reinterpret_cast<int64_t>(this), 0, 0, 0, 0, m->loader, 0); (this, reinterpret_cast<int64_t>(this), 0, 0, NewState, NormalPriority,
0, 0, 0, m->loader, 0, 0, 0);
} }
} }
@ -2140,6 +2272,28 @@ allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type,
} }
} }
object
makeNewGeneral(Thread* t, object class_)
{
assert(t, t->state == Thread::ActiveState);
object instance = makeNew(t, class_);
PROTECT(t, instance);
if (classVmFlags(t, class_) & WeakReferenceFlag) {
ACQUIRE(t, t->m->referenceLock);
jreferenceVmNext(t, instance) = t->m->weakReferences;
t->m->weakReferences = instance;
}
if (classVmFlags(t, class_) & HasFinalizerFlag) {
addFinalizer(t, instance, finalizeObject);
}
return instance;
}
object object
makeByteArray(Thread* t, const char* format, ...) makeByteArray(Thread* t, const char* format, ...)
{ {
@ -2406,7 +2560,8 @@ parseClass(Thread* t, const uint8_t* data, unsigned size)
set(t, class_, ClassSuper, sc); set(t, class_, ClassSuper, sc);
classVmFlags(t, class_) classVmFlags(t, class_)
|= (classVmFlags(t, sc) & (ReferenceFlag | WeakReferenceFlag)); |= (classVmFlags(t, sc)
& (ReferenceFlag | WeakReferenceFlag | HasFinalizerFlag));
} }
parseInterfaceTable(t, s, class_, pool); parseInterfaceTable(t, s, class_, pool);
@ -2519,24 +2674,57 @@ resolveClass(Thread* t, object spec)
} }
object object
resolveMethod(Thread* t, const char* className, const char* methodName, resolveMethod(Thread* t, object class_, const char* methodName,
const char* methodSpec) const char* methodSpec)
{ {
object class_ = resolveClass(t, makeByteArray(t, "%s", className));
if (LIKELY(t->exception == 0)) {
PROTECT(t, class_); PROTECT(t, class_);
object name = makeByteArray(t, methodName); object name = makeByteArray(t, methodName);
PROTECT(t, name); PROTECT(t, name);
object spec = makeByteArray(t, methodSpec); object spec = makeByteArray(t, methodSpec);
object reference = makeReference(t, class_, name, spec);
return findMethodInClass(t, class_, referenceName(t, reference), object method = findMethodInClass(t, class_, name, spec);
referenceSpec(t, reference));
if (t->exception == 0 and method == 0) {
object message = makeString
(t, "%s %s not found in %s", methodName, methodSpec,
&byteArrayBody(t, className(t, class_), 0));
t->exception = makeNoSuchMethodError(t, message);
return 0;
} else {
return method;
}
} }
object
resolveField(Thread* t, object class_, const char* fieldName,
const char* fieldSpec)
{
PROTECT(t, class_);
object name = makeByteArray(t, fieldName);
PROTECT(t, name);
object spec = makeByteArray(t, fieldSpec);
PROTECT(t, spec);
object field = 0;
for (; class_ != 0 and field == 0; class_ = classSuper(t, class_)) {
field = findFieldInClass(t, class_, name, spec);
}
if (t->exception == 0 and field == 0) {
object message = makeString
(t, "%s %s not found in %s", fieldName, fieldSpec,
&byteArrayBody(t, className(t, class_), 0));
t->exception = makeNoSuchFieldError(t, message);
return 0; return 0;
} else {
return field;
}
} }
object object
@ -2565,6 +2753,92 @@ resolveObjectArrayClass(Thread* t, object elementSpec)
return resolveClass(t, spec); return resolveClass(t, spec);
} }
bool
classNeedsInit(Thread* t, object c)
{
if (classVmFlags(t, c) & NeedInitFlag) {
if (classVmFlags(t, c) & InitFlag) {
// the class is currently being initialized. If this the thread
// which is initializing it, we should not try to initialize it
// recursively. Otherwise, we must wait for the responsible
// thread to finish.
for (Thread::ClassInitStack* s = t->classInitStack; s; s = s->next) {
if (s->class_ == c) {
return false;
}
}
}
return true;
} else {
return false;
}
}
bool
preInitClass(Thread* t, object c)
{
if (classVmFlags(t, c) & NeedInitFlag) {
PROTECT(t, c);
ACQUIRE(t, t->m->classLock);
if (classVmFlags(t, c) & NeedInitFlag) {
if (classVmFlags(t, c) & InitFlag) {
// the class is currently being initialized. If this the
// thread which is initializing it, we should not try to
// initialize it recursively.
for (Thread::ClassInitStack* s = t->classInitStack; s; s = s->next) {
if (s->class_ == c) {
return false;
}
}
// some other thread is on the job - wait for it to finish.
while (classVmFlags(t, c) & InitFlag) {
ENTER(t, Thread::IdleState);
t->m->classLock->wait(t->systemThread, 0);
}
} else if (classVmFlags(t, c) & InitErrorFlag) {
object message = makeString
(t, "%s", &byteArrayBody(t, className(t, c), 0));
t->exception = makeNoClassDefFoundError(t, message);
} else {
classVmFlags(t, c) |= InitFlag;
return true;
}
}
}
return false;
}
void
postInitClass(Thread* t, object c)
{
PROTECT(t, c);
ACQUIRE(t, t->m->classLock);
if (t->exception) {
t->exception = makeExceptionInInitializerError(t, t->exception);
classVmFlags(t, c) |= NeedInitFlag | InitErrorFlag;
classVmFlags(t, c) &= ~InitFlag;
} else {
classVmFlags(t, c) &= ~(NeedInitFlag | InitFlag);
}
t->m->classLock->notifyAll(t->systemThread);
}
void
initClass(Thread* t, object c)
{
PROTECT(t, c);
if (preInitClass(t, c)) {
Thread::ClassInitStack stack(t, c);
t->m->processor->invoke(t, classInitializer(t, c), 0);
postInitClass(t, c);
}
}
object object
makeObjectArray(Thread* t, object elementClass, unsigned count) makeObjectArray(Thread* t, object elementClass, unsigned count)
{ {
@ -2856,6 +3130,7 @@ visitRoots(Machine* m, Heap::Visitor* v)
v->visit(&(m->bootstrapClassMap)); v->visit(&(m->bootstrapClassMap));
v->visit(&(m->monitorMap)); v->visit(&(m->monitorMap));
v->visit(&(m->stringMap)); v->visit(&(m->stringMap));
v->visit(&(m->byteArrayMap));
v->visit(&(m->types)); v->visit(&(m->types));
v->visit(&(m->jniMethodTable)); v->visit(&(m->jniMethodTable));
@ -2972,11 +3247,11 @@ makeTrace(Thread* t, Thread* target)
void void
runJavaThread(Thread* t) runJavaThread(Thread* t)
{ {
object method = resolveMethod(t, "java/lang/Thread", "run", "()V"); object method = resolveMethod
(t, "java/lang/Thread", "run", "(Ljava/lang/Thread;)V");
if (t->exception == 0) { if (t->exception == 0) {
t->m->processor->invoke t->m->processor->invoke(t, method, 0, t->javaThread);
(t, findMethod(t, method, objectClass(t, t->javaThread)),
t->javaThread);
} }
} }
@ -3025,3 +3300,29 @@ vmPrintTrace(Thread* t)
t->m->processor->walkStack(t, &v); t->m->processor->walkStack(t, &v);
} }
// also for debugging
void*
vmAddressFromLine(Thread* t, object m, unsigned line)
{
object code = methodCode(t, m);
printf("code: %p\n", code);
object lnt = codeLineNumberTable(t, code);
printf("lnt: %p\n", lnt);
if (lnt) {
unsigned last = 0;
unsigned bottom = 0;
unsigned top = lineNumberTableLength(t, lnt);
for(unsigned i = bottom; i < top; i++)
{
LineNumber* ln = lineNumberTableBody(t, lnt, i);
if(lineNumberLine(ln) == line)
return reinterpret_cast<void*>(lineNumberIp(ln));
else if(lineNumberLine(ln) > line)
return reinterpret_cast<void*>(last);
last = lineNumberIp(ln);
}
}
return 0;
}

View File

@ -76,6 +76,7 @@ const int UnknownLine = -2;
// class flags (note that we must be careful not to overlap the // class flags (note that we must be careful not to overlap the
// standard ACC_* flags): // standard ACC_* flags):
const unsigned HasFinalMemberFlag = 1 << 13;
const unsigned SingletonFlag = 1 << 14; const unsigned SingletonFlag = 1 << 14;
const unsigned ContinuationFlag = 1 << 15; const unsigned ContinuationFlag = 1 << 15;
@ -84,9 +85,10 @@ const unsigned ReferenceFlag = 1 << 0;
const unsigned WeakReferenceFlag = 1 << 1; const unsigned WeakReferenceFlag = 1 << 1;
const unsigned NeedInitFlag = 1 << 2; const unsigned NeedInitFlag = 1 << 2;
const unsigned InitFlag = 1 << 3; const unsigned InitFlag = 1 << 3;
const unsigned PrimitiveFlag = 1 << 4; const unsigned InitErrorFlag = 1 << 4;
const unsigned BootstrapFlag = 1 << 5; const unsigned PrimitiveFlag = 1 << 5;
const unsigned HasFinalMemberFlag = 1 << 6; const unsigned BootstrapFlag = 1 << 6;
const unsigned HasFinalizerFlag = 1 << 7;
// method vmFlags: // method vmFlags:
const unsigned ClassInitFlag = 1 << 0; const unsigned ClassInitFlag = 1 << 0;
@ -1190,6 +1192,7 @@ class Machine {
object bootstrapClassMap; object bootstrapClassMap;
object monitorMap; object monitorMap;
object stringMap; object stringMap;
object byteArrayMap;
object types; object types;
object jniMethodTable; object jniMethodTable;
object finalizers; object finalizers;
@ -1198,6 +1201,7 @@ class Machine {
object weakReferences; object weakReferences;
object tenuredWeakReferences; object tenuredWeakReferences;
bool unsafe; bool unsafe;
bool triedBuiltinOnLoad;
JavaVMVTable javaVMVTable; JavaVMVTable javaVMVTable;
JNIEnvVTable jniEnvVTable; JNIEnvVTable jniEnvVTable;
uintptr_t* heapPool[ThreadHeapPoolSize]; uintptr_t* heapPool[ThreadHeapPoolSize];
@ -1265,6 +1269,25 @@ class Thread {
object* p; object* p;
}; };
class ClassInitStack {
public:
ClassInitStack(Thread* t, object class_):
next(t->classInitStack),
class_(class_),
protector(t, &(this->class_))
{
t->classInitStack = this;
}
~ClassInitStack() {
protector.t->classInitStack = next;
}
ClassInitStack* next;
object class_;
SingleProtector protector;
};
class Runnable: public System::Runnable { class Runnable: public System::Runnable {
public: public:
Runnable(Thread* t): t(t) { } Runnable(Thread* t): t(t) { }
@ -1317,6 +1340,7 @@ class Thread {
unsigned heapIndex; unsigned heapIndex;
unsigned heapOffset; unsigned heapOffset;
Protector* protector; Protector* protector;
ClassInitStack* classInitStack;
Runnable runnable; Runnable runnable;
uintptr_t* defaultHeap; uintptr_t* defaultHeap;
uintptr_t* heap; uintptr_t* heap;
@ -1710,7 +1734,7 @@ makeClassNotFoundException(Thread* t, object message)
{ {
PROTECT(t, message); PROTECT(t, message);
object trace = makeTrace(t); object trace = makeTrace(t);
return makeClassNotFoundException(t, message, trace, 0); return makeClassNotFoundException(t, message, trace, 0, 0);
} }
inline object inline object
@ -1761,6 +1785,14 @@ makeNoSuchMethodError(Thread* t, object message)
return makeNoSuchMethodError(t, message, trace, 0); return makeNoSuchMethodError(t, message, trace, 0);
} }
inline object
makeNoClassDefFoundError(Thread* t, object message)
{
PROTECT(t, message);
object trace = makeTrace(t);
return makeNoClassDefFoundError(t, message, trace, 0);
}
inline object inline object
makeUnsatisfiedLinkError(Thread* t, object message) makeUnsatisfiedLinkError(Thread* t, object message)
{ {
@ -1774,7 +1806,7 @@ makeExceptionInInitializerError(Thread* t, object cause)
{ {
PROTECT(t, cause); PROTECT(t, cause);
object trace = makeTrace(t); object trace = makeTrace(t);
return makeExceptionInInitializerError(t, 0, trace, cause); return makeExceptionInInitializerError(t, 0, trace, cause, cause);
} }
inline object inline object
@ -1790,27 +1822,16 @@ makeNew(Thread* t, object class_)
return instance; return instance;
} }
inline object object
makeNewWeakReference(Thread* t, object class_) makeNewGeneral(Thread* t, object class_);
{
assert(t, t->state == Thread::ActiveState);
object instance = makeNew(t, class_);
PROTECT(t, instance);
ACQUIRE(t, t->m->referenceLock);
jreferenceVmNext(t, instance) = t->m->weakReferences;
t->m->weakReferences = instance;
return instance;
}
inline object inline object
make(Thread* t, object class_) make(Thread* t, object class_)
{ {
if (UNLIKELY(classVmFlags(t, class_) & WeakReferenceFlag)) { if (UNLIKELY(classVmFlags(t, class_)
return makeNewWeakReference(t, class_); & (WeakReferenceFlag | HasFinalizerFlag)))
{
return makeNewGeneral(t, class_);
} else { } else {
return makeNew(t, class_); return makeNew(t, class_);
} }
@ -1933,9 +1954,9 @@ stringCharAt(Thread* t, object s, int i)
if (objectClass(t, data) if (objectClass(t, data)
== arrayBody(t, t->m->types, Machine::ByteArrayType)) == arrayBody(t, t->m->types, Machine::ByteArrayType))
{ {
return byteArrayBody(t, data, i); return byteArrayBody(t, data, stringOffset(t, s) + i);
} else { } else {
return charArrayBody(t, data, i); return charArrayBody(t, data, stringOffset(t, s) + i);
} }
} }
@ -2051,33 +2072,72 @@ fieldSize(Thread* t, object field)
object object
findLoadedClass(Thread* t, object spec); findLoadedClass(Thread* t, object spec);
inline bool
emptyMethod(Thread* t, object method)
{
return ((methodFlags(t, method) & ACC_NATIVE) == 0)
and (codeLength(t, methodCode(t, method)) == 1)
and (codeBody(t, methodCode(t, method), 0) == return_);
}
object object
parseClass(Thread* t, const uint8_t* data, unsigned length); parseClass(Thread* t, const uint8_t* data, unsigned length);
object object
resolveClass(Thread* t, object spec); resolveClass(Thread* t, object name);
inline object
resolveClass(Thread* t, const char* name)
{
return resolveClass(t, makeByteArray(t, "%s", name));
}
object object
resolveMethod(Thread* t, const char* className, const char* methodName, resolveMethod(Thread* t, object class_, const char* methodName,
const char* methodSpec); const char* methodSpec);
inline object
resolveMethod(Thread* t, const char* className, const char* methodName,
const char* methodSpec)
{
object class_ = resolveClass(t, className);
if (LIKELY(t->exception == 0)) {
return resolveMethod(t, class_, methodName, methodSpec);
} else {
return 0;
}
}
object
resolveField(Thread* t, object class_, const char* fieldName,
const char* fieldSpec);
inline object
resolveField(Thread* t, const char* className, const char* fieldName,
const char* fieldSpec)
{
object class_ = resolveClass(t, className);
if (LIKELY(t->exception == 0)) {
return resolveField(t, class_, fieldName, fieldSpec);
} else {
return 0;
}
}
object object
resolveObjectArrayClass(Thread* t, object elementSpec); resolveObjectArrayClass(Thread* t, object elementSpec);
inline bool bool
classNeedsInit(Thread* t, object c) classNeedsInit(Thread* t, object c);
{
return classVmFlags(t, c) & NeedInitFlag
and (classVmFlags(t, c) & InitFlag) == 0;
}
inline void bool
initClass(Thread* t, object c) preInitClass(Thread* t, object c);
{
if (classNeedsInit(t, c)) { void
t->m->processor->initClass(t, c); postInitClass(Thread* t, object c);
}
} void
initClass(Thread* t, object c);
object object
makeObjectArray(Thread* t, object elementClass, unsigned count); makeObjectArray(Thread* t, object elementClass, unsigned count);
@ -2388,4 +2448,7 @@ dumpHeap(Thread* t, FILE* out);
void void
vmPrintTrace(vm::Thread* t); vmPrintTrace(vm::Thread* t);
void*
vmAddressFromLine(vm::Thread* t, vm::object m, unsigned line);
#endif//MACHINE_H #endif//MACHINE_H

View File

@ -83,6 +83,10 @@ main(int ac, const char** av)
++ vmArgs.nOptions; ++ vmArgs.nOptions;
#endif #endif
#ifdef BOOT_BUILTINS
++ vmArgs.nOptions;
#endif
JavaVMOption options[vmArgs.nOptions]; JavaVMOption options[vmArgs.nOptions];
vmArgs.options = options; vmArgs.options = options;
@ -103,6 +107,11 @@ main(int ac, const char** av)
= const_cast<char*>("-Davian.bootstrap=" BOOT_LIBRARY); = const_cast<char*>("-Davian.bootstrap=" BOOT_LIBRARY);
#endif #endif
#ifdef BOOT_BUILTINS
options[optionIndex++].optionString
= const_cast<char*>("-Davian.builtins=" BOOT_BUILTINS);
#endif
#define CLASSPATH_PROPERTY "-Djava.class.path=" #define CLASSPATH_PROPERTY "-Djava.class.path="
unsigned classpathSize = strlen(classpath); unsigned classpathSize = strlen(classpath);

View File

@ -124,10 +124,8 @@ class MySystem: public System {
r->setInterrupted(true); r->setInterrupted(true);
if (flags & Waiting) {
pthread_kill(thread, InterruptSignal); pthread_kill(thread, InterruptSignal);
} }
}
virtual void join() { virtual void join() {
int rv UNUSED = pthread_join(thread, 0); int rv UNUSED = pthread_join(thread, 0);
@ -852,6 +850,7 @@ handleSignal(int signal, siginfo_t* info, void* context)
} else { } else {
switch (signal) { switch (signal) {
case VisitSignal: case VisitSignal:
case InterruptSignal:
break; break;
default: default:

View File

@ -78,9 +78,6 @@ class Processor {
virtual void virtual void
initVtable(Thread* t, object c) = 0; initVtable(Thread* t, object c) = 0;
virtual void
initClass(Thread* t, object c) = 0;
virtual void virtual void
visitObjects(Thread* t, Heap::Visitor* v) = 0; visitObjects(Thread* t, Heap::Visitor* v) = 0;

View File

@ -38,7 +38,7 @@ THUNK(makeMultidimensionalArray)
THUNK(throw_) THUNK(throw_)
THUNK(checkCast) THUNK(checkCast)
THUNK(instanceOf64) THUNK(instanceOf64)
THUNK(makeNewWeakReference64) THUNK(makeNewGeneral64)
THUNK(makeNew64) THUNK(makeNew64)
THUNK(set) THUNK(set)
THUNK(gcIfNecessary) THUNK(gcIfNecessary)

View File

@ -144,8 +144,9 @@
(type illegalMonitorStateException java/lang/IllegalMonitorStateException) (type illegalMonitorStateException java/lang/IllegalMonitorStateException)
(type arrayIndexOutOfBoundsException (type indexOutOfBoundsException java/lang/IndexOutOfBoundsException)
java/lang/ArrayIndexOutOfBoundsException)
(type arrayIndexOutOfBoundsException java/lang/ArrayIndexOutOfBoundsException)
(type arrayStoreException java/lang/ArrayStoreException) (type arrayStoreException java/lang/ArrayStoreException)
@ -161,6 +162,8 @@
(type error java/lang/Error) (type error java/lang/Error)
(type virtualMachineError java/lang/VirtualMachineError)
(type stackOverflowError java/lang/StackOverflowError) (type stackOverflowError java/lang/StackOverflowError)
(type linkageError java/lang/LinkageError) (type linkageError java/lang/LinkageError)
@ -171,6 +174,8 @@
(type noSuchMethodError java/lang/NoSuchMethodError) (type noSuchMethodError java/lang/NoSuchMethodError)
(type noClassDefFoundError java/lang/NoClassDefFoundError)
(type unsatisfiedLinkError java/lang/UnsatisfiedLinkError) (type unsatisfiedLinkError java/lang/UnsatisfiedLinkError)
(type exceptionInInitializerError java/lang/ExceptionInInitializerError) (type exceptionInInitializerError java/lang/ExceptionInInitializerError)

View File

@ -110,6 +110,11 @@ class Vector {
append(&v, BytesPerWord); append(&v, BytesPerWord);
} }
void set2(unsigned offset, uint16_t v) {
assert(s, offset <= position - 2);
memcpy(data + offset, &v, 2);
}
unsigned get(unsigned offset) { unsigned get(unsigned offset) {
uint8_t v; get(offset, &v, 1); uint8_t v; get(offset, &v, 1);
return v; return v;

View File

@ -574,11 +574,20 @@ class MySystem: public System {
if (handler) { if (handler) {
segFaultHandler = handler; segFaultHandler = handler;
#ifdef __i386__
oldSegFaultHandler = SetUnhandledExceptionFilter(handleException); oldSegFaultHandler = SetUnhandledExceptionFilter(handleException);
#elif defined __x86_64__
AddVectoredExceptionHandler(1, handleException);
oldSegFaultHandler = 0;
#endif
return 0; return 0;
} else if (segFaultHandler) { } else if (segFaultHandler) {
segFaultHandler = 0; segFaultHandler = 0;
#ifdef __i386__
SetUnhandledExceptionFilter(oldSegFaultHandler); SetUnhandledExceptionFilter(oldSegFaultHandler);
#elif defined __x86_64__
//do nothing, handlers are never "unregistered" anyway
#endif
return 0; return 0;
} else { } else {
return 1; return 1;
@ -600,10 +609,15 @@ class MySystem: public System {
CONTEXT context; CONTEXT context;
rv = GetThreadContext(target->thread, &context); rv = GetThreadContext(target->thread, &context);
expect(this, rv); expect(this, rv);
#ifdef __i386__
visitor->visit(reinterpret_cast<void*>(context.Eip), visitor->visit(reinterpret_cast<void*>(context.Eip),
reinterpret_cast<void*>(context.Ebp), reinterpret_cast<void*>(context.Ebp),
reinterpret_cast<void*>(context.Esp)); reinterpret_cast<void*>(context.Esp));
#elif defined __x86_64__
visitor->visit(reinterpret_cast<void*>(context.Rip),
reinterpret_cast<void*>(context.Rbp),
reinterpret_cast<void*>(context.Rsp));
#endif
rv = ResumeThread(target->thread); rv = ResumeThread(target->thread);
expect(this, rv != -1); expect(this, rv != -1);
@ -798,7 +812,7 @@ dump(LPEXCEPTION_POINTERS e, const char* directory)
char name[MAX_PATH]; char name[MAX_PATH];
_timeb tb; _timeb tb;
_ftime(&tb); _ftime(&tb);
snprintf(name, MAX_PATH, "%s\\crash-%lld.mdmp", directory, snprintf(name, MAX_PATH, "%s\\crash-%"LLD".mdmp", directory,
(static_cast<int64_t>(tb.time) * 1000) (static_cast<int64_t>(tb.time) * 1000)
+ static_cast<int64_t>(tb.millitm)); + static_cast<int64_t>(tb.millitm));
@ -830,18 +844,31 @@ LONG CALLBACK
handleException(LPEXCEPTION_POINTERS e) handleException(LPEXCEPTION_POINTERS e)
{ {
if (e->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { if (e->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) {
#ifdef __i386__
void* ip = reinterpret_cast<void*>(e->ContextRecord->Eip); void* ip = reinterpret_cast<void*>(e->ContextRecord->Eip);
void* base = reinterpret_cast<void*>(e->ContextRecord->Ebp); void* base = reinterpret_cast<void*>(e->ContextRecord->Ebp);
void* stack = reinterpret_cast<void*>(e->ContextRecord->Esp); void* stack = reinterpret_cast<void*>(e->ContextRecord->Esp);
void* thread = reinterpret_cast<void*>(e->ContextRecord->Ebx); void* thread = reinterpret_cast<void*>(e->ContextRecord->Ebx);
#elif defined __x86_64__
void* ip = reinterpret_cast<void*>(e->ContextRecord->Rip);
void* base = reinterpret_cast<void*>(e->ContextRecord->Rbp);
void* stack = reinterpret_cast<void*>(e->ContextRecord->Rsp);
void* thread = reinterpret_cast<void*>(e->ContextRecord->Rbx);
#endif
bool jump = system->segFaultHandler->handleSignal bool jump = system->segFaultHandler->handleSignal
(&ip, &base, &stack, &thread); (&ip, &base, &stack, &thread);
#ifdef __i386__
e->ContextRecord->Eip = reinterpret_cast<DWORD>(ip); e->ContextRecord->Eip = reinterpret_cast<DWORD>(ip);
e->ContextRecord->Ebp = reinterpret_cast<DWORD>(base); e->ContextRecord->Ebp = reinterpret_cast<DWORD>(base);
e->ContextRecord->Esp = reinterpret_cast<DWORD>(stack); e->ContextRecord->Esp = reinterpret_cast<DWORD>(stack);
e->ContextRecord->Ebx = reinterpret_cast<DWORD>(thread); e->ContextRecord->Ebx = reinterpret_cast<DWORD>(thread);
#elif defined __x86_64__
e->ContextRecord->Rip = reinterpret_cast<DWORD64>(ip);
e->ContextRecord->Rbp = reinterpret_cast<DWORD64>(base);
e->ContextRecord->Rsp = reinterpret_cast<DWORD64>(stack);
e->ContextRecord->Rbx = reinterpret_cast<DWORD64>(thread);
#endif
if (jump) { if (jump) {
return EXCEPTION_CONTINUE_EXECUTION; return EXCEPTION_CONTINUE_EXECUTION;

161
src/x86.S
View File

@ -8,16 +8,145 @@
There is NO WARRANTY for this software. See license.txt for There is NO WARRANTY for this software. See license.txt for
details. */ details. */
#include "types.h" #include "types.h"
#define LOCAL(x) .L##x #define LOCAL(x) .L##x
#if defined __APPLE__ || defined __MINGW32__ || defined __CYGWIN32__
# define GLOBAL(x) _##x
#else
# define GLOBAL(x) x
#endif
.text .text
#ifdef __x86_64__ #ifdef __x86_64__
.globl vmNativeCall #ifdef __MINGW32__
vmNativeCall:
.globl GLOBAL(vmNativeCall)
GLOBAL(vmNativeCall):
pushq %rbp
//save nonvolatile registers
pushq %r12
pushq %r13
pushq %r14
pushq %r15
movq %rsp, %rbp
// %rcx: function
// %rdx: arguments
// %r8: arguments count
// %r9: return type
movq %rcx, %r10
movq %rdx, %r11
movq %r8, %r12
movq %r9, %r13
// %r10: function
// %r11: arguments
// %r12: arguments count
// %r13: return type
//allocate initial stack space
subq $32, %rsp
//first arg
cmp $0, %r12
je LOCAL(call)
movq 0(%r11),%rcx
movq 0(%r11),%xmm0
subq $1, %r12
//second arg
cmp $0, %r12
je LOCAL(call)
movq 8(%r11),%rdx
movq 8(%r11),%xmm1
subq $1, %r12
//third arg
cmp $0, %r12
je LOCAL(call)
movq 16(%r11),%r8
movq 16(%r11),%xmm2
subq $1, %r12
//fourth arg
cmp $0, %r12
je LOCAL(call)
movq 24(%r11),%r9
movq 24(%r11),%xmm3
subq $1, %r12
//calculate stack space for arguments, aligned
movq $8, %r15
leaq (%r15, %r12, 8), %r15
andq $0xFFFFFFFFFFFFFFF0, %r15
//reserve stack space for arguments
subq %r15, %rsp
//reset the counter
addq $3, %r12
jmp LOCAL(loopend)
LOCAL(loop):
movq (%r11, %r12, 8), %r14
movq %r14, (%rsp, %r12, 8);
subq $1, %r12
LOCAL(loopend):
//we don't need to move arg 3 and lower
cmpq $3, %r12
jne LOCAL(loop)
LOCAL(call):
call *%r10
LOCAL(void):
cmpq $VOID_TYPE,%r13
jne LOCAL(float)
jmp LOCAL(exit)
LOCAL(float):
cmpq $FLOAT_TYPE,%r13
je LOCAL(copy)
cmpq $DOUBLE_TYPE,%r13
jne LOCAL(exit)
LOCAL(copy):
movq %xmm0,%rax
LOCAL(exit):
movq %rbp, %rsp
//return nonvolatile registers to their former state
popq %r15
popq %r14
popq %r13
popq %r12
popq %rbp
ret
.globl GLOBAL(vmJump)
GLOBAL(vmJump):
movq %rdx,%rbp
movq 8(%rsp),%rax
movq 16(%rsp),%rdx
movq %r8,%rsp
movq %r9,%rbx
jmp *%rcx
#else // not __MINGW32__
.globl GLOBAL(vmNativeCall)
GLOBAL(vmNativeCall):
pushq %rbp pushq %rbp
movq %rsp,%rbp movq %rsp,%rbp
@ -113,8 +242,8 @@ LOCAL(exit):
popq %rbp popq %rbp
ret ret
.globl vmJump .globl GLOBAL(vmJump)
vmJump: GLOBAL(vmJump):
movq %rsi,%rbp movq %rsi,%rbp
movq %rdx,%rsp movq %rdx,%rsp
movq %rcx,%rbx movq %rcx,%rbx
@ -122,15 +251,12 @@ vmJump:
movq %r9,%rdx movq %r9,%rdx
jmp *%rdi jmp *%rdi
#endif // not __MINGW32__
#elif defined __i386__ #elif defined __i386__
# if defined __APPLE__ || defined __MINGW32__ || defined __CYGWIN32__ .globl GLOBAL(vmNativeCall)
.globl _vmNativeCall GLOBAL(vmNativeCall):
_vmNativeCall:
# else
.globl vmNativeCall
vmNativeCall:
# endif
pushl %ebp pushl %ebp
movl %esp,%ebp movl %esp,%ebp
@ -201,13 +327,8 @@ LOCAL(exit):
popl %ebp popl %ebp
ret ret
# if defined __APPLE__ || defined __MINGW32__ || defined __CYGWIN32__ .globl GLOBAL(vmJump)
.globl _vmJump GLOBAL(vmJump):
_vmJump:
# else
.globl vmJump
vmJump:
# endif
movl 4(%esp),%esi movl 4(%esp),%esi
movl 8(%esp),%ebp movl 8(%esp),%ebp
movl 16(%esp),%ebx movl 16(%esp),%ebx
@ -216,6 +337,4 @@ vmJump:
movl 12(%esp),%esp movl 12(%esp),%esp
jmp *%esi jmp *%esi
#else #endif //def __x86_64__
# error unsupported platform
#endif

File diff suppressed because it is too large Load Diff

View File

@ -58,11 +58,24 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t*,
# define THREAD_REGISTER(context) (context->uc_mcontext.gregs[REG_RBX]) # define THREAD_REGISTER(context) (context->uc_mcontext.gregs[REG_RBX])
extern "C" uint64_t extern "C" uint64_t
# ifdef __MINGW32__
vmNativeCall(void* function, void* stack, unsigned stackSize,
unsigned returnType);
# else
vmNativeCall(void* function, void* stack, unsigned stackSize, vmNativeCall(void* function, void* stack, unsigned stackSize,
void* gprTable, void* sseTable, unsigned returnType); void* gprTable, void* sseTable, unsigned returnType);
# endif
namespace vm { namespace vm {
# ifdef __MINGW32__
inline uint64_t
dynamicCall(void* function, uint64_t* arguments, UNUSED uint8_t* argumentTypes,
unsigned argumentCount, unsigned, unsigned returnType)
{
return vmNativeCall(function, arguments, argumentCount, returnType);
}
# else
inline uint64_t inline uint64_t
dynamicCall(void* function, uint64_t* arguments, uint8_t* argumentTypes, dynamicCall(void* function, uint64_t* arguments, uint8_t* argumentTypes,
unsigned argumentCount, unsigned, unsigned returnType) unsigned argumentCount, unsigned, unsigned returnType)
@ -103,6 +116,7 @@ dynamicCall(void* function, uint64_t* arguments, uint8_t* argumentTypes,
(gprIndex ? gprTable : 0), (gprIndex ? gprTable : 0),
(sseIndex ? sseTable : 0), returnType); (sseIndex ? sseTable : 0), returnType);
} }
#endif
} // namespace vm } // namespace vm

34
test/Finalizers.java Normal file
View File

@ -0,0 +1,34 @@
public class Finalizers {
private static boolean finalized = false;
private static void expect(boolean v) {
if (! v) throw new RuntimeException();
}
protected void finalize() {
finalized = true;
}
public static void main(String[] args) {
new Finalizers();
expect(! finalized);
System.gc();
expect(finalized);
new Finalizers2();
finalized = false;
expect(! finalized);
System.gc();
expect(finalized);
}
private static class Finalizers2 extends Finalizers { }
}

View File

@ -3,13 +3,14 @@ public class Subroutine {
if (! v) throw new RuntimeException(); if (! v) throw new RuntimeException();
} }
// This test is intended to cover the jsr and ret instructions. // These tests are intended to cover the jsr and ret instructions.
// However, recent Sun javac versions avoid generating these // However, recent Sun javac versions avoid generating these
// instructions by default, so we must compile this class using // instructions by default, so we must compile this class using
// -source 1.2 -target 1.1 -XDjsrlimit=0. // -source 1.2 -target 1.1 -XDjsrlimit=0.
// //
// http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4381996 // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4381996
// //
private static void test(boolean throw_, boolean predicate) { private static void test(boolean throw_, boolean predicate) {
int x = 42; int x = 42;
int y = 99; int y = 99;
@ -32,10 +33,159 @@ public class Subroutine {
} }
} }
private static Object test2(int path) {
try {
try {
switch (path) {
case 1:
return new Object();
case 2: {
int a = 42;
return Integer.valueOf(a);
}
case 3:
throw new DummyException();
}
} finally {
System.gc();
}
return null;
} catch (DummyException e) {
e.printStackTrace();
return null;
}
}
private static Object test3(int path1, int path2, int path3) {
try {
try {
switch (path1) {
case 1:
return new Object();
case 2: {
int a = 42;
return Integer.valueOf(a);
}
case 3:
throw new DummyException();
}
} finally {
try {
switch (path2) {
case 1:
return new Object();
case 2: {
int a = 42;
return Integer.valueOf(a);
}
case 3:
throw new DummyException();
}
} finally {
try {
switch (path3) {
case 1:
return new Object();
case 2: {
int a = 42;
return Integer.valueOf(a);
}
case 3:
throw new DummyException();
}
} finally {
System.gc();
}
}
}
return null;
} catch (DummyException e) {
e.printStackTrace();
return null;
}
}
private static long test4(int path) {
try {
try {
switch (path) {
case 1:
return 42L;
case 2: {
int a = 42;
return 52L;
}
case 3:
throw new DummyException();
}
} finally {
System.gc();
}
return 0L;
} catch (DummyException e) {
e.printStackTrace();
return 0L;
}
}
public static void main(String[] args) { public static void main(String[] args) {
test(false, false); test(false, false);
test(false, true); test(false, true);
test(true, false); test(true, false);
String.valueOf(test2(1));
String.valueOf(test2(2));
String.valueOf(test2(3));
String.valueOf(test3(1, 1, 1));
String.valueOf(test3(2, 1, 1));
String.valueOf(test3(3, 1, 1));
String.valueOf(test3(1, 2, 1));
String.valueOf(test3(2, 2, 1));
String.valueOf(test3(3, 2, 1));
String.valueOf(test3(1, 3, 1));
String.valueOf(test3(2, 3, 1));
String.valueOf(test3(3, 3, 1));
String.valueOf(test3(1, 1, 2));
String.valueOf(test3(2, 1, 2));
String.valueOf(test3(3, 1, 2));
String.valueOf(test3(1, 2, 2));
String.valueOf(test3(2, 2, 2));
String.valueOf(test3(3, 2, 2));
String.valueOf(test3(1, 3, 2));
String.valueOf(test3(2, 3, 2));
String.valueOf(test3(3, 3, 2));
String.valueOf(test3(1, 1, 3));
String.valueOf(test3(2, 1, 3));
String.valueOf(test3(3, 1, 3));
String.valueOf(test3(1, 2, 3));
String.valueOf(test3(2, 2, 3));
String.valueOf(test3(3, 2, 3));
String.valueOf(test3(1, 3, 3));
String.valueOf(test3(2, 3, 3));
String.valueOf(test3(3, 3, 3));
String.valueOf(test4(1));
String.valueOf(test4(2));
String.valueOf(test4(3));
} }
private static class DummyException extends RuntimeException { } private static class DummyException extends RuntimeException { }

View File

@ -88,26 +88,4 @@ public class Tree {
isEqual(printMap(map), "a=A, b=B, c=C, q=Q, y=Y, z=Z"); isEqual(printMap(map), "a=A, b=B, c=C, q=Q, y=Y, z=Z");
} }
private static class MyEntry<K,V> implements Map.Entry<K,V> {
public final K key;
public V value;
public MyEntry(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey() {
return key;
}
public V getValue() {
return value;
}
public void setValue(V value) {
this.value = value;
}
}
} }

View File

@ -9,7 +9,9 @@ public class Zip {
ZipFile file = new ZipFile("build/classpath.jar"); ZipFile file = new ZipFile("build/classpath.jar");
byte[] buffer = new byte[4096]; byte[] buffer = new byte[4096];
for (Enumeration<ZipEntry> e = file.entries(); e.hasMoreElements();) { for (Enumeration<? extends ZipEntry> e = file.entries();
e.hasMoreElements();)
{
ZipEntry entry = e.nextElement(); ZipEntry entry = e.nextElement();
InputStream in = file.getInputStream(entry); InputStream in = file.getInputStream(entry);
try { try {

4
vm.pro
View File

@ -73,7 +73,9 @@
# Thread.run is called by name in the VM # Thread.run is called by name in the VM
-keepclassmembernames class java.lang.Thread { void run(); } -keepclassmembers class java.lang.Thread {
private static void run(java.lang.Thread);
}
# when continuations are enabled, the VM may call these methods by name: # when continuations are enabled, the VM may call these methods by name: