mirror of
https://github.com/corda/corda.git
synced 2025-01-03 19:54:13 +00:00
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:
commit
1d3ef1fc43
16
classpath/avian/Callback.java
Normal file
16
classpath/avian/Callback.java
Normal 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);
|
||||
}
|
15
classpath/avian/CallbackReceiver.java
Normal file
15
classpath/avian/CallbackReceiver.java
Normal file
@ -0,0 +1,15 @@
|
||||
/* Copyright (c) 2009, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
package avian;
|
||||
|
||||
public interface CallbackReceiver<T> {
|
||||
public T receive(Callback<T> callback) throws Exception;
|
||||
}
|
@ -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;
|
238
classpath/avian/Continuations.java
Normal file
238
classpath/avian/Continuations.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
21
classpath/avian/IncompatibleContinuationException.java
Normal file
21
classpath/avian/IncompatibleContinuationException.java
Normal file
@ -0,0 +1,21 @@
|
||||
/* Copyright (c) 2009, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
package avian;
|
||||
|
||||
public class IncompatibleContinuationException extends Exception {
|
||||
public IncompatibleContinuationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public IncompatibleContinuationException() {
|
||||
super();
|
||||
}
|
||||
}
|
17
classpath/avian/Machine.java
Normal file
17
classpath/avian/Machine.java
Normal file
@ -0,0 +1,17 @@
|
||||
/* Copyright (c) 2009, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
package avian;
|
||||
|
||||
public abstract class Machine {
|
||||
|
||||
public static native void dumpHeap(String outputFile);
|
||||
|
||||
}
|
@ -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);
|
@ -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;
|
101
classpath/avian/resource/Handler.java
Normal file
101
classpath/avian/resource/Handler.java
Normal file
@ -0,0 +1,101 @@
|
||||
/* Copyright (c) 2008-2009, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
package avian.resource;
|
||||
|
||||
import java.net.URL;
|
||||
import java.net.URLStreamHandler;
|
||||
import java.net.URLConnection;
|
||||
import java.io.IOException;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class Handler extends URLStreamHandler {
|
||||
protected URLConnection openConnection(URL url) {
|
||||
return new ResourceConnection(url);
|
||||
}
|
||||
|
||||
private static class ResourceConnection extends URLConnection {
|
||||
public ResourceConnection(URL url) {
|
||||
super(url);
|
||||
}
|
||||
|
||||
public int getContentLength() {
|
||||
return ResourceInputStream.getContentLength(url.getFile());
|
||||
}
|
||||
|
||||
public InputStream getInputStream() throws IOException {
|
||||
return new ResourceInputStream(url.getFile());
|
||||
}
|
||||
}
|
||||
|
||||
private static class ResourceInputStream extends InputStream {
|
||||
private long peer;
|
||||
private int position;
|
||||
|
||||
public ResourceInputStream(String path) throws IOException {
|
||||
peer = open(path);
|
||||
if (peer == 0) {
|
||||
throw new FileNotFoundException(path);
|
||||
}
|
||||
}
|
||||
|
||||
private static native int getContentLength(String path);
|
||||
|
||||
private static native long open(String path) throws IOException;
|
||||
|
||||
private static native int read(long peer, int position) throws IOException;
|
||||
|
||||
private static native int read(long peer, int position,
|
||||
byte[] b, int offset, int length)
|
||||
throws IOException;
|
||||
|
||||
public static native void close(long peer) throws IOException;
|
||||
|
||||
public int read() throws IOException {
|
||||
if (peer != 0) {
|
||||
int c = read(peer, position);
|
||||
if (c >= 0) {
|
||||
++ position;
|
||||
}
|
||||
return c;
|
||||
} else {
|
||||
throw new IOException();
|
||||
}
|
||||
}
|
||||
|
||||
public int read(byte[] b, int offset, int length) throws IOException {
|
||||
if (peer != 0) {
|
||||
if (b == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
if (offset < 0 || offset + length > b.length) {
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
|
||||
int c = read(peer, position, b, offset, length);
|
||||
if (c >= 0) {
|
||||
position += c;
|
||||
}
|
||||
return c;
|
||||
} else {
|
||||
throw new IOException();
|
||||
}
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
if (peer != 0) {
|
||||
close(peer);
|
||||
peer = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
22
classpath/java/lang/Appendable.java
Normal file
22
classpath/java/lang/Appendable.java
Normal file
@ -0,0 +1,22 @@
|
||||
/* Copyright (c) 2009, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
package java.lang;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface Appendable {
|
||||
public Appendable append(char c) throws IOException;
|
||||
|
||||
public Appendable append(CharSequence sequence) throws IOException;
|
||||
|
||||
public Appendable append(CharSequence sequence, int start, int end)
|
||||
throws IOException;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2008, Avian Contributors
|
||||
/* Copyright (c) 2008-2009, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
@ -10,7 +10,7 @@
|
||||
|
||||
package java.lang;
|
||||
|
||||
public class ArrayIndexOutOfBoundsException extends RuntimeException {
|
||||
public class ArrayIndexOutOfBoundsException extends IndexOutOfBoundsException {
|
||||
public ArrayIndexOutOfBoundsException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
@ -187,4 +187,40 @@ public final class Character implements Comparable<Character> {
|
||||
return isHighSurrogate(high) && isLowSurrogate(low);
|
||||
}
|
||||
|
||||
public static int codePointAt(CharSequence sequence, int offset) {
|
||||
int length = sequence.length();
|
||||
if (offset < 0 || offset >= length) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
|
||||
char high = sequence.charAt(offset);
|
||||
if (! isHighSurrogate(high) || offset >= length) {
|
||||
return high;
|
||||
}
|
||||
char low = sequence.charAt(offset + 1);
|
||||
if (! isLowSurrogate(low)) {
|
||||
return high;
|
||||
}
|
||||
|
||||
return toCodePoint(high, low);
|
||||
}
|
||||
|
||||
public static int codePointCount(CharSequence sequence, int start, int end) {
|
||||
int length = sequence.length();
|
||||
if (start < 0 || start > end || end >= length) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
for (int i = start; i < end; ++i) {
|
||||
if (isHighSurrogate(sequence.charAt(i))
|
||||
&& (i + 1) < end
|
||||
&& isLowSurrogate(sequence.charAt(i + 1)))
|
||||
{
|
||||
++ i;
|
||||
}
|
||||
++ count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
@ -14,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();
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2008, Avian Contributors
|
||||
/* Copyright (c) 2008-2009, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
@ -11,8 +11,11 @@
|
||||
package java.lang;
|
||||
|
||||
public class ClassNotFoundException extends Exception {
|
||||
private final Throwable cause2;
|
||||
|
||||
public ClassNotFoundException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
cause2 = cause;
|
||||
}
|
||||
|
||||
public ClassNotFoundException(String message) {
|
||||
|
@ -53,4 +53,12 @@ public abstract class Enum<E extends Enum<E>> implements Comparable<E> {
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Class<E> getDeclaringClass() {
|
||||
Class c = getClass();
|
||||
while (c.getSuperclass() != Enum.class) {
|
||||
c = c.getSuperclass();
|
||||
}
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2008, Avian Contributors
|
||||
/* Copyright (c) 2008-2009, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
@ -11,11 +11,14 @@
|
||||
package java.lang;
|
||||
|
||||
public class ExceptionInInitializerError extends Error {
|
||||
private final Throwable cause2;
|
||||
|
||||
public ExceptionInInitializerError(String message) {
|
||||
super(message);
|
||||
cause2 = null;
|
||||
}
|
||||
|
||||
public ExceptionInInitializerError() {
|
||||
super();
|
||||
this(null);
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2008, Avian Contributors
|
||||
/* Copyright (c) 2008-2009, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
@ -10,9 +10,9 @@
|
||||
|
||||
package java.lang;
|
||||
|
||||
public class StackOverflowError extends Error {
|
||||
public class StackOverflowError extends VirtualMachineError {
|
||||
public StackOverflowError(String message) {
|
||||
super(message, null);
|
||||
super(message);
|
||||
}
|
||||
|
||||
public StackOverflowError() {
|
||||
|
@ -18,8 +18,8 @@ public class StackTraceElement {
|
||||
private String file;
|
||||
private int line;
|
||||
|
||||
private StackTraceElement(String class_, String method, String file,
|
||||
int line)
|
||||
public StackTraceElement(String class_, String method, String file,
|
||||
int line)
|
||||
{
|
||||
this.class_ = class_;
|
||||
this.method = method;
|
||||
@ -56,7 +56,7 @@ public class StackTraceElement {
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
return class_;
|
||||
return class_.replace('/', '.');
|
||||
}
|
||||
|
||||
public String getMethodName() {
|
||||
|
@ -12,14 +12,30 @@ package java.lang;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.Comparator;
|
||||
import java.util.Locale;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.Serializable;
|
||||
|
||||
public final class String
|
||||
implements Comparable<String>, CharSequence, Serializable
|
||||
{
|
||||
public static Comparator<String> CASE_INSENSITIVE_ORDER
|
||||
= new Comparator<String>() {
|
||||
public int compare(String a, String b) {
|
||||
return a.compareToIgnoreCase(b);
|
||||
}
|
||||
};
|
||||
|
||||
public final class String implements Comparable<String>, CharSequence {
|
||||
private final Object data;
|
||||
private final int offset;
|
||||
private final int length;
|
||||
private int hashCode;
|
||||
|
||||
public String() {
|
||||
this(new char[0], 0, 0);
|
||||
}
|
||||
|
||||
public String(char[] data, int offset, int length, boolean copy) {
|
||||
this((Object) data, offset, length, copy);
|
||||
}
|
||||
@ -32,9 +48,11 @@ public final class String implements Comparable<String>, CharSequence {
|
||||
this(data, 0, data.length);
|
||||
}
|
||||
|
||||
public String(byte bytes[], int offset, int length, String charsetName) throws UnsupportedEncodingException {
|
||||
public String(byte bytes[], int offset, int length, String charsetName)
|
||||
throws UnsupportedEncodingException
|
||||
{
|
||||
this(bytes, offset, length);
|
||||
if (!charsetName.equals("UTF-8")) {
|
||||
if (! charsetName.equalsIgnoreCase("UTF-8")) {
|
||||
throw new UnsupportedEncodingException(charsetName);
|
||||
}
|
||||
}
|
||||
@ -57,12 +75,29 @@ public final class String implements Comparable<String>, CharSequence {
|
||||
|
||||
public String(byte[] data, String charset)
|
||||
throws UnsupportedEncodingException
|
||||
{
|
||||
this(data);
|
||||
if (! charset.equals("UTF-8")) {
|
||||
throw new UnsupportedEncodingException(charset);
|
||||
}
|
||||
{
|
||||
this(data);
|
||||
if (! charset.equals("UTF-8")) {
|
||||
throw new UnsupportedEncodingException(charset);
|
||||
}
|
||||
}
|
||||
|
||||
public String(byte bytes[], int highByte, int offset, int length) {
|
||||
if (offset < 0 || offset + length > bytes.length) {
|
||||
throw new IndexOutOfBoundsException
|
||||
(offset + " < 0 or " + offset + " + " + length + " > " + bytes.length);
|
||||
}
|
||||
|
||||
char[] c = new char[length];
|
||||
int mask = highByte << 8;
|
||||
for (int i = 0; i < length; ++i) {
|
||||
c[i] = (char) ((bytes[offset + i] & 0xFF) | mask);
|
||||
}
|
||||
|
||||
this.data = c;
|
||||
this.offset = 0;
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
private String(Object data, int offset, int length, boolean copy) {
|
||||
int l;
|
||||
@ -200,7 +235,7 @@ public final class String implements Comparable<String>, CharSequence {
|
||||
}
|
||||
|
||||
public boolean equalsIgnoreCase(String s) {
|
||||
return this == s || compareToIgnoreCase(s) == 0;
|
||||
return this == s || (s != null && compareToIgnoreCase(s) == 0);
|
||||
}
|
||||
|
||||
public int compareTo(String s) {
|
||||
@ -381,7 +416,7 @@ public final class String implements Comparable<String>, CharSequence {
|
||||
}
|
||||
} else {
|
||||
throw new IndexOutOfBoundsException
|
||||
(start + " not in (0, " + end + ") or " + end + " > " + length);
|
||||
(start + " not in [0, " + end + ") or " + end + " > " + length);
|
||||
}
|
||||
}
|
||||
|
||||
@ -534,6 +569,10 @@ public final class String implements Comparable<String>, CharSequence {
|
||||
return Pattern.matches(regex, this);
|
||||
}
|
||||
|
||||
public String replaceAll(String regex, String replacement) {
|
||||
return Pattern.compile(regex).matcher(this).replaceAll(replacement);
|
||||
}
|
||||
|
||||
public native String intern();
|
||||
|
||||
public static String valueOf(Object s) {
|
||||
@ -557,7 +596,9 @@ public final class String implements Comparable<String>, CharSequence {
|
||||
}
|
||||
|
||||
public static String valueOf(int v) {
|
||||
return Integer.toString(v);
|
||||
// use Integer.toString(int, int), because GNU Classpath's
|
||||
// Integer.toString(int) just calls String.valueOf(int):
|
||||
return Integer.toString(v, 10);
|
||||
}
|
||||
|
||||
public static String valueOf(long v) {
|
||||
@ -572,6 +613,14 @@ public final class String implements Comparable<String>, CharSequence {
|
||||
return Double.toString(v);
|
||||
}
|
||||
|
||||
public static String valueOf(char[] data, int offset, int length) {
|
||||
return new String(data, offset, length);
|
||||
}
|
||||
|
||||
public static String valueOf(char[] data) {
|
||||
return valueOf(data, 0, data.length);
|
||||
}
|
||||
|
||||
public int lastIndexOf(int ch, int lastIndex) {
|
||||
for (int i = lastIndex ; i >= 0; --i) {
|
||||
if (charAt(i) == ch) {
|
||||
@ -581,4 +630,63 @@ public final class String implements Comparable<String>, CharSequence {
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public boolean regionMatches(int thisOffset, String match, int matchOffset,
|
||||
int length)
|
||||
{
|
||||
return regionMatches(false, thisOffset, match, matchOffset, length);
|
||||
}
|
||||
|
||||
public boolean regionMatches(boolean ignoreCase, int thisOffset,
|
||||
String match, int matchOffset, int length)
|
||||
{
|
||||
String a = substring(thisOffset, thisOffset + length);
|
||||
String b = match.substring(matchOffset, matchOffset + length);
|
||||
if (ignoreCase) {
|
||||
return a.equalsIgnoreCase(b);
|
||||
} else {
|
||||
return a.equals(b);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return length == 0;
|
||||
}
|
||||
|
||||
public boolean contains(String match) {
|
||||
return indexOf(match) != -1;
|
||||
}
|
||||
|
||||
public int codePointAt(int offset) {
|
||||
return Character.codePointAt(this, offset);
|
||||
}
|
||||
|
||||
public int codePointCount(int start, int end) {
|
||||
return Character.codePointCount(this, start, end);
|
||||
}
|
||||
|
||||
public String replace(CharSequence match, CharSequence replacement) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public String toUpperCase(Locale locale) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public String toLowerCase(Locale locale) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
// for GNU Classpath compatibility:
|
||||
static char[] zeroBasedStringValue(String s) {
|
||||
if (s.offset == 0) {
|
||||
if (s.data instanceof char[]) {
|
||||
char[] data = (char[]) s.data;
|
||||
if (data.length == s.length) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
||||
return s.toCharArray();
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
package java.lang;
|
||||
|
||||
public class StringBuilder implements CharSequence {
|
||||
public class StringBuilder implements CharSequence, Appendable {
|
||||
private static final int BufferSize = 32;
|
||||
|
||||
private Cell chain;
|
||||
@ -54,6 +54,14 @@ public class StringBuilder implements CharSequence {
|
||||
}
|
||||
}
|
||||
|
||||
public StringBuilder append(CharSequence sequence) {
|
||||
return append(sequence.toString());
|
||||
}
|
||||
|
||||
public Appendable append(CharSequence sequence, int start, int end) {
|
||||
return append(sequence.subSequence(start, end));
|
||||
}
|
||||
|
||||
public StringBuilder append(char[] b, int offset, int length) {
|
||||
return append(new String(b, offset, length));
|
||||
}
|
||||
@ -150,6 +158,10 @@ public class StringBuilder implements CharSequence {
|
||||
return this;
|
||||
}
|
||||
|
||||
public StringBuilder insert(int i, CharSequence s) {
|
||||
return insert(i, s.toString());
|
||||
}
|
||||
|
||||
public StringBuilder insert(int i, char c) {
|
||||
return insert(i, new String(new char[] { c }, 0, 1, false));
|
||||
}
|
||||
@ -332,4 +344,8 @@ public class StringBuilder implements CharSequence {
|
||||
deleteCharAt(index);
|
||||
insert(index, ch);
|
||||
}
|
||||
|
||||
public void ensureCapacity(int capacity) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2008, Avian Contributors
|
||||
/* Copyright (c) 2008-2009, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
@ -15,14 +15,30 @@ import java.util.WeakHashMap;
|
||||
|
||||
public class Thread implements Runnable {
|
||||
private long peer;
|
||||
private boolean interrupted;
|
||||
private boolean daemon;
|
||||
private byte state;
|
||||
private byte priority;
|
||||
private final Runnable task;
|
||||
private Map<ThreadLocal, Object> locals;
|
||||
private boolean interrupted;
|
||||
private Object sleepLock;
|
||||
private ClassLoader classLoader;
|
||||
private String name;
|
||||
private UncaughtExceptionHandler exceptionHandler;
|
||||
|
||||
public Thread(Runnable task, String name) {
|
||||
// package private for GNU Classpath, which inexplicably bypasses
|
||||
// the accessor methods:
|
||||
String name;
|
||||
ThreadGroup group;
|
||||
|
||||
private static UncaughtExceptionHandler defaultExceptionHandler;
|
||||
|
||||
public static final int MIN_PRIORITY = 1;
|
||||
public static final int NORM_PRIORITY = 5;
|
||||
public static final int MAX_PRIORITY = 10;
|
||||
|
||||
public Thread(ThreadGroup group, Runnable task, String name, long stackSize)
|
||||
{
|
||||
this.group = group;
|
||||
this.task = task;
|
||||
this.name = name;
|
||||
|
||||
@ -41,8 +57,28 @@ public class Thread implements Runnable {
|
||||
classLoader = current.classLoader;
|
||||
}
|
||||
|
||||
public Thread(ThreadGroup group, Runnable task, String name) {
|
||||
this(group, task, name, 0);
|
||||
}
|
||||
|
||||
public Thread(ThreadGroup group, String name) {
|
||||
this(null, null, name);
|
||||
}
|
||||
|
||||
public Thread(Runnable task, String name) {
|
||||
this(null, task, name);
|
||||
}
|
||||
|
||||
public Thread(Runnable task) {
|
||||
this(task, "Thread["+task+"]");
|
||||
this(null, task, "Thread["+task+"]");
|
||||
}
|
||||
|
||||
public Thread(String name) {
|
||||
this(null, null, name);
|
||||
}
|
||||
|
||||
public Thread() {
|
||||
this((Runnable) null);
|
||||
}
|
||||
|
||||
public synchronized void start() {
|
||||
@ -58,6 +94,28 @@ public class Thread implements Runnable {
|
||||
|
||||
private native long doStart();
|
||||
|
||||
private static void run(Thread t) throws Throwable {
|
||||
t.state = (byte) State.RUNNABLE.ordinal();
|
||||
try {
|
||||
t.run();
|
||||
} catch (Throwable e) {
|
||||
UncaughtExceptionHandler eh = t.exceptionHandler;
|
||||
UncaughtExceptionHandler deh = defaultExceptionHandler;
|
||||
if (eh != null) {
|
||||
eh.uncaughtException(t, e);
|
||||
} else if (deh != null) {
|
||||
deh.uncaughtException(t, e);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
} finally {
|
||||
synchronized (t) {
|
||||
t.state = (byte) State.TERMINATED.ordinal();
|
||||
t.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void run() {
|
||||
if (task != null) {
|
||||
task.run();
|
||||
@ -101,6 +159,10 @@ public class Thread implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isInterrupted() {
|
||||
return currentThread().interrupted;
|
||||
}
|
||||
|
||||
public static void sleep(long milliseconds) throws InterruptedException {
|
||||
Thread t = currentThread();
|
||||
if (t.sleepLock == null) {
|
||||
@ -111,6 +173,16 @@ public class Thread implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
public static void sleep(long milliseconds, int nanoseconds)
|
||||
throws InterruptedException
|
||||
{
|
||||
if (nanoseconds > 0) {
|
||||
++ milliseconds;
|
||||
}
|
||||
|
||||
sleep(milliseconds);
|
||||
}
|
||||
|
||||
public StackTraceElement[] getStackTrace() {
|
||||
return Throwable.resolveTrace(getStackTrace(peer));
|
||||
}
|
||||
@ -124,5 +196,125 @@ public class Thread implements Runnable {
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public UncaughtExceptionHandler getUncaughtExceptionHandler() {
|
||||
UncaughtExceptionHandler eh = exceptionHandler;
|
||||
return (eh == null ? group : eh);
|
||||
}
|
||||
|
||||
public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler() {
|
||||
return defaultExceptionHandler;
|
||||
}
|
||||
|
||||
public void setUncaughtExceptionHandler(UncaughtExceptionHandler h) {
|
||||
exceptionHandler = h;
|
||||
}
|
||||
|
||||
public static void setDefaultUncaughtExceptionHandler
|
||||
(UncaughtExceptionHandler h)
|
||||
{
|
||||
defaultExceptionHandler = h;
|
||||
}
|
||||
|
||||
public State getState() {
|
||||
return State.values()[state];
|
||||
}
|
||||
|
||||
public boolean isAlive() {
|
||||
switch (getState()) {
|
||||
case NEW:
|
||||
case TERMINATED:
|
||||
return false;
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public int getPriority() {
|
||||
return priority;
|
||||
}
|
||||
|
||||
public void setPriority(int priority) {
|
||||
if (priority < MIN_PRIORITY || priority > MAX_PRIORITY) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
this.priority = (byte) priority;
|
||||
}
|
||||
|
||||
public boolean isDaemon() {
|
||||
return daemon;
|
||||
}
|
||||
|
||||
public void setDaemon(boolean v) {
|
||||
daemon = v;
|
||||
}
|
||||
|
||||
public static native void yield();
|
||||
|
||||
public synchronized void join() throws InterruptedException {
|
||||
while (getState() != State.TERMINATED) {
|
||||
wait();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void join(long milliseconds) throws InterruptedException
|
||||
{
|
||||
long then = System.currentTimeMillis();
|
||||
long remaining = milliseconds;
|
||||
while (remaining > 0 && getState() != State.TERMINATED) {
|
||||
wait(remaining);
|
||||
|
||||
remaining = milliseconds - (System.currentTimeMillis() - then);
|
||||
}
|
||||
}
|
||||
|
||||
public void join(long milliseconds, int nanoseconds)
|
||||
throws InterruptedException
|
||||
{
|
||||
if (nanoseconds > 0) {
|
||||
++ milliseconds;
|
||||
}
|
||||
|
||||
join(milliseconds);
|
||||
}
|
||||
|
||||
public ThreadGroup getThreadGroup() {
|
||||
return group;
|
||||
}
|
||||
|
||||
public static native boolean holdsLock(Object o);
|
||||
|
||||
public long getId() {
|
||||
return peer;
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public void stop(Throwable t) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public void suspend() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public void resume() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public interface UncaughtExceptionHandler {
|
||||
public void uncaughtException(Thread t, Throwable e);
|
||||
}
|
||||
|
||||
public enum State {
|
||||
NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED
|
||||
}
|
||||
|
||||
}
|
||||
|
15
classpath/java/lang/ThreadDeath.java
Normal file
15
classpath/java/lang/ThreadDeath.java
Normal file
@ -0,0 +1,15 @@
|
||||
/* Copyright (c) 2009, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
package java.lang;
|
||||
|
||||
public class ThreadDeath extends Error {
|
||||
public ThreadDeath() { }
|
||||
}
|
35
classpath/java/lang/ThreadGroup.java
Normal file
35
classpath/java/lang/ThreadGroup.java
Normal file
@ -0,0 +1,35 @@
|
||||
/* Copyright (c) 2009, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
package java.lang;
|
||||
|
||||
public class ThreadGroup implements Thread.UncaughtExceptionHandler {
|
||||
private final ThreadGroup parent;
|
||||
private final String name;
|
||||
|
||||
public ThreadGroup(ThreadGroup parent, String name) {
|
||||
this.parent = parent;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void uncaughtException(Thread t, Throwable e) {
|
||||
if (parent != null) {
|
||||
parent.uncaughtException(t, e);
|
||||
} else {
|
||||
Thread.UncaughtExceptionHandler deh
|
||||
= Thread.getDefaultUncaughtExceptionHandler();
|
||||
if (deh != null) {
|
||||
deh.uncaughtException(t, e);
|
||||
} else if (! (e instanceof ThreadDeath)) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -13,8 +13,9 @@ package java.lang;
|
||||
import java.io.PrintStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
|
||||
public class Throwable {
|
||||
public class Throwable implements Serializable {
|
||||
private String message;
|
||||
private Object trace;
|
||||
private Throwable cause;
|
||||
@ -109,4 +110,9 @@ public class Throwable {
|
||||
cause.printStackTrace(sb, nl);
|
||||
}
|
||||
}
|
||||
|
||||
public Throwable fillInStackTrace() {
|
||||
trace = trace(0);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
21
classpath/java/lang/VirtualMachineError.java
Normal file
21
classpath/java/lang/VirtualMachineError.java
Normal file
@ -0,0 +1,21 @@
|
||||
/* Copyright (c) 2009, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
package java.lang;
|
||||
|
||||
public class VirtualMachineError extends Error {
|
||||
public VirtualMachineError(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public VirtualMachineError() {
|
||||
this(null);
|
||||
}
|
||||
}
|
@ -22,6 +22,10 @@ public abstract class Reference<T> {
|
||||
this.queue = queue;
|
||||
}
|
||||
|
||||
protected Reference(T target) {
|
||||
this(target, null);
|
||||
}
|
||||
|
||||
public T get() {
|
||||
return target;
|
||||
}
|
||||
|
@ -10,7 +10,9 @@
|
||||
|
||||
package java.lang.reflect;
|
||||
|
||||
public class Constructor<T> extends AccessibleObject implements Member {
|
||||
public class Constructor<T> extends AccessibleObject
|
||||
implements Member, GenericDeclaration
|
||||
{
|
||||
private Method<T> method;
|
||||
|
||||
public Constructor(Method<T> method) {
|
||||
@ -46,6 +48,18 @@ public class Constructor<T> extends AccessibleObject implements Member {
|
||||
return method.getName();
|
||||
}
|
||||
|
||||
public boolean isSynthetic() {
|
||||
return method.isSynthetic();
|
||||
}
|
||||
|
||||
public TypeVariable<Constructor<T>>[] getTypeParameters() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public Type[] getGenericParameterTypes() {
|
||||
return method.getGenericParameterTypes();
|
||||
}
|
||||
|
||||
private static native <T> T make(Class<T> c);
|
||||
|
||||
public T newInstance(Object ... arguments)
|
||||
|
@ -101,6 +101,38 @@ public class Field<T> extends AccessibleObject {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getBoolean(Object instance) throws IllegalAccessException {
|
||||
return ((Boolean) get(instance)).booleanValue();
|
||||
}
|
||||
|
||||
public byte getByte(Object instance) throws IllegalAccessException {
|
||||
return ((Byte) get(instance)).byteValue();
|
||||
}
|
||||
|
||||
public short getShort(Object instance) throws IllegalAccessException {
|
||||
return ((Short) get(instance)).shortValue();
|
||||
}
|
||||
|
||||
public char getChar(Object instance) throws IllegalAccessException {
|
||||
return ((Character) get(instance)).charValue();
|
||||
}
|
||||
|
||||
public int getInt(Object instance) throws IllegalAccessException {
|
||||
return ((Integer) get(instance)).intValue();
|
||||
}
|
||||
|
||||
public float getFloat(Object instance) throws IllegalAccessException {
|
||||
return ((Float) get(instance)).floatValue();
|
||||
}
|
||||
|
||||
public long getLong(Object instance) throws IllegalAccessException {
|
||||
return ((Long) get(instance)).longValue();
|
||||
}
|
||||
|
||||
public double getDouble(Object instance) throws IllegalAccessException {
|
||||
return ((Double) get(instance)).doubleValue();
|
||||
}
|
||||
|
||||
public void set(Object instance, Object value)
|
||||
throws IllegalAccessException
|
||||
{
|
||||
@ -162,6 +194,10 @@ public class Field<T> extends AccessibleObject {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEnumConstant() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
private static native long getPrimitive
|
||||
(Object instance, int code, int offset);
|
||||
|
||||
|
15
classpath/java/lang/reflect/GenericDeclaration.java
Normal file
15
classpath/java/lang/reflect/GenericDeclaration.java
Normal file
@ -0,0 +1,15 @@
|
||||
/* Copyright (c) 2009, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
package java.lang.reflect;
|
||||
|
||||
public interface GenericDeclaration {
|
||||
public TypeVariable<?>[] getTypeParameters();
|
||||
}
|
@ -19,4 +19,6 @@ public interface Member {
|
||||
public int getModifiers();
|
||||
|
||||
public String getName();
|
||||
|
||||
public boolean isSynthetic();
|
||||
}
|
||||
|
@ -10,7 +10,9 @@
|
||||
|
||||
package java.lang.reflect;
|
||||
|
||||
public class Method<T> extends AccessibleObject implements Member {
|
||||
public class Method<T> extends AccessibleObject
|
||||
implements Member, GenericDeclaration
|
||||
{
|
||||
private byte vmFlags;
|
||||
private byte returnCode;
|
||||
private byte parameterCount;
|
||||
@ -124,4 +126,28 @@ public class Method<T> extends AccessibleObject implements Member {
|
||||
}
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
public boolean isSynthetic() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public Object getDefaultValue() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public Type[] getGenericParameterTypes() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public Type getGenericReturnType() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public Class[] getExceptionTypes() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public TypeVariable<Method<T>>[] getTypeParameters() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
@ -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; }
|
||||
}
|
||||
|
13
classpath/java/lang/reflect/Type.java
Normal file
13
classpath/java/lang/reflect/Type.java
Normal file
@ -0,0 +1,13 @@
|
||||
/* Copyright (c) 2009, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
package java.lang.reflect;
|
||||
|
||||
public interface Type { }
|
19
classpath/java/lang/reflect/TypeVariable.java
Normal file
19
classpath/java/lang/reflect/TypeVariable.java
Normal file
@ -0,0 +1,19 @@
|
||||
/* Copyright (c) 2009, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
package java.lang.reflect;
|
||||
|
||||
public interface TypeVariable<T extends GenericDeclaration>
|
||||
extends Type
|
||||
{
|
||||
public Type[] getBounds();
|
||||
public T getGenericDeclaration();
|
||||
public String getName();
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2008, Avian Contributors
|
||||
/* Copyright (c) 2008-2009, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
@ -11,7 +11,6 @@
|
||||
package java.net;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public final class URL {
|
||||
@ -73,7 +72,7 @@ public final class URL {
|
||||
throws MalformedURLException
|
||||
{
|
||||
if ("resource".equals(protocol)) {
|
||||
return new ResourceHandler();
|
||||
return new avian.resource.Handler();
|
||||
} else {
|
||||
throw new MalformedURLException("unknown protocol: " + protocol);
|
||||
}
|
||||
@ -88,87 +87,4 @@ public final class URL {
|
||||
this.file = file;
|
||||
this.ref = ref;
|
||||
}
|
||||
|
||||
private static class ResourceHandler extends URLStreamHandler {
|
||||
protected URLConnection openConnection(URL url) {
|
||||
return new ResourceConnection(url);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ResourceConnection extends URLConnection {
|
||||
public ResourceConnection(URL url) {
|
||||
super(url);
|
||||
}
|
||||
|
||||
public int getContentLength() {
|
||||
return ResourceInputStream.getContentLength(url.getFile());
|
||||
}
|
||||
|
||||
public InputStream getInputStream() throws IOException {
|
||||
return new ResourceInputStream(url.getFile());
|
||||
}
|
||||
}
|
||||
|
||||
private static class ResourceInputStream extends InputStream {
|
||||
private long peer;
|
||||
private int position;
|
||||
|
||||
public ResourceInputStream(String path) throws IOException {
|
||||
peer = open(path);
|
||||
if (peer == 0) {
|
||||
throw new FileNotFoundException(path);
|
||||
}
|
||||
}
|
||||
|
||||
private static native int getContentLength(String path);
|
||||
|
||||
private static native long open(String path) throws IOException;
|
||||
|
||||
private static native int read(long peer, int position) throws IOException;
|
||||
|
||||
private static native int read(long peer, int position,
|
||||
byte[] b, int offset, int length)
|
||||
throws IOException;
|
||||
|
||||
public static native void close(long peer) throws IOException;
|
||||
|
||||
public int read() throws IOException {
|
||||
if (peer != 0) {
|
||||
int c = read(peer, position);
|
||||
if (c >= 0) {
|
||||
++ position;
|
||||
}
|
||||
return c;
|
||||
} else {
|
||||
throw new IOException();
|
||||
}
|
||||
}
|
||||
|
||||
public int read(byte[] b, int offset, int length) throws IOException {
|
||||
if (peer != 0) {
|
||||
if (b == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
if (offset < 0 || offset + length > b.length) {
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
|
||||
int c = read(peer, position, b, offset, length);
|
||||
if (c >= 0) {
|
||||
position += c;
|
||||
}
|
||||
return c;
|
||||
} else {
|
||||
throw new IOException();
|
||||
}
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
if (peer != 0) {
|
||||
close(peer);
|
||||
peer = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
13
classpath/java/security/AllPermission.java
Normal file
13
classpath/java/security/AllPermission.java
Normal file
@ -0,0 +1,13 @@
|
||||
/* Copyright (c) 2009, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
package java.security;
|
||||
|
||||
public class AllPermission extends Permission { }
|
13
classpath/java/security/CodeSource.java
Normal file
13
classpath/java/security/CodeSource.java
Normal file
@ -0,0 +1,13 @@
|
||||
/* Copyright (c) 2009, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
package java.security;
|
||||
|
||||
public class CodeSource { }
|
17
classpath/java/security/Permission.java
Normal file
17
classpath/java/security/Permission.java
Normal file
@ -0,0 +1,17 @@
|
||||
/* Copyright (c) 2009, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
package java.security;
|
||||
|
||||
public abstract class Permission {
|
||||
public PermissionCollection newPermissionCollection() {
|
||||
return null;
|
||||
}
|
||||
}
|
15
classpath/java/security/PermissionCollection.java
Normal file
15
classpath/java/security/PermissionCollection.java
Normal file
@ -0,0 +1,15 @@
|
||||
/* Copyright (c) 2009, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
package java.security;
|
||||
|
||||
public abstract class PermissionCollection {
|
||||
public abstract void add(Permission p);
|
||||
}
|
41
classpath/java/security/Permissions.java
Normal file
41
classpath/java/security/Permissions.java
Normal file
@ -0,0 +1,41 @@
|
||||
/* Copyright (c) 2009, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
package java.security;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
|
||||
public class Permissions extends PermissionCollection {
|
||||
private final Map<Class,PermissionCollection> collections = new HashMap();
|
||||
|
||||
public void add(Permission p) {
|
||||
Class c = p.getClass();
|
||||
PermissionCollection pc = collections.get(c);
|
||||
if (pc == null) {
|
||||
pc = p.newPermissionCollection();
|
||||
if (pc == null) {
|
||||
pc = new MyPermissionCollection();
|
||||
}
|
||||
collections.put(c, pc);
|
||||
}
|
||||
pc.add(p);
|
||||
}
|
||||
|
||||
private static class MyPermissionCollection extends PermissionCollection {
|
||||
private final Set<Permission> permissions = new HashSet();
|
||||
|
||||
public void add(Permission p) {
|
||||
permissions.add(p);
|
||||
}
|
||||
}
|
||||
}
|
23
classpath/java/security/ProtectionDomain.java
Normal file
23
classpath/java/security/ProtectionDomain.java
Normal file
@ -0,0 +1,23 @@
|
||||
/* Copyright (c) 2009, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
package java.security;
|
||||
|
||||
public class ProtectionDomain {
|
||||
private final CodeSource codeSource;
|
||||
private final PermissionCollection permissions;
|
||||
|
||||
public ProtectionDomain(CodeSource codeSource,
|
||||
PermissionCollection permissions)
|
||||
{
|
||||
this.codeSource = codeSource;
|
||||
this.permissions = permissions;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
15
classpath/java/util/AbstractList.java
Normal file
15
classpath/java/util/AbstractList.java
Normal file
@ -0,0 +1,15 @@
|
||||
/* Copyright (c) 2009, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
package java.util;
|
||||
|
||||
public abstract class AbstractList<T> extends AbstractCollection<T>
|
||||
implements List<T>
|
||||
{ }
|
15
classpath/java/util/AbstractSequentialList.java
Normal file
15
classpath/java/util/AbstractSequentialList.java
Normal file
@ -0,0 +1,15 @@
|
||||
/* Copyright (c) 2009, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
package java.util;
|
||||
|
||||
public abstract class AbstractSequentialList<T> extends AbstractList<T>
|
||||
implements List<T>
|
||||
{ }
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ public class Hashtable<K, V> implements Map<K, V> {
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
public synchronized String toString() {
|
||||
return map.toString();
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
205
classpath/java/util/TreeMap.java
Normal file
205
classpath/java/util/TreeMap.java
Normal 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());
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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() {
|
||||
|
15
classpath/java/util/concurrent/Callable.java
Normal file
15
classpath/java/util/concurrent/Callable.java
Normal file
@ -0,0 +1,15 @@
|
||||
/* Copyright (c) 2009, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
package java.util.concurrent;
|
||||
|
||||
public interface Callable<T> {
|
||||
public T call() throws Exception;
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
170
makefile
@ -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)
|
||||
|
23
readme.txt
23
readme.txt
@ -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.
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
668
src/builtin.cpp
668
src/builtin.cpp
File diff suppressed because it is too large
Load Diff
34
src/common.h
34
src/common.h
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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__
|
||||
|
3065
src/compile.cpp
3065
src/compile.cpp
File diff suppressed because it is too large
Load Diff
874
src/compiler.cpp
874
src/compiler.cpp
File diff suppressed because it is too large
Load Diff
@ -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
161
src/continuations-x86.S
Normal file
@ -0,0 +1,161 @@
|
||||
#ifdef __x86_64__
|
||||
|
||||
#define THREAD_CONTINUATION 168
|
||||
#define THREAD_EXCEPTION 64
|
||||
#define THREAD_EXCEPTION_STACK_ADJUSTMENT 176
|
||||
#define THREAD_EXCEPTION_OFFSET 184
|
||||
#define THREAD_EXCEPTION_HANDLER 192
|
||||
|
||||
#define CONTINUATION_NEXT 8
|
||||
#define CONTINUATION_ADDRESS 32
|
||||
#define CONTINUATION_RETURN_ADDRESS_OFFSET 40
|
||||
#define CONTINUATION_FRAME_POINTER_OFFSET 48
|
||||
#define CONTINUATION_LENGTH 56
|
||||
#define CONTINUATION_BODY 64
|
||||
|
||||
// call the next continuation, if any
|
||||
movq THREAD_CONTINUATION(%rbx),%rcx
|
||||
cmpq $0,%rcx
|
||||
je LOCAL(vmInvoke_exit)
|
||||
|
||||
// allocate a frame of size (continuation.length * BYTES_PER_WORD)
|
||||
// + CALLEE_SAVED_REGISTER_FOOTPRINT
|
||||
movq CONTINUATION_LENGTH(%rcx),%rsi
|
||||
shlq $3,%rsi
|
||||
subq %rsi,%rsp
|
||||
subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%rsp
|
||||
|
||||
// copy the continuation body into the frame
|
||||
leaq CONTINUATION_BODY(%rcx),%rdi
|
||||
|
||||
movq $0,%r9
|
||||
jmp LOCAL(vmInvoke_continuationTest)
|
||||
|
||||
LOCAL(vmInvoke_continuationLoop):
|
||||
movq (%rdi,%r9,1),%r8
|
||||
movq %r8,(%rsp,%r9,1)
|
||||
addq $8,%r9
|
||||
|
||||
LOCAL(vmInvoke_continuationTest):
|
||||
cmpq %rsi,%r9
|
||||
jb LOCAL(vmInvoke_continuationLoop)
|
||||
|
||||
// set the return address to vmInvoke_returnAddress
|
||||
movq CONTINUATION_RETURN_ADDRESS_OFFSET(%rcx),%rdi
|
||||
movq vmInvoke_returnAddress@GOTPCREL(%rip),%r10
|
||||
movq %r10,(%rsp,%rdi,1)
|
||||
|
||||
// save the current base pointer in the frame and update it
|
||||
movq CONTINUATION_FRAME_POINTER_OFFSET(%rcx),%rdi
|
||||
movq %rbp,(%rsp,%rdi,1)
|
||||
addq %rsp,%rdi
|
||||
movq %rdi,%rbp
|
||||
|
||||
// consume the continuation
|
||||
movq CONTINUATION_NEXT(%rcx),%rdi
|
||||
movq %rdi,THREAD_CONTINUATION(%rbx)
|
||||
|
||||
// call the continuation unless we're handling an exception
|
||||
movq THREAD_EXCEPTION(%rbx),%rsi
|
||||
cmpq $0,%rsi
|
||||
jne LOCAL(vmInvoke_handleException)
|
||||
jmp *CONTINUATION_ADDRESS(%rcx)
|
||||
|
||||
LOCAL(vmInvoke_handleException):
|
||||
// we're handling an exception - call the exception handler instead
|
||||
movq $0,THREAD_EXCEPTION(%rbx)
|
||||
movq THREAD_EXCEPTION_STACK_ADJUSTMENT(%rbx),%rdi
|
||||
subq %rdi,%rsp
|
||||
movq THREAD_EXCEPTION_OFFSET(%rbx),%rdi
|
||||
movq %rsi,(%rsp,%rdi,1)
|
||||
|
||||
jmp *THREAD_EXCEPTION_HANDLER(%rbx)
|
||||
|
||||
LOCAL(vmInvoke_exit):
|
||||
|
||||
#elif defined __i386__
|
||||
|
||||
#define THREAD_CONTINUATION 96
|
||||
#define THREAD_EXCEPTION 36
|
||||
#define THREAD_EXCEPTION_STACK_ADJUSTMENT 100
|
||||
#define THREAD_EXCEPTION_OFFSET 104
|
||||
#define THREAD_EXCEPTION_HANDLER 108
|
||||
|
||||
#define CONTINUATION_NEXT 4
|
||||
#define CONTINUATION_ADDRESS 16
|
||||
#define CONTINUATION_RETURN_ADDRESS_OFFSET 20
|
||||
#define CONTINUATION_FRAME_POINTER_OFFSET 24
|
||||
#define CONTINUATION_LENGTH 28
|
||||
#define CONTINUATION_BODY 32
|
||||
|
||||
// call the next continuation, if any
|
||||
movl THREAD_CONTINUATION(%ebx),%ecx
|
||||
cmpl $0,%ecx
|
||||
je LOCAL(vmInvoke_exit)
|
||||
|
||||
// allocate a frame of size (continuation.length * BYTES_PER_WORD)
|
||||
movl CONTINUATION_LENGTH(%ecx),%esi
|
||||
shll $2,%esi
|
||||
subl %esi,%esp
|
||||
|
||||
// copy the continuation body into the frame
|
||||
leal CONTINUATION_BODY(%ecx),%edi
|
||||
|
||||
push %eax
|
||||
push %edx
|
||||
|
||||
movl $0,%edx
|
||||
jmp LOCAL(vmInvoke_continuationTest)
|
||||
|
||||
LOCAL(vmInvoke_continuationLoop):
|
||||
movl (%edi,%edx,1),%eax
|
||||
movl %eax,8(%esp,%edx,1)
|
||||
addl $4,%edx
|
||||
|
||||
LOCAL(vmInvoke_continuationTest):
|
||||
cmpl %esi,%edx
|
||||
jb LOCAL(vmInvoke_continuationLoop)
|
||||
|
||||
pop %edx
|
||||
pop %eax
|
||||
|
||||
// set the return address to vmInvoke_returnAddress
|
||||
movl CONTINUATION_RETURN_ADDRESS_OFFSET(%ecx),%edi
|
||||
call LOCAL(getPC)
|
||||
addl $_GLOBAL_OFFSET_TABLE_,%esi
|
||||
movl vmInvoke_returnAddress@GOT(%esi),%esi
|
||||
movl %esi,(%esp,%edi,1)
|
||||
|
||||
// save the current base pointer in the frame and update it
|
||||
movl CONTINUATION_FRAME_POINTER_OFFSET(%ecx),%edi
|
||||
movl %ebp,(%esp,%edi,1)
|
||||
addl %esp,%edi
|
||||
movl %edi,%ebp
|
||||
|
||||
// consume the continuation
|
||||
movl CONTINUATION_NEXT(%ecx),%edi
|
||||
movl %edi,THREAD_CONTINUATION(%ebx)
|
||||
|
||||
// call the continuation unless we're handling an exception
|
||||
movl THREAD_EXCEPTION(%ebx),%esi
|
||||
cmpl $0,%esi
|
||||
jne LOCAL(vmInvoke_handleException)
|
||||
|
||||
jmp *CONTINUATION_ADDRESS(%ecx)
|
||||
|
||||
LOCAL(vmInvoke_handleException):
|
||||
// we're handling an exception - call the exception handler instead
|
||||
movl $0,THREAD_EXCEPTION(%ebx)
|
||||
movl THREAD_EXCEPTION_STACK_ADJUSTMENT(%ebx),%edi
|
||||
subl %edi,%esp
|
||||
movl THREAD_EXCEPTION_OFFSET(%ebx),%edi
|
||||
movl %esi,(%esp,%edi,1)
|
||||
|
||||
jmp *THREAD_EXCEPTION_HANDLER(%ebx)
|
||||
|
||||
LOCAL(vmInvoke_exit):
|
||||
|
||||
#else
|
||||
# error unsupported architecture
|
||||
#endif
|
||||
|
413
src/gnu.cpp
Normal file
413
src/gnu.cpp
Normal 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);
|
||||
}
|
37
src/heap.cpp
37
src/heap.cpp
@ -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;
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ class Context {
|
||||
while (stack) {
|
||||
Stack* dead = stack;
|
||||
stack = dead->next;
|
||||
thread->m->heap->free(stack, sizeof(Stack));
|
||||
thread->m->heap->free(dead, sizeof(Stack));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,8 @@ const unsigned FrameMethodOffset = 2;
|
||||
const unsigned FrameIpOffset = 3;
|
||||
const unsigned FrameFootprint = 4;
|
||||
|
||||
class ClassInitList;
|
||||
|
||||
class Thread: public vm::Thread {
|
||||
public:
|
||||
static const unsigned StackSizeInBytes = 64 * 1024;
|
||||
@ -36,16 +38,39 @@ class Thread: public vm::Thread {
|
||||
ip(0),
|
||||
sp(0),
|
||||
frame(-1),
|
||||
code(0)
|
||||
code(0),
|
||||
classInitList(0)
|
||||
{ }
|
||||
|
||||
unsigned ip;
|
||||
unsigned sp;
|
||||
int frame;
|
||||
object code;
|
||||
ClassInitList* classInitList;
|
||||
uintptr_t stack[StackSizeInWords];
|
||||
};
|
||||
|
||||
class ClassInitList {
|
||||
public:
|
||||
ClassInitList(Thread* t, object class_, ClassInitList* next):
|
||||
t(t), class_(class_), next(next)
|
||||
{ }
|
||||
|
||||
static void push(Thread* t, object class_) {
|
||||
t->classInitList = new (t->m->heap->allocate(sizeof(ClassInitList)))
|
||||
ClassInitList(t, class_, t->classInitList);
|
||||
}
|
||||
|
||||
void pop() {
|
||||
t->classInitList = next;
|
||||
t->m->heap->free(this, sizeof(ClassInitList));
|
||||
}
|
||||
|
||||
Thread* t;
|
||||
object class_;
|
||||
ClassInitList* next;
|
||||
};
|
||||
|
||||
inline void
|
||||
pushObject(Thread* t, object o)
|
||||
{
|
||||
@ -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));
|
||||
}
|
||||
|
118
src/jnienv.cpp
118
src/jnienv.cpp
@ -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;
|
||||
|
517
src/machine.cpp
517
src/machine.cpp
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
210
src/machine.h
210
src/machine.h
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -161,4 +161,6 @@ vmJump:
|
||||
mtlr r3
|
||||
mr r1,r5
|
||||
mr r13,r6
|
||||
mr r4,r7
|
||||
mr r3,r8
|
||||
blr
|
||||
|
181
src/powerpc.cpp
181
src/powerpc.cpp
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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_)
|
||||
|
@ -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_, ...)
|
||||
{
|
||||
|
@ -38,7 +38,7 @@ THUNK(makeMultidimensionalArray)
|
||||
THUNK(throw_)
|
||||
THUNK(checkCast)
|
||||
THUNK(instanceOf64)
|
||||
THUNK(makeNewWeakReference64)
|
||||
THUNK(makeNewGeneral64)
|
||||
THUNK(makeNew64)
|
||||
THUNK(set)
|
||||
THUNK(gcIfNecessary)
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user