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
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
details. */
package java.util;
package avian;
public class Cell <T> {
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
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
details. */
package java.util;
package avian;
import java.util.Comparator;
public class PersistentSet <T> implements Iterable <T> {
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
# include <windows.h>
# include <io.h>
# include <direct.h>
# define OPEN _open
# define CLOSE _close

View File

@ -82,7 +82,7 @@ namespace {
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) {
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
for any purpose with or without fee is hereby granted, provided
@ -10,7 +10,7 @@
package java.lang;
public class ArrayIndexOutOfBoundsException extends RuntimeException {
public class ArrayIndexOutOfBoundsException extends IndexOutOfBoundsException {
public ArrayIndexOutOfBoundsException(String message, Throwable cause) {
super(message, cause);
}

View File

@ -187,4 +187,40 @@ public final class Character implements Comparable<Character> {
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.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.GenericDeclaration;
import java.lang.annotation.Annotation;
import java.io.InputStream;
import java.io.IOException;
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 short flags;
@ -84,6 +91,9 @@ public final class Class <T> {
ClassLoader loader)
throws ClassNotFoundException
{
if (loader == null) {
loader = Class.class.loader;
}
Class c = loader.loadClass(name);
if (initialize) {
c.initialize();
@ -168,6 +178,8 @@ public final class Class <T> {
private Method findMethod(String name, Class[] parameterTypes) {
if (methodTable != null) {
if (parameterTypes == null)
parameterTypes = new Class[0];
for (int i = 0; i < methodTable.length; ++i) {
if (methodTable[i].getName().equals(name)
&& match(parameterTypes, methodTable[i].getParameterTypes()))
@ -434,8 +446,63 @@ public final class Class <T> {
return null;
}
}
public boolean desiredAssertionStatus() {
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
for any purpose with or without fee is hereby granted, provided
@ -11,8 +11,11 @@
package java.lang;
public class ClassNotFoundException extends Exception {
private final Throwable cause2;
public ClassNotFoundException(String message, Throwable cause) {
super(message, cause);
cause2 = cause;
}
public ClassNotFoundException(String message) {

View File

@ -53,4 +53,12 @@ public abstract class Enum<E extends Enum<E>> implements Comparable<E> {
public String toString() {
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
for any purpose with or without fee is hereby granted, provided
@ -11,11 +11,14 @@
package java.lang;
public class ExceptionInInitializerError extends Error {
private final Throwable cause2;
public ExceptionInInitializerError(String message) {
super(message);
cause2 = null;
}
public ExceptionInInitializerError() {
super();
this(null);
}
}

View File

@ -25,7 +25,7 @@ public class Object {
return this == o;
}
protected void finalize() { }
protected void finalize() throws Throwable { }
public native final Class<? extends Object> getClass();
@ -41,5 +41,14 @@ public class Object {
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
for any purpose with or without fee is hereby granted, provided
@ -10,9 +10,9 @@
package java.lang;
public class StackOverflowError extends Error {
public class StackOverflowError extends VirtualMachineError {
public StackOverflowError(String message) {
super(message, null);
super(message);
}
public StackOverflowError() {

View File

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

View File

@ -12,14 +12,30 @@ package java.lang;
import java.io.UnsupportedEncodingException;
import java.util.regex.Pattern;
import java.util.Comparator;
import java.util.Locale;
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 int offset;
private final int length;
private int hashCode;
public String() {
this(new char[0], 0, 0);
}
public String(char[] data, int offset, int length, boolean copy) {
this((Object) data, offset, length, copy);
}
@ -32,9 +48,11 @@ public final class String implements Comparable<String>, CharSequence {
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);
if (!charsetName.equals("UTF-8")) {
if (! charsetName.equalsIgnoreCase("UTF-8")) {
throw new UnsupportedEncodingException(charsetName);
}
}
@ -57,12 +75,29 @@ public final class String implements Comparable<String>, CharSequence {
public String(byte[] data, String charset)
throws UnsupportedEncodingException
{
this(data);
if (! charset.equals("UTF-8")) {
throw new UnsupportedEncodingException(charset);
}
{
this(data);
if (! charset.equals("UTF-8")) {
throw new UnsupportedEncodingException(charset);
}
}
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) {
int l;
@ -200,7 +235,7 @@ public final class String implements Comparable<String>, CharSequence {
}
public boolean equalsIgnoreCase(String s) {
return this == s || compareToIgnoreCase(s) == 0;
return this == s || (s != null && compareToIgnoreCase(s) == 0);
}
public int compareTo(String s) {
@ -381,7 +416,7 @@ public final class String implements Comparable<String>, CharSequence {
}
} else {
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);
}
public String replaceAll(String regex, String replacement) {
return Pattern.compile(regex).matcher(this).replaceAll(replacement);
}
public native String intern();
public static String valueOf(Object s) {
@ -557,7 +596,9 @@ public final class String implements Comparable<String>, CharSequence {
}
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) {
@ -572,6 +613,14 @@ public final class String implements Comparable<String>, CharSequence {
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) {
for (int i = lastIndex ; i >= 0; --i) {
if (charAt(i) == ch) {
@ -581,4 +630,63 @@ public final class String implements Comparable<String>, CharSequence {
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;
public class StringBuilder implements CharSequence {
public class StringBuilder implements CharSequence, Appendable {
private static final int BufferSize = 32;
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) {
return append(new String(b, offset, length));
}
@ -150,6 +158,10 @@ public class StringBuilder implements CharSequence {
return this;
}
public StringBuilder insert(int i, CharSequence s) {
return insert(i, s.toString());
}
public StringBuilder insert(int i, char c) {
return insert(i, new String(new char[] { c }, 0, 1, false));
}
@ -332,4 +344,8 @@ public class StringBuilder implements CharSequence {
deleteCharAt(index);
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
for any purpose with or without fee is hereby granted, provided
@ -15,14 +15,30 @@ import java.util.WeakHashMap;
public class Thread implements Runnable {
private long peer;
private boolean interrupted;
private boolean daemon;
private byte state;
private byte priority;
private final Runnable task;
private Map<ThreadLocal, Object> locals;
private boolean interrupted;
private Object sleepLock;
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.name = name;
@ -41,8 +57,28 @@ public class Thread implements Runnable {
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) {
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() {
@ -58,6 +94,28 @@ public class Thread implements Runnable {
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() {
if (task != null) {
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 {
Thread t = currentThread();
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() {
return Throwable.resolveTrace(getStackTrace(peer));
}
@ -124,5 +196,125 @@ public class Thread implements Runnable {
public String getName() {
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.PrintWriter;
import java.io.IOException;
import java.io.Serializable;
public class Throwable {
public class Throwable implements Serializable {
private String message;
private Object trace;
private Throwable cause;
@ -109,4 +110,9 @@ public class Throwable {
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;
}
protected Reference(T target) {
this(target, null);
}
public T get() {
return target;
}

View File

@ -10,7 +10,9 @@
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;
public Constructor(Method<T> method) {
@ -46,6 +48,18 @@ public class Constructor<T> extends AccessibleObject implements Member {
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);
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)
throws IllegalAccessException
{
@ -162,6 +194,10 @@ public class Field<T> extends AccessibleObject {
}
}
public boolean isEnumConstant() {
throw new UnsupportedOperationException();
}
private static native long getPrimitive
(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 String getName();
public boolean isSynthetic();
}

View File

@ -10,7 +10,9 @@
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 returnCode;
private byte parameterCount;
@ -124,4 +126,28 @@ public class Method<T> extends AccessibleObject implements Member {
}
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
for any purpose with or without fee is hereby granted, provided
@ -11,7 +11,6 @@
package java.net;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.io.InputStream;
public final class URL {
@ -73,7 +72,7 @@ public final class URL {
throws MalformedURLException
{
if ("resource".equals(protocol)) {
return new ResourceHandler();
return new avian.resource.Handler();
} else {
throw new MalformedURLException("unknown protocol: " + protocol);
}
@ -88,87 +87,4 @@ public final class URL {
this.file = file;
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
for any purpose with or without fee is hereby granted, provided
@ -10,6 +10,9 @@
package java.util;
import avian.PersistentSet;
import avian.Cell;
public class TreeSet<T> extends AbstractSet<T> implements Collection<T> {
private PersistentSet<Cell<T>> set;
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
for any purpose with or without fee is hereby granted, provided
@ -63,7 +63,7 @@ public class ZipFile {
return index.size();
}
public Enumeration<ZipEntry> entries() {
public Enumeration<? extends ZipEntry> entries() {
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)))
platform = $(bootimage-platform)
ifeq ($(platform),windows)
arch = i386
endif
mode = fast
process = compile
@ -43,6 +39,23 @@ endif
ifeq ($(continuations),true)
options := $(options)-continuations
endif
ifdef gnu
options := $(options)-gnu
gnu-sources = $(src)/gnu.cpp
gnu-jar = $(gnu)/share/classpath/glibj.zip
gnu-libraries = \
$(gnu)/lib/classpath/libjavaio.a \
$(gnu)/lib/classpath/libjavalang.a \
$(gnu)/lib/classpath/libjavalangreflect.a \
$(gnu)/lib/classpath/libjavamath.a \
$(gnu)/lib/classpath/libjavanet.a \
$(gnu)/lib/classpath/libjavanio.a \
$(gnu)/lib/classpath/libjavautil.a
gnu-object-dep = $(build)/gnu-object.dep
gnu-cflags = -DBOOT_BUILTINS=\"javaio,javalang,javalangreflect,javamath,javanet,javanio,javautil\" -DAVIAN_GNU
gnu-lflags = -lgmp
gnu-objects = $(shell find $(build)/gnu-objects -name "*.o")
endif
root = $(shell (cd .. && pwd))
build = build
@ -53,6 +66,12 @@ src = src
classpath = classpath
test = test
ifdef gnu
avian-classpath-build = $(build)/avian-classpath
else
avian-classpath-build = $(classpath-build)
endif
input = List
build-cxx = g++
@ -83,13 +102,14 @@ warnings = -Wall -Wextra -Werror -Wunused-parameter -Winit-self \
common-cflags = $(warnings) -fno-rtti -fno-exceptions -fno-omit-frame-pointer \
"-I$(JAVA_HOME)/include" -idirafter $(src) -I$(native-build) \
-D__STDC_LIMIT_MACROS -D_JNI_IMPLEMENTATION_ -DAVIAN_VERSION=\"$(version)\" \
$(gnu-cflags)
build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \
"-I$(JAVA_HOME)/include/linux" -I$(src) -pthread
cflags = $(build-cflags)
common-lflags = -lm -lz
common-lflags = -lm -lz $(gnu-lflags)
build-lflags =
@ -167,6 +187,21 @@ ifeq ($(platform),windows)
native-path = cygpath -m
endif
endif
ifeq ($(arch),x86_64)
cxx = x86_64-pc-mingw32-g++
cc = x86_64-pc-mingw32-gcc
dlltool = x86_64-pc-mingw32-dlltool
ar = x86_64-pc-mingw32-ar
ranlib = x86_64-pc-mingw32-ranlib
objcopy = x86_64-pc-mingw32-objcopy
strip = :
inc = "$(root)/win64/include"
lib = "$(root)/win64/lib"
pointer-size = 8
object-format = pe-x86-64
endif
endif
ifeq ($(mode),debug)
@ -232,7 +267,8 @@ vm-sources = \
$(src)/$(process).cpp \
$(src)/builtin.cpp \
$(src)/jnienv.cpp \
$(src)/process.cpp
$(src)/process.cpp \
$(gnu-sources)
vm-asm-sources = $(src)/$(asm).S
@ -314,16 +350,43 @@ classpath-sources = $(shell find $(classpath) -name '*.java')
classpath-classes = \
$(call java-classes,$(classpath-sources),$(classpath),$(classpath-build))
classpath-object = $(native-build)/classpath-jar.o
classpath-dep = $(classpath-build)/dep
classpath-dep = $(classpath-build).dep
gnu-blacklist = \
java/lang/AbstractStringBuffer.class \
java/lang/reflect/Proxy.class
gnu-overrides = \
avian/*.class \
avian/resource/*.class \
java/lang/Class.class \
java/lang/Enum.class \
java/lang/InheritableThreadLocal.class \
java/lang/Object.class \
java/lang/StackTraceElement.class \
java/lang/String*.class \
java/lang/StringBuffer.class \
java/lang/StringBuilder.class \
java/lang/Thread.class \
java/lang/ThreadLocal.class \
java/lang/Throwable.class \
java/lang/ref/PhantomReference.class \
java/lang/ref/Reference.class \
java/lang/ref/ReferenceQueue.class \
java/lang/ref/WeakReference.class \
java/lang/reflect/AccessibleObject.class \
java/lang/reflect/Constructor.class \
java/lang/reflect/Field.class \
java/lang/reflect/Method.class
test-sources = $(wildcard $(test)/*.java)
test-classes = $(call java-classes,$(test-sources),$(test),$(test-build))
test-dep = $(test-build)/dep
test-dep = $(test-build).dep
test-extra-sources = $(wildcard $(test)/extra/*.java)
test-extra-classes = \
$(call java-classes,$(test-extra-sources),$(test),$(test-build))
test-extra-dep = $(test-build)/extra/dep
test-extra-dep = $(test-build)-extra.dep
class-name = $(patsubst $(1)/%.class,%,$(2))
class-names = $(foreach x,$(2),$(call class-name,$(1),$(x)))
@ -393,11 +456,24 @@ $(native-build)/type-generator.o: \
$(classpath-build)/%.class: $(classpath)/%.java
@echo $(<)
$(classpath-dep): $(classpath-sources)
$(classpath-dep): $(classpath-sources) $(gnu-jar)
@echo "compiling classpath classes"
@mkdir -p $(dir $(@))
$(javac) -d $(dir $(@)) -bootclasspath $(classpath-build) \
@mkdir -p $(avian-classpath-build)
$(javac) -d $(avian-classpath-build) \
-bootclasspath $(avian-classpath-build) \
$(shell $(MAKE) -s --no-print-directory $(classpath-classes))
ifdef gnu
(wd=$$(pwd) && \
cd $(avian-classpath-build) && \
$(jar) c0f "$$($(native-path) "$${wd}/$(build)/overrides.jar")" \
$(gnu-overrides))
@mkdir -p $(classpath-build)
(wd=$$(pwd) && \
cd $(classpath-build) && \
$(jar) xf $(gnu-jar) && \
rm $(gnu-blacklist) && \
jar xf "$$($(native-path) "$${wd}/$(build)/overrides.jar")")
endif
@touch $(@)
$(test-build)/%.class: $(test)/%.java
@ -405,16 +481,16 @@ $(test-build)/%.class: $(test)/%.java
$(test-dep): $(test-sources)
@echo "compiling test classes"
@mkdir -p $(dir $(@))
$(javac) -d $(dir $(@)) -bootclasspath $(classpath-build) \
@mkdir -p $(test-build)
$(javac) -d $(test-build) -bootclasspath $(classpath-build) \
$(shell $(MAKE) -s --no-print-directory $(test-classes))
$(javac) -source 1.2 -target 1.1 -XDjsrlimit=0 -d $(dir $(@)) \
$(javac) -source 1.2 -target 1.1 -XDjsrlimit=0 -d $(test-build) \
test/Subroutine.java
@touch $(@)
$(test-extra-dep): $(test-extra-sources)
@echo "compiling extra test classes"
@mkdir -p $(dir $(@))
@mkdir -p $(test-build)
$(javac) -d $(test-build) -bootclasspath $(classpath-build) \
$(shell $(MAKE) -s --no-print-directory $(test-extra-classes))
@touch $(@)
@ -456,9 +532,9 @@ $(boot-object): $(boot-source)
$(compile-object)
$(build)/classpath.jar: $(classpath-dep)
(wd=$$(pwd); \
cd $(classpath-build); \
$(jar) c0f "$$($(native-path) "$${wd}/$(@)")" $$(find . -name '*.class'))
(wd=$$(pwd) && \
cd $(classpath-build) && \
$(jar) c0f "$$($(native-path) "$${wd}/$(@)")" .)
$(binaryToMacho): $(src)/binaryToMacho.cpp
$(cxx) $(^) -o $(@)
@ -469,8 +545,8 @@ ifeq ($(platform),darwin)
$(binaryToMacho) $(asm) $(build)/classpath.jar __TEXT __text \
__binary_classpath_jar_start __binary_classpath_jar_end > $(@)
else
(wd=$$(pwd); \
cd $(build); \
(wd=$$(pwd) && \
cd $(build) && \
$(objcopy) -I binary classpath.jar \
-O $(object-format) -B $(object-arch) "$${wd}/$(@)")
endif
@ -484,10 +560,11 @@ $(generator-objects): $(native-build)/%.o: $(src)/%.cpp
$(jni-objects): $(native-build)/%.o: $(classpath)/%.cpp
$(compile-object)
$(static-library): $(gnu-object-dep)
$(static-library): $(vm-objects) $(jni-objects) $(vm-heapwalk-objects)
@echo "creating $(@)"
rm -rf $(@)
$(ar) cru $(@) $(^)
$(ar) cru $(@) $(^) $(call gnu-objects)
$(ranlib) $(@)
$(bootimage-bin): $(bootimage-generator)
@ -499,24 +576,32 @@ ifeq ($(platform),darwin)
$(binaryToMacho) $(asm) $(<) __BOOT __boot \
__binary_bootimage_bin_start __binary_bootimage_bin_end > $(@)
else
(wd=$$(pwd); \
cd $(native-build); \
(wd=$$(pwd) && \
cd $(native-build) && \
$(objcopy) --rename-section=.data=.boot -I binary bootimage.bin \
-O $(object-format) -B $(object-arch) "$${wd}/$(@).tmp"; \
-O $(object-format) -B $(object-arch) "$${wd}/$(@).tmp" && \
$(objcopy) --set-section-flags .boot=alloc,load,code "$${wd}/$(@).tmp" \
"$${wd}/$(@)")
endif
$(gnu-object-dep): $(gnu-libraries)
@mkdir -p $(build)/gnu-objects
(cd $(build)/gnu-objects && \
for x in $(gnu-libraries); do ar x $${x}; done)
@touch $(@)
$(executable): $(gnu-object-dep)
$(executable): \
$(vm-objects) $(jni-objects) $(driver-object) $(vm-heapwalk-objects) \
$(boot-object) $(vm-classpath-object)
@echo "linking $(@)"
ifeq ($(platform),windows)
$(dlltool) -z $(@).def $(^)
$(dlltool) -z $(@).def $(^) $(call gnu-objects)
$(dlltool) -d $(@).def -e $(@).exp
$(cc) $(@).exp $(^) $(lflags) -o $(@)
$(cc) $(@).exp $(^) $(call gnu-objects) $(lflags) -o $(@)
else
$(cc) $(^) $(rdynamic) $(lflags) $(bootimage-lflags) -o $(@)
$(cc) $(^) $(call gnu-objects) $(rdynamic) $(lflags) $(bootimage-lflags) \
-o $(@)
endif
$(strip) $(strip-all) $(@)
@ -545,11 +630,13 @@ else
$(cc) $(^) $(rdynamic) $(lflags) -o $(@)
endif
$(dynamic-library): $(gnu-object-dep)
$(dynamic-library): \
$(vm-objects) $(dynamic-object) $(jni-objects) $(vm-heapwalk-objects) \
$(boot-object) $(vm-classpath-object)
$(boot-object) $(vm-classpath-object) $(gnu-libraries)
@echo "linking $(@)"
$(cc) $(^) $(shared) $(lflags) $(bootimage-lflags) -o $(@)
$(cc) $(^) $(call gnu-objects) $(shared) $(lflags) $(bootimage-lflags) \
-o $(@)
$(strip) $(strip-all) $(@)
$(executable-dynamic): $(driver-dynamic-object) $(dynamic-library)
@ -560,4 +647,3 @@ $(executable-dynamic): $(driver-dynamic-object) $(dynamic-library)
$(generator): $(generator-objects)
@echo "linking $(@)"
$(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)));
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);
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
extern "C" JNIEXPORT int64_t JNICALL
@ -530,7 +549,9 @@ Avian_java_lang_System_arraycopy
int32_t length = arguments[4];
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));
if (LIKELY(elementSize)) {
@ -602,6 +623,10 @@ Avian_java_lang_Runtime_load
and (s[length] == ',' or s[length] == 0))
{
// library is built in to this executable
if (not t->m->triedBuiltinOnLoad) {
t->m->triedBuiltinOnLoad = true;
runOnLoadIfFound(t, t->m->libraries);
}
return;
} else {
while (*s and *s != ',') ++ s;
@ -625,6 +650,7 @@ Avian_java_lang_Runtime_load
System::Library* lib;
if (LIKELY(t->m->system->success(t->m->system->load(&lib, n, mapName)))) {
last->setNext(lib);
runOnLoadIfFound(t, lib);
} else {
object message = makeString(t, "library not found: %s", n);
t->exception = makeUnsatisfiedLinkError(t, message);
@ -836,7 +862,7 @@ Avian_java_lang_Thread_enumerate
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_java_net_URL_00024ResourceInputStream_getContentLength
Avian_avian_resource_Handler_00024ResourceInputStream_getContentLength
(Thread* t, object, uintptr_t* arguments)
{
object path = reinterpret_cast<object>(*arguments);
@ -856,7 +882,7 @@ Avian_java_net_URL_00024ResourceInputStream_getContentLength
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_java_net_URL_00024ResourceInputStream_open
Avian_avian_resource_Handler_00024ResourceInputStream_open
(Thread* t, object, uintptr_t* arguments)
{
object path = reinterpret_cast<object>(*arguments);
@ -873,7 +899,7 @@ Avian_java_net_URL_00024ResourceInputStream_open
}
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)
{
int64_t peer; memcpy(&peer, arguments, 8);
@ -888,7 +914,7 @@ Avian_java_net_URL_00024ResourceInputStream_read__JI
}
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)
{
int64_t peer; memcpy(&peer, arguments, 8);
@ -913,7 +939,7 @@ Avian_java_net_URL_00024ResourceInputStream_read__JI_3BII
}
extern "C" JNIEXPORT void JNICALL
Avian_java_net_URL_00024ResourceInputStream_close
Avian_avian_resource_Handler_00024ResourceInputStream_close
(Thread*, object, uintptr_t* arguments)
{
int64_t peer; memcpy(&peer, arguments, 8);

View File

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

View File

@ -21,19 +21,140 @@
.text
#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
#ifdef __MINGW32__
#define CALLEE_SAVED_REGISTER_FOOTPRINT 64
.globl GLOBAL(vmInvoke)
GLOBAL(vmInvoke):
pushq %rbp
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
@ -88,65 +209,7 @@ GLOBAL(vmInvoke_returnAddress):
movq %rbp,%rsp
#ifdef AVIAN_CONTINUATIONS
// 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):
# include "continuations-x86.S"
#endif // AVIAN_CONTINUATIONS
// restore callee-saved registers (below the stack pointer, but in
@ -215,21 +278,10 @@ LOCAL(vmJumpAndInvoke_argumentTest):
// enabled
int3
#endif // not AVIAN_CONTINUATIONS
#endif // not __MINGW32__
#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
@ -286,72 +338,7 @@ vmInvoke_returnAddress:
movl %ecx,%esp
#ifdef AVIAN_CONTINUATIONS
// 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):
# include "continuations-x86.S"
#endif // AVIAN_CONTINUATIONS
// restore callee-saved registers
@ -443,5 +430,5 @@ LOCAL(vmJumpAndInvoke_argumentTest):
#endif // AVIAN_CONTINUATIONS
#else
# error unsupported platform
#endif
#error unsupported architecture
#endif //def __x86_64__

File diff suppressed because it is too large Load Diff

View File

@ -2052,7 +2052,7 @@ class MultiRead: public Read {
}
lastRead = cell;
// fprintf(stderr, "append %p to %p for %p\n", r, lastTarget, this);
// fprintf(stderr, "append %p to %p for %p\n", r, lastTarget, this);
lastTarget->value = r;
}
@ -2064,7 +2064,7 @@ class MultiRead: public Read {
void allocateTarget(Context* c) {
Cell* cell = cons(c, 0, 0);
// fprintf(stderr, "allocate target for %p: %p\n", this, cell);
// fprintf(stderr, "allocate target for %p: %p\n", this, cell);
if (lastTarget) {
lastTarget->next = cell;
@ -4016,6 +4016,31 @@ appendSaveLocals(Context* 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 {
public:
DummyEvent(Context* c):
@ -4927,11 +4952,12 @@ class MyCompiler: public Compiler {
}
virtual void endSubroutine(Subroutine* subroutine) {
appendCleanLocals(&c);
static_cast<MySubroutine*>(subroutine)->forkState = ::saveState(&c);
}
virtual void restoreFromSubroutine(Subroutine* subroutine) {
::restoreState(&c, static_cast<MySubroutine*>(subroutine)->forkState);
virtual void linkSubroutine(Subroutine* subroutine) {
restoreState(static_cast<MySubroutine*>(subroutine)->forkState);
}
virtual void init(unsigned logicalCodeLength, unsigned parameterFootprint,
@ -5032,12 +5058,30 @@ class MyCompiler: public Compiler {
(c.zone->allocate(sizeof(LogicalInstruction)))
LogicalInstruction(logicalIp, c.stack, c.locals);
if (c.subroutine) {
bool startSubroutine = c.subroutine != 0;
if (startSubroutine) {
c.logicalCode[logicalIp]->subroutine = c.subroutine;
c.subroutine = 0;
}
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) {

View File

@ -43,7 +43,7 @@ class Compiler {
virtual Subroutine* startSubroutine() = 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,
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) {
Stack* dead = stack;
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 FrameFootprint = 4;
class ClassInitList;
class Thread: public vm::Thread {
public:
static const unsigned StackSizeInBytes = 64 * 1024;
@ -36,16 +38,39 @@ class Thread: public vm::Thread {
ip(0),
sp(0),
frame(-1),
code(0)
code(0),
classInitList(0)
{ }
unsigned ip;
unsigned sp;
int frame;
object code;
ClassInitList* classInitList;
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
pushObject(Thread* t, object o)
{
@ -348,12 +373,14 @@ popFrame(Thread* t)
}
}
if (UNLIKELY(methodVmFlags(t, method) & ClassInitFlag)) {
if (t->exception) {
t->exception = makeExceptionInInitializerError(t, t->exception);
}
classVmFlags(t, methodClass(t, method)) &= ~(NeedInitFlag | InitFlag);
release(t, t->m->classLock);
if (UNLIKELY(methodVmFlags(t, method) & ClassInitFlag)
and t->classInitList)
{
assert(t, t->classInitList->class_ == methodClass(t, method));
t->classInitList->pop();
postInitClass(t, methodClass(t, method));
}
t->sp = frameBase(t, t->frame);
@ -732,17 +759,21 @@ invokeNative(Thread* t, object method)
bool
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_);
acquire(t, t->m->classLock);
if (classVmFlags(t, class_) & NeedInitFlag
and (classVmFlags(t, class_) & InitFlag) == 0)
{
classVmFlags(t, class_) |= InitFlag;
if (preInitClass(t, class_)) {
ClassInitList::push(t, class_);
t->code = classInitializer(t, class_);
t->ip -= ipOffset;
return true;
} else {
release(t, t->m->classLock);
return false;
}
}
@ -3070,22 +3101,6 @@ class MyProcessor: public Processor {
// 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
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));
}
}
for (ClassInitList* list = t->classInitList; list; list = list->next) {
v->visit(reinterpret_cast<object*>(&(list->class_)));
}
}
virtual void

View File

@ -62,8 +62,10 @@ AttachCurrentThread(Machine* m, Thread** t, void*)
*t = static_cast<Thread*>(m->localThread->get());
if (*t == 0) {
*t = m->processor->makeThread(m, 0, m->rootThread);
m->system->attach(&((*t)->runnable));
enter(*t, Thread::ActiveState);
enter(*t, Thread::IdleState);
m->localThread->set(*t);
}
@ -264,6 +266,26 @@ ExceptionCheck(Thread* t)
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
GetObjectClass(Thread* t, jobject o)
{
@ -823,22 +845,12 @@ CallStaticVoidMethod(Thread* t, jclass c, jmethodID m, ...)
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
GetFieldID(Thread* t, jclass c, const char* name, const char* spec)
{
ENTER(t, Thread::ActiveState);
object field = findField(t, c, name, spec);
object field = resolveField(t, *c, name, spec);
if (UNLIKELY(t->exception)) return 0;
return fieldOffset(t, field);
@ -849,7 +861,7 @@ GetStaticFieldID(Thread* t, jclass c, const char* name, const char* spec)
{
ENTER(t, Thread::ActiveState);
object field = findField(t, c, name, spec);
object field = resolveField(t, *c, name, spec);
if (UNLIKELY(t->exception)) return 0;
return fieldOffset(t, field);
@ -1889,6 +1901,17 @@ append(char** p, const char* value, unsigned length, char tail)
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
populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable)
{
@ -1914,6 +1937,9 @@ populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable)
envTable->FindClass = ::FindClass;
envTable->ThrowNew = ::ThrowNew;
envTable->ExceptionCheck = ::ExceptionCheck;
envTable->NewDirectByteBuffer = ::NewDirectByteBuffer;
envTable->GetDirectBufferAddress = ::GetDirectBufferAddress;
envTable->GetDirectBufferCapacity = ::GetDirectBufferCapacity;
envTable->DeleteLocalRef = ::DeleteLocalRef;
envTable->GetObjectClass = ::GetObjectClass;
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
makeByteArray(Thread* t, const char* format, va_list a)
{
@ -497,21 +524,31 @@ makeByteArray(Thread* t, const char* format, va_list a)
}
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;
for (unsigned si = 0; si < length; ++si) {
unsigned a = s.read1();
for (; vi < byteCount; ++vi) {
charArrayBody(t, value, vi) = byteArrayBody(t, bytesSoFar, vi);
}
unsigned a = lastByteRead;
unsigned si = sourceIndex;
while (true) {
if (a & 0x80) {
// todo: handle non-ASCII characters properly
if (a & 0x20) {
// 3 bytes
si += 2;
assert(t, si < length);
/*unsigned b = */s.read1();
/*unsigned c = */s.read1();
byteArrayBody(t, value, vi++) = '_';
unsigned b = s.read1();
unsigned c = s.read1();
charArrayBody(t, value, vi++)
= ((a & 0xf) << 12) | ((b & 0x3f) << 6) | (c & 0x3f);
} else {
// 2 bytes
++ si;
@ -519,9 +556,55 @@ parseUtf8(Thread* t, Stream& s, unsigned length)
unsigned b = s.read1();
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;
} else {
byteArrayBody(t, value, vi++) = '_';
return parseUtf8NonAscii(t, s, value, vi, si, a);
}
}
} else {
@ -541,6 +624,28 @@ parseUtf8(Thread* t, Stream& s, unsigned length)
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
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: {
if (singletonObject(t, pool, i) == 0) {
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);
}
} return 1;
@ -583,7 +693,8 @@ parsePoolEntry(Thread* t, Stream& s, uint32_t* index, object pool, unsigned i)
parsePoolEntry(t, s, index, 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);
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);
}
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 {
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)
or classFixedSize(t, bootstrapClass) >= classFixedSize(t, class_));
expect(t, (classVmFlags(t, class_) & HasFinalizerFlag) == 0);
PROTECT(t, bootstrapClass);
PROTECT(t, class_);
@ -1513,7 +1637,7 @@ boot(Thread* t)
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);
arrayLength(t, m->types) = TypeCount;
@ -1707,6 +1831,7 @@ Machine::Machine(System* system, Heap* heap, Finder* finder,
bootstrapClassMap(0),
monitorMap(0),
stringMap(0),
byteArrayMap(0),
types(0),
jniMethodTable(0),
finalizers(0),
@ -1715,6 +1840,7 @@ Machine::Machine(System* system, Heap* heap, Finder* finder,
weakReferences(0),
tenuredWeakReferences(0),
unsafe(false),
triedBuiltinOnLoad(false),
heapPoolIndex(0)
{
heap->setClient(heapClient);
@ -1777,6 +1903,7 @@ Thread::Thread(Machine* m, object javaThread, Thread* parent):
heapIndex(0),
heapOffset(0),
protector(0),
classInitStack(0),
runnable(this),
defaultHeap(static_cast<uintptr_t*>
(m->heap->allocate(ThreadHeapSizeInBytes))),
@ -1827,6 +1954,7 @@ Thread::init()
boot(this);
}
m->byteArrayMap = makeWeakHashMap(this, 0, 0);
m->monitorMap = makeWeakHashMap(this, 0, 0);
m->jniMethodTable = makeVector(this, 0, 0);
@ -1840,8 +1968,12 @@ Thread::init()
if (javaThread) {
threadPeer(this, javaThread) = reinterpret_cast<jlong>(this);
} else {
const unsigned NewState = 0;
const unsigned NormalPriority = 5;
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
makeByteArray(Thread* t, const char* format, ...)
{
@ -2406,7 +2560,8 @@ parseClass(Thread* t, const uint8_t* data, unsigned size)
set(t, class_, ClassSuper, sc);
classVmFlags(t, class_)
|= (classVmFlags(t, sc) & (ReferenceFlag | WeakReferenceFlag));
|= (classVmFlags(t, sc)
& (ReferenceFlag | WeakReferenceFlag | HasFinalizerFlag));
}
parseInterfaceTable(t, s, class_, pool);
@ -2519,24 +2674,57 @@ resolveClass(Thread* t, object spec)
}
object
resolveMethod(Thread* t, const char* className, const char* methodName,
resolveMethod(Thread* t, object class_, const char* methodName,
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);
PROTECT(t, name);
object name = makeByteArray(t, methodName);
PROTECT(t, name);
object spec = makeByteArray(t, methodSpec);
object reference = makeReference(t, class_, name, spec);
object spec = makeByteArray(t, methodSpec);
return findMethodInClass(t, class_, referenceName(t, reference),
referenceSpec(t, reference));
object method = findMethodInClass(t, class_, name, spec);
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);
}
return 0;
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;
} else {
return field;
}
}
object
@ -2565,6 +2753,92 @@ resolveObjectArrayClass(Thread* t, object elementSpec)
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
makeObjectArray(Thread* t, object elementClass, unsigned count)
{
@ -2856,6 +3130,7 @@ visitRoots(Machine* m, Heap::Visitor* v)
v->visit(&(m->bootstrapClassMap));
v->visit(&(m->monitorMap));
v->visit(&(m->stringMap));
v->visit(&(m->byteArrayMap));
v->visit(&(m->types));
v->visit(&(m->jniMethodTable));
@ -2972,11 +3247,11 @@ makeTrace(Thread* t, Thread* target)
void
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) {
t->m->processor->invoke
(t, findMethod(t, method, objectClass(t, t->javaThread)),
t->javaThread);
t->m->processor->invoke(t, method, 0, t->javaThread);
}
}
@ -3025,3 +3300,29 @@ vmPrintTrace(Thread* t)
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
// standard ACC_* flags):
const unsigned HasFinalMemberFlag = 1 << 13;
const unsigned SingletonFlag = 1 << 14;
const unsigned ContinuationFlag = 1 << 15;
@ -84,9 +85,10 @@ const unsigned ReferenceFlag = 1 << 0;
const unsigned WeakReferenceFlag = 1 << 1;
const unsigned NeedInitFlag = 1 << 2;
const unsigned InitFlag = 1 << 3;
const unsigned PrimitiveFlag = 1 << 4;
const unsigned BootstrapFlag = 1 << 5;
const unsigned HasFinalMemberFlag = 1 << 6;
const unsigned InitErrorFlag = 1 << 4;
const unsigned PrimitiveFlag = 1 << 5;
const unsigned BootstrapFlag = 1 << 6;
const unsigned HasFinalizerFlag = 1 << 7;
// method vmFlags:
const unsigned ClassInitFlag = 1 << 0;
@ -1190,6 +1192,7 @@ class Machine {
object bootstrapClassMap;
object monitorMap;
object stringMap;
object byteArrayMap;
object types;
object jniMethodTable;
object finalizers;
@ -1198,6 +1201,7 @@ class Machine {
object weakReferences;
object tenuredWeakReferences;
bool unsafe;
bool triedBuiltinOnLoad;
JavaVMVTable javaVMVTable;
JNIEnvVTable jniEnvVTable;
uintptr_t* heapPool[ThreadHeapPoolSize];
@ -1265,6 +1269,25 @@ class Thread {
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 {
public:
Runnable(Thread* t): t(t) { }
@ -1317,6 +1340,7 @@ class Thread {
unsigned heapIndex;
unsigned heapOffset;
Protector* protector;
ClassInitStack* classInitStack;
Runnable runnable;
uintptr_t* defaultHeap;
uintptr_t* heap;
@ -1710,7 +1734,7 @@ makeClassNotFoundException(Thread* t, object message)
{
PROTECT(t, message);
object trace = makeTrace(t);
return makeClassNotFoundException(t, message, trace, 0);
return makeClassNotFoundException(t, message, trace, 0, 0);
}
inline object
@ -1761,6 +1785,14 @@ makeNoSuchMethodError(Thread* t, object message)
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
makeUnsatisfiedLinkError(Thread* t, object message)
{
@ -1774,7 +1806,7 @@ makeExceptionInInitializerError(Thread* t, object cause)
{
PROTECT(t, cause);
object trace = makeTrace(t);
return makeExceptionInInitializerError(t, 0, trace, cause);
return makeExceptionInInitializerError(t, 0, trace, cause, cause);
}
inline object
@ -1790,27 +1822,16 @@ makeNew(Thread* t, object class_)
return instance;
}
inline object
makeNewWeakReference(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;
}
object
makeNewGeneral(Thread* t, object class_);
inline object
make(Thread* t, object class_)
{
if (UNLIKELY(classVmFlags(t, class_) & WeakReferenceFlag)) {
return makeNewWeakReference(t, class_);
if (UNLIKELY(classVmFlags(t, class_)
& (WeakReferenceFlag | HasFinalizerFlag)))
{
return makeNewGeneral(t, class_);
} else {
return makeNew(t, class_);
}
@ -1933,9 +1954,9 @@ stringCharAt(Thread* t, object s, int i)
if (objectClass(t, data)
== arrayBody(t, t->m->types, Machine::ByteArrayType))
{
return byteArrayBody(t, data, i);
return byteArrayBody(t, data, stringOffset(t, s) + i);
} else {
return charArrayBody(t, data, i);
return charArrayBody(t, data, stringOffset(t, s) + i);
}
}
@ -2051,33 +2072,72 @@ fieldSize(Thread* t, object field)
object
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
parseClass(Thread* t, const uint8_t* data, unsigned length);
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
resolveMethod(Thread* t, const char* className, const char* methodName,
resolveMethod(Thread* t, object class_, const char* methodName,
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
resolveObjectArrayClass(Thread* t, object elementSpec);
inline bool
classNeedsInit(Thread* t, object c)
{
return classVmFlags(t, c) & NeedInitFlag
and (classVmFlags(t, c) & InitFlag) == 0;
}
bool
classNeedsInit(Thread* t, object c);
inline void
initClass(Thread* t, object c)
{
if (classNeedsInit(t, c)) {
t->m->processor->initClass(t, c);
}
}
bool
preInitClass(Thread* t, object c);
void
postInitClass(Thread* t, object c);
void
initClass(Thread* t, object c);
object
makeObjectArray(Thread* t, object elementClass, unsigned count);
@ -2388,4 +2448,7 @@ dumpHeap(Thread* t, FILE* out);
void
vmPrintTrace(vm::Thread* t);
void*
vmAddressFromLine(vm::Thread* t, vm::object m, unsigned line);
#endif//MACHINE_H

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -574,11 +574,20 @@ class MySystem: public System {
if (handler) {
segFaultHandler = handler;
#ifdef __i386__
oldSegFaultHandler = SetUnhandledExceptionFilter(handleException);
#elif defined __x86_64__
AddVectoredExceptionHandler(1, handleException);
oldSegFaultHandler = 0;
#endif
return 0;
} else if (segFaultHandler) {
segFaultHandler = 0;
#ifdef __i386__
SetUnhandledExceptionFilter(oldSegFaultHandler);
#elif defined __x86_64__
//do nothing, handlers are never "unregistered" anyway
#endif
return 0;
} else {
return 1;
@ -600,10 +609,15 @@ class MySystem: public System {
CONTEXT context;
rv = GetThreadContext(target->thread, &context);
expect(this, rv);
#ifdef __i386__
visitor->visit(reinterpret_cast<void*>(context.Eip),
reinterpret_cast<void*>(context.Ebp),
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);
expect(this, rv != -1);
@ -798,7 +812,7 @@ dump(LPEXCEPTION_POINTERS e, const char* directory)
char name[MAX_PATH];
_timeb 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.millitm));
@ -830,18 +844,31 @@ LONG CALLBACK
handleException(LPEXCEPTION_POINTERS e)
{
if (e->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) {
#ifdef __i386__
void* ip = reinterpret_cast<void*>(e->ContextRecord->Eip);
void* base = reinterpret_cast<void*>(e->ContextRecord->Ebp);
void* stack = reinterpret_cast<void*>(e->ContextRecord->Esp);
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
(&ip, &base, &stack, &thread);
#ifdef __i386__
e->ContextRecord->Eip = reinterpret_cast<DWORD>(ip);
e->ContextRecord->Ebp = reinterpret_cast<DWORD>(base);
e->ContextRecord->Esp = reinterpret_cast<DWORD>(stack);
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) {
return EXCEPTION_CONTINUE_EXECUTION;

163
src/x86.S
View File

@ -8,16 +8,145 @@
There is NO WARRANTY for this software. See license.txt for
details. */
#include "types.h"
#define LOCAL(x) .L##x
#if defined __APPLE__ || defined __MINGW32__ || defined __CYGWIN32__
# define GLOBAL(x) _##x
#else
# define GLOBAL(x) x
#endif
.text
#ifdef __x86_64__
#ifdef __MINGW32__
.globl GLOBAL(vmNativeCall)
GLOBAL(vmNativeCall):
pushq %rbp
//save nonvolatile registers
pushq %r12
pushq %r13
pushq %r14
pushq %r15
movq %rsp, %rbp
.globl vmNativeCall
vmNativeCall:
// %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
movq %rsp,%rbp
@ -113,24 +242,21 @@ LOCAL(exit):
popq %rbp
ret
.globl vmJump
vmJump:
.globl GLOBAL(vmJump)
GLOBAL(vmJump):
movq %rsi,%rbp
movq %rdx,%rsp
movq %rcx,%rbx
movq %r8,%rax
movq %r9,%rdx
jmp *%rdi
#endif // not __MINGW32__
#elif defined __i386__
# if defined __APPLE__ || defined __MINGW32__ || defined __CYGWIN32__
.globl _vmNativeCall
_vmNativeCall:
# else
.globl vmNativeCall
vmNativeCall:
# endif
.globl GLOBAL(vmNativeCall)
GLOBAL(vmNativeCall):
pushl %ebp
movl %esp,%ebp
@ -201,13 +327,8 @@ LOCAL(exit):
popl %ebp
ret
# if defined __APPLE__ || defined __MINGW32__ || defined __CYGWIN32__
.globl _vmJump
_vmJump:
# else
.globl vmJump
vmJump:
# endif
.globl GLOBAL(vmJump)
GLOBAL(vmJump):
movl 4(%esp),%esi
movl 8(%esp),%ebp
movl 16(%esp),%ebx
@ -216,6 +337,4 @@ vmJump:
movl 12(%esp),%esp
jmp *%esi
#else
# error unsupported platform
#endif
#endif //def __x86_64__

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])
extern "C" uint64_t
# ifdef __MINGW32__
vmNativeCall(void* function, void* stack, unsigned stackSize,
unsigned returnType);
# else
vmNativeCall(void* function, void* stack, unsigned stackSize,
void* gprTable, void* sseTable, unsigned returnType);
# endif
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
dynamicCall(void* function, uint64_t* arguments, uint8_t* argumentTypes,
unsigned argumentCount, unsigned, unsigned returnType)
@ -103,6 +116,7 @@ dynamicCall(void* function, uint64_t* arguments, uint8_t* argumentTypes,
(gprIndex ? gprTable : 0),
(sseIndex ? sseTable : 0), returnType);
}
#endif
} // 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();
}
// 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
// instructions by default, so we must compile this class using
// -source 1.2 -target 1.1 -XDjsrlimit=0.
//
// http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4381996
//
private static void test(boolean throw_, boolean predicate) {
int x = 42;
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) {
test(false, false);
test(false, true);
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 { }

View File

@ -88,26 +88,4 @@ public class Tree {
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");
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();
InputStream in = file.getInputStream(entry);
try {

4
vm.pro
View File

@ -73,7 +73,9 @@
# 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: