Merge branch 'master' of git://oss.readytalk.com/avian, fixed problems that occured in broader testing

Conflicts:
	src/compile.cpp
	src/compiler.cpp
	src/powerpc.cpp
	src/x86.S
	src/x86.cpp
This commit is contained in:
Josh warner 2009-08-10 13:20:23 -06:00
commit 1d3ef1fc43
119 changed files with 8964 additions and 2310 deletions

View File

@ -0,0 +1,16 @@
/* 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 avian;
public interface Callback<T> {
public void handleResult(T result);
public void handleException(Throwable exception);
}

View File

@ -0,0 +1,15 @@
/* Copyright (c) 2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian;
public interface CallbackReceiver<T> {
public T receive(Callback<T> callback) throws Exception;
}

View File

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

View File

@ -0,0 +1,238 @@
/* 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 avian;
import java.util.concurrent.Callable;
/**
* This class provides methods to capture continuations and manage
* control flow when calling continuations.
*
* <p>A continuation is a snapshot of a thread's call stack which can
* be captured via <code>callWithCurrentContinuation</code> and later
* restored any number of times. The program may restore this
* snapshot by either feeding it a result (to be returned by
* <code>callWithCurrentContinuation</code>) or feeding it an
* exception (to be thrown by
* <code>callWithCurrentContinuation</code>). Continuations may be
* used to implement features such as coroutines, generators, and
* cooperative multitasking.
*
* <p>This class provides two static methods,
* <code>callWithCurrentContinuation</code> and
* <code>dynamicWind</code>, with similar semantics to the Scheme
* functions <code>call-with-current-continuation</code> and
* <code>dynamic-wind</code>, respectively. In addition, we define
* how continuations work with respect to native code, exceptions,
* try/finally blocks, synchronized blocks, and multithreading.
*
* <h3>Continuations and Continuation Contexts</h3>
*
* <p>A continuation can be thought of as a singly-linked list of
* stack frames representing the call trace, where the head of the
* list is the frame of the method most recently called (i.e. the top
* of the stack). However, this trace only extends as far as the most
* recent chain of Java frames - it ends just prior to the most recent
* native frame in the stack. The reason for this is that the VM
* cannot, in general, safely capture and restore native frames.
* Therefore, each call from native code to Java (including the
* original invocation of <code>main(String[])</code> or
* <code>Thread.run()</code>) represents a new continuation context in
* which continuations may be captured, and these will only contain
* frames from within that context.
*
* <p>Calling a continuation (i.e. feeding it a result or exception)
* causes the current continuation to be replaced with the calling
* continuation. When the last method in this new continuation
* returns, it returns to the native frame which created the current
* context, which may not be the same as the context in which that
* continuation was created.
*
* <p>We define the return type of a continuation context as the
* return type of the first method called in that context. A
* continuation may be called from a different context than the one in
* which it was created, provided the return type of the latter is
* compatible with the current context.
*
* <p>Given a thread executing in context "A" which wants to call a
* continuation created in context "B", the following rules apply:
*
* <ul>
*
* <li>If the return type of "A" is <code>void</code>, the return
* type of "B" may be anything, including <code>void</code></li>
*
* <li>If the return type of "A" is a primitive type, the return
* type of "B" must match exactly</li>
*
* <li>If the return type of "A" is an object type, that type must
* assignable from the return type of "B" (i.e. the latter must
* either be the same as the former or a superclass or
* superinterface of it)</li>
*
* </ul>
*
* <p>A thread may call a continuation created by a different thread
* provided the return types are compatible. Multiple threads may
* safely call the same continuation simultaneously without
* synchronization. Any attempt to call a continuation from a context
* with an incompatible return type will throw an {@link
* avian.IncompatibleContinuationException}.
*
* <h3>Winding, Unwinding, and Rewinding</h3>
*
* <p>Traditionally, Java provides one way to wind the execution stack
* (recursive method calls) and two ways to unwind it (normal returns
* and exception unwinding). With continuations, we add a new way to
* rewind the stack and a new way to unwind it.
*
* <p>The call stack of a continuation may share frames with other
* continuations - in which case they share a common history. When
* calling a continuation "B" from the current continuation "A", the
* VM must unwind past any frames which are in "A" but not in "B" and
* rewind past any frames in "B" but not in "A". During this
* unwinding and rewinding, control may pass through synchronized and
* try/finally blocks while going down the old stack and up the new
* stack.
*
* <p>However, unlike the traditional processes of winding and
* unwinding, the VM will ignore these blocks - monitors will not be
* released or acquired and finally blocks will not execute. This is
* by design. The purpose of such a block is to acquire a resource,
* such as a file handle or monitor, once before executing a task and
* release it after the task is finished, regardless of how often the
* task might temporarily yield control to other continuations.
*
* <p>Conversely, one might wish to acquire and release a resource
* each time control (re)winds to or unwinds from a continuation,
* respectively. In this case, we use <code>dynamicWind</code> to
* register functions which will run every time that frame is passed,
* regardless of how the stack is wound or unwound.
*/
public class Continuations {
private Continuations() { }
/**
* Captures the current continuation, passing a reference to the
* specified receiver.
*
* <p>This method will either return the result returned by
* <code>receiver.receive(Callback)</code>, propagate the exception
* thrown by that method, return the result passed to the
* handleResult(T) method of the continuation, or throw the
* exception passed to the handleException(Throwable) of the
* continuation.
*/
public static native <T> T callWithCurrentContinuation
(CallbackReceiver<T> receiver) throws Exception;
/**
* Calls the specified "before" and "after" tasks each time a
* continuation containing the call is wound or unwound,
* respectively.
*
* <p>This method first calls <code>before.run()</code>, then
* <code>thunk.call()</code>, and finally <code>after.run()</code>,
* returning the result of the second call. If
* <code>before.run()</code> does not return normally, the second
* and third calls will not happen. If <code>thunk.call()</code>
* throws an exception, <code>after.run()</code>, will be called
* before the exception is propagated.
*
* <p>If <code>thunk.call()</code> calls a continuation (directly or
* via a subroutine) which does not include the current call to
* <code>dynamicWind<code>, <code>after.run()</code> will be called
* before control passes to that continuation. If this call throws
* an exception, the exception will propagate to the current caller
* of <code>dynamicWind</code>.
*
* <p>If <code>thunk.call()</code> creates a continuation which is
* later called from a continuation which does not include the
* current call to <code>dynamicWind</code>,
* <code>before.run()</code> will be called before control passes to
* that continuation. As above, if this call throws an exception,
* the exception will propagate to the current caller of
* <code>dynamicWind</code>.
*/
public static <T> T dynamicWind(Runnable before,
Callable<T> thunk,
Runnable after)
throws Exception
{
UnwindResult result = dynamicWind2(before, thunk, after);
if (result.continuation != null) {
after.run();
if (result.exception != null) {
result.continuation.handleException(result.exception);
} else {
result.continuation.handleResult(result.result);
}
throw new AssertionError();
} else {
return (T) result.result;
}
}
private static native UnwindResult dynamicWind2(Runnable before,
Callable thunk,
Runnable after)
throws Exception;
private static UnwindResult wind(Runnable before,
Callable thunk,
Runnable after)
throws Exception
{
before.run();
try {
return new UnwindResult(null, thunk.call(), null);
} finally {
after.run();
}
}
private static void rewind(Runnable before,
Callback continuation,
Object result,
Throwable exception)
throws Exception
{
before.run();
if (exception != null) {
continuation.handleException(exception);
} else {
continuation.handleResult(result);
}
throw new AssertionError();
}
private static class Continuation<T> implements Callback<T> {
public native void handleResult(T result);
public native void handleException(Throwable exception);
}
private static class UnwindResult {
public final Callback continuation;
public final Object result;
public final Throwable exception;
public UnwindResult(Callback continuation, Object result,
Throwable exception)
{
this.continuation = continuation;
this.result = result;
this.exception = exception;
}
}
}

View File

@ -0,0 +1,21 @@
/* Copyright (c) 2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian;
public class IncompatibleContinuationException extends Exception {
public IncompatibleContinuationException(String message) {
super(message);
}
public IncompatibleContinuationException() {
super();
}
}

View File

@ -0,0 +1,17 @@
/* Copyright (c) 2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian;
public abstract class Machine {
public static native void dumpHeap(String outputFile);
}

View File

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

View File

@ -8,7 +8,7 @@
There is NO WARRANTY for this software. See license.txt for
details. */
package java.lang;
package avian;
import java.net.URL;
import java.net.MalformedURLException;

View File

@ -0,0 +1,101 @@
/* Copyright (c) 2008-2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package avian.resource;
import java.net.URL;
import java.net.URLStreamHandler;
import java.net.URLConnection;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.io.InputStream;
public class Handler extends URLStreamHandler {
protected URLConnection openConnection(URL url) {
return new ResourceConnection(url);
}
private static class ResourceConnection extends URLConnection {
public ResourceConnection(URL url) {
super(url);
}
public int getContentLength() {
return ResourceInputStream.getContentLength(url.getFile());
}
public InputStream getInputStream() throws IOException {
return new ResourceInputStream(url.getFile());
}
}
private static class ResourceInputStream extends InputStream {
private long peer;
private int position;
public ResourceInputStream(String path) throws IOException {
peer = open(path);
if (peer == 0) {
throw new FileNotFoundException(path);
}
}
private static native int getContentLength(String path);
private static native long open(String path) throws IOException;
private static native int read(long peer, int position) throws IOException;
private static native int read(long peer, int position,
byte[] b, int offset, int length)
throws IOException;
public static native void close(long peer) throws IOException;
public int read() throws IOException {
if (peer != 0) {
int c = read(peer, position);
if (c >= 0) {
++ position;
}
return c;
} else {
throw new IOException();
}
}
public int read(byte[] b, int offset, int length) throws IOException {
if (peer != 0) {
if (b == null) {
throw new NullPointerException();
}
if (offset < 0 || offset + length > b.length) {
throw new ArrayIndexOutOfBoundsException();
}
int c = read(peer, position, b, offset, length);
if (c >= 0) {
position += c;
}
return c;
} else {
throw new IOException();
}
}
public void close() throws IOException {
if (peer != 0) {
close(peer);
peer = 0;
}
}
}
}

View File

@ -305,6 +305,21 @@ Java_java_io_File_isDirectory(JNIEnv* e, jclass, jstring path)
}
}
extern "C" JNIEXPORT jboolean JNICALL
Java_java_io_File_isFile(JNIEnv* e, jclass, jstring path)
{
const char* chars = e->GetStringUTFChars(path, 0);
if (chars) {
STRUCT_STAT s;
int r = STAT(chars, &s);
bool v = (r == 0 and S_ISREG(s.st_mode));
e->ReleaseStringUTFChars(path, chars);
return v;
} else {
return false;
}
}
extern "C" JNIEXPORT jboolean JNICALL
Java_java_io_File_exists(JNIEnv* e, jclass, jstring path)
{

View File

@ -7,7 +7,7 @@
There is NO WARRANTY for this software. See license.txt for
details. */
#include "math.h"
#include "stdlib.h"
#include "sys/time.h"
@ -32,11 +32,14 @@
# define SO_PREFIX ""
#else
# define SO_PREFIX "lib"
#include <sys/sysctl.h>
#include "sys/utsname.h"
#include "sys/wait.h"
#endif
#ifdef __APPLE__
# define SO_SUFFIX ".jnilib"
#include <CoreServices/CoreServices.h>
#elif defined WIN32
# define SO_SUFFIX ".dll"
#else
@ -349,6 +352,44 @@ Java_java_lang_System_getProperty(JNIEnv* e, jclass, jstring name,
r = e->NewStringUTF("\\");
} else if (strcmp(chars, "os.name") == 0) {
r = e->NewStringUTF("Windows");
} else if (strcmp(chars, "os.version") == 0) {
unsigned size = 32;
char buffer[size];
OSVERSIONINFO OSversion;
OSversion.dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
::GetVersionEx(&OSversion);
snprintf(buffer, size, "%i.%i", (int)OSversion.dwMajorVersion, (int)OSversion.dwMinorVersion);
r = e->NewStringUTF(buffer);
} else if (strcmp(chars, "os.arch") == 0) {
#ifdef __i386__
r = e->NewStringUTF("x86");
#else
#ifdef __x86_64__
r = e->NewStringUTF("x86_64");
#else
#if defined(__ppc__) || defined(__powerpc__) || defined(__ppc64__) || defined(__powerpc64__)
r = e->NewStringUTF("ppc");
#else
#ifdef __ia64__
r = e->NewStringUTF("ia64");
#else
#ifdef __arm__
r = e->NewStringUTF("arm");
#else
#ifdef __alpha__
r = e->NewStringUTF("alpha");
#else
#ifdef __sparc64__
r = e->NewStringUTF("sparc64");
#else
r = e->NewStringUTF("unknown");
#endif
#endif
#endif
#endif
#endif
#endif
#endif
} else if (strcmp(chars, "java.io.tmpdir") == 0) {
TCHAR buffer[MAX_PATH];
GetTempPath(MAX_PATH, buffer);
@ -368,10 +409,56 @@ Java_java_lang_System_getProperty(JNIEnv* e, jclass, jstring name,
#else
r = e->NewStringUTF("Linux");
#endif
} else if (strcmp(chars, "os.version") == 0) {
#ifdef __APPLE__
unsigned size = 32;
char buffer[size];
long minorVersion, majorVersion;
Gestalt(gestaltSystemVersionMajor, &majorVersion);
Gestalt(gestaltSystemVersionMinor, &minorVersion);
snprintf(buffer, size, "%ld.%ld", majorVersion, minorVersion);
r = e->NewStringUTF(buffer);
#else
struct utsname system_id;
uname(&system_id);
r = e->NewStringUTF(system_id.release);
#endif
} else if (strcmp(chars, "os.arch") == 0) {
#ifdef __i386__
r = e->NewStringUTF("x86");
#else
#ifdef __x86_64__
r = e->NewStringUTF("x86_64");
#else
#if defined(__ppc__) || defined(__powerpc__) || defined(__ppc64__) || defined(__powerpc64__)
r = e->NewStringUTF("ppc");
#else
#ifdef __ia64__
r = e->NewStringUTF("ia64");
#else
#ifdef __arm__
r = e->NewStringUTF("arm");
#else
#ifdef __alpha__
r = e->NewStringUTF("alpha");
#else
#ifdef __sparc64__
r = e->NewStringUTF("sparc64");
#else
r = e->NewStringUTF("unknown");
#endif
#endif
#endif
#endif
#endif
#endif
#endif
} else if (strcmp(chars, "java.io.tmpdir") == 0) {
r = e->NewStringUTF("/tmp");
} else if (strcmp(chars, "user.home") == 0) {
r = e->NewStringUTF(getenv("HOME"));
r = e->NewStringUTF(getenv("HOME"));
}
#endif

View File

@ -154,17 +154,19 @@ eagain()
}
bool
makeNonblocking(JNIEnv* e, int d)
setBlocking(JNIEnv* e, int d, bool blocking)
{
#ifdef WIN32
u_long a = 1;
u_long a = (blocking ? 0 : 1);
int r = ioctlsocket(d, FIONBIO, &a);
if (r != 0) {
throwIOException(e);
return false;
}
#else
int r = fcntl(d, F_SETFL, fcntl(d, F_GETFL) | O_NONBLOCK);
int r = fcntl(d, F_SETFL, (blocking
? (fcntl(d, F_GETFL) & (~O_NONBLOCK))
: (fcntl(d, F_GETFL) | O_NONBLOCK)));
if (r < 0) {
throwIOException(e);
return false;
@ -231,7 +233,6 @@ doAccept(JNIEnv* e, int s)
socklen_t length = sizeof(address);
int r = ::accept(s, &address, &length);
if (r >= 0) {
makeNonblocking(e, r);
return r;
} else {
throwIOException(e);
@ -260,7 +261,7 @@ doWrite(int fd, const void* buffer, size_t count)
}
int
makeSocket(JNIEnv* e, bool blocking = false)
makeSocket(JNIEnv* e)
{
#ifdef WIN32
static bool wsaInitialized = false;
@ -279,8 +280,6 @@ makeSocket(JNIEnv* e, bool blocking = false)
return s;
}
if (not blocking) makeNonblocking(e, s);
return s;
}
@ -311,6 +310,15 @@ Java_java_nio_channels_ServerSocketChannel_natDoListen(JNIEnv *e,
return s;
}
extern "C" JNIEXPORT void JNICALL
Java_java_nio_channels_SocketChannel_configureBlocking(JNIEnv *e,
jclass,
jint socket,
jboolean blocking)
{
setBlocking(e, socket, blocking);
}
extern "C" JNIEXPORT void JNICALL
Java_java_nio_channels_SocketChannel_natSetTcpNoDelay(JNIEnv *e,
jclass,
@ -325,11 +333,14 @@ Java_java_nio_channels_SocketChannel_natDoConnect(JNIEnv *e,
jclass,
jstring host,
jint port,
jboolean blocking,
jbooleanArray retVal)
{
int s = makeSocket(e);
if (e->ExceptionOccurred()) return 0;
setBlocking(e, s, blocking);
sockaddr_in address;
init(e, &address, host, port);
if (e->ExceptionOccurred()) return 0;
@ -425,7 +436,8 @@ class Pipe {
address.sin_family = AF_INET;
address.sin_port = 0;
address.sin_addr.s_addr = inet_addr("127.0.0.1"); //INADDR_LOOPBACK;
listener_ = makeSocket(e, false);
listener_ = makeSocket(e);
setBlocking(e, listener_, false);
::doListen(e, listener_, &address);
socklen_t length = sizeof(sockaddr_in);
@ -435,7 +447,8 @@ class Pipe {
throwIOException(e);
}
writer_ = makeSocket(e, true);
writer_ = makeSocket(e);
setBlocking(e, writer_, true);
connected_ = ::doConnect(e, writer_, &address);
}
@ -485,8 +498,8 @@ class Pipe {
return;
}
if (makeNonblocking(e, pipe[0])) {
makeNonblocking(e, pipe[1]);
if (setBlocking(e, pipe[0], false)) {
setBlocking(e, pipe[1], false);
}
}
@ -626,7 +639,17 @@ Java_java_nio_channels_SocketSelector_natDoSocketSelect(JNIEnv *e, jclass,
}
#endif
timeval time = { interval / 1000, (interval % 1000) * 1000 };
timeval time;
if (interval > 0) {
time.tv_sec = interval / 1000;
time.tv_usec = (interval % 1000) * 1000;
} else if (interval < 0) {
time.tv_sec = 0;
time.tv_usec = 0;
} else {
time.tv_sec = INT32_MAX;
time.tv_usec = 0;
}
int r = ::select(max + 1, &(s->read), &(s->write), &(s->except), &time);
if (r < 0) {

View File

@ -41,6 +41,12 @@ public class File {
return isDirectory(path);
}
private static native boolean isFile(String path);
public boolean isFile() {
return isFile(path);
}
public String getName() {
int index = path.lastIndexOf(FileSeparator);
if (index >= 0) {
@ -141,6 +147,19 @@ public class File {
return mkdir();
}
public File[] listFiles() {
return listFiles(null);
}
public File[] listFiles(FilenameFilter filter) {
String[] list = list(filter);
File[] result = new File[list.length];
for (int i = 0; i < list.length; ++i) {
result[i] = new File(this, list[i]);
}
return result;
}
public String[] list() {
return list(null);
}

View File

@ -0,0 +1,22 @@
/* Copyright (c) 2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.lang;
import java.io.IOException;
public interface Appendable {
public Appendable append(char c) throws IOException;
public Appendable append(CharSequence sequence) throws IOException;
public Appendable append(CharSequence sequence, int start, int end)
throws IOException;
}

View File

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

View File

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

View File

@ -14,13 +14,20 @@ 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> {
private static final int PrimitiveFlag = 1 << 4;
public final class Class <T> implements Type, GenericDeclaration {
private static final int PrimitiveFlag = 1 << 5;
private short flags;
private byte vmFlags;
@ -55,6 +62,34 @@ public final class Class <T> {
}
public String getName() {
if (name == null) {
if ((vmFlags & PrimitiveFlag) != 0) {
if (this == primitiveClass('V')) {
name = "void".getBytes();
} else if (this == primitiveClass('Z')) {
name = "boolean".getBytes();
} else if (this == primitiveClass('B')) {
name = "byte".getBytes();
} else if (this == primitiveClass('C')) {
name = "char".getBytes();
} else if (this == primitiveClass('S')) {
name = "short".getBytes();
} else if (this == primitiveClass('I')) {
name = "int".getBytes();
} else if (this == primitiveClass('F')) {
name = "float".getBytes();
} else if (this == primitiveClass('J')) {
name = "long".getBytes();
} else if (this == primitiveClass('D')) {
name = "double".getBytes();
} else {
throw new AssertionError();
}
} else {
throw new AssertionError();
}
}
return new String
(replace('/', '.', name, 0, name.length - 1), 0, name.length - 1, false);
}
@ -84,6 +119,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();
@ -436,8 +474,63 @@ public final class Class <T> {
return null;
}
}
public boolean desiredAssertionStatus() {
return false;
}
public T cast(Object o) {
return (T) o;
}
public Object[] getSigners() {
throw new UnsupportedOperationException();
}
public Annotation[] getDeclaredAnnotations() {
throw new UnsupportedOperationException();
}
public boolean isEnum() {
throw new UnsupportedOperationException();
}
public TypeVariable<Class<T>>[] getTypeParameters() {
throw new UnsupportedOperationException();
}
public String getSimpleName() {
throw new UnsupportedOperationException();
}
public Method getEnclosingMethod() {
throw new UnsupportedOperationException();
}
public Constructor getEnclosingConstructor() {
throw new UnsupportedOperationException();
}
public Class getEnclosingClass() {
throw new UnsupportedOperationException();
}
public Class[] getDeclaredClasses() {
throw new UnsupportedOperationException();
}
public <A extends Annotation> A getAnnotation(Class<A> c) {
throw new UnsupportedOperationException();
}
public ProtectionDomain getProtectionDomain() {
Permissions p = new Permissions();
p.add(new AllPermission());
return new ProtectionDomain(null, p);
}
// for GNU Classpath compatibility:
void setSigners(Object[] signers) {
throw new UnsupportedOperationException();
}
}

View File

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

View File

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

View File

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

View File

@ -66,7 +66,7 @@ public final class Long extends Number implements Comparable<Long> {
char[] array = new char[size];
int i = array.length - 1;
int i = size - 1;
for (long n = v; n != 0; n /= radix) {
long digit = n % radix;
if (negative) digit = -digit;
@ -83,7 +83,7 @@ public final class Long extends Number implements Comparable<Long> {
array[i] = '-';
}
return new String(array);
return new String(array, 0, size, false);
}
public static String toString(long v) {

View File

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

View File

@ -75,8 +75,6 @@ public class Runtime {
public native long totalMemory();
public static native void dumpHeap(String outputFile);
private static class MyProcess extends Process {
private long pid;
private final int in;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,15 @@
/* Copyright (c) 2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.lang;
public class ThreadDeath extends Error {
public ThreadDeath() { }
}

View File

@ -0,0 +1,35 @@
/* Copyright (c) 2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.lang;
public class ThreadGroup implements Thread.UncaughtExceptionHandler {
private final ThreadGroup parent;
private final String name;
public ThreadGroup(ThreadGroup parent, String name) {
this.parent = parent;
this.name = name;
}
public void uncaughtException(Thread t, Throwable e) {
if (parent != null) {
parent.uncaughtException(t, e);
} else {
Thread.UncaughtExceptionHandler deh
= Thread.getDefaultUncaughtExceptionHandler();
if (deh != null) {
deh.uncaughtException(t, e);
} else if (! (e instanceof ThreadDeath)) {
e.printStackTrace();
}
}
}
}

View File

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

View File

@ -0,0 +1,21 @@
/* Copyright (c) 2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.lang;
public class VirtualMachineError extends Error {
public VirtualMachineError(String message) {
super(message);
}
public VirtualMachineError() {
this(null);
}
}

View File

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

View File

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

View File

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

View File

@ -0,0 +1,15 @@
/* Copyright (c) 2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.lang.reflect;
public interface GenericDeclaration {
public TypeVariable<?>[] getTypeParameters();
}

View File

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

View File

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

View File

@ -35,4 +35,5 @@ public final class Modifier {
public static boolean isSuper (int v) { return (v & SUPER) != 0; }
public static boolean isNative (int v) { return (v & NATIVE) != 0; }
public static boolean isAbstract (int v) { return (v & ABSTRACT) != 0; }
public static boolean isInterface(int v) { return (v & INTERFACE) != 0; }
}

View File

@ -0,0 +1,13 @@
/* Copyright (c) 2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.lang.reflect;
public interface Type { }

View File

@ -0,0 +1,19 @@
/* Copyright (c) 2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.lang.reflect;
public interface TypeVariable<T extends GenericDeclaration>
extends Type
{
public Type[] getBounds();
public T getGenericDeclaration();
public String getName();
}

View File

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

View File

@ -42,7 +42,11 @@ public abstract class Selector {
public abstract Selector wakeup();
public abstract int selectNow() throws IOException;
public abstract int select(long interval) throws IOException;
public abstract int select() throws IOException;
public abstract void close();
}

View File

@ -23,7 +23,7 @@ public class ServerSocketChannel extends SelectableChannel {
return new ServerSocketChannel();
}
public SelectableChannel configureBlocking(boolean v) {
public SelectableChannel configureBlocking(boolean v) throws IOException {
return channel.configureBlocking(v);
}
@ -61,6 +61,7 @@ public class ServerSocketChannel extends SelectableChannel {
throw new IllegalArgumentException();
}
channel.socket = doListen(a.getHostName(), a.getPort());
channel.configureBlocking(channel.isBlocking());
}
}

View File

@ -24,21 +24,29 @@ public class SocketChannel extends SelectableChannel
int socket = InvalidSocket;
boolean connected = false;
boolean blocking = true;
public static SocketChannel open() {
return new SocketChannel();
}
public SelectableChannel configureBlocking(boolean v) {
if (v) throw new IllegalArgumentException();
public SelectableChannel configureBlocking(boolean v) throws IOException {
blocking = v;
if (socket != InvalidSocket) {
configureBlocking(socket, v);
}
return this;
}
public boolean isBlocking() {
return blocking;
}
public Socket socket() {
return new Handle();
}
public boolean connect(SocketAddress address) throws Exception {
public boolean connect(SocketAddress address) throws IOException {
InetSocketAddress a;
try {
a = (InetSocketAddress) address;
@ -46,6 +54,7 @@ public class SocketChannel extends SelectableChannel
throw new UnsupportedAddressTypeException();
}
socket = doConnect(a.getHostName(), a.getPort());
configureBlocking(blocking);
return connected;
}
@ -56,11 +65,11 @@ public class SocketChannel extends SelectableChannel
}
}
private int doConnect(String host, int port) throws Exception {
private int doConnect(String host, int port) throws IOException {
if (host == null) throw new NullPointerException();
boolean b[] = new boolean[1];
int s = natDoConnect(host, port, b);
int s = natDoConnect(host, port, blocking, b);
connected = b[0];
return s;
}
@ -109,11 +118,14 @@ public class SocketChannel extends SelectableChannel
}
}
private static native void configureBlocking(int socket, boolean blocking)
throws IOException;
private static native void natSetTcpNoDelay(int socket, boolean on)
throws SocketException;
private static native int natDoConnect(String host, int port, boolean[] connected)
throws Exception;
private static native int natDoConnect(String host, int port, boolean blocking, boolean[] connected)
throws IOException;
private static native int natRead(int socket, byte[] buffer, int offset, int length)
throws IOException;
private static native int natWrite(int socket, byte[] buffer, int offset, int length)

View File

@ -48,7 +48,21 @@ class SocketSelector extends Selector {
}
}
public synchronized int selectNow() throws IOException {
return doSelect(-1);
}
public synchronized int select() throws IOException {
return doSelect(0);
}
public synchronized int select(long interval) throws IOException {
if (interval < 0) throw new IllegalArgumentException();
return doSelect(interval);
}
public int doSelect(long interval) throws IOException {
selectedKeys.clear();
if (clearWoken()) return 0;

View File

@ -0,0 +1,13 @@
/* Copyright (c) 2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.security;
public class AllPermission extends Permission { }

View File

@ -0,0 +1,13 @@
/* Copyright (c) 2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.security;
public class CodeSource { }

View File

@ -0,0 +1,17 @@
/* Copyright (c) 2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.security;
public abstract class Permission {
public PermissionCollection newPermissionCollection() {
return null;
}
}

View File

@ -0,0 +1,15 @@
/* Copyright (c) 2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.security;
public abstract class PermissionCollection {
public abstract void add(Permission p);
}

View File

@ -0,0 +1,41 @@
/* Copyright (c) 2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.security;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.HashSet;
public class Permissions extends PermissionCollection {
private final Map<Class,PermissionCollection> collections = new HashMap();
public void add(Permission p) {
Class c = p.getClass();
PermissionCollection pc = collections.get(c);
if (pc == null) {
pc = p.newPermissionCollection();
if (pc == null) {
pc = new MyPermissionCollection();
}
collections.put(c, pc);
}
pc.add(p);
}
private static class MyPermissionCollection extends PermissionCollection {
private final Set<Permission> permissions = new HashSet();
public void add(Permission p) {
permissions.add(p);
}
}
}

View File

@ -0,0 +1,23 @@
/* Copyright (c) 2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.security;
public class ProtectionDomain {
private final CodeSource codeSource;
private final PermissionCollection permissions;
public ProtectionDomain(CodeSource codeSource,
PermissionCollection permissions)
{
this.codeSource = codeSource;
this.permissions = permissions;
}
}

View File

@ -62,6 +62,10 @@ public abstract class AbstractCollection<T> implements Collection<T> {
public abstract int size();
public Object[] toArray() {
return toArray(new Object[size()]);
}
public <S> S[] toArray(S[] array) {
return Collections.toArray(this, array);
}

View File

@ -0,0 +1,15 @@
/* Copyright (c) 2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.util;
public abstract class AbstractList<T> extends AbstractCollection<T>
implements List<T>
{ }

View File

@ -0,0 +1,15 @@
/* Copyright (c) 2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.util;
public abstract class AbstractSequentialList<T> extends AbstractList<T>
implements List<T>
{ }

View File

@ -10,7 +10,7 @@
package java.util;
public class ArrayList<T> implements List<T> {
public class ArrayList<T> extends AbstractList<T> {
private static final int MinimumCapacity = 16;
private Object[] array;
@ -94,7 +94,7 @@ public class ArrayList<T> implements List<T> {
return true;
}
public int indexOf(T element) {
public int indexOf(Object element) {
for (int i = 0; i < size; ++i) {
if (equal(element, array[i])) {
return i;
@ -103,8 +103,8 @@ public class ArrayList<T> implements List<T> {
return -1;
}
public int lastIndexOf(T element) {
for (int i = size; i >= 0; --i) {
public int lastIndexOf(Object element) {
for (int i = size - 1; i >= 0; --i) {
if (equal(element, array[i])) {
return i;
}
@ -159,23 +159,23 @@ public class ArrayList<T> implements List<T> {
return size() == 0;
}
public <S> S[] toArray(S[] a) {
return Collections.toArray(this, a);
}
public void clear() {
array = null;
size = 0;
}
public Iterator<T> iterator() {
return new Collections.ArrayListIterator(this);
return listIterator();
}
public ListIterator<T> listIterator(int index) {
return new Collections.ArrayListIterator(this, index);
}
public ListIterator<T> listIterator() {
return listIterator(0);
}
public String toString() {
return Collections.toString(this);
}

View File

@ -73,6 +73,24 @@ public class Arrays {
return false;
}
public int indexOf(Object element) {
for (int i = 0; i < array.length; ++i) {
if (equal(element, array[i])) {
return i;
}
}
return -1;
}
public int lastIndexOf(Object element) {
for (int i = array.length - 1; i >= 0; --i) {
if (equal(element, array[i])) {
return i;
}
}
return -1;
}
public T get(int index) {
return array[index];
}
@ -81,6 +99,10 @@ public class Arrays {
throw new UnsupportedOperationException();
}
public Object[] toArray() {
return toArray(new Object[size()]);
}
public <S> S[] toArray(S[] a) {
return (S[])array;
}
@ -102,7 +124,15 @@ public class Arrays {
}
public Iterator<T> iterator() {
return new Collections.ArrayListIterator(this);
return listIterator();
}
public ListIterator<T> listIterator(int index) {
return new Collections.ArrayListIterator(this, index);
}
public ListIterator<T> listIterator() {
return listIterator(0);
}
};
}

View File

@ -23,6 +23,8 @@ public interface Collection<T> extends Iterable<T> {
public boolean remove(Object element);
public Object[] toArray();
public <S> S[] toArray(S[] array);
public void clear();

View File

@ -64,6 +64,22 @@ public class Collections {
return sb.toString();
}
static String toString(Map m) {
StringBuilder sb = new StringBuilder();
sb.append("{");
for (Iterator<Map.Entry> it = m.entrySet().iterator(); it.hasNext();) {
Map.Entry e = it.next();
sb.append(e.getKey())
.append("=")
.append(e.getValue());
if (it.hasNext()) {
sb.append(",");
}
}
sb.append("}");
return sb.toString();
}
static class IteratorEnumeration<T> implements Enumeration<T> {
private final Iterator<T> it;
@ -113,6 +129,10 @@ public class Collections {
synchronized (lock) { return collection.remove((T)e); }
}
public Object[] toArray() {
return toArray(new Object[size()]);
}
public <T> T[] toArray(T[] array) {
synchronized (lock) { return collection.toArray(array); }
}
@ -182,7 +202,6 @@ public class Collections {
return new SynchronizedMap<K, V> (map);
}
static class SynchronizedSet<T>
extends SynchronizedCollection<T>
implements Set<T>
@ -216,7 +235,7 @@ public class Collections {
static class ArrayListIterator<T> implements ListIterator<T> {
private final List<T> list;
private boolean canRemove = false;
private int toRemove = -1;
private int index;
public ArrayListIterator(List<T> list) {
@ -234,7 +253,7 @@ public class Collections {
public T previous() {
if (hasPrevious()) {
canRemove = true;
toRemove = index;
return list.get(index--);
} else {
throw new NoSuchElementException();
@ -243,8 +262,8 @@ public class Collections {
public T next() {
if (hasNext()) {
canRemove = true;
return list.get(++index);
toRemove = ++index;
return list.get(index);
} else {
throw new NoSuchElementException();
}
@ -255,9 +274,10 @@ public class Collections {
}
public void remove() {
if (canRemove) {
canRemove = false;
list.remove(index--);
if (toRemove != -1) {
list.remove(toRemove);
index = toRemove - 1;
toRemove = -1;
} else {
throw new IllegalStateException();
}
@ -303,13 +323,56 @@ public class Collections {
return inner.size();
}
public Object[] toArray() {
return toArray(new Object[size()]);
}
public <S> S[] toArray(S[] array) {
return inner.toArray(array);
}
}
}
public static <T> Set<T> unmodifiableSet(Set<T> hs) {
return new UnmodifiableSet<T>(hs);
}
static class KeyIterator<K, V> implements Iterator<K> {
private final Iterator<Map.Entry<K, V>> it;
public KeyIterator(Iterator<Map.Entry<K, V>> it) {
this.it = it;
}
public K next() {
return it.next().getKey();
}
public boolean hasNext() {
return it.hasNext();
}
public void remove() {
it.remove();
}
}
static class ValueIterator<K, V> implements Iterator<V> {
private final Iterator<Map.Entry<K, V>> it;
public ValueIterator(Iterator<Map.Entry<K, V>> it) {
this.it = it;
}
public V next() {
return it.next().getValue();
}
public boolean hasNext() {
return it.hasNext();
}
public void remove() {
it.remove();
}
}
}

View File

@ -40,19 +40,7 @@ public class HashMap<K, V> implements Map<K, V> {
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("{");
for (Iterator<Entry<K, V>> it = iterator(); it.hasNext();) {
Entry<K, V> e = it.next();
sb.append(e.getKey())
.append("=")
.append(e.getValue());
if (it.hasNext()) {
sb.append(",");
}
}
sb.append("}");
return sb.toString();
return Collections.toString(this);
}
private static int nextPowerOfTwo(int n) {
@ -324,7 +312,8 @@ public class HashMap<K, V> implements Map<K, V> {
}
public boolean contains(Object o) {
return (o instanceof Entry<?,?>) ? containsKey(((Entry<?,?>)o).getKey()) : false;
return (o instanceof Entry<?,?>)
&& containsKey(((Entry<?,?>)o).getKey());
}
public boolean add(Entry<K, V> e) {
@ -337,14 +326,18 @@ public class HashMap<K, V> implements Map<K, V> {
return change;
}
public boolean remove(Object o) {
return (o instanceof Entry<?,?>) ? remove((Entry<?,?>)o) : false;
}
public boolean remove(Object o) {
return (o instanceof Entry<?,?>) && remove((Entry<?,?>)o);
}
public boolean remove(Entry<K, V> e) {
return removeCell(e.getKey()) != null;
}
public Object[] toArray() {
return toArray(new Object[size()]);
}
public <T> T[] toArray(T[] array) {
return Collections.toArray(this, array);
}
@ -385,6 +378,10 @@ public class HashMap<K, V> implements Map<K, V> {
return removeCell(key) != null;
}
public Object[] toArray() {
return toArray(new Object[size()]);
}
public <T> T[] toArray(T[] array) {
return Collections.toArray(this, array);
}
@ -394,11 +391,10 @@ public class HashMap<K, V> implements Map<K, V> {
}
public Iterator<K> iterator() {
return new KeyIterator(new MyIterator());
return new Collections.KeyIterator(new MyIterator());
}
}
private class Values implements Collection<V> {
public int size() {
return HashMap.this.size();
@ -424,6 +420,10 @@ public class HashMap<K, V> implements Map<K, V> {
throw new UnsupportedOperationException();
}
public Object[] toArray() {
return toArray(new Object[size()]);
}
public <T> T[] toArray(T[] array) {
return Collections.toArray(this, array);
}
@ -433,7 +433,7 @@ public class HashMap<K, V> implements Map<K, V> {
}
public Iterator<V> iterator() {
return new ValueIterator(new MyIterator());
return new Collections.ValueIterator(new MyIterator());
}
}
@ -495,44 +495,4 @@ public class HashMap<K, V> implements Map<K, V> {
}
}
}
private static class KeyIterator<K, V> implements Iterator<K> {
private final Iterator<Entry<K, V>> it;
public KeyIterator(Iterator<Entry<K, V>> it) {
this.it = it;
}
public K next() {
return it.next().getKey();
}
public boolean hasNext() {
return it.hasNext();
}
public void remove() {
it.remove();
}
}
private static class ValueIterator<K, V> implements Iterator<V> {
private final Iterator<Entry<K, V>> it;
public ValueIterator(Iterator<Entry<K, V>> it) {
this.it = it;
}
public V next() {
return it.next().getValue();
}
public boolean hasNext() {
return it.hasNext();
}
public void remove() {
it.remove();
}
}
}

View File

@ -10,7 +10,7 @@
package java.util;
public class HashSet<T> implements Set<T> {
public class HashSet<T> extends AbstractSet<T> implements Set<T> {
private static final Object Value = new Object();
private final HashMap<T, Object> map;
@ -54,10 +54,6 @@ public class HashSet<T> implements Set<T> {
return map.remove(element) != Value;
}
public <T> T[] toArray(T[] array) {
return Collections.toArray(this, array);
}
public void clear() {
map.clear();
}

View File

@ -28,7 +28,7 @@ public class Hashtable<K, V> implements Map<K, V> {
}
}
public String toString() {
public synchronized String toString() {
return map.toString();
}

View File

@ -10,7 +10,7 @@
package java.util;
public class LinkedList<T> implements List<T> {
public class LinkedList<T> extends AbstractSequentialList<T> {
private Cell<T> front;
private Cell<T> rear;
private int size;
@ -85,10 +85,6 @@ public class LinkedList<T> implements List<T> {
}
}
public <S> S[] toArray(S[] a) {
return Collections.toArray(this, a);
}
public int size() {
return size;
}
@ -97,8 +93,26 @@ public class LinkedList<T> implements List<T> {
return find(element) != null;
}
public void addAll(Collection<T> c) {
for (T t: c) add(t);
public int indexOf(Object element) {
int i = 0;
for (Cell<T> c = front; c != null; c = c.next) {
if (equal(c.value, element)) {
return i;
}
++ i;
}
return -1;
}
public int lastIndexOf(Object element) {
int i = size;
for (Cell<T> c = rear; c != null; c = c.prev) {
-- i;
if (equal(c.value, element)) {
return i;
}
}
return -1;
}
public boolean add(T element) {
@ -202,7 +216,19 @@ public class LinkedList<T> implements List<T> {
}
public Iterator<T> iterator() {
return new MyIterator(front);
return listIterator();
}
public ListIterator<T> listIterator(int index) {
MyIterator it = new MyIterator();
for (int i = 0; i < index; ++i) {
it.next();
}
return it;
}
public ListIterator<T> listIterator() {
return listIterator(0);
}
public String toString() {
@ -221,18 +247,29 @@ public class LinkedList<T> implements List<T> {
}
}
private class MyIterator implements Iterator<T> {
private class MyIterator implements ListIterator<T> {
private Cell<T> toRemove;
private Cell<T> current;
private Cell<T> next;
public MyIterator(Cell<T> start) {
next = start;
public T previous() {
if (hasPrevious()) {
T v = current.value;
toRemove = current;
current = current.prev;
return v;
} else {
throw new NoSuchElementException();
}
}
public T next() {
if (hasNext()) {
current = next;
next = next.next;
if (current == null) {
current = front;
} else {
current = current.next;
}
toRemove = current;
return current.value;
} else {
throw new NoSuchElementException();
@ -240,13 +277,22 @@ public class LinkedList<T> implements List<T> {
}
public boolean hasNext() {
return next != null;
if (current == null) {
return front != null;
} else {
return current.next != null;
}
}
public boolean hasPrevious() {
return current != null;
}
public void remove() {
if (current != null) {
LinkedList.this.remove(current);
current = null;
if (toRemove != null) {
current = toRemove.prev;
LinkedList.this.remove(toRemove);
toRemove = null;
} else {
throw new IllegalStateException();
}

View File

@ -21,5 +21,13 @@ public interface List<T> extends Collection<T> {
public void add(int index, T element);
public int indexOf(Object value);
public int lastIndexOf(Object value);
public boolean isEmpty();
public ListIterator<T> listIterator(int index);
public ListIterator<T> listIterator();
}

View File

@ -0,0 +1,205 @@
/* Copyright (c) 2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.util;
public class TreeMap<K,V> implements Map<K,V> {
private TreeSet<MyEntry<K,V>> set;
public TreeMap(final Comparator<K> comparator) {
set = new TreeSet(new Comparator<MyEntry<K,V>>() {
public int compare(MyEntry<K,V> a, MyEntry<K,V> b) {
return comparator.compare(a.key, b.key);
}
});
}
public TreeMap() {
this(new Comparator<K>() {
public int compare(K a, K b) {
return ((Comparable) a).compareTo(b);
}
});
}
public String toString() {
return Collections.toString(this);
}
public V get(Object key) {
MyEntry<K,V> e = set.find(new MyEntry(key, null));
return e == null ? null : e.value;
}
public V put(K key, V value) {
MyEntry<K,V> e = set.addAndReplace(new MyEntry(key, value));
return e == null ? null : e.value;
}
public void putAll(Map<? extends K,? extends V> elts) {
for (Map.Entry<? extends K, ? extends V> entry : elts.entrySet()) {
put(entry.getKey(), entry.getValue());
}
}
public V remove(Object key) {
MyEntry<K,V> e = set.removeAndReturn(new MyEntry(key, null));
return e == null ? null : e.value;
}
public void clear() {
set.clear();
}
public int size() {
return set.size();
}
public boolean isEmpty() {
return size() == 0;
}
public boolean containsKey(Object key) {
return set.contains(new MyEntry(key, null));
}
private boolean equal(Object a, Object b) {
return a == null ? b == null : a.equals(b);
}
public boolean containsValue(Object value) {
for (V v: values()) {
if (equal(v, value)) {
return true;
}
}
return false;
}
public Set<Entry<K, V>> entrySet() {
return (Set<Entry<K, V>>) (Set) set;
}
public Set<K> keySet() {
return new KeySet();
}
public Collection<V> values() {
return new Values();
}
private static class MyEntry<K,V> implements 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;
}
}
private class KeySet implements Set<K> {
public int size() {
return TreeMap.this.size();
}
public boolean isEmpty() {
return TreeMap.this.isEmpty();
}
public boolean contains(Object key) {
return containsKey(key);
}
public boolean add(K key) {
return set.addAndReplace(new MyEntry(key, null)) != null;
}
public boolean addAll(Collection<? extends K> collection) {
boolean change = false;
for (K k: collection) if (add(k)) change = true;
return change;
}
public boolean remove(Object key) {
return set.removeAndReturn(new MyEntry(key, null)) != null;
}
public Object[] toArray() {
return toArray(new Object[size()]);
}
public <T> T[] toArray(T[] array) {
return Collections.toArray(this, array);
}
public void clear() {
TreeMap.this.clear();
}
public Iterator<K> iterator() {
return new Collections.KeyIterator(set.iterator());
}
}
private class Values implements Collection<V> {
public int size() {
return TreeMap.this.size();
}
public boolean isEmpty() {
return TreeMap.this.isEmpty();
}
public boolean contains(Object value) {
return containsValue(value);
}
public boolean add(V value) {
throw new UnsupportedOperationException();
}
public boolean addAll(Collection<? extends V> collection) {
throw new UnsupportedOperationException();
}
public boolean remove(Object value) {
throw new UnsupportedOperationException();
}
public Object[] toArray() {
return toArray(new Object[size()]);
}
public <T> T[] toArray(T[] array) {
return Collections.toArray(this, array);
}
public void clear() {
TreeMap.this.clear();
}
public Iterator<V> iterator() {
return new Collections.ValueIterator(set.iterator());
}
}
}

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2008, Avian Contributors
/* Copyright (c) 2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
@ -10,7 +10,10 @@
package java.util;
public class TreeSet<T> extends AbstractSet<T> implements Collection<T> {
import avian.PersistentSet;
import avian.Cell;
public class TreeSet<T> extends AbstractSet<T> implements Collection<T> {
private PersistentSet<Cell<T>> set;
private int size;
@ -49,34 +52,52 @@ public class TreeSet<T> extends AbstractSet<T> implements Collection<T> {
return false;
}
// Used by hashMaps for replacement
public void addAndReplace(T value) {
T addAndReplace(T value) {
PersistentSet.Path<Cell<T>> p = set.find(new Cell(value, null));
if (p.fresh()) {
set = p.add();
++size;
return null;
} else {
T old = p.value().value;
set = p.replaceWith(new Cell(value, null));
return old;
}
}
public boolean remove(Object value) {
T find(T value) {
PersistentSet.Path<Cell<T>> p = set.find(new Cell(value, null));
return p.fresh() ? null : p.value().value;
}
T removeAndReturn(T value) {
Cell<T> cell = removeCell(value);
return cell == null ? null : cell.value;
}
private Cell<T> removeCell(Object value) {
PersistentSet.Path<Cell<T>> p = set.find(new Cell(value, null));
if (p.fresh()) {
return false;
return null;
} else {
--size;
Cell<T> old = p.value();
if (p.value().next != null) {
set = p.replaceWith(p.value().next);
} else {
set = p.remove();
}
return true;
return old;
}
}
public boolean remove(Object value) {
return removeCell(value) != null;
}
public int size() {
return size;
}

View File

@ -10,7 +10,7 @@
package java.util;
public class Vector<T> implements List<T> {
public class Vector<T> extends AbstractList<T> {
private final ArrayList<T> list;
public Vector(int capacity) {
@ -77,10 +77,6 @@ public class Vector<T> implements List<T> {
return list.isEmpty();
}
public synchronized <S> S[] toArray(S[] a) {
return list.toArray(a);
}
public void removeElementAt(int index) {
remove(index);
}
@ -97,11 +93,11 @@ public class Vector<T> implements List<T> {
list.clear();
}
public synchronized int indexOf(T element) {
public synchronized int indexOf(Object element) {
return list.indexOf(element);
}
public synchronized int lastIndexOf(T element) {
public synchronized int lastIndexOf(Object element) {
return list.lastIndexOf(element);
}
@ -112,7 +108,15 @@ public class Vector<T> implements List<T> {
}
public Iterator<T> iterator() {
return new Collections.ArrayListIterator(this);
return listIterator();
}
public ListIterator<T> listIterator(int index) {
return new Collections.ArrayListIterator(this, index);
}
public ListIterator<T> listIterator() {
return listIterator(0);
}
public Enumeration<T> elements() {

View File

@ -0,0 +1,15 @@
/* Copyright (c) 2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.util.concurrent;
public interface Callable<T> {
public T call() throws Exception;
}

View File

@ -113,8 +113,9 @@ public class Logger {
if (level.intValue() < getEffectiveLevel().intValue()) {
return;
}
LogRecord r = new LogRecord(name, caller.getName(), level, message,
exception);
LogRecord r = new LogRecord
(name, caller == null ? "<unknown>" : caller.getName(), level, message,
exception);
publish(r);
}

View File

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

170
makefile
View File

@ -14,7 +14,9 @@ build-platform = \
| sed 's/^cygwin.*$$/cygwin/')
arch = $(build-arch)
platform = $(subst cygwin,windows,$(subst mingw32,windows,$(build-platform)))
bootimage-platform = \
$(subst cygwin,windows,$(subst mingw32,windows,$(build-platform)))
platform = $(bootimage-platform)
mode = fast
process = compile
@ -31,6 +33,29 @@ endif
ifeq ($(heapdump),true)
options := $(options)-heapdump
endif
ifeq ($(tails),true)
options := $(options)-tails
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
@ -41,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++
@ -71,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 =
@ -111,7 +143,7 @@ endif
ifeq ($(platform),darwin)
build-cflags = $(common-cflags) -fPIC -fvisibility=hidden -I$(src)
lflags = $(common-lflags) -ldl -framework CoreFoundation
lflags = $(common-lflags) -ldl -framework CoreFoundation -framework CoreServices
ifeq ($(bootimage),true)
bootimage-lflags = -Wl,-segprot,__BOOT,rwx,rwx
endif
@ -166,7 +198,6 @@ ifeq ($(platform),windows)
strip = :
inc = "$(root)/win64/include"
lib = "$(root)/win64/lib"
cflags += -D__x86_64__ -D__WINDOWS__
pointer-size = 8
object-format = pe-x86-64
endif
@ -236,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
@ -266,11 +298,20 @@ ifeq ($(heapdump),true)
cflags += -DAVIAN_HEAPDUMP
endif
ifeq ($(tails),true)
cflags += -DAVIAN_TAILS
endif
ifeq ($(continuations),true)
cflags += -DAVIAN_CONTINUATIONS
asmflags += -DAVIAN_CONTINUATIONS
endif
bootimage-generator-sources = $(src)/bootimage.cpp
bootimage-generator-objects = \
$(call cpp-objects,$(bootimage-generator-sources),$(src),$(native-build))
bootimage-generator = \
$(build)/$(build-platform)-$(build-arch)$(options)/bootimage-generator
$(build)/$(bootimage-platform)-$(build-arch)$(options)/bootimage-generator
bootimage-bin = $(native-build)/bootimage.bin
bootimage-object = $(native-build)/bootimage-bin.o
@ -309,11 +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
class-name = $(patsubst $(1)/%.class,%,$(2))
class-names = $(foreach x,$(2),$(call class-name,$(1),$(x)))
@ -324,7 +397,7 @@ args = $(flags) $(input)
.PHONY: build
build: $(static-library) $(executable) $(dynamic-library) \
$(executable-dynamic) $(classpath-dep) $(test-dep)
$(executable-dynamic) $(classpath-dep) $(test-dep) $(test-extra-dep)
$(test-classes): $(classpath-dep)
@ -355,7 +428,7 @@ tarball:
.PHONY: javadoc
javadoc:
javadoc -sourcepath classpath -d build/javadoc -subpackages java \
javadoc -sourcepath classpath -d build/javadoc -subpackages avian:java \
-windowtitle "Avian v$(version) Class Library API" \
-doctitle "Avian v$(version) Class Library API" \
-header "Avian v$(version)" \
@ -383,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
@ -395,13 +481,20 @@ $(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 $(test-build)
$(javac) -d $(test-build) -bootclasspath $(classpath-build) \
$(shell $(MAKE) -s --no-print-directory $(test-extra-classes))
@touch $(@)
define compile-object
@echo "compiling $(@)"
@mkdir -p $(dir $(@))
@ -411,7 +504,7 @@ endef
define compile-asm-object
@echo "compiling $(@)"
@mkdir -p $(dir $(@))
$(cc) $(cflags) -I$(src) -c $(<) -o $(@)
$(cc) -I$(src) $(asmflags) -c $(<) -o $(@)
endef
$(vm-cpp-objects): $(native-build)/%.o: $(src)/%.cpp $(vm-depends)
@ -439,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 $(@)
@ -452,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
@ -467,14 +560,15 @@ $(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)
$(<) $(classpath-build) > $(@)
$(<) $(classpath-build) $(@)
$(bootimage-object): $(bootimage-bin) $(binaryToMacho)
@echo "creating $(@)"
@ -482,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) $(@)
@ -509,7 +611,7 @@ make-bootimage-generator:
(unset MAKEFLAGS && \
make mode=$(mode) \
arch=$(build-arch) \
platform=$(build-platform) \
platform=$(bootimage-platform) \
bootimage=$(bootimage) \
heapdump=$(heapdump) \
bootimage-generator= \
@ -528,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)

View File

@ -76,7 +76,8 @@ certain flags described below, all of which are optional.
$ make platform={linux,windows,darwin} arch={i386,x86_64,powerpc} \
process={compile,interpret} mode={debug,debug-fast,fast,small} \
bootimage={true,false} heapdump={true,false}
bootimage={true,false} heapdump={true,false} tails={true,false} \
continuations={true,false}
* platform - the target platform
default: output of $(uname -s | tr [:upper:] [:lower:]),
@ -86,7 +87,7 @@ certain flags described below, all of which are optional.
default: output of $(uname -m), normalized in some cases
(e.g. i686 -> i386)
* mode - which set of compilation flags to use, which determine
* mode - which set of compilation flags to use to determine
optimization level, debug symbols, and whether to enable
assertions
default: fast
@ -105,6 +106,18 @@ certain flags described below, all of which are optional.
heapdump.cpp for details.
default: false
* tails - if true, optimize each tail call by replacing the caller's
stack frame with the callee's. This convention ensures proper
tail recursion, suitable for languages such as Scheme. This
option is only valid for process=compile builds.
default: false
* continuations - if true, support continuations via the
avian.Continuations methods callWithCurrentContinuation and
dynamicWind. See Continuations.java for details. This option is
only valid for process=compile builds.
default: false
These flags determine the name of the directory used for the build.
The name always starts with ${platform}-${arch}, and each non-default
build option is appended to the name. For example, a debug build with
@ -390,12 +403,12 @@ Step 5: Run ProGuard with stage1 as input and stage2 as output.
$ java -jar ../../proguard4.3/lib/proguard.jar \
-injars stage1 -outjars stage2 @../vm.pro @hello.pro
(note: pass -dontusemixedcaseclassnames to ProGuard when building on systems with case-insensitive filesystems such as Windows and OS X)
(note: pass -dontusemixedcaseclassnames to ProGuard when building on
systems with case-insensitive filesystems such as Windows and OS X)
Step 6: Build the boot image.
$ ../build/linux-i386-bootimage/bootimage-generator stage2 \
> bootimage.bin
$ ../build/linux-i386-bootimage/bootimage-generator stage2 bootimage.bin
Step 7: Make an object file out of the boot image.

View File

@ -14,7 +14,8 @@
#include "common.h"
extern "C" void NO_RETURN
vmJump(void* address, void* base, void* stack, void* thread);
vmJump(void* address, void* base, void* stack, void* thread,
uintptr_t returnLow, uintptr_t returnHigh);
#if (defined __i386__) || (defined __x86_64__)
# include "x86.h"

View File

@ -16,6 +16,12 @@
namespace vm {
#ifdef AVIAN_TAILS
const bool TailCalls = true;
#else
const bool TailCalls = false;
#endif
enum Operation {
Return,
LoadBarrier,
@ -31,13 +37,20 @@ enum UnaryOperation {
AlignedCall,
Jump,
LongJump,
AlignedJump,
JumpIfLess,
JumpIfGreater,
JumpIfLessOrEqual,
JumpIfGreaterOrEqual,
JumpIfEqual,
JumpIfNotEqual,
JumpIfUnordered
JumpIfFloatUnordered,
JumpIfFloatLess,
JumpIfFloatGreater,
JumpIfFloatLessOrEqual,
JumpIfFloatGreaterOrEqual,
JumpIfFloatEqual,
JumpIfFloatNotEqual,
};
const unsigned UnaryOperationCount = JumpIfNotEqual + 1;
@ -225,12 +238,6 @@ class DelayedPromise: public ListenPromise {
DelayedPromise* next;
};
class TraceHandler {
public:
virtual void handleTrace(Promise* address, unsigned padIndex,
unsigned padding) = 0;
};
class Assembler {
public:
class Operand { };
@ -259,7 +266,7 @@ class Assembler {
class Memory: public Operand {
public:
Memory(int base, int offset, int index = NoRegister, unsigned scale = 0):
Memory(int base, int offset, int index = NoRegister, unsigned scale = 1):
base(base), offset(offset), index(index), scale(scale)
{ }
@ -290,22 +297,33 @@ class Assembler {
virtual unsigned floatRegisterCount() = 0;
virtual uint64_t generalRegisters() = 0;
virtual uint64_t floatRegisters() = 0;
virtual uint64_t allRegisters() = 0;
virtual int stack() = 0;
virtual int thread() = 0;
virtual int returnLow() = 0;
virtual int returnHigh() = 0;
virtual int virtualCallTarget() = 0;
virtual int virtualCallIndex() = 0;
virtual bool bigEndian() = 0;
virtual bool supportsFloatCompare(unsigned size) = 0;
virtual bool alwaysCondensed(BinaryOperation op) = 0;
virtual bool alwaysCondensed(TernaryOperation op) = 0;
virtual bool reserved(int register_) = 0;
virtual unsigned frameFootprint(unsigned footprint) = 0;
virtual unsigned argumentFootprint(unsigned footprint) = 0;
virtual unsigned argumentRegisterCount() = 0;
virtual int argumentRegister(unsigned index) = 0;
virtual unsigned stackAlignmentInWords() = 0;
virtual bool matchCall(void* returnAddress, void* target) = 0;
virtual void updateCall(UnaryOperation op, bool assertAlignment,
void* returnAddress, void* newTarget) = 0;
@ -318,6 +336,8 @@ class Assembler {
virtual unsigned frameHeaderSize() = 0;
virtual unsigned frameReturnAddressSize() = 0;
virtual unsigned frameFooterSize() = 0;
virtual int returnAddressOffset() = 0;
virtual int framePointerOffset() = 0;
virtual void nextFrame(void** stack, void** base) = 0;
virtual BinaryOperation hasBinaryIntrinsic(Thread* t, object method) = 0;
@ -361,7 +381,15 @@ class Assembler {
virtual void saveFrame(unsigned stackOffset, unsigned baseOffset) = 0;
virtual void pushFrame(unsigned argumentCount, ...) = 0;
virtual void allocateFrame(unsigned footprint) = 0;
virtual void adjustFrame(unsigned footprint) = 0;
virtual void popFrame() = 0;
virtual void popFrameForTailCall(unsigned footprint, int offset,
int returnAddressSurrogate,
int framePointerSurrogate) = 0;
virtual void popFrameAndPopArgumentsAndReturn(unsigned argumentFootprint)
= 0;
virtual void popFrameAndUpdateStackAndReturn(unsigned stackOffsetFromThread)
= 0;
virtual void apply(Operation op) = 0;

View File

@ -33,12 +33,9 @@ endsWith(const char* suffix, const char* s, unsigned length)
object
makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code,
unsigned capacity, uintptr_t* codeMap, const char* className,
uintptr_t* codeMap, const char* className,
const char* methodName, const char* methodSpec)
{
unsigned size = 0;
t->m->processor->compileThunks(t, image, code, &size, capacity);
object constants = 0;
PROTECT(t, constants);
@ -79,8 +76,7 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code,
== 0)))
{
t->m->processor->compileMethod
(t, zone, code, &size, capacity, &constants, &calls, &addresses,
method);
(t, zone, &constants, &calls, &addresses, method);
}
}
}
@ -119,8 +115,6 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code,
- reinterpret_cast<intptr_t>(code));
}
image->codeSize = size;
return constants;
}
@ -144,7 +138,7 @@ visitRoots(Thread* t, BootImage* image, HeapWalker* w, object constants)
image->loader = w->visitRoot(m->loader);
image->types = w->visitRoot(m->types);
m->processor->visitRoots(image, w);
m->processor->visitRoots(w);
for (; constants; constants = tripleThird(t, constants)) {
w->visitRoot(tripleFirst(t, constants));
@ -187,7 +181,7 @@ makeHeapImage(Thread* t, BootImage* image, uintptr_t* heap, uintptr_t* map,
and (currentOffset * BytesPerWord) == ClassStaticTable)
{
FixedAllocator allocator
(t, reinterpret_cast<uint8_t*>(heap + position),
(t->m->system, reinterpret_cast<uint8_t*>(heap + position),
(capacity - position) * BytesPerWord);
unsigned totalInBytes;
@ -285,21 +279,18 @@ offset(object a, uintptr_t* b)
}
void
writeBootImage(Thread* t, FILE* out, const char* className,
writeBootImage(Thread* t, FILE* out, BootImage* image, uint8_t* code,
unsigned codeCapacity, const char* className,
const char* methodName, const char* methodSpec)
{
Zone zone(t->m->system, t->m->heap, 64 * 1024);
BootImage image;
const unsigned CodeCapacity = 32 * 1024 * 1024;
uint8_t* code = static_cast<uint8_t*>(t->m->heap->allocate(CodeCapacity));
uintptr_t* codeMap = static_cast<uintptr_t*>
(t->m->heap->allocate(codeMapSize(CodeCapacity)));
memset(codeMap, 0, codeMapSize(CodeCapacity));
(t->m->heap->allocate(codeMapSize(codeCapacity)));
memset(codeMap, 0, codeMapSize(codeCapacity));
object constants = makeCodeImage
(t, &zone, &image, code, CodeCapacity, codeMap, className, methodName,
methodSpec);
(t, &zone, image, code, codeMap, className, methodName, methodSpec);
if (t->exception) return;
@ -312,16 +303,20 @@ writeBootImage(Thread* t, FILE* out, const char* className,
(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
(t, &image, heap, heapMap, HeapCapacity, constants);
(t, image, heap, heapMap, HeapCapacity, constants);
updateConstants(t, constants, code, codeMap, heapWalker->map());
image.classCount = hashMapSize(t, t->m->classMap);
image->classCount = hashMapSize(t, t->m->classMap);
unsigned* classTable = static_cast<unsigned*>
(t->m->heap->allocate(image.classCount * sizeof(unsigned)));
(t->m->heap->allocate(image->classCount * sizeof(unsigned)));
{ unsigned i = 0;
for (HashMapIterator it(t, t->m->classMap); it.hasMore();) {
@ -329,9 +324,9 @@ writeBootImage(Thread* t, FILE* out, const char* className,
}
}
image.stringCount = hashMapSize(t, t->m->stringMap);
image->stringCount = hashMapSize(t, t->m->stringMap);
unsigned* stringTable = static_cast<unsigned*>
(t->m->heap->allocate(image.stringCount * sizeof(unsigned)));
(t->m->heap->allocate(image->stringCount * sizeof(unsigned)));
{ unsigned i = 0;
for (HashMapIterator it(t, t->m->stringMap); it.hasMore();) {
@ -340,29 +335,28 @@ writeBootImage(Thread* t, FILE* out, const char* className,
}
}
unsigned* callTable = t->m->processor->makeCallTable
(t, &image, heapWalker, code);
unsigned* callTable = t->m->processor->makeCallTable(t, heapWalker);
heapWalker->dispose();
image.magic = BootImage::Magic;
image.codeBase = reinterpret_cast<uintptr_t>(code);
image->magic = BootImage::Magic;
image->codeBase = reinterpret_cast<uintptr_t>(code);
fprintf(stderr, "class count %d string count %d call count %d\n"
"heap size %d code size %d\n",
image.classCount, image.stringCount, image.callCount, image.heapSize,
image.codeSize);
image->classCount, image->stringCount, image->callCount,
image->heapSize, image->codeSize);
if (true) {
fwrite(&image, sizeof(BootImage), 1, out);
fwrite(image, sizeof(BootImage), 1, out);
fwrite(classTable, image.classCount * sizeof(unsigned), 1, out);
fwrite(stringTable, image.stringCount * sizeof(unsigned), 1, out);
fwrite(callTable, image.callCount * sizeof(unsigned) * 2, 1, out);
fwrite(classTable, image->classCount * sizeof(unsigned), 1, out);
fwrite(stringTable, image->stringCount * sizeof(unsigned), 1, out);
fwrite(callTable, image->callCount * sizeof(unsigned) * 2, 1, out);
unsigned offset = (image.classCount * sizeof(unsigned))
+ (image.stringCount * sizeof(unsigned))
+ (image.callCount * sizeof(unsigned) * 2);
unsigned offset = (image->classCount * sizeof(unsigned))
+ (image->stringCount * sizeof(unsigned))
+ (image->callCount * sizeof(unsigned) * 2);
while (offset % BytesPerWord) {
uint8_t c = 0;
@ -370,11 +364,11 @@ writeBootImage(Thread* t, FILE* out, const char* className,
++ offset;
}
fwrite(heapMap, pad(heapMapSize(image.heapSize)), 1, out);
fwrite(heap, pad(image.heapSize), 1, out);
fwrite(heapMap, pad(heapMapSize(image->heapSize)), 1, out);
fwrite(heap, pad(image->heapSize), 1, out);
fwrite(codeMap, pad(codeMapSize(image.codeSize)), 1, out);
fwrite(code, pad(image.codeSize), 1, out);
fwrite(codeMap, pad(codeMapSize(image->codeSize)), 1, out);
fwrite(code, pad(image->codeSize), 1, out);
}
}
@ -383,8 +377,8 @@ writeBootImage(Thread* t, FILE* out, const char* className,
int
main(int ac, const char** av)
{
if (ac < 2 or ac > 5) {
fprintf(stderr, "usage: %s <classpath> "
if (ac < 3 or ac > 6) {
fprintf(stderr, "usage: %s <classpath> <output file> "
"[<class name> [<method name> [<method spec>]]]\n", av[0]);
return -1;
}
@ -393,15 +387,29 @@ main(int ac, const char** av)
Heap* h = makeHeap(s, 128 * 1024 * 1024);
Finder* f = makeFinder(s, av[1], 0);
Processor* p = makeProcessor(s, h);
BootImage image;
const unsigned CodeCapacity = 32 * 1024 * 1024;
uint8_t* code = static_cast<uint8_t*>(h->allocate(CodeCapacity));
p->initialize(&image, code, CodeCapacity);
Machine* m = new (h->allocate(sizeof(Machine))) Machine(s, h, f, p, 0, 0);
Thread* t = p->makeThread(m, 0, 0);
enter(t, Thread::ActiveState);
enter(t, Thread::IdleState);
FILE* output = fopen(av[2], "wb");
if (output == 0) {
fprintf(stderr, "unable to open %s\n", av[2]);
return -1;
}
writeBootImage
(t, stdout, (ac > 2 ? av[2] : 0), (ac > 3 ? av[3] : 0),
(ac > 4 ? av[4] : 0));
(t, output, &image, code, CodeCapacity,
(ac > 3 ? av[3] : 0), (ac > 4 ? av[4] : 0), (ac > 5 ? av[5] : 0));
fclose(output);
if (t->exception) {
printTrace(t, t->exception);

View File

@ -39,10 +39,12 @@ class BootImage {
unsigned types;
unsigned methodTree;
unsigned methodTreeSentinal;
unsigned virtualThunks;
uintptr_t codeBase;
unsigned defaultThunk;
unsigned defaultVirtualThunk;
unsigned nativeThunk;
unsigned aioobThunk;
@ -50,6 +52,7 @@ class BootImage {
unsigned thunkSize;
unsigned compileMethodCall;
unsigned compileVirtualMethodCall;
unsigned invokeNativeCall;
unsigned throwArrayIndexOutOfBoundsCall;

File diff suppressed because it is too large Load Diff

View File

@ -30,7 +30,7 @@
#endif
#if (defined __i386__) || (defined __POWERPC__)
# define LD "d"
# define LD "ld"
# define LLD "lld"
#ifdef __APPLE__
# define ULD "lu"
@ -39,16 +39,18 @@
# define LX "x"
# define ULD "u"
#endif
#elif defined __x86_64__ && defined __LINUX__
# define LD "ld"
# define LX "lx"
# define LLD "ld"
# define ULD "lu"
#elif defined __x86_64__ && defined __WINDOWS__
# define LD "I64d"
# define LX "I64x"
# define LLD "I64d"
# define ULD "I64x"
#elif defined __x86_64__
# 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
@ -108,10 +110,16 @@ avg(unsigned a, unsigned b)
return (a + b) / 2;
}
inline unsigned
pad(unsigned n, unsigned alignment)
{
return (n + (alignment - 1)) & ~(alignment - 1);
}
inline unsigned
pad(unsigned n)
{
return (n + (BytesPerWord - 1)) & ~(BytesPerWord - 1);
return pad(n, BytesPerWord);
}
inline unsigned
@ -286,7 +294,7 @@ bitsToFloat(uint32_t bits)
return f;
}
inline intptr_t
inline int
difference(void* a, void* b)
{
return reinterpret_cast<intptr_t>(a) - reinterpret_cast<intptr_t>(b);

View File

@ -17,14 +17,28 @@
#define ARGUMENT_BASE BYTES_PER_WORD * LINKAGE_AREA
#define LOCAL(x) L##x
#ifdef __APPLE__
.globl _vmInvoke
_vmInvoke:
# define GLOBAL(x) _##x
#else
.globl vmInvoke
vmInvoke:
# define GLOBAL(x) x
#endif
#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
.globl GLOBAL(vmInvoke)
GLOBAL(vmInvoke):
// save return address
mflr r0
stw r0,8(r1)
@ -73,24 +87,94 @@ vmInvoke:
// copy arguments into place
li r16,0
b LOCAL(test)
addi r18,r1,ARGUMENT_BASE
b LOCAL(vmInvoke_argumentTest)
LOCAL(loop):
LOCAL(vmInvoke_argumentLoop):
lwzx r17,r16,r5
addi r18,r16,ARGUMENT_BASE
stwx r17,r18,r1
stwx r17,r16,r18
addi r16,r16,BYTES_PER_WORD
LOCAL(test):
LOCAL(vmInvoke_argumentTest):
cmplw r16,r6
blt LOCAL(loop)
blt LOCAL(vmInvoke_argumentLoop)
// load and call function address
mtctr r4
bctrl
LOCAL(vmInvoke_returnAddress):
// restore stack pointer
lwz r1,0(r1)
#ifdef AVIAN_CONTINUATIONS
// call the next continuation, if any
lwz r5,THREAD_CONTINUATION(r13)
cmplwi r5,0
beq LOCAL(vmInvoke_exit)
lwz r6,CONTINUATION_LENGTH(r5)
slwi r6,r6,2
subfic r7,r6,-80
stwux r1,r1,r7
addi r7,r5,CONTINUATION_BODY
li r8,0
addi r10,r1,ARGUMENT_BASE
b LOCAL(vmInvoke_continuationTest)
LOCAL(vmInvoke_continuationLoop):
lwzx r9,r7,r8
stwx r9,r10,r8
addi r8,r8,4
LOCAL(vmInvoke_continuationTest):
cmplw r8,r6
ble LOCAL(vmInvoke_continuationLoop)
lwz r7,CONTINUATION_RETURN_ADDRESS_OFFSET(r5)
bl LOCAL(vmInvoke_getPC)
LOCAL(vmInvoke_getPC):
mflr r10
la r10,lo16(LOCAL(vmInvoke_returnAddress)-LOCAL(vmInvoke_getPC))(r10)
stwx r10,r1,r7
lwz r7,CONTINUATION_FRAME_POINTER_OFFSET(r5)
lwz r8,0(r1)
add r7,r7,r1
stw r8,0(r7)
stw r7,0(r1)
lwz r7,CONTINUATION_NEXT(r5)
stw r7,THREAD_CONTINUATION(r13)
// call the continuation unless we're handling an exception
lwz r7,THREAD_EXCEPTION(r13)
cmpwi r7,0
bne LOCAL(vmInvoke_handleException)
lwz r7,CONTINUATION_ADDRESS(r5)
mtctr r7
bctr
LOCAL(vmInvoke_handleException):
// we're handling an exception - call the exception handler instead
li r8,0
stw r8,THREAD_EXCEPTION(r13)
lwz r8,THREAD_EXCEPTION_STACK_ADJUSTMENT(r13)
lwz r9,0(r1)
subfic r8,r8,0
stwux r9,r1,r8
lwz r8,THREAD_EXCEPTION_OFFSET(r13)
stwx r7,r1,r8
lwz r7,THREAD_EXCEPTION_HANDLER(r13)
mtctr r7
bctr
LOCAL(vmInvoke_exit):
#endif // AVIAN_CONTINUATIONS
// restore callee-saved registers
subi r9,r1,80
@ -118,23 +202,82 @@ LOCAL(test):
// handle return value based on expected type
lwz r8,44(r1)
LOCAL(void):
LOCAL(vmInvoke_void):
cmplwi r8,VOID_TYPE
bne LOCAL(int64)
b LOCAL(exit)
bne LOCAL(vmInvoke_int64)
b LOCAL(vmInvoke_return)
LOCAL(int64):
LOCAL(vmInvoke_int64):
cmplwi r8,INT64_TYPE
bne LOCAL(int32)
b LOCAL(exit)
bne LOCAL(vmInvoke_int32)
b LOCAL(vmInvoke_return)
LOCAL(int32):
LOCAL(vmInvoke_int32):
li r3,0
LOCAL(exit):
LOCAL(vmInvoke_return):
// load return address
lwz r0,8(r1)
mtlr r0
// return
blr
.globl GLOBAL(vmJumpAndInvoke)
GLOBAL(vmJumpAndInvoke):
#ifdef AVIAN_CONTINUATIONS
// r3: thread
// r4: address
// r5: (unused)
// r6: stack
// r7: argumentFootprint
// r8: arguments
// r9: frameSize
// restore (pseudo)-stack pointer (we don't want to touch the real
// stack pointer, since we haven't copied the arguments yet)
lwz r6,0(r6)
// make everything between r1 and r6 one big stack frame while we
// shuffle things around
stw r6,0(r1)
// allocate new frame, adding room for callee-saved registers
subfic r10,r9,-80
stwux r6,r6,r10
mr r13,r3
// copy arguments into place
li r9,0
addi r11,r6,ARGUMENT_BASE
b LOCAL(vmJumpAndInvoke_argumentTest)
LOCAL(vmJumpAndInvoke_argumentLoop):
lwzx r12,r8,r9
stwx r12,r11,r9
addi r9,r9,4
LOCAL(vmJumpAndInvoke_argumentTest):
cmplw r9,r7
ble LOCAL(vmJumpAndInvoke_argumentLoop)
// the arguments have been copied, so we can set the real stack
// pointer now
mr r1,r6
// set return address to vmInvoke_returnAddress
bl LOCAL(vmJumpAndInvoke_getPC)
LOCAL(vmJumpAndInvoke_getPC):
mflr r10
la r10,lo16(LOCAL(vmInvoke_returnAddress)-LOCAL(vmJumpAndInvoke_getPC))(r10)
mtlr r10
mtctr r4
bctr
#else // not AVIAN_CONTINUATIONS
// vmJumpAndInvoke should only be called when continuations are
// enabled
trap
#endif // not AVIAN_CONTINUATIONS

View File

@ -12,23 +12,25 @@
#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 __WINDOWS__
# if defined __APPLE__ || defined __MINGW32__ || defined __CYGWIN32__
.globl _vmInvoke
_vmInvoke:
# else
.globl vmInvoke
vmInvoke:
#error other
# endif
#ifdef __MINGW32__
#define CALLEE_SAVED_REGISTER_FOOTPRINT 64
.globl GLOBAL(vmInvoke)
GLOBAL(vmInvoke):
pushq %rbp
movq %rsp,%rbp
//NEW
// %rcx: thread
// %rdx: function
// %r8 : arguments
@ -39,7 +41,7 @@ vmInvoke:
// allocate stack space, adding room for callee-saved registers
movl 48(%rbp),%eax
subq %rax,%rsp
subq $64,%rsp
subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%rsp
// save callee-saved registers
movq %rsp,%r11
@ -58,26 +60,33 @@ vmInvoke:
// copy arguments into place
movq $0,%r11
jmp LOCAL(test)
jmp LOCAL(vmInvoke_argumentTest)
LOCAL(loop):
LOCAL(vmInvoke_argumentLoop):
movq (%r8,%r11,1),%rsi
movq %rsi,(%rsp,%r11,1)
addq $8,%r11
LOCAL(test):
LOCAL(vmInvoke_argumentTest):
cmpq %r9,%r11
jb LOCAL(loop)
jb LOCAL(vmInvoke_argumentLoop)
// call function
call *%rdx
.globl GLOBAL(vmInvoke_returnAddress)
GLOBAL(vmInvoke_returnAddress):
// restore stack pointer
movq %rbp,%rsp
// restore callee-saved registers
#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 $64,%r11
subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%r11
movq 0(%r11),%rbx
movq 8(%r11),%r12
@ -90,16 +99,67 @@ LOCAL(test):
// return
popq %rbp
ret
#elif defined __LINUX__
.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
# if defined __APPLE__ || defined __MINGW32__ || defined __CYGWIN32__
.globl _vmInvoke
_vmInvoke:
# else
.globl vmInvoke
vmInvoke:
# endif
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
.globl GLOBAL(vmInvoke)
GLOBAL(vmInvoke):
pushq %rbp
movq %rsp,%rbp
@ -111,8 +171,8 @@ vmInvoke:
// %r9 : returnType (ignored)
// allocate stack space, adding room for callee-saved registers
subq %r8,%rsp
subq $48,%rsp
subq %r8,%rsp
subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%rsp
// save callee-saved registers
movq %rsp,%r9
@ -129,26 +189,33 @@ vmInvoke:
// copy arguments into place
movq $0,%r9
jmp LOCAL(test)
jmp LOCAL(vmInvoke_argumentTest)
LOCAL(loop):
LOCAL(vmInvoke_argumentLoop):
movq (%rdx,%r9,1),%r8
movq %r8,(%rsp,%r9,1)
addq $8,%r9
LOCAL(test):
LOCAL(vmInvoke_argumentTest):
cmpq %rcx,%r9
jb LOCAL(loop)
jb LOCAL(vmInvoke_argumentLoop)
// call function
call *%rsi
.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
// restore callee-saved registers (below the stack pointer, but in
// the red zone)
movq %rsp,%r9
subq $48,%r9
subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%r9
movq 0(%r9),%rbx
movq 8(%r9),%r12
@ -160,19 +227,66 @@ LOCAL(test):
popq %rbp
ret
#else
#error unsupported platorm / architecture combo
#endif //defined __WINDOWS__
.globl GLOBAL(vmJumpAndInvoke)
GLOBAL(vmJumpAndInvoke):
#ifdef AVIAN_CONTINUATIONS
// %rdi: thread
// %rsi: address
// %rdx: base
// %rcx: (unused)
// %r8 : argumentFootprint
// %r9 : arguments
// 8(%rsp): frameSize
movq %rdx,%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,%rcx
// allocate new frame, adding room for callee-saved registers
movl 8(%rsp),%eax
subq %rax,%rcx
subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%rcx
movq %rdi,%rbx
// set return address
movq vmInvoke_returnAddress@GOTPCREL(%rip),%r10
movq %r10,(%rcx)
// copy arguments into place
movq $0,%r11
jmp LOCAL(vmJumpAndInvoke_argumentTest)
LOCAL(vmJumpAndInvoke_argumentLoop):
movq (%r9,%r11,1),%r10
movq %r10,8(%rcx,%r11,1)
addq $8,%r11
LOCAL(vmJumpAndInvoke_argumentTest):
cmpq %r8,%r11
jb LOCAL(vmJumpAndInvoke_argumentLoop)
// the arguments have been copied, so we can set the real stack
// pointer now
movq %rcx,%rsp
jmp *%rsi
#else // not AVIAN_CONTINUATIONS
// vmJumpAndInvoke should only be called when continuations are
// enabled
int3
#endif // not AVIAN_CONTINUATIONS
#endif // not __MINGW32__
#elif defined __i386__
# if defined __APPLE__ || defined __MINGW32__ || defined __CYGWIN32__
.globl _vmInvoke
_vmInvoke:
# else
.globl vmInvoke
vmInvoke:
# endif
#define CALLEE_SAVED_REGISTER_FOOTPRINT 16
.globl GLOBAL(vmInvoke)
GLOBAL(vmInvoke):
pushl %ebp
movl %esp,%ebp
@ -185,7 +299,7 @@ vmInvoke:
// allocate stack space, adding room for callee-saved registers
subl 24(%ebp),%esp
subl $16,%esp
subl $CALLEE_SAVED_REGISTER_FOOTPRINT,%esp
// save callee-saved registers
movl %esp,%ecx
@ -201,26 +315,33 @@ vmInvoke:
// copy arguments into place
movl $0,%ecx
movl 16(%ebp),%edx
jmp LOCAL(test)
jmp LOCAL(vmInvoke_argumentTest)
LOCAL(loop):
LOCAL(vmInvoke_argumentLoop):
movl (%edx,%ecx,1),%eax
movl %eax,(%esp,%ecx,1)
addl $4,%ecx
LOCAL(test):
LOCAL(vmInvoke_argumentTest):
cmpl 20(%ebp),%ecx
jb LOCAL(loop)
jb LOCAL(vmInvoke_argumentLoop)
// call function
call *12(%ebp)
// restore stack pointer
movl %ebp,%esp
.globl vmInvoke_returnAddress
vmInvoke_returnAddress:
// restore stack pointer, preserving the area containing saved
// registers
movl %ebp,%ecx
subl $CALLEE_SAVED_REGISTER_FOOTPRINT,%ecx
movl %ecx,%esp
#ifdef AVIAN_CONTINUATIONS
# include "continuations-x86.S"
#endif // AVIAN_CONTINUATIONS
// restore callee-saved registers
subl $16,%esp
movl 0(%esp),%ebx
movl 4(%esp),%esi
movl 8(%esp),%edi
@ -228,24 +349,86 @@ LOCAL(test):
// handle return value based on expected type
movl 28(%ebp),%ecx
addl $16,%esp
addl $CALLEE_SAVED_REGISTER_FOOTPRINT,%esp
LOCAL(void):
LOCAL(vmInvoke_void):
cmpl $VOID_TYPE,%ecx
jne LOCAL(int64)
jmp LOCAL(exit)
jne LOCAL(vmInvoke_int64)
jmp LOCAL(vmInvoke_return)
LOCAL(int64):
LOCAL(vmInvoke_int64):
cmpl $INT64_TYPE,%ecx
jne LOCAL(int32)
jmp LOCAL(exit)
jne LOCAL(vmInvoke_int32)
jmp LOCAL(vmInvoke_return)
LOCAL(int32):
LOCAL(vmInvoke_int32):
movl $0,%edx
LOCAL(exit):
LOCAL(vmInvoke_return):
popl %ebp
ret
LOCAL(getPC):
movl (%esp),%esi
ret
.globl GLOBAL(vmJumpAndInvoke)
GLOBAL(vmJumpAndInvoke):
#ifdef AVIAN_CONTINUATIONS
// 4(%esp): thread
// 8(%esp): address
// 12(%esp): base
// 16(%esp): (unused)
// 20(%esp): argumentFootprint
// 24(%esp): arguments
// 28(%esp): frameSize
movl 12(%esp),%ebp
// restore (pseudo)-stack pointer (we don't want to touch the real
// stack pointer, since we haven't copied the arguments yet)
movl %ebp,%ecx
// allocate new frame, adding room for callee-saved registers
subl 28(%esp),%ecx
subl $CALLEE_SAVED_REGISTER_FOOTPRINT,%ecx
movl 4(%esp),%ebx
// set return address
call LOCAL(getPC)
addl $_GLOBAL_OFFSET_TABLE_,%esi
movl vmInvoke_returnAddress@GOT(%esi),%esi
movl %esi,(%ecx)
// copy arguments into place
movl $0,%esi
movl 20(%esp),%edx
movl 24(%esp),%eax
jmp LOCAL(vmJumpAndInvoke_argumentTest)
LOCAL(vmJumpAndInvoke_argumentLoop):
movl (%eax,%esi,1),%edi
movl %edi,4(%ecx,%esi,1)
addl $4,%esi
LOCAL(vmJumpAndInvoke_argumentTest):
cmpl %edx,%esi
jb LOCAL(vmJumpAndInvoke_argumentLoop)
movl 8(%esp),%esi
// the arguments have been copied, so we can set the real stack
// pointer now
movl %ecx,%esp
jmp *%esi
#else // not AVIAN_CONTINUATIONS
// vmJumpAndInvoke should only be called when continuations are
// enabled
int3
#endif // AVIAN_CONTINUATIONS
#else
#error unsupported architecture
#endif //def __x86_64__

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -17,6 +17,11 @@
namespace vm {
class TraceHandler {
public:
virtual void handleTrace(Promise* address, unsigned argumentIndex) = 0;
};
class Compiler {
public:
class Client {
@ -28,9 +33,9 @@ class Compiler {
static const unsigned Aligned = 1 << 0;
static const unsigned NoReturn = 1 << 1;
static const unsigned TailJump = 1 << 2;
class Operand { };
class StackElement { };
class State { };
class Subroutine { };
@ -39,7 +44,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;
@ -52,16 +57,16 @@ class Compiler {
virtual Promise* poolAppend(intptr_t value) = 0;
virtual Promise* poolAppendPromise(Promise* value) = 0;
virtual Operand* constant(int64_t value) = 0;
virtual Operand* promiseConstant(Promise* value) = 0;
virtual Operand* constant(int64_t value, unsigned code) = 0;
virtual Operand* promiseConstant(Promise* value, unsigned code) = 0;
virtual Operand* address(Promise* address) = 0;
virtual Operand* memory(Operand* base,
unsigned code,
int displacement = 0,
Operand* index = 0,
unsigned scale = 1) = 0;
virtual Operand* stack() = 0;
virtual Operand* thread() = 0;
virtual Operand* register_(int number) = 0;
virtual void push(unsigned footprint) = 0;
virtual void push(unsigned footprint, Operand* value) = 0;
@ -69,15 +74,14 @@ class Compiler {
virtual Operand* pop(unsigned footprint) = 0;
virtual void pushed() = 0;
virtual void popped(unsigned footprint) = 0;
virtual StackElement* top() = 0;
virtual unsigned footprint(StackElement*) = 0;
virtual unsigned index(StackElement*) = 0;
virtual unsigned topOfStack() = 0;
virtual Operand* peek(unsigned footprint, unsigned index) = 0;
virtual Operand* call(Operand* address,
unsigned flags,
TraceHandler* traceHandler,
unsigned resultSize,
unsigned resultCode,
unsigned argumentCount,
...) = 0;
@ -85,11 +89,12 @@ class Compiler {
unsigned flags,
TraceHandler* traceHandler,
unsigned resultSize,
unsigned resultCode,
unsigned argumentFootprint) = 0;
virtual void return_(unsigned size, Operand* value) = 0;
virtual void initLocal(unsigned size, unsigned index) = 0;
virtual void initLocal(unsigned size, unsigned index, unsigned code) = 0;
virtual void initLocalsFromLogicalIp(unsigned logicalIp) = 0;
virtual void storeLocal(unsigned footprint, Operand* src,
unsigned index) = 0;
@ -114,8 +119,15 @@ class Compiler {
virtual void jge(Operand* address) = 0;
virtual void je(Operand* address) = 0;
virtual void jne(Operand* address) = 0;
virtual void juo(Operand* address) = 0;
virtual void fjl(Operand* address) = 0;
virtual void fjg(Operand* address) = 0;
virtual void fjle(Operand* address) = 0;
virtual void fjge(Operand* address) = 0;
virtual void fje(Operand* address) = 0;
virtual void fjne(Operand* address) = 0;
virtual void fjuo(Operand* address) = 0;
virtual void jmp(Operand* address) = 0;
virtual void exit(Operand* address) = 0;
virtual Operand* add(unsigned size, Operand* a, Operand* b) = 0;
virtual Operand* sub(unsigned size, Operand* a, Operand* b) = 0;
virtual Operand* mul(unsigned size, Operand* a, Operand* b) = 0;
@ -134,8 +146,8 @@ class Compiler {
virtual Operand* xor_(unsigned size, Operand* a, Operand* b) = 0;
virtual Operand* neg(unsigned size, Operand* a) = 0;
virtual Operand* fneg(unsigned size, Operand* a) = 0;
virtual Operand* operation(BinaryOperation op, unsigned aSize, unsigned resSize, Operand* a) = 0;
virtual Operand* operation(TernaryOperation op, unsigned aSize, unsigned bSize, unsigned resSize, Operand* a, Operand* b) = 0;
virtual Operand* operation(BinaryOperation op, unsigned aSize, unsigned resSize, unsigned resCode, Operand* a) = 0;
virtual Operand* operation(TernaryOperation op, unsigned aSize, unsigned bSize, unsigned resSize, unsigned resCode, Operand* a, Operand* b) = 0;
virtual Operand* f2f(unsigned aSize, unsigned resSize, Operand* a) = 0;
virtual Operand* f2i(unsigned aSize, unsigned resSize, Operand* a) = 0;
virtual Operand* i2f(unsigned aSize, unsigned resSize, Operand* a) = 0;

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

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

413
src/gnu.cpp Normal file
View File

@ -0,0 +1,413 @@
/* 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
#ifdef __i386__
setProperty(t, method, properties, "os.arch", "x86");
#elif defined __x86_64__
setProperty(t, method, properties, "os.arch", "x86_64");
#elif defined(__ppc__) || defined(__powerpc__) \
|| defined(__ppc64__) || defined(__powerpc64__)
setProperty(t, method, properties, "os.arch", "ppc");
#elif defined __ia64__
setProperty(t, method, properties, "os.arch", "ia64");
#elif defined __arm__
setProperty(t, method, properties, "os.arch", "arm");
#elif defined __alpha__
setProperty(t, method, properties, "os.arch", "alpha");
#elif defined __sparc64__
setProperty(t, method, properties, "os.arch", "sparc64");
#else
setProperty(t, method, properties, "os.arch", "unknown");
#endif
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_gnu_classpath_VMStackWalker_getClassContext
(Thread* t, object, uintptr_t*)
{
class Visitor: public Processor::StackVisitor {
public:
Visitor(Thread* t):
t(t), skipCount(1), trace(0), index(0), protector(t, &trace)
{ }
virtual bool visit(Processor::StackWalker* walker) {
if (skipCount == 0) {
if (trace == 0) {
trace = makeObjectArray
(t, arrayBody(t, t->m->types, Machine::ClassType),
walker->count());
}
assert(t, index < objectArrayLength(t, trace));
set(t, trace, ArrayBody + (index * BytesPerWord),
methodClass(t, walker->method()));
++ index;
return true;
} else {
-- skipCount;
return true;
}
}
Thread* t;
unsigned skipCount;
object trace;
unsigned index;
Thread::SingleProtector protector;
} v(t);
t->m->processor->walkStack(t, &v);
if (v.trace == 0) {
v.trace = makeObjectArray
(t, arrayBody(t, t->m->types, Machine::ClassType), 0);
}
return reinterpret_cast<int64_t>(v.trace);
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_gnu_classpath_VMStackWalker_getClassLoader
(Thread* t, object, uintptr_t* arguments)
{
return reinterpret_cast<int64_t>
(classLoader(t, reinterpret_cast<object>(arguments[0])));
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_java_lang_VMRuntime_mapLibraryName
(Thread* t, object, uintptr_t* arguments)
{
object name = reinterpret_cast<object>(arguments[0]);
PROTECT(t, name);
const unsigned soPrefixLength = sizeof(SO_PREFIX) - 1;
const unsigned nameLength = stringLength(t, name);
const unsigned soSuffixLength = sizeof(SO_SUFFIX) - 1;
const unsigned total = soPrefixLength + nameLength + soSuffixLength;
object s = makeByteArray(t, total + 1);
char* p = reinterpret_cast<char*>(&byteArrayBody(t, s, 0));
memcpy(p, SO_PREFIX, soPrefixLength);
stringChars(t, name, p + soPrefixLength);
memcpy(p + soPrefixLength + nameLength, SO_SUFFIX, soSuffixLength);
p[total] = 0;
return reinterpret_cast<int64_t>(makeString(t, s, 0, total, 0));
}
extern "C" JNIEXPORT void JNICALL
Avian_java_lang_System_arraycopy
(Thread*, object, uintptr_t*);
extern "C" JNIEXPORT void JNICALL
Avian_java_lang_VMSystem_arraycopy
(Thread* t, object, uintptr_t* arguments)
{
Avian_java_lang_System_arraycopy(t, 0, arguments);
}
extern "C" JNIEXPORT void JNICALL
Avian_java_lang_Runtime_load
(Thread* t, object, uintptr_t*);
extern "C" JNIEXPORT int64_t JNICALL
Avian_java_lang_VMRuntime_nativeLoad
(Thread* t, object, uintptr_t* arguments)
{
object name = reinterpret_cast<object>(arguments[0]);
// given that we set java.library.path to LIBRARY_PATH_SENTINAL, we
// can determine which names are filenames and which are library
// names by looking for the prefix LIBRARY_PATH_SENTINAL
// FILE_SEPARATOR
unsigned length = stringLength(t, name);
char n[length + 1];
stringChars(t, name, n);
const unsigned pathPrefixLength
= sizeof(LIBRARY_PATH_SENTINAL) - 1
+ sizeof(FILE_SEPARATOR) - 1;
bool mapName = (strncmp(n, LIBRARY_PATH_SENTINAL FILE_SEPARATOR,
pathPrefixLength) == 0);
if (mapName) {
// strip the path prefix, SO prefix, and SO suffix before passing
// the name to Runtime.load
const unsigned soPrefixLength = sizeof(SO_PREFIX) - 1;
const unsigned soSuffixLength = sizeof(SO_SUFFIX) - 1;
const unsigned newOffset
= stringOffset(t, name) + pathPrefixLength + soPrefixLength;
const unsigned newLength
= length - pathPrefixLength - soPrefixLength - soSuffixLength;
name = makeString(t, stringData(t, name), newOffset, newLength, 0);
}
uintptr_t args[] = { reinterpret_cast<uintptr_t>(name), mapName };
Avian_java_lang_Runtime_load(t, 0, args);
if (t->exception) {
t->exception = 0;
return 0;
} else {
return 1;
}
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_java_lang_Class_primitiveClass
(Thread* t, object, uintptr_t*);
extern "C" JNIEXPORT int64_t JNICALL
Avian_java_lang_VMClassLoader_getPrimitiveClass
(Thread* t, object, uintptr_t* arguments)
{
return Avian_java_lang_Class_primitiveClass(t, 0, arguments);
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_java_lang_System_identityHashCode
(Thread*, object, uintptr_t*);
extern "C" JNIEXPORT int64_t JNICALL
Avian_java_lang_VMSystem_identityHashCode
(Thread* t, object, uintptr_t* arguments)
{
return Avian_java_lang_System_identityHashCode(t, 0, arguments);
}
extern "C" JNIEXPORT void JNICALL
Avian_java_lang_Runtime_gc
(Thread*, object, uintptr_t*);
extern "C" JNIEXPORT void JNICALL
Avian_java_lang_VMRuntime_gc
(Thread* t, object, uintptr_t*)
{
Avian_java_lang_Runtime_gc(t, 0, 0);
}
extern "C" JNIEXPORT void JNICALL
Avian_java_lang_VMRuntime_runFinalizationForExit
(Thread*, object, uintptr_t*)
{
// ignore
}
extern "C" JNIEXPORT void JNICALL
Avian_java_lang_VMRuntime_exit
(Thread*, object, uintptr_t* arguments)
{
exit(arguments[0]);
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_avian_SystemClassLoader_findClass
(Thread*, object, uintptr_t*);
extern "C" JNIEXPORT int64_t JNICALL
Avian_java_lang_VMClassLoader_loadClass
(Thread* t, object, uintptr_t* arguments)
{
uintptr_t args[] = { 0, arguments[0] };
return Avian_avian_SystemClassLoader_findClass(t, 0, args);
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_avian_SystemClassLoader_findLoadedClass
(Thread*, object, uintptr_t*);
extern "C" JNIEXPORT int64_t JNICALL
Avian_java_lang_VMClassLoader_findLoadedClass
(Thread* t, object, uintptr_t* arguments)
{
uintptr_t args[] = { 0, arguments[1] };
return Avian_avian_SystemClassLoader_findLoadedClass(t, 0, args);
}

View File

@ -34,6 +34,12 @@ const bool Verbose2 = false;
const bool Debug = false;
const bool DebugFixies = false;
#ifdef NDEBUG
const bool DebugAllocation = false;
#else
const bool DebugAllocation = true;
#endif
#define ACQUIRE(x) MutexLock MAKE_NAME(monitorLock_) (x)
class MutexLock {
@ -422,7 +428,9 @@ class Segment {
}
void dispose() {
free(context, data, (footprint(capacity())) * BytesPerWord);
if (data) {
free(context, data, (footprint(capacity())) * BytesPerWord);
}
data = 0;
map = 0;
}
@ -1673,11 +1681,22 @@ void* tryAllocate(Context* c, unsigned size)
{
ACQUIRE(c->lock);
if (DebugAllocation) {
size = pad(size) + 2 * BytesPerWord;
}
if (size + c->count < c->limit) {
void* p = c->system->tryAllocate(size);
if (p) {
c->count += size;
return p;
if (DebugAllocation) {
static_cast<uintptr_t*>(p)[0] = 0x22377322;
static_cast<uintptr_t*>(p)[(size / BytesPerWord) - 1] = 0x22377322;
return static_cast<uintptr_t*>(p) + 1;
} else {
return p;
}
}
}
return 0;
@ -1686,7 +1705,21 @@ void* tryAllocate(Context* c, unsigned size)
void free(Context* c, const void* p, unsigned size) {
ACQUIRE(c->lock);
if (DebugAllocation) {
size = pad(size) + 2 * BytesPerWord;
memset(const_cast<void*>(p), 0xFE, size - (2 * BytesPerWord));
p = static_cast<const uintptr_t*>(p) - 1;
expect(c->system, static_cast<const uintptr_t*>(p)[0] == 0x22377322);
expect(c->system, static_cast<const uintptr_t*>(p)
[(size / BytesPerWord) - 1] == 0x22377322);
}
expect(c->system, c->count >= size);
c->system->free(p);
c->count -= size;
}

View File

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

View File

@ -26,6 +26,8 @@ const unsigned FrameMethodOffset = 2;
const unsigned FrameIpOffset = 3;
const unsigned FrameFootprint = 4;
class ClassInitList;
class Thread: public vm::Thread {
public:
static const unsigned StackSizeInBytes = 64 * 1024;
@ -36,16 +38,39 @@ class Thread: public vm::Thread {
ip(0),
sp(0),
frame(-1),
code(0)
code(0),
classInitList(0)
{ }
unsigned ip;
unsigned sp;
int frame;
object code;
ClassInitList* classInitList;
uintptr_t stack[StackSizeInWords];
};
class ClassInitList {
public:
ClassInitList(Thread* t, object class_, ClassInitList* next):
t(t), class_(class_), next(next)
{ }
static void push(Thread* t, object class_) {
t->classInitList = new (t->m->heap->allocate(sizeof(ClassInitList)))
ClassInitList(t, class_, t->classInitList);
}
void pop() {
t->classInitList = next;
t->m->heap->free(this, sizeof(ClassInitList));
}
Thread* t;
object class_;
ClassInitList* next;
};
inline void
pushObject(Thread* t, object o)
{
@ -142,7 +167,7 @@ popLong(Thread* t)
return (b << 32) | a;
}
inline float
inline double
popDouble(Thread* t)
{
return bitsToDouble(popLong(t));
@ -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);
@ -410,8 +437,7 @@ makeNativeMethodData(Thread* t, object method, void* function)
object data = makeNativeMethodData(t,
function,
0, // argument table size
count,
false);
count);
unsigned argumentTableSize = BytesPerWord * 2;
unsigned index = 0;
@ -460,7 +486,7 @@ makeNativeMethodData(Thread* t, object method, void* function)
return data;
}
inline object
inline void
resolveNativeMethodData(Thread* t, object method)
{
if (methodCode(t, method) == 0) {
@ -468,8 +494,13 @@ resolveNativeMethodData(Thread* t, object method)
if (LIKELY(p)) {
PROTECT(t, method);
object data = makeNativeMethodData(t, method, p);
// ensure other threads see updated methodVmFlags before
// methodCode, and that the native method data is initialized
// before it is visible to those threads:
memoryBarrier();
set(t, method, MethodCode, data);
return data;
} else {
object message = makeString
(t, "%s.%s%s",
@ -477,11 +508,8 @@ resolveNativeMethodData(Thread* t, object method)
&byteArrayBody(t, methodName(t, method), 0),
&byteArrayBody(t, methodSpec(t, method), 0));
t->exception = makeUnsatisfiedLinkError(t, message);
return 0;
}
} else {
return methodCode(t, method);
}
}
}
inline void
@ -498,35 +526,79 @@ checkStack(Thread* t, object method)
}
}
unsigned
invokeNative(Thread* t, object method)
void
pushResult(Thread* t, unsigned returnCode, uint64_t result, bool indirect)
{
PROTECT(t, method);
switch (returnCode) {
case ByteField:
case BooleanField:
if (DebugRun) {
fprintf(stderr, "result: %d\n", static_cast<int8_t>(result));
}
pushInt(t, static_cast<int8_t>(result));
break;
object data = resolveNativeMethodData(t, method);
if (UNLIKELY(t->exception)) {
return VoidField;
case CharField:
if (DebugRun) {
fprintf(stderr, "result: %d\n", static_cast<uint16_t>(result));
}
pushInt(t, static_cast<uint16_t>(result));
break;
case ShortField:
if (DebugRun) {
fprintf(stderr, "result: %d\n", static_cast<int16_t>(result));
}
pushInt(t, static_cast<int16_t>(result));
break;
case FloatField:
case IntField:
if (DebugRun) {
fprintf(stderr, "result: %d\n", static_cast<int32_t>(result));
}
pushInt(t, result);
break;
case LongField:
case DoubleField:
if (DebugRun) {
fprintf(stderr, "result: %"LLD"\n", result);
}
pushLong(t, result);
break;
case ObjectField:
if (indirect) {
if (DebugRun) {
fprintf(stderr, "result: %p at %p\n",
static_cast<uintptr_t>(result) == 0 ? 0 :
*reinterpret_cast<object*>(static_cast<uintptr_t>(result)),
reinterpret_cast<object*>(static_cast<uintptr_t>(result)));
}
pushObject(t, static_cast<uintptr_t>(result) == 0 ? 0 :
*reinterpret_cast<object*>(static_cast<uintptr_t>(result)));
} else {
if (DebugRun) {
fprintf(stderr, "result: %p\n", reinterpret_cast<object>(result));
}
pushObject(t, reinterpret_cast<object>(result));
}
break;
case VoidField:
break;
default:
abort(t);
}
}
PROTECT(t, data);
pushFrame(t, method);
unsigned count = nativeMethodDataLength(t, data) - 1;
unsigned size = nativeMethodDataArgumentTableSize(t, data);
uintptr_t args[size / BytesPerWord];
void
marshalArguments(Thread* t, uintptr_t* args, unsigned i, unsigned count,
object data, bool indirect)
{
unsigned offset = 0;
args[offset++] = reinterpret_cast<uintptr_t>(t);
unsigned i = 0;
if (methodFlags(t, method) & ACC_STATIC) {
++ i;
args[offset++] = reinterpret_cast<uintptr_t>
(pushReference(t, methodClass(t, method)));
}
unsigned sp = frameBase(t, t->frame);
for (; i < count; ++i) {
unsigned type = nativeMethodDataParameterTypes(t, data, i + 1);
@ -548,16 +620,48 @@ invokeNative(Thread* t, object method)
} break;
case POINTER_TYPE: {
object* v = reinterpret_cast<object*>(t->stack + ((sp++) * 2) + 1);
if (*v == 0) {
v = 0;
if (indirect) {
object* v = reinterpret_cast<object*>(t->stack + ((sp++) * 2) + 1);
if (*v == 0) {
v = 0;
}
args[offset++] = reinterpret_cast<uintptr_t>(v);
} else {
args[offset++] = reinterpret_cast<uintptr_t>(peekObject(t, sp++));
}
args[offset++] = reinterpret_cast<uintptr_t>(v);
} break;
default: abort(t);
}
}
}
unsigned
invokeNativeSlow(Thread* t, object method)
{
PROTECT(t, method);
object data = methodCode(t, method);
PROTECT(t, data);
pushFrame(t, method);
unsigned count = nativeMethodDataLength(t, data) - 1;
unsigned size = nativeMethodDataArgumentTableSize(t, data);
uintptr_t args[size / BytesPerWord];
unsigned offset = 0;
args[offset++] = reinterpret_cast<uintptr_t>(t);
unsigned i = 0;
if (methodFlags(t, method) & ACC_STATIC) {
++ i;
args[offset++] = reinterpret_cast<uintptr_t>
(pushReference(t, methodClass(t, method)));
}
marshalArguments(t, args + offset, i, count, data, true);
unsigned returnCode = methodReturnCode(t, method);
unsigned returnType = fieldType(t, returnCode);
@ -609,80 +713,67 @@ invokeNative(Thread* t, object method)
return VoidField;
}
switch (returnCode) {
case ByteField:
case BooleanField:
if (DebugRun) {
fprintf(stderr, "result: %d\n", static_cast<int8_t>(result));
}
pushInt(t, static_cast<int8_t>(result));
break;
case CharField:
if (DebugRun) {
fprintf(stderr, "result: %d\n", static_cast<uint16_t>(result));
}
pushInt(t, static_cast<uint16_t>(result));
break;
case ShortField:
if (DebugRun) {
fprintf(stderr, "result: %d\n", static_cast<int16_t>(result));
}
pushInt(t, static_cast<int16_t>(result));
break;
case FloatField:
case IntField:
if (DebugRun) {
fprintf(stderr, "result: %d\n", static_cast<int32_t>(result));
}
pushInt(t, result);
break;
case LongField:
case DoubleField:
if (DebugRun) {
fprintf(stderr, "result: %"LLD"\n", result);
}
pushLong(t, result);
break;
case ObjectField:
if (DebugRun) {
fprintf(stderr, "result: %p at %p\n",
static_cast<uintptr_t>(result) == 0 ? 0 :
*reinterpret_cast<object*>(static_cast<uintptr_t>(result)),
reinterpret_cast<object*>(static_cast<uintptr_t>(result)));
}
pushObject(t, static_cast<uintptr_t>(result) == 0 ? 0 :
*reinterpret_cast<object*>(static_cast<uintptr_t>(result)));
break;
case VoidField:
break;
default:
abort(t);
}
pushResult(t, returnCode, result, true);
return returnCode;
}
unsigned
invokeNative(Thread* t, object method)
{
PROTECT(t, method);
resolveNativeMethodData(t, method);
if (UNLIKELY(t->exception)) {
return VoidField;
}
if (methodVmFlags(t, method) & FastNative) {
pushFrame(t, method);
object data = methodCode(t, method);
uintptr_t arguments[methodParameterFootprint(t, method)];
marshalArguments
(t, arguments, (methodFlags(t, method) & ACC_STATIC) ? 1 : 0,
nativeMethodDataLength(t, data) - 1, data, false);
uint64_t result = reinterpret_cast<FastNativeFunction>
(nativeMethodDataFunction(t, methodCode(t, method)))
(t, method, arguments);
popFrame(t);
if (UNLIKELY(t->exception)) {
return VoidField;
}
pushResult(t, methodReturnCode(t, method), result, false);
return methodReturnCode(t, method);
} else {
return invokeNativeSlow(t, 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;
}
}
@ -911,7 +1002,7 @@ interpret(Thread* t)
object class_ = resolveClassInPool(t, codePool(t, code), index - 1);
if (UNLIKELY(exception)) goto throw_;
pushObject(t, makeObjectArray(t, class_, count, true));
pushObject(t, makeObjectArray(t, class_, count));
} else {
object message = makeString(t, "%d", count);
exception = makeNegativeArraySizeException(t, message);
@ -2352,7 +2443,7 @@ interpret(Thread* t)
}
}
object array = makeArray(t, counts[0], true);
object array = makeArray(t, counts[0]);
setObjectClass(t, array, class_);
PROTECT(t, array);
@ -2383,35 +2474,35 @@ interpret(Thread* t)
switch (type) {
case T_BOOLEAN:
array = makeBooleanArray(t, count, true);
array = makeBooleanArray(t, count);
break;
case T_CHAR:
array = makeCharArray(t, count, true);
array = makeCharArray(t, count);
break;
case T_FLOAT:
array = makeFloatArray(t, count, true);
array = makeFloatArray(t, count);
break;
case T_DOUBLE:
array = makeDoubleArray(t, count, true);
array = makeDoubleArray(t, count);
break;
case T_BYTE:
array = makeByteArray(t, count, true);
array = makeByteArray(t, count);
break;
case T_SHORT:
array = makeShortArray(t, count, true);
array = makeShortArray(t, count);
break;
case T_INT:
array = makeIntArray(t, count, true);
array = makeIntArray(t, count);
break;
case T_LONG:
array = makeLongArray(t, count, true);
array = makeLongArray(t, count);
break;
default: abort(t);
@ -3001,7 +3092,7 @@ class MyProcessor: public Processor {
return vm::makeClass
(t, flags, vmFlags, arrayDimensions, fixedSize, arrayElementSize,
objectMask, name, super, interfaceTable, virtualTable, fieldTable,
methodTable, staticTable, loader, 0, false);
methodTable, staticTable, loader, 0);
}
virtual void
@ -3010,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)
{
@ -3038,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
@ -3157,25 +3236,21 @@ class MyProcessor: public Processor {
return 0;
}
virtual void compileThunks(vm::Thread*, BootImage*, uint8_t*, unsigned*,
unsigned)
virtual void initialize(BootImage*, uint8_t*, unsigned) {
abort(s);
}
virtual void compileMethod(vm::Thread*, Zone*, object*, object*,
DelayedPromise**, object)
{
abort(s);
}
virtual void compileMethod(vm::Thread*, Zone*, uint8_t*, unsigned*, unsigned,
object*, object*, DelayedPromise**, object)
{
virtual void visitRoots(HeapWalker*) {
abort(s);
}
virtual void visitRoots(BootImage*, HeapWalker*) {
abort(s);
}
virtual unsigned* makeCallTable(vm::Thread*, BootImage*, HeapWalker*,
uint8_t*)
{
virtual unsigned* makeCallTable(vm::Thread*, HeapWalker*) {
abort(s);
}
@ -3183,6 +3258,29 @@ class MyProcessor: public Processor {
expect(s, image == 0);
}
virtual void callWithCurrentContinuation(vm::Thread*, object) {
abort(s);
}
virtual void dynamicWind(vm::Thread*, object, object, object) {
abort(s);
}
virtual void feedResultToContinuation(vm::Thread*, object, object){
abort(s);
}
virtual void feedExceptionToContinuation(vm::Thread*, object, object) {
abort(s);
}
virtual void walkContinuationBody(vm::Thread*, Heap::Walker*, object,
unsigned)
{
abort(s);
}
virtual void dispose(vm::Thread* t) {
t->m->heap->free(t, sizeof(Thread));
}

View File

@ -99,6 +99,14 @@ GetEnv(Machine* m, Thread** t, jint version)
}
}
jsize JNICALL
GetVersion(Thread* t)
{
ENTER(t, Thread::ActiveState);
return JNI_VERSION_1_6;
}
jsize JNICALL
GetStringLength(Thread* t, jstring s)
{
@ -258,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)
{
@ -817,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);
@ -843,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);
@ -998,7 +1016,7 @@ GetStaticObjectField(Thread* t, jclass c, jfieldID field)
{
ENTER(t, Thread::ActiveState);
return makeLocalReference(t, arrayBody(t, classStaticTable(t, *c), field));
return makeLocalReference(t, cast<object>(classStaticTable(t, *c), field));
}
jboolean JNICALL
@ -1006,8 +1024,7 @@ GetStaticBooleanField(Thread* t, jclass c, jfieldID field)
{
ENTER(t, Thread::ActiveState);
object v = arrayBody(t, classStaticTable(t, *c), field);
return v ? intValue(t, v) != 0 : false;
return cast<int8_t>(classStaticTable(t, *c), field);
}
jbyte JNICALL
@ -1015,8 +1032,7 @@ GetStaticByteField(Thread* t, jclass c, jfieldID field)
{
ENTER(t, Thread::ActiveState);
object v = arrayBody(t, classStaticTable(t, *c), field);
return static_cast<jbyte>(v ? intValue(t, v) : 0);
return cast<int8_t>(classStaticTable(t, *c), field);
}
jchar JNICALL
@ -1024,8 +1040,7 @@ GetStaticCharField(Thread* t, jclass c, jfieldID field)
{
ENTER(t, Thread::ActiveState);
object v = arrayBody(t, classStaticTable(t, *c), field);
return static_cast<jchar>(v ? intValue(t, v) : 0);
return cast<uint16_t>(classStaticTable(t, *c), field);
}
jshort JNICALL
@ -1033,8 +1048,7 @@ GetStaticShortField(Thread* t, jclass c, jfieldID field)
{
ENTER(t, Thread::ActiveState);
object v = arrayBody(t, classStaticTable(t, *c), field);
return static_cast<jshort>(v ? intValue(t, v) : 0);
return cast<int16_t>(classStaticTable(t, *c), field);
}
jint JNICALL
@ -1042,8 +1056,7 @@ GetStaticIntField(Thread* t, jclass c, jfieldID field)
{
ENTER(t, Thread::ActiveState);
object v = arrayBody(t, classStaticTable(t, *c), field);
return v ? intValue(t, v) : 0;
return cast<int32_t>(classStaticTable(t, *c), field);
}
jlong JNICALL
@ -1051,8 +1064,7 @@ GetStaticLongField(Thread* t, jclass c, jfieldID field)
{
ENTER(t, Thread::ActiveState);
object v = arrayBody(t, classStaticTable(t, *c), field);
return static_cast<jlong>(v ? longValue(t, v) : 0);
return cast<int64_t>(classStaticTable(t, *c), field);
}
jfloat JNICALL
@ -1060,10 +1072,7 @@ GetStaticFloatField(Thread* t, jclass c, jfieldID field)
{
ENTER(t, Thread::ActiveState);
object v = arrayBody(t, classStaticTable(t, *c), field);
jint i = v ? intValue(t, v) : 0;
jfloat f; memcpy(&f, &i, 4);
return f;
return cast<float>(classStaticTable(t, *c), field);
}
jdouble JNICALL
@ -1071,10 +1080,7 @@ GetStaticDoubleField(Thread* t, jclass c, jfieldID field)
{
ENTER(t, Thread::ActiveState);
object v = arrayBody(t, classStaticTable(t, *c), field);
jlong i = v ? longValue(t, v) : 0;
jdouble f; memcpy(&f, &i, 4);
return f;
return cast<double>(classStaticTable(t, *c), field);
}
void JNICALL
@ -1082,17 +1088,15 @@ SetStaticObjectField(Thread* t, jclass c, jfieldID field, jobject v)
{
ENTER(t, Thread::ActiveState);
set(t, classStaticTable(t, *c), ArrayBody + (field * BytesPerWord),
(v ? *v : 0));
set(t, classStaticTable(t, *c), field, (v ? *v : 0));
}
void JNICALL
SetStaticBooleanField(Thread* t, jclass c, jfieldID field, jboolean v)
{
ENTER(t, Thread::ActiveState);
object o = makeInt(t, v ? 1 : 0);
set(t, classStaticTable(t, *c), ArrayBody + (field * BytesPerWord), o);
cast<int8_t>(classStaticTable(t, *c), field) = v;
}
void JNICALL
@ -1100,8 +1104,7 @@ SetStaticByteField(Thread* t, jclass c, jfieldID field, jbyte v)
{
ENTER(t, Thread::ActiveState);
object o = makeInt(t, v);
set(t, classStaticTable(t, *c), ArrayBody + (field * BytesPerWord), o);
cast<int8_t>(classStaticTable(t, *c), field) = v;
}
void JNICALL
@ -1109,8 +1112,7 @@ SetStaticCharField(Thread* t, jclass c, jfieldID field, jchar v)
{
ENTER(t, Thread::ActiveState);
object o = makeInt(t, v);
set(t, classStaticTable(t, *c), ArrayBody + (field * BytesPerWord), o);
cast<uint16_t>(classStaticTable(t, *c), field) = v;
}
void JNICALL
@ -1118,8 +1120,7 @@ SetStaticShortField(Thread* t, jclass c, jfieldID field, jshort v)
{
ENTER(t, Thread::ActiveState);
object o = makeInt(t, v);
set(t, classStaticTable(t, *c), ArrayBody + (field * BytesPerWord), o);
cast<int16_t>(classStaticTable(t, *c), field) = v;
}
void JNICALL
@ -1127,8 +1128,7 @@ SetStaticIntField(Thread* t, jclass c, jfieldID field, jint v)
{
ENTER(t, Thread::ActiveState);
object o = makeInt(t, v);
set(t, classStaticTable(t, *c), ArrayBody + (field * BytesPerWord), o);
cast<int32_t>(classStaticTable(t, *c), field) = v;
}
void JNICALL
@ -1136,8 +1136,7 @@ SetStaticLongField(Thread* t, jclass c, jfieldID field, jlong v)
{
ENTER(t, Thread::ActiveState);
object o = makeLong(t, v);
set(t, classStaticTable(t, *c), ArrayBody + (field * BytesPerWord), o);
cast<int64_t>(classStaticTable(t, *c), field) = v;
}
void JNICALL
@ -1145,9 +1144,7 @@ SetStaticFloatField(Thread* t, jclass c, jfieldID field, jfloat v)
{
ENTER(t, Thread::ActiveState);
jint i; memcpy(&i, &v, 4);
object o = makeInt(t, i);
set(t, classStaticTable(t, *c), ArrayBody + (field * BytesPerWord), o);
cast<float>(classStaticTable(t, *c), field) = v;
}
void JNICALL
@ -1155,9 +1152,7 @@ SetStaticDoubleField(Thread* t, jclass c, jfieldID field, jdouble v)
{
ENTER(t, Thread::ActiveState);
jlong i; memcpy(&i, &v, 8);
object o = makeLong(t, i);
set(t, classStaticTable(t, *c), ArrayBody + (field * BytesPerWord), o);
cast<double>(classStaticTable(t, *c), field) = v;
}
jobject JNICALL
@ -1883,6 +1878,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)
{
@ -1895,6 +1901,7 @@ populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable)
memset(envTable, 0, sizeof(JNIEnvVTable));
envTable->GetVersion = ::GetVersion;
envTable->GetStringLength = ::GetStringLength;
envTable->GetStringChars = ::GetStringChars;
envTable->ReleaseStringChars = ::ReleaseStringChars;
@ -1907,6 +1914,9 @@ populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable)
envTable->FindClass = ::FindClass;
envTable->ThrowNew = ::ThrowNew;
envTable->ExceptionCheck = ::ExceptionCheck;
envTable->NewDirectByteBuffer = ::NewDirectByteBuffer;
envTable->GetDirectBufferAddress = ::GetDirectBufferAddress;
envTable->GetDirectBufferCapacity = ::GetDirectBufferCapacity;
envTable->DeleteLocalRef = ::DeleteLocalRef;
envTable->GetObjectClass = ::GetObjectClass;
envTable->IsInstanceOf = ::IsInstanceOf;

View File

@ -196,7 +196,7 @@ visitRoots(Thread* t, Heap::Visitor* v)
}
}
void
bool
walk(Thread*, Heap::Walker* w, uint32_t* mask, unsigned fixedSize,
unsigned arrayElementSize, unsigned arrayLength, unsigned start)
{
@ -207,7 +207,7 @@ walk(Thread*, Heap::Walker* w, uint32_t* mask, unsigned fixedSize,
for (unsigned i = start; i < fixedSizeInWords; ++i) {
if (mask[i / 32] & (static_cast<uint32_t>(1) << (i % 32))) {
if (not w->visit(i)) {
return;
return false;
}
}
}
@ -240,12 +240,31 @@ walk(Thread*, Heap::Walker* w, uint32_t* mask, unsigned fixedSize,
if (not w->visit
(fixedSizeInWords + (i * arrayElementSizeInWords) + j))
{
return;
return false;
}
}
}
}
}
return true;
}
object
findInInterfaces(Thread* t, object class_, object name, object spec,
object (*find)(Thread*, object, object, object))
{
object result = 0;
if (classInterfaceTable(t, class_)) {
for (unsigned i = 0;
i < arrayLength(t, classInterfaceTable(t, class_)) and result == 0;
i += 2)
{
result = find
(t, arrayBody(t, classInterfaceTable(t, class_), i), name, spec);
}
}
return result;
}
void
@ -479,6 +498,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)
{
@ -495,21 +541,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;
@ -517,9 +573,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 {
@ -539,6 +641,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)
{
@ -561,6 +685,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;
@ -581,7 +710,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);
}
@ -628,8 +758,13 @@ object
parsePool(Thread* t, Stream& s)
{
unsigned count = s.read2() - 1;
object pool = makeSingletonOfSize(t, count);
unsigned old;
unsigned floatMaskSize = 0;
do {
old = floatMaskSize;
floatMaskSize = singletonMaskSize(count + floatMaskSize);
} while (floatMaskSize != old);
object pool = makeSingletonOfSize(t, count + floatMaskSize);
PROTECT(t, pool);
if (count) {
@ -641,12 +776,18 @@ parsePool(Thread* t, Stream& s)
switch (s.read1()) {
case CONSTANT_Class:
case CONSTANT_String:
assert(t, !singletonIsFloat(t, pool, i));
singletonMarkObject(t, pool, i);
s.skip(2);
break;
case CONSTANT_Integer:
assert(t, !singletonIsFloat(t, pool, i));
s.skip(4);
break;
case CONSTANT_Float:
singletonMarkBit(t, pool, count, i);
assert(t, singletonIsFloat(t, pool, i));
s.skip(4);
break;
@ -654,17 +795,27 @@ parsePool(Thread* t, Stream& s)
case CONSTANT_Fieldref:
case CONSTANT_Methodref:
case CONSTANT_InterfaceMethodref:
assert(t, !singletonIsFloat(t, pool, i));
singletonMarkObject(t, pool, i);
s.skip(4);
break;
case CONSTANT_Long:
assert(t, !singletonIsFloat(t, pool, i));
s.skip(8);
++ i;
break;
case CONSTANT_Double:
singletonMarkBit(t, pool, count, i);
singletonMarkBit(t, pool, count, i + 1);
assert(t, singletonIsFloat(t, pool, i));
assert(t, singletonIsFloat(t, pool, i + 1));
s.skip(8);
++ i;
break;
case CONSTANT_Utf8:
assert(t, !singletonIsFloat(t, pool, i));
singletonMarkObject(t, pool, i);
s.skip(s.read2());
break;
@ -728,6 +879,8 @@ parseInterfaceTable(Thread* t, Stream& s, object class_, object pool)
PROTECT(t, name);
object interface = resolveClass(t, name);
if (UNLIKELY(t->exception)) return;
PROTECT(t, interface);
hashMapInsertMaybe(t, map, name, interface, byteArrayHash, byteArrayEqual);
@ -1161,6 +1314,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;
@ -1313,14 +1477,9 @@ updateBootstrapClass(Thread* t, object bootstrapClass, object class_)
expect(t, classSuper(t, bootstrapClass) == classSuper(t, class_));
expect(t, bootstrapClass == arrayBody(t, t->m->types, Machine::ClassType)
or classFixedSize(t, bootstrapClass) == classFixedSize(t, class_));
or classFixedSize(t, bootstrapClass) >= classFixedSize(t, class_));
expect(t,
(classVmFlags(t, bootstrapClass) & ReferenceFlag)
or (classObjectMask(t, bootstrapClass) == 0
and classObjectMask(t, class_) == 0)
or intArrayEqual(t, classObjectMask(t, bootstrapClass),
classObjectMask(t, class_)));
expect(t, (classVmFlags(t, class_) & HasFinalizerFlag) == 0);
PROTECT(t, bootstrapClass);
PROTECT(t, class_);
@ -1329,7 +1488,7 @@ updateBootstrapClass(Thread* t, object bootstrapClass, object class_)
classVmFlags(t, bootstrapClass) &= ~BootstrapFlag;
classVmFlags(t, bootstrapClass) |= classVmFlags(t, class_);
classFlags(t, bootstrapClass) = classFlags(t, class_);
classFlags(t, bootstrapClass) |= classFlags(t, class_);
set(t, bootstrapClass, ClassSuper, classSuper(t, class_));
set(t, bootstrapClass, ClassInterfaceTable, classInterfaceTable(t, class_));
@ -1518,7 +1677,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;
@ -1544,9 +1703,12 @@ boot(Thread* t)
m->unsafe = false;
classVmFlags(t, arrayBody(t, m->types, Machine::SingletonType))
classFlags(t, arrayBody(t, m->types, Machine::SingletonType))
|= SingletonFlag;
classFlags(t, arrayBody(t, m->types, Machine::ContinuationType))
|= ContinuationFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JreferenceType))
|= ReferenceFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::WeakReferenceType))
@ -1709,6 +1871,7 @@ Machine::Machine(System* system, Heap* heap, Finder* finder,
bootstrapClassMap(0),
monitorMap(0),
stringMap(0),
byteArrayMap(0),
types(0),
jniMethodTable(0),
finalizers(0),
@ -1717,6 +1880,7 @@ Machine::Machine(System* system, Heap* heap, Finder* finder,
weakReferences(0),
tenuredWeakReferences(0),
unsafe(false),
triedBuiltinOnLoad(false),
heapPoolIndex(0)
{
heap->setClient(heapClient);
@ -1779,6 +1943,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))),
@ -1829,6 +1994,7 @@ Thread::init()
boot(this);
}
m->byteArrayMap = makeWeakHashMap(this, 0, 0);
m->monitorMap = makeWeakHashMap(this, 0, 0);
m->jniMethodTable = makeVector(this, 0, 0);
@ -1842,8 +2008,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);
}
}
@ -2057,44 +2227,53 @@ allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type,
// another thread wants to enter the exclusive state, either for a
// collection or some other reason. We give it a chance here.
ENTER(t, Thread::IdleState);
while (t->m->exclusive) {
t->m->stateLock->wait(t->systemThread, 0);
}
}
switch (type) {
case Machine::MovableAllocation:
if (t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
> ThreadHeapSizeInWords)
{
t->heap = 0;
if (t->m->heapPoolIndex < ThreadHeapPoolSize) {
t->heap = static_cast<uintptr_t*>
(t->m->heap->tryAllocate(ThreadHeapSizeInBytes));
do {
switch (type) {
case Machine::MovableAllocation:
if (t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
> ThreadHeapSizeInWords)
{
t->heap = 0;
if (t->m->heapPoolIndex < ThreadHeapPoolSize) {
t->heap = static_cast<uintptr_t*>
(t->m->heap->tryAllocate(ThreadHeapSizeInBytes));
if (t->heap) {
memset(t->heap, 0, ThreadHeapSizeInBytes);
if (t->heap) {
memset(t->heap, 0, ThreadHeapSizeInBytes);
t->m->heapPool[t->m->heapPoolIndex++] = t->heap;
t->heapOffset += t->heapIndex;
t->heapIndex = 0;
t->m->heapPool[t->m->heapPoolIndex++] = t->heap;
t->heapOffset += t->heapIndex;
t->heapIndex = 0;
}
}
}
break;
case Machine::FixedAllocation:
if (t->m->fixedFootprint + sizeInBytes > FixedFootprintThresholdInBytes)
{
t->heap = 0;
}
break;
case Machine::ImmortalAllocation:
break;
}
break;
case Machine::FixedAllocation:
if (t->m->fixedFootprint + sizeInBytes > FixedFootprintThresholdInBytes) {
t->heap = 0;
if (t->heap == 0) {
// fprintf(stderr, "gc");
// vmPrintTrace(t);
collect(t, Heap::MinorCollection);
}
break;
case Machine::ImmortalAllocation:
break;
}
if (t->heap == 0) {
// fprintf(stderr, "gc");
// vmPrintTrace(t);
collect(t, Heap::MinorCollection);
}
} while (type == Machine::MovableAllocation
and t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
> ThreadHeapSizeInWords);
switch (type) {
case Machine::MovableAllocation: {
@ -2133,6 +2312,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, ...)
{
@ -2399,7 +2600,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);
@ -2432,6 +2634,8 @@ parseClass(Thread* t, const uint8_t* data, unsigned size)
classLoader(t, class_),
vtableLength);
PROTECT(t, real);
t->m->processor->initVtable(t, real);
updateClassTables(t, real, class_);
@ -2510,24 +2714,58 @@ 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 = findInInterfaces(t, class_, name, spec, findFieldInClass);
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
@ -2556,6 +2794,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)
{
@ -2606,7 +2930,6 @@ findInHierarchy(Thread* t, object class_, object name, object spec,
object (*makeError)(Thread*, object))
{
object originalClass = class_;
PROTECT(t, class_);
object o = 0;
if ((classFlags(t, class_) & ACC_INTERFACE)
@ -2617,9 +2940,17 @@ findInHierarchy(Thread* t, object class_, object name, object spec,
}
if (o == 0) {
if (find == findFieldInClass) {
o = findInInterfaces(t, originalClass, name, spec, find);
}
for (; o == 0 and class_; class_ = classSuper(t, class_)) {
o = find(t, class_, name, spec);
}
if (o == 0 and find == findMethodInClass) {
o = findInInterfaces(t, originalClass, name, spec, find);
}
}
if (o == 0) {
@ -2760,13 +3091,6 @@ collect(Thread* t, Heap::CollectionType type)
postCollect(m->rootThread);
for (object f = m->finalizeQueue; f; f = finalizerNext(t, f)) {
void (*function)(Thread*, object);
memcpy(&function, &finalizerFinalize(t, f), BytesPerWord);
function(t, finalizerTarget(t, f));
}
m->finalizeQueue = 0;
killZombies(t, m->rootThread);
for (unsigned i = 0; i < m->heapPoolIndex; ++i) {
@ -2779,6 +3103,14 @@ collect(Thread* t, Heap::CollectionType type)
#ifdef VM_STRESS
if (not stress) t->stress = false;
#endif
object f = m->finalizeQueue;
m->finalizeQueue = 0;
for (; f; f = finalizerNext(t, f)) {
void (*function)(Thread*, object);
memcpy(&function, &finalizerFinalize(t, f), BytesPerWord);
function(t, finalizerTarget(t, f));
}
}
void
@ -2788,6 +3120,8 @@ walk(Thread* t, Heap::Walker* w, object o, unsigned start)
object objectMask = static_cast<object>
(t->m->heap->follow(classObjectMask(t, class_)));
bool more = true;
if (objectMask) {
unsigned fixedSize = classFixedSize(t, class_);
unsigned arrayElementSize = classArrayElementSize(t, class_);
@ -2799,17 +3133,21 @@ walk(Thread* t, Heap::Walker* w, object o, unsigned start)
memcpy(mask, &intArrayBody(t, objectMask, 0),
intArrayLength(t, objectMask) * 4);
::walk(t, w, mask, fixedSize, arrayElementSize, arrayLength, start);
} else if (classVmFlags(t, class_) & SingletonFlag) {
more = ::walk(t, w, mask, fixedSize, arrayElementSize, arrayLength, start);
} else if (classFlags(t, class_) & SingletonFlag) {
unsigned length = singletonLength(t, o);
if (length) {
::walk(t, w, singletonMask(t, o),
(singletonCount(t, o) + 2) * BytesPerWord, 0, 0, start);
more = ::walk(t, w, singletonMask(t, o),
(singletonCount(t, o) + 2) * BytesPerWord, 0, 0, start);
} else if (start == 0) {
w->visit(0);
more = w->visit(0);
}
} else if (start == 0) {
w->visit(0);
more = w->visit(0);
}
if (more and classFlags(t, class_) & ContinuationFlag) {
t->m->processor->walkContinuationBody(t, w, o, start);
}
}
@ -2840,16 +3178,17 @@ 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));
for (Reference* r = m->jniReferences; r; r = r->next) {
v->visit(&(r->target));
}
for (Thread* t = m->rootThread; t; t = t->peer) {
::visitRoots(t, v);
}
for (Reference* r = m->jniReferences; r; r = r->next) {
v->visit(&(r->target));
}
}
void
@ -2956,11 +3295,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);
}
}

View File

@ -74,20 +74,31 @@ enum StackTag {
const int NativeLine = -1;
const int UnknownLine = -2;
// class flags:
// 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;
// class vmFlags:
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 SingletonFlag = 1 << 5;
const unsigned InitErrorFlag = 1 << 4;
const unsigned PrimitiveFlag = 1 << 5;
const unsigned BootstrapFlag = 1 << 6;
const unsigned HasFinalMemberFlag = 1 << 7;
const unsigned HasFinalizerFlag = 1 << 7;
// method flags:
// method vmFlags:
const unsigned ClassInitFlag = 1 << 0;
const unsigned CompiledFlag = 1 << 1;
const unsigned ConstructorFlag = 1 << 2;
const unsigned FastNative = 1 << 3;
#ifndef JNI_VERSION_1_6
#define JNI_VERSION_1_6 0x00010006
#endif
typedef Machine JavaVM;
typedef Thread JNIEnv;
@ -1181,6 +1192,7 @@ class Machine {
object bootstrapClassMap;
object monitorMap;
object stringMap;
object byteArrayMap;
object types;
object jniMethodTable;
object finalizers;
@ -1189,6 +1201,7 @@ class Machine {
object weakReferences;
object tenuredWeakReferences;
bool unsafe;
bool triedBuiltinOnLoad;
JavaVMVTable javaVMVTable;
JNIEnvVTable jniEnvVTable;
uintptr_t* heapPool[ThreadHeapPoolSize];
@ -1256,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) { }
@ -1308,6 +1340,7 @@ class Thread {
unsigned heapIndex;
unsigned heapOffset;
Protector* protector;
ClassInitStack* classInitStack;
Runnable runnable;
uintptr_t* defaultHeap;
uintptr_t* heap;
@ -1320,6 +1353,8 @@ class Thread {
#endif // VM_STRESS
};
typedef uint64_t (JNICALL *FastNativeFunction)(Thread*, object, uintptr_t*);
inline object
objectClass(Thread*, object o)
{
@ -1454,17 +1489,17 @@ expect(Thread* t, bool v)
class FixedAllocator: public Allocator {
public:
FixedAllocator(Thread* t, uint8_t* base, unsigned capacity):
t(t), base(base), offset(0), capacity(capacity)
FixedAllocator(System* s, uint8_t* base, unsigned capacity):
s(s), base(base), offset(0), capacity(capacity)
{ }
virtual void* tryAllocate(unsigned) {
abort(t);
abort(s);
}
virtual void* allocate(unsigned size) {
unsigned paddedSize = pad(size);
expect(t, offset + paddedSize < capacity);
expect(s, offset + paddedSize < capacity);
void* p = base + offset;
offset += paddedSize;
@ -1472,10 +1507,10 @@ class FixedAllocator: public Allocator {
}
virtual void free(const void*, unsigned) {
abort(t);
abort(s);
}
Thread* t;
System* s;
uint8_t* base;
unsigned offset;
unsigned capacity;
@ -1508,6 +1543,9 @@ allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type,
inline object
allocateSmall(Thread* t, unsigned sizeInBytes)
{
assert(t, t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
<= ThreadHeapSizeInWords);
object o = reinterpret_cast<object>(t->heap + t->heapIndex);
t->heapIndex += ceiling(sizeInBytes, BytesPerWord);
cast<object>(o, 0) = 0;
@ -1696,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
@ -1719,6 +1757,12 @@ makeInterruptedException(Thread* t)
return makeInterruptedException(t, 0, makeTrace(t), 0);
}
inline object
makeIncompatibleContinuationException(Thread* t)
{
return makeIncompatibleContinuationException(t, 0, makeTrace(t), 0);
}
inline object
makeStackOverflowError(Thread* t)
{
@ -1741,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)
{
@ -1754,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
@ -1770,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_);
}
@ -1913,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);
}
}
@ -1936,15 +1977,6 @@ stringEqual(Thread* t, object a, object b)
}
}
inline bool
intArrayEqual(Thread* t, object a, object b)
{
return a == b or
((intArrayLength(t, a) == intArrayLength(t, b)) and
memcmp(&intArrayBody(t, a, 0), &intArrayBody(t, b, 0),
intArrayLength(t, a) * 4) == 0);
}
inline uint32_t
methodHash(Thread* t, object method)
{
@ -2040,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);
@ -2095,13 +2166,6 @@ findInHierarchy(Thread* t, object class_, object name, object spec,
object (*find)(Thread*, object, object, object),
object (*makeError)(Thread*, object));
inline object
findField(Thread* t, object class_, object name, object spec)
{
return findInHierarchy
(t, class_, name, spec, findFieldInClass, makeNoSuchFieldError);
}
inline object
findMethod(Thread* t, object class_, object name, object spec)
{
@ -2369,6 +2433,26 @@ makeSingletonOfSize(Thread* t, unsigned count)
return o;
}
inline void
singletonMarkBit(Thread* t, object singleton, unsigned start, unsigned index)
{
uintptr_t& val = singletonValue(t, singleton, start + (index / BitsPerWord));
val |= static_cast<uintptr_t>(1) << (index % BitsPerWord);
}
inline bool
singletonGetBit(Thread* t, object singleton, unsigned start, unsigned index)
{
uintptr_t& val = singletonValue(t, singleton, start + (index / BitsPerWord));
return (val & static_cast<uintptr_t>(1) << (index % BitsPerWord)) != 0;
}
inline bool
singletonIsFloat(Thread* t, object singleton, unsigned index)
{
return singletonGetBit(t, singleton, singletonLength(t, singleton) - 2 * singletonMaskSize(t, singleton), index);
}
void
dumpHeap(Thread* t, FILE* out);

View File

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

View File

@ -63,8 +63,6 @@ const unsigned VisitSignalIndex = 0;
const unsigned SegFaultSignalIndex = 1;
const unsigned InterruptSignalIndex = 2;
const unsigned ExecutableAreaSizeInBytes = 16 * 1024 * 1024;
class MySystem;
MySystem* system;
@ -126,9 +124,7 @@ class MySystem: public System {
r->setInterrupted(true);
if (flags & Waiting) {
pthread_kill(thread, InterruptSignal);
}
pthread_kill(thread, InterruptSignal);
}
virtual void join() {
@ -518,9 +514,7 @@ class MySystem: public System {
MySystem():
threadVisitor(0),
visitTarget(0),
executableArea(0),
executableOffset(0)
visitTarget(0)
{
expect(this, system == 0);
system = this;
@ -559,33 +553,23 @@ class MySystem: public System {
}
virtual void* tryAllocateExecutable(unsigned sizeInBytes) {
if (executableArea == 0) {
#ifdef __x86_64__
const unsigned Extra = MAP_32BIT;
const unsigned Extra = MAP_32BIT;
#else
const unsigned Extra = 0;
const unsigned Extra = 0;
#endif
void* p = mmap(0, ExecutableAreaSizeInBytes, PROT_EXEC | PROT_READ
| PROT_WRITE, MAP_PRIVATE | MAP_ANON | Extra, -1, 0);
void* p = mmap(0, sizeInBytes, PROT_EXEC | PROT_READ
| PROT_WRITE, MAP_PRIVATE | MAP_ANON | Extra, -1, 0);
if (p != MAP_FAILED) {
executableArea = static_cast<uint8_t*>(p);
}
}
if (executableArea
and executableOffset + pad(sizeInBytes) < ExecutableAreaSizeInBytes)
{
void* r = executableArea + executableOffset;
executableOffset += pad(sizeInBytes);
return r;
} else {
if (p == MAP_FAILED) {
return 0;
} else {
return static_cast<uint8_t*>(p);
}
}
virtual void freeExecutable(const void*, unsigned) {
// ignore
virtual void freeExecutable(const void* p, unsigned sizeInBytes) {
munmap(const_cast<void*>(p), sizeInBytes);
}
virtual bool success(Status s) {
@ -642,13 +626,16 @@ class MySystem: public System {
visitTarget = target;
int rv = pthread_kill(target->thread, VisitSignal);
expect(this, rv == 0);
while (visitTarget) visitLock->wait(t, 0);
if (rv == 0) {
while (visitTarget) visitLock->wait(t, 0);
threadVisitor = 0;
threadVisitor = 0;
return 0;
return 0;
} else {
return -1;
}
}
virtual uint64_t call(void* function, uintptr_t* arguments, uint8_t* types,
@ -780,11 +767,6 @@ class MySystem: public System {
registerHandler(0, VisitSignalIndex);
system = 0;
if (executableArea) {
int r UNUSED = munmap(executableArea, ExecutableAreaSizeInBytes);
assert(this, r == 0);
}
::free(this);
}
@ -850,7 +832,7 @@ handleSignal(int signal, siginfo_t* info, void* context)
sigaddset(&set, SegFaultSignal);
sigprocmask(SIG_UNBLOCK, &set, 0);
vmJump(ip, base, stack, thread);
vmJump(ip, base, stack, thread, 0, 0);
}
} break;
@ -868,6 +850,7 @@ handleSignal(int signal, siginfo_t* info, void* context)
} else {
switch (signal) {
case VisitSignal:
case InterruptSignal:
break;
default:

View File

@ -161,4 +161,6 @@ vmJump:
mtlr r3
mr r1,r5
mr r13,r6
mr r4,r7
mr r3,r8
blr

View File

@ -65,6 +65,7 @@ inline int sth(int rs, int ra, int i) { return D(44, rs, ra, i); }
inline int sthx(int rs, int ra, int rb) { return X(31, rs, ra, rb, 407, 0); }
inline int stw(int rs, int ra, int i) { return D(36, rs, ra, i); }
inline int stwu(int rs, int ra, int i) { return D(37, rs, ra, i); }
inline int stwux(int rs, int ra, int rb) { return X(31, rs, ra, rb, 183, 0); }
inline int stwx(int rs, int ra, int rb) { return X(31, rs, ra, rb, 151, 0); }
inline int add(int rt, int ra, int rb) { return XO(31, rt, ra, rb, 0, 266, 0); }
inline int addc(int rt, int ra, int rb) { return XO(31, rt, ra, rb, 0, 10, 0); }
@ -136,7 +137,7 @@ inline int blt(int i) { return bc(12, 0, i, 0); }
inline int bgt(int i) { return bc(12, 1, i, 0); }
inline int bge(int i) { return bc(4, 0, i, 0); }
inline int ble(int i) { return bc(4, 1, i, 0); }
inline int be(int i) { return bc(12, 2, i, 0); }
inline int beq(int i) { return bc(12, 2, i, 0); }
inline int bne(int i) { return bc(4, 2, i, 0); }
inline int cmpw(int ra, int rb) { return cmp(0, ra, rb); }
inline int cmplw(int ra, int rb) { return cmpl(0, ra, rb); }
@ -158,6 +159,9 @@ carry16(intptr_t v)
const unsigned FrameFooterSize = 6;
const unsigned StackAlignmentInBytes = 16;
const unsigned StackAlignmentInWords = StackAlignmentInBytes / BytesPerWord;
const int StackRegister = 1;
const int ThreadRegister = 13;
@ -905,9 +909,15 @@ moveAndUpdateRM(Context* c, unsigned srcSize UNUSED, Assembler::Register* src,
{
assert(c, srcSize == BytesPerWord);
assert(c, dstSize == BytesPerWord);
assert(c, dst->index == NoRegister);
issue(c, stwu(src->low, dst->base, dst->offset));
if (dst->index == NoRegister) {
issue(c, stwu(src->low, dst->base, dst->offset));
} else {
assert(c, dst->offset == 0);
assert(c, dst->scale == 1);
issue(c, stwux(src->low, dst->base, dst->index));
}
}
void
@ -1498,7 +1508,7 @@ jumpIfEqualC(Context* c, unsigned size UNUSED, Assembler::Constant* target)
assert(c, size == BytesPerWord);
appendOffsetTask(c, target->value, offset(c), true);
issue(c, be(0));
issue(c, beq(0));
}
void
@ -1588,6 +1598,9 @@ populateTables(ArchitectureContext* c)
uo[index(Jump, R)] = CAST1(jumpR);
uo[index(Jump, C)] = CAST1(jumpC);
uo[index(AlignedJump, R)] = CAST1(jumpR);
uo[index(AlignedJump, C)] = CAST1(jumpC);
uo[index(JumpIfEqual, C)] = CAST1(jumpIfEqualC);
uo[index(JumpIfNotEqual, C)] = CAST1(jumpIfNotEqualC);
uo[index(JumpIfGreater, C)] = CAST1(jumpIfGreaterC);
@ -1679,6 +1692,14 @@ class MyArchitecture: public Assembler::Architecture {
return (BytesPerWord == 4 ? 3 : NoRegister);
}
virtual int virtualCallTarget() {
return 4;
}
virtual int virtualCallIndex() {
return 3;
}
virtual bool bigEndian() {
return true;
}
@ -1695,8 +1716,12 @@ class MyArchitecture: public Assembler::Architecture {
}
}
virtual unsigned frameFootprint(unsigned footprint) {
return max(footprint, StackAlignmentInWords);
}
virtual unsigned argumentFootprint(unsigned footprint) {
return footprint;
return max(pad(footprint, StackAlignmentInWords), StackAlignmentInWords);
}
virtual unsigned argumentRegisterCount() {
@ -1708,6 +1733,30 @@ class MyArchitecture: public Assembler::Architecture {
return index + 3;
}
virtual uint64_t generalRegisters() {
return (static_cast<uint64_t>(1) << 32) - 1;
}
virtual uint64_t floatRegisters() {
return 0;
}
virtual uint64_t allRegisters() {
return generalRegisters() | floatRegisters();
}
virtual unsigned stackAlignmentInWords() {
return StackAlignmentInWords;
}
virtual bool matchCall(void* returnAddress, void* target) {
uint32_t* instruction = static_cast<uint32_t*>(returnAddress) - 1;
return *instruction == static_cast<uint32_t>
(bl(static_cast<uint8_t*>(target)
- reinterpret_cast<uint8_t*>(instruction)));
}
virtual void updateCall(UnaryOperation op UNUSED,
bool assertAlignment UNUSED, void* returnAddress,
@ -1730,6 +1779,10 @@ class MyArchitecture: public Assembler::Architecture {
}
}
virtual unsigned constantCallSize() {
return 4;
}
virtual uintptr_t getConstant(const void* src) {
const int32_t* p = static_cast<const int32_t*>(src);
return (p[0] << 16) | (p[1] & 0xFFFF);
@ -1740,7 +1793,7 @@ class MyArchitecture: public Assembler::Architecture {
}
virtual unsigned alignFrameSize(unsigned sizeInWords) {
const unsigned alignment = 16 / BytesPerWord;
const unsigned alignment = StackAlignmentInBytes / BytesPerWord;
return (ceiling(sizeInWords + FrameFooterSize, alignment) * alignment);
}
@ -1760,6 +1813,14 @@ class MyArchitecture: public Assembler::Architecture {
return FrameFooterSize;
}
virtual int returnAddressOffset() {
return 8 / BytesPerWord;
}
virtual int framePointerOffset() {
return 0;
}
virtual void nextFrame(void** stack, void**) {
assert(&c, *static_cast<void**>(*stack) != *stack);
@ -1778,6 +1839,14 @@ class MyArchitecture: public Assembler::Architecture {
return false;
}
virtual bool alwaysCondensed(BinaryOperation op) {
return false;
}
virtual bool alwaysCondensed(TernaryOperation op) {
return false;
}
virtual void plan
(UnaryOperation,
unsigned, uint8_t* aTypeMask, uint64_t* aRegisterMask,
@ -1898,8 +1967,8 @@ class MyArchitecture: public Assembler::Architecture {
unsigned, const uint8_t* bTypeMask, const uint64_t* bRegisterMask,
unsigned, uint8_t* cTypeMask, uint64_t* cRegisterMask)
{
*cTypeMask = *bTypeMask;
*cRegisterMask = *bRegisterMask;
*cTypeMask = (1 << RegisterOperand);
*cRegisterMask = ~static_cast<uint64_t>(0);
}
virtual void acquire() {
@ -1990,18 +2059,110 @@ class MyAssembler: public Assembler {
moveAndUpdateRM(&c, BytesPerWord, &stack, BytesPerWord, &stackDst);
}
virtual void adjustFrame(unsigned footprint) {
Register nextStack(0);
Memory stackSrc(StackRegister, 0);
moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &nextStack);
Memory stackDst(StackRegister, -footprint * BytesPerWord);
moveAndUpdateRM(&c, BytesPerWord, &nextStack, BytesPerWord, &stackDst);
}
virtual void popFrame() {
Register stack(StackRegister);
Memory stackSrc(StackRegister, 0);
moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &stack);
Assembler::Register returnAddress(0);
Assembler::Memory returnAddressSrc(StackRegister, 8);
Register returnAddress(0);
Memory returnAddressSrc(StackRegister, 8);
moveMR(&c, BytesPerWord, &returnAddressSrc, BytesPerWord, &returnAddress);
issue(&c, mtlr(returnAddress.low));
}
virtual void popFrameForTailCall(unsigned footprint,
int offset,
int returnAddressSurrogate,
int framePointerSurrogate)
{
if (TailCalls) {
if (offset) {
Register tmp(0);
Memory returnAddressSrc(StackRegister, 8 + (footprint * BytesPerWord));
moveMR(&c, BytesPerWord, &returnAddressSrc, BytesPerWord, &tmp);
issue(&c, mtlr(tmp.low));
Memory stackSrc(StackRegister, footprint * BytesPerWord);
moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &tmp);
Memory stackDst(StackRegister, (footprint - offset) * BytesPerWord);
moveAndUpdateRM(&c, BytesPerWord, &tmp, BytesPerWord, &stackDst);
if (returnAddressSurrogate != NoRegister) {
assert(&c, offset > 0);
Register ras(returnAddressSurrogate);
Memory dst(StackRegister, 8 + (offset * BytesPerWord));
moveRM(&c, BytesPerWord, &ras, BytesPerWord, &dst);
}
if (framePointerSurrogate != NoRegister) {
assert(&c, offset > 0);
Register fps(framePointerSurrogate);
Memory dst(StackRegister, offset * BytesPerWord);
moveRM(&c, BytesPerWord, &fps, BytesPerWord, &dst);
}
} else {
popFrame();
}
} else {
abort(&c);
}
}
virtual void popFrameAndPopArgumentsAndReturn(unsigned argumentFootprint) {
popFrame();
assert(&c, argumentFootprint >= StackAlignmentInWords);
assert(&c, (argumentFootprint % StackAlignmentInWords) == 0);
if (TailCalls and argumentFootprint > StackAlignmentInWords) {
Register tmp(0);
Memory stackSrc(StackRegister, 0);
moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &tmp);
Memory stackDst(StackRegister,
(argumentFootprint - StackAlignmentInWords)
* BytesPerWord);
moveAndUpdateRM(&c, BytesPerWord, &tmp, BytesPerWord, &stackDst);
}
return_(&c);
}
virtual void popFrameAndUpdateStackAndReturn(unsigned stackOffsetFromThread)
{
popFrame();
Register tmp1(0);
Memory stackSrc(StackRegister, 0);
moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &tmp1);
Register tmp2(5);
Memory newStackSrc(ThreadRegister, stackOffsetFromThread);
moveMR(&c, BytesPerWord, &newStackSrc, BytesPerWord, &tmp2);
Register stack(StackRegister);
subR(&c, BytesPerWord, &stack, &tmp2, &tmp2);
Memory stackDst(StackRegister, 0, tmp2.low);
moveAndUpdateRM(&c, BytesPerWord, &tmp1, BytesPerWord, &stackDst);
return_(&c);
}
virtual void apply(Operation op) {
arch_->c.operations[op](&c);
}

View File

@ -67,7 +67,7 @@ mangle(int8_t c, char* dst)
unsigned
jniNameLength(Thread* t, object method, bool decorate)
{
unsigned size = 5;
unsigned size = 0;
object className = ::className(t, methodClass(t, method));
for (unsigned i = 0; i < byteArrayLength(t, className) - 1; ++i) {
@ -96,10 +96,11 @@ jniNameLength(Thread* t, object method, bool decorate)
}
void
makeJNIName(Thread* t, char* name, object method, bool decorate)
makeJNIName(Thread* t, const char* prefix, unsigned prefixLength, char* name,
object method, bool decorate)
{
memcpy(name, "Java_", 5);
name += 5;
memcpy(name, prefix, prefixLength);
name += prefixLength;
object className = ::className(t, methodClass(t, method));
for (unsigned i = 0; i < byteArrayLength(t, className) - 1; ++i) {
@ -146,31 +147,30 @@ resolveNativeMethod(Thread* t, const char* undecorated, const char* decorated)
return 0;
}
} // namespace
namespace vm {
void*
resolveNativeMethod2(Thread* t, object method)
resolveNativeMethod(Thread* t, object method, const char* prefix,
unsigned prefixLength, int footprint UNUSED)
{
unsigned undecoratedSize = jniNameLength(t, method, false);
unsigned undecoratedSize = prefixLength + jniNameLength(t, method, false);
char undecorated[undecoratedSize + 1 + 6]; // extra 6 is for code below
makeJNIName(t, undecorated + 1, method, false);
makeJNIName(t, prefix, prefixLength, undecorated + 1, method, false);
unsigned decoratedSize = jniNameLength(t, method, true);
unsigned decoratedSize = prefixLength + jniNameLength(t, method, true);
char decorated[decoratedSize + 1 + 6]; // extra 6 is for code below
makeJNIName(t, decorated + 1, method, true);
makeJNIName(t, prefix, prefixLength, decorated + 1, method, true);
void* p = ::resolveNativeMethod(t, undecorated + 1, decorated + 1);
void* p = resolveNativeMethod(t, undecorated + 1, decorated + 1);
if (p) {
return p;
}
#ifdef __MINGW32__
// on windows, we also try the _%s@%d and %s@%d variants
unsigned footprint = methodParameterFootprint(t, method) + 1;
if (methodFlags(t, method) & ACC_STATIC) {
++ footprint;
if (footprint == -1) {
footprint = methodParameterFootprint(t, method) + 1;
if (methodFlags(t, method) & ACC_STATIC) {
++ footprint;
}
}
*undecorated = '_';
@ -181,13 +181,13 @@ resolveNativeMethod2(Thread* t, object method)
snprintf(decorated + decoratedSize + 1, 5, "@%d",
footprint * BytesPerWord);
p = ::resolveNativeMethod(t, undecorated, decorated);
p = resolveNativeMethod(t, undecorated, decorated);
if (p) {
return p;
}
// one more try without the leading underscore
p = ::resolveNativeMethod(t, undecorated + 1, decorated + 1);
p = resolveNativeMethod(t, undecorated + 1, decorated + 1);
if (p) {
return p;
}
@ -196,6 +196,27 @@ resolveNativeMethod2(Thread* t, object method)
return 0;
}
} // namespace
namespace vm {
void*
resolveNativeMethod(Thread* t, object method)
{
void* p = ::resolveNativeMethod(t, method, "Java_", 5, -1);
if (p) {
return p;
}
p = ::resolveNativeMethod(t, method, "Avian_", 6, 3);
if (p) {
methodVmFlags(t, method) |= FastNative;
return p;
}
return 0;
}
int
findLineNumber(Thread* t, object method, unsigned ip)
{

View File

@ -126,17 +126,7 @@ isSpecialMethod(Thread* t, object method, object class_)
}
void*
resolveNativeMethod2(Thread* t, object method);
inline void*
resolveNativeMethod(Thread* t, object method)
{
if (methodCode(t, method)) {
return pointerValue(t, methodCode(t, method));
} else {
return resolveNativeMethod2(t, method);
}
}
resolveNativeMethod(Thread* t, object method);
inline object
findInterfaceMethod(Thread* t, object method, object class_)

View File

@ -78,9 +78,6 @@ class Processor {
virtual void
initVtable(Thread* t, object c) = 0;
virtual void
initClass(Thread* t, object c) = 0;
virtual void
visitObjects(Thread* t, Heap::Visitor* v) = 0;
@ -117,23 +114,38 @@ class Processor {
getStackTrace(Thread* t, Thread* target) = 0;
virtual void
compileThunks(Thread* t, BootImage* image, uint8_t* code, unsigned* size,
unsigned capacity) = 0;
initialize(BootImage* image, uint8_t* code, unsigned capacity) = 0;
virtual void
compileMethod(Thread* t, Zone* zone, uint8_t* code, unsigned* offset,
unsigned capacity, object* constants, object* calls,
compileMethod(Thread* t, Zone* zone, object* constants, object* calls,
DelayedPromise** addresses, object method) = 0;
virtual void
visitRoots(BootImage* image, HeapWalker* w) = 0;
visitRoots(HeapWalker* w) = 0;
virtual unsigned*
makeCallTable(Thread* t, BootImage* image, HeapWalker* w, uint8_t* code) = 0;
makeCallTable(Thread* t, HeapWalker* w) = 0;
virtual void
boot(Thread* t, BootImage* image) = 0;
virtual void
callWithCurrentContinuation(Thread* t, object receiver) = 0;
virtual void
dynamicWind(Thread* t, object before, object thunk, object after) = 0;
virtual void
feedResultToContinuation(Thread* t, object continuation, object result) = 0;
virtual void
feedExceptionToContinuation(Thread* t, object continuation,
object exception) = 0;
virtual void
walkContinuationBody(Thread* t, Heap::Walker* w, object o, unsigned start)
= 0;
object
invoke(Thread* t, object method, object this_, ...)
{

View File

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

View File

@ -1323,12 +1323,6 @@ parseJavaClass(Object* type, Stream* s, Object* declarations)
}
}
if (equal(typeJavaName(type), "java/lang/Class")) {
// add inline vtable
addMember(type, Array::make
(type, 0, "void*", "vtable", sizeOf("void*", 0)));
}
if (typeSuper(type)) {
for (Object* p = typeMethods(typeSuper(type)); p; p = cdr(p)) {
addMethod(type, car(p));
@ -1372,23 +1366,25 @@ parseType(Object::ObjectType type, Object* p, Object* declarations,
Type* t = Type::make(type, name, javaName);
if (javaName and *javaName != '[') {
assert(cdr(p) == 0);
bool isJavaType = javaName and *javaName != '[';
if (isJavaType) {
const char* file = append(javaClassDirectory, "/", javaName, ".class");
Stream s(fopen(file, "rb"), true);
parseJavaClass(t, &s, declarations);
} else {
for (p = cdr(p); p; p = cdr(p)) {
if (type == Object::Type) {
parseSubdeclaration(t, car(p), declarations);
} else {
Object* member = parseMember(t, car(p), declarations);
assert(member->type == Object::Scalar);
addMember(t, member);
}
}
}
for (p = cdr(p); p; p = cdr(p)) {
if (type == Object::Type) {
parseSubdeclaration(t, car(p), declarations);
} else {
Object* member = parseMember(t, car(p), declarations);
assert(member->type == Object::Scalar);
addMember(t, member);
}
}
if (not isJavaType) {
if (type == Object::Type and typeSuper(t)) {
for (Object* p = typeMethods(typeSuper(t)); p; p = cdr(p)) {
addMethod(t, car(p));

Some files were not shown because too many files have changed in this diff Show More