mirror of
https://github.com/corda/corda.git
synced 2025-01-07 13:38:47 +00:00
Merge branch 'gnu'
This commit is contained in:
commit
08dd7d0a5a
@ -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;
|
@ -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);
|
101
classpath/avian/resource/Handler.java
Normal file
101
classpath/avian/resource/Handler.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -23,6 +23,7 @@
|
||||
#ifdef WIN32
|
||||
# include <windows.h>
|
||||
# include <io.h>
|
||||
# include <direct.h>
|
||||
|
||||
# define OPEN _open
|
||||
# define CLOSE _close
|
||||
|
@ -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));
|
||||
}
|
||||
|
22
classpath/java/lang/Appendable.java
Normal file
22
classpath/java/lang/Appendable.java
Normal 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;
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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() {
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
15
classpath/java/lang/ThreadDeath.java
Normal file
15
classpath/java/lang/ThreadDeath.java
Normal 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() { }
|
||||
}
|
35
classpath/java/lang/ThreadGroup.java
Normal file
35
classpath/java/lang/ThreadGroup.java
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
21
classpath/java/lang/VirtualMachineError.java
Normal file
21
classpath/java/lang/VirtualMachineError.java
Normal 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);
|
||||
}
|
||||
}
|
@ -22,6 +22,10 @@ public abstract class Reference<T> {
|
||||
this.queue = queue;
|
||||
}
|
||||
|
||||
protected Reference(T target) {
|
||||
this(target, null);
|
||||
}
|
||||
|
||||
public T get() {
|
||||
return target;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
||||
|
15
classpath/java/lang/reflect/GenericDeclaration.java
Normal file
15
classpath/java/lang/reflect/GenericDeclaration.java
Normal 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();
|
||||
}
|
@ -19,4 +19,6 @@ public interface Member {
|
||||
public int getModifiers();
|
||||
|
||||
public String getName();
|
||||
|
||||
public boolean isSynthetic();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
13
classpath/java/lang/reflect/Type.java
Normal file
13
classpath/java/lang/reflect/Type.java
Normal 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 { }
|
19
classpath/java/lang/reflect/TypeVariable.java
Normal file
19
classpath/java/lang/reflect/TypeVariable.java
Normal 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();
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
13
classpath/java/security/AllPermission.java
Normal file
13
classpath/java/security/AllPermission.java
Normal 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 { }
|
13
classpath/java/security/CodeSource.java
Normal file
13
classpath/java/security/CodeSource.java
Normal 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 { }
|
17
classpath/java/security/Permission.java
Normal file
17
classpath/java/security/Permission.java
Normal 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;
|
||||
}
|
||||
}
|
15
classpath/java/security/PermissionCollection.java
Normal file
15
classpath/java/security/PermissionCollection.java
Normal 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);
|
||||
}
|
41
classpath/java/security/Permissions.java
Normal file
41
classpath/java/security/Permissions.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
23
classpath/java/security/ProtectionDomain.java
Normal file
23
classpath/java/security/ProtectionDomain.java
Normal 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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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
148
makefile
@ -18,10 +18,6 @@ bootimage-platform = \
|
||||
$(subst cygwin,windows,$(subst mingw32,windows,$(build-platform)))
|
||||
platform = $(bootimage-platform)
|
||||
|
||||
ifeq ($(platform),windows)
|
||||
arch = i386
|
||||
endif
|
||||
|
||||
mode = fast
|
||||
process = compile
|
||||
|
||||
@ -43,6 +39,23 @@ endif
|
||||
ifeq ($(continuations),true)
|
||||
options := $(options)-continuations
|
||||
endif
|
||||
ifdef gnu
|
||||
options := $(options)-gnu
|
||||
gnu-sources = $(src)/gnu.cpp
|
||||
gnu-jar = $(gnu)/share/classpath/glibj.zip
|
||||
gnu-libraries = \
|
||||
$(gnu)/lib/classpath/libjavaio.a \
|
||||
$(gnu)/lib/classpath/libjavalang.a \
|
||||
$(gnu)/lib/classpath/libjavalangreflect.a \
|
||||
$(gnu)/lib/classpath/libjavamath.a \
|
||||
$(gnu)/lib/classpath/libjavanet.a \
|
||||
$(gnu)/lib/classpath/libjavanio.a \
|
||||
$(gnu)/lib/classpath/libjavautil.a
|
||||
gnu-object-dep = $(build)/gnu-object.dep
|
||||
gnu-cflags = -DBOOT_BUILTINS=\"javaio,javalang,javalangreflect,javamath,javanet,javanio,javautil\" -DAVIAN_GNU
|
||||
gnu-lflags = -lgmp
|
||||
gnu-objects = $(shell find $(build)/gnu-objects -name "*.o")
|
||||
endif
|
||||
|
||||
root = $(shell (cd .. && pwd))
|
||||
build = build
|
||||
@ -53,6 +66,12 @@ src = src
|
||||
classpath = classpath
|
||||
test = test
|
||||
|
||||
ifdef gnu
|
||||
avian-classpath-build = $(build)/avian-classpath
|
||||
else
|
||||
avian-classpath-build = $(classpath-build)
|
||||
endif
|
||||
|
||||
input = List
|
||||
|
||||
build-cxx = g++
|
||||
@ -83,13 +102,14 @@ warnings = -Wall -Wextra -Werror -Wunused-parameter -Winit-self \
|
||||
common-cflags = $(warnings) -fno-rtti -fno-exceptions -fno-omit-frame-pointer \
|
||||
"-I$(JAVA_HOME)/include" -idirafter $(src) -I$(native-build) \
|
||||
-D__STDC_LIMIT_MACROS -D_JNI_IMPLEMENTATION_ -DAVIAN_VERSION=\"$(version)\" \
|
||||
$(gnu-cflags)
|
||||
|
||||
build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \
|
||||
"-I$(JAVA_HOME)/include/linux" -I$(src) -pthread
|
||||
|
||||
cflags = $(build-cflags)
|
||||
|
||||
common-lflags = -lm -lz
|
||||
common-lflags = -lm -lz $(gnu-lflags)
|
||||
|
||||
build-lflags =
|
||||
|
||||
@ -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 $(@)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
16
src/common.h
16
src/common.h
@ -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)
|
||||
{
|
||||
|
@ -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__
|
||||
|
928
src/compile.cpp
928
src/compile.cpp
File diff suppressed because it is too large
Load Diff
@ -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) {
|
||||
|
@ -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
161
src/continuations-x86.S
Normal 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
394
src/gnu.cpp
Normal 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);
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
357
src/machine.cpp
357
src/machine.cpp
@ -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;
|
||||
}
|
||||
|
141
src/machine.h
141
src/machine.h
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
||||
|
@ -38,7 +38,7 @@ THUNK(makeMultidimensionalArray)
|
||||
THUNK(throw_)
|
||||
THUNK(checkCast)
|
||||
THUNK(instanceOf64)
|
||||
THUNK(makeNewWeakReference64)
|
||||
THUNK(makeNewGeneral64)
|
||||
THUNK(makeNew64)
|
||||
THUNK(set)
|
||||
THUNK(gcIfNecessary)
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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
163
src/x86.S
@ -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__
|
||||
|
693
src/x86.cpp
693
src/x86.cpp
File diff suppressed because it is too large
Load Diff
14
src/x86.h
14
src/x86.h
@ -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
34
test/Finalizers.java
Normal 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 { }
|
||||
|
||||
}
|
@ -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 { }
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user