mirror of
https://github.com/corda/corda.git
synced 2025-01-19 11:16:54 +00:00
Merge branch 'master' into compiler
Conflicts: src/compile.cpp src/compiler.cpp src/compiler.h
This commit is contained in:
commit
525f733171
@ -519,31 +519,6 @@ Java_java_lang_Math_pow(JNIEnv*, jclass, jdouble val, jdouble exp)
|
|||||||
return pow(val, exp);
|
return pow(val, exp);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT void JNICALL
|
|
||||||
Java_java_lang_Math_natRandomInitialize(JNIEnv*, jclass, jlong val)
|
|
||||||
{
|
|
||||||
#ifdef WIN32
|
|
||||||
srand(val);
|
|
||||||
#else
|
|
||||||
srand48(val);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" JNIEXPORT jdouble JNICALL
|
|
||||||
Java_java_lang_Math_natRandom(JNIEnv*, jclass)
|
|
||||||
{
|
|
||||||
#ifdef WIN32
|
|
||||||
double r = static_cast<double>(rand()) / static_cast<double>(RAND_MAX);
|
|
||||||
if (r < 0 or r >= 1) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
return drand48();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" JNIEXPORT jdouble JNICALL
|
extern "C" JNIEXPORT jdouble JNICALL
|
||||||
Java_java_lang_Math_floor(JNIEnv*, jclass, jdouble val)
|
Java_java_lang_Math_floor(JNIEnv*, jclass, jdouble val)
|
||||||
{
|
{
|
||||||
|
@ -575,6 +575,13 @@ Java_java_nio_channels_SocketSelector_natDoSocketSelect(JNIEnv *e, jclass,
|
|||||||
timeval time = { interval / 1000, (interval % 1000) * 1000 };
|
timeval time = { interval / 1000, (interval % 1000) * 1000 };
|
||||||
int r = ::select(max + 1, &(s->read), &(s->write), &(s->except), &time);
|
int r = ::select(max + 1, &(s->read), &(s->write), &(s->except), &time);
|
||||||
|
|
||||||
|
if (r < 0) {
|
||||||
|
if (errno != EINTR) {
|
||||||
|
throwIOException(e);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
if (FD_ISSET(s->control.writer(), &(s->write)) or
|
if (FD_ISSET(s->control.writer(), &(s->write)) or
|
||||||
FD_ISSET(s->control.writer(), &(s->except)))
|
FD_ISSET(s->control.writer(), &(s->except)))
|
||||||
@ -618,11 +625,6 @@ Java_java_nio_channels_SocketSelector_natDoSocketSelect(JNIEnv *e, jclass,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r < 0) {
|
|
||||||
if (errno != EINTR) {
|
|
||||||
throwIOException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,10 @@ public class ByteArrayInputStream extends InputStream {
|
|||||||
this.limit = offset + length;
|
this.limit = offset + length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ByteArrayInputStream(byte[] array) {
|
||||||
|
this(array, 0, array.length);
|
||||||
|
}
|
||||||
|
|
||||||
public int read() {
|
public int read() {
|
||||||
if (position < limit) {
|
if (position < limit) {
|
||||||
return array[position++] & 0xff;
|
return array[position++] & 0xff;
|
||||||
|
@ -52,5 +52,17 @@ public abstract class InputStream {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void mark(int limit) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset() throws IOException {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean markSupported() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public void close() throws IOException { }
|
public void close() throws IOException { }
|
||||||
}
|
}
|
||||||
|
21
classpath/java/lang/ArithmeticException.java
Normal file
21
classpath/java/lang/ArithmeticException.java
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/* Copyright (c) 2008, 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 ArithmeticException extends RuntimeException {
|
||||||
|
public ArithmeticException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArithmeticException() {
|
||||||
|
this(null);
|
||||||
|
}
|
||||||
|
}
|
@ -11,6 +11,9 @@
|
|||||||
package java.lang;
|
package java.lang;
|
||||||
|
|
||||||
public final class Character implements Comparable<Character> {
|
public final class Character implements Comparable<Character> {
|
||||||
|
public static final int MIN_RADIX = 2;
|
||||||
|
public static final int MAX_RADIX = 36;
|
||||||
|
|
||||||
public static final Class TYPE = Class.forCanonicalName("C");
|
public static final Class TYPE = Class.forCanonicalName("C");
|
||||||
|
|
||||||
private final char value;
|
private final char value;
|
||||||
@ -67,6 +70,23 @@ public final class Character implements Comparable<Character> {
|
|||||||
return c >= '0' && c <= '9';
|
return c >= '0' && c <= '9';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int digit(char c, int radix) {
|
||||||
|
int digit = 0;
|
||||||
|
if ((c >= '0') && (c <= '9')) {
|
||||||
|
digit = c - '0';
|
||||||
|
} else if ((c >= 'a') && (c <= 'z')) {
|
||||||
|
digit = c - 'a' + 10;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (digit < radix) {
|
||||||
|
return digit;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isLetter(char c) {
|
public static boolean isLetter(char c) {
|
||||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
|
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
|
||||||
}
|
}
|
||||||
|
@ -376,6 +376,10 @@ public final class Class <T> {
|
|||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isInterface() {
|
||||||
|
return (flags & Modifier.INTERFACE) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
public Class getSuperclass() {
|
public Class getSuperclass() {
|
||||||
return super_;
|
return super_;
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,10 @@ public final class Integer extends Number implements Comparable<Integer> {
|
|||||||
return Long.toString(((long) v) & 0xFFFFFFFFL, 16);
|
return Long.toString(((long) v) & 0xFFFFFFFFL, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String toBinaryString(int v) {
|
||||||
|
return Long.toString(((long) v) & 0xFFFFFFFFL, 2);
|
||||||
|
}
|
||||||
|
|
||||||
public byte byteValue() {
|
public byte byteValue() {
|
||||||
return (byte) value;
|
return (byte) value;
|
||||||
}
|
}
|
||||||
|
@ -11,8 +11,10 @@
|
|||||||
package java.lang;
|
package java.lang;
|
||||||
|
|
||||||
public final class Long extends Number implements Comparable<Long> {
|
public final class Long extends Number implements Comparable<Long> {
|
||||||
|
public static final Long MIN_VALUE = -9223372036854775808l;
|
||||||
|
public static final Long MAX_VALUE = 9223372036854775807l;
|
||||||
|
|
||||||
public static final Class TYPE = Class.forCanonicalName("J");
|
public static final Class TYPE = Class.forCanonicalName("J");
|
||||||
public static final Long MAX_VALUE = 9223372036854775807l;
|
|
||||||
|
|
||||||
private final long value;
|
private final long value;
|
||||||
|
|
||||||
@ -131,16 +133,13 @@ public final class Long extends Number implements Comparable<Long> {
|
|||||||
|
|
||||||
for (; i < s.length(); ++i) {
|
for (; i < s.length(); ++i) {
|
||||||
char c = s.charAt(i);
|
char c = s.charAt(i);
|
||||||
if (((c >= '0') && (c <= '9')) ||
|
int digit = Character.digit(c, radix);
|
||||||
((c >= 'a') && (c <= 'z'))) {
|
if (digit >= 0) {
|
||||||
long digit = ((c >= '0' && c <= '9') ? (c - '0') : (c - 'a' + 10));
|
number += digit * pow(radix, (s.length() - i - 1));
|
||||||
if (digit < radix) {
|
} else {
|
||||||
number += digit * pow(radix, (s.length() - i - 1));
|
throw new NumberFormatException("invalid character " + c + " code " +
|
||||||
continue;
|
(int) c);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
throw new NumberFormatException("invalid character " + c + " code " +
|
|
||||||
(int) c);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (negative) {
|
if (negative) {
|
||||||
|
@ -10,10 +10,12 @@
|
|||||||
|
|
||||||
package java.lang;
|
package java.lang;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
public final class Math {
|
public final class Math {
|
||||||
public static final double E = 2.718281828459045;
|
public static final double E = 2.718281828459045;
|
||||||
public static final double PI = 3.141592653589793;
|
public static final double PI = 3.141592653589793;
|
||||||
private static boolean randomInitialized = false;
|
private static final Random random = new Random();
|
||||||
|
|
||||||
private Math() { }
|
private Math() { }
|
||||||
|
|
||||||
@ -74,17 +76,9 @@ public final class Math {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static double random() {
|
public static double random() {
|
||||||
if (randomInitialized) {
|
return random.nextDouble();
|
||||||
natRandomInitialize(System.currentTimeMillis());
|
|
||||||
randomInitialized = true;
|
|
||||||
}
|
|
||||||
return natRandom();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static native void natRandomInitialize(long val);
|
|
||||||
|
|
||||||
public static native double natRandom();
|
|
||||||
|
|
||||||
public static native double floor(double v);
|
public static native double floor(double v);
|
||||||
|
|
||||||
public static native double ceil(double v);
|
public static native double ceil(double v);
|
||||||
|
@ -108,4 +108,14 @@ public class Thread implements Runnable {
|
|||||||
t.sleepLock.wait(milliseconds);
|
t.sleepLock.wait(milliseconds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public StackTraceElement[] getStackTrace() {
|
||||||
|
return Throwable.resolveTrace(getStackTrace(peer));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static native Object getStackTrace(long peer);
|
||||||
|
|
||||||
|
public static native int activeCount();
|
||||||
|
|
||||||
|
public static native int enumerate(Thread[] array);
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ public class Throwable {
|
|||||||
|
|
||||||
private static native Object trace(int skipCount);
|
private static native Object trace(int skipCount);
|
||||||
|
|
||||||
private static native StackTraceElement[] resolveTrace(Object trace);
|
static native StackTraceElement[] resolveTrace(Object trace);
|
||||||
|
|
||||||
private StackTraceElement[] resolveTrace() {
|
private StackTraceElement[] resolveTrace() {
|
||||||
if (! (trace instanceof StackTraceElement[])) {
|
if (! (trace instanceof StackTraceElement[])) {
|
||||||
|
@ -33,4 +33,6 @@ public final class Modifier {
|
|||||||
public static boolean isStatic (int v) { return (v & STATIC) != 0; }
|
public static boolean isStatic (int v) { return (v & STATIC) != 0; }
|
||||||
public static boolean isFinal (int v) { return (v & FINAL) != 0; }
|
public static boolean isFinal (int v) { return (v & FINAL) != 0; }
|
||||||
public static boolean isSuper (int v) { return (v & SUPER) != 0; }
|
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; }
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
package java.net;
|
package java.net;
|
||||||
|
|
||||||
public class InetSocketAddress {
|
public class InetSocketAddress extends SocketAddress {
|
||||||
private final String host;
|
private final String host;
|
||||||
private final int port;
|
private final int port;
|
||||||
|
|
||||||
|
17
classpath/java/net/ServerSocket.java
Normal file
17
classpath/java/net/ServerSocket.java
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
/* Copyright (c) 2008, 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.net;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public abstract class ServerSocket {
|
||||||
|
public abstract void bind(SocketAddress address) throws IOException;
|
||||||
|
}
|
13
classpath/java/net/SocketAddress.java
Normal file
13
classpath/java/net/SocketAddress.java
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/* Copyright (c) 2008, 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.net;
|
||||||
|
|
||||||
|
public abstract class SocketAddress { }
|
59
classpath/java/nio/Buffer.java
Normal file
59
classpath/java/nio/Buffer.java
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/* Copyright (c) 2008, 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.nio;
|
||||||
|
|
||||||
|
public abstract class Buffer {
|
||||||
|
protected int capacity;
|
||||||
|
protected int position;
|
||||||
|
protected int limit;
|
||||||
|
|
||||||
|
public int limit() {
|
||||||
|
return limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int remaining() {
|
||||||
|
return limit-position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int position() {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int capacity() {
|
||||||
|
return capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Buffer limit(int newLimit) {
|
||||||
|
limit = newLimit;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Buffer position(int newPosition) {
|
||||||
|
position = newPosition;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasRemaining() {
|
||||||
|
return remaining() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Buffer clear() {
|
||||||
|
position = 0;
|
||||||
|
limit = capacity;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Buffer flip() {
|
||||||
|
limit = position;
|
||||||
|
position = 0;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
@ -10,27 +10,28 @@
|
|||||||
|
|
||||||
package java.nio;
|
package java.nio;
|
||||||
|
|
||||||
public class ByteBuffer implements Comparable<ByteBuffer> {
|
public class ByteBuffer extends Buffer implements Comparable<ByteBuffer> {
|
||||||
private final byte[] array;
|
private final byte[] array;
|
||||||
private int arrayOffset;
|
private int arrayOffset;
|
||||||
private int capacity;
|
|
||||||
private int position;
|
|
||||||
private int limit;
|
|
||||||
private final boolean readOnly;
|
private final boolean readOnly;
|
||||||
|
|
||||||
public static ByteBuffer allocate(int capacity) {
|
public static ByteBuffer allocate(int capacity) {
|
||||||
return new ByteBuffer(new byte[capacity], false);
|
return new ByteBuffer(new byte[capacity], 0, capacity, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ByteBuffer wrap(byte[] array) {
|
public static ByteBuffer wrap(byte[] array) {
|
||||||
return new ByteBuffer(array, false);
|
return wrap(array, 0, array.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ByteBuffer(byte[] array, boolean readOnly) {
|
public static ByteBuffer wrap(byte[] array, int offset, int length) {
|
||||||
|
return new ByteBuffer(array, offset, length, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ByteBuffer(byte[] array, int offset, int length, boolean readOnly) {
|
||||||
this.array = array;
|
this.array = array;
|
||||||
this.readOnly = readOnly;
|
this.readOnly = readOnly;
|
||||||
arrayOffset = 0;
|
arrayOffset = offset;
|
||||||
capacity = array.length;
|
capacity = length;
|
||||||
limit = capacity;
|
limit = capacity;
|
||||||
position = 0;
|
position = 0;
|
||||||
}
|
}
|
||||||
@ -55,35 +56,8 @@ public class ByteBuffer implements Comparable<ByteBuffer> {
|
|||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ByteBuffer clear() {
|
|
||||||
position = 0;
|
|
||||||
limit = capacity;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ByteBuffer slice() {
|
public ByteBuffer slice() {
|
||||||
ByteBuffer buf = new ByteBuffer(array, true);
|
return new ByteBuffer(array, arrayOffset + position, remaining(), true);
|
||||||
buf.arrayOffset = arrayOffset + position;
|
|
||||||
buf.position = 0;
|
|
||||||
buf.capacity = remaining();
|
|
||||||
buf.limit = buf.capacity;
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int limit() {
|
|
||||||
return limit;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int remaining() {
|
|
||||||
return limit-position;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int position() {
|
|
||||||
return position;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int capacity() {
|
|
||||||
return capacity;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int arrayOffset() {
|
public int arrayOffset() {
|
||||||
@ -100,16 +74,6 @@ public class ByteBuffer implements Comparable<ByteBuffer> {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ByteBuffer limit(int newLimit) {
|
|
||||||
limit = newLimit;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ByteBuffer position(int newPosition) {
|
|
||||||
position = newPosition;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ByteBuffer put(byte val) {
|
public ByteBuffer put(byte val) {
|
||||||
checkPut(1);
|
checkPut(1);
|
||||||
array[arrayOffset+(position++)] = val;
|
array[arrayOffset+(position++)] = val;
|
||||||
@ -164,10 +128,6 @@ public class ByteBuffer implements Comparable<ByteBuffer> {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasRemaining() {
|
|
||||||
return remaining() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte get() {
|
public byte get() {
|
||||||
checkGet(1);
|
checkGet(1);
|
||||||
return array[arrayOffset+(position++)];
|
return array[arrayOffset+(position++)];
|
||||||
@ -189,12 +149,6 @@ public class ByteBuffer implements Comparable<ByteBuffer> {
|
|||||||
return array[arrayOffset+position];
|
return array[arrayOffset+position];
|
||||||
}
|
}
|
||||||
|
|
||||||
public ByteBuffer flip() {
|
|
||||||
limit = position;
|
|
||||||
position = 0;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getInt() {
|
public int getInt() {
|
||||||
checkGet(4);
|
checkGet(4);
|
||||||
int i = get() << 24;
|
int i = get() << 24;
|
||||||
|
@ -16,22 +16,23 @@ import java.nio.ByteBuffer;
|
|||||||
public abstract class SelectableChannel implements Channel {
|
public abstract class SelectableChannel implements Channel {
|
||||||
private SelectionKey key;
|
private SelectionKey key;
|
||||||
|
|
||||||
public abstract int read(ByteBuffer b) throws Exception;
|
public abstract SelectableChannel configureBlocking(boolean v)
|
||||||
public abstract int write(ByteBuffer b) throws Exception;
|
throws IOException;
|
||||||
public abstract boolean isOpen();
|
|
||||||
|
|
||||||
public SelectionKey register(Selector selector, int interestOps,
|
public SelectionKey register(Selector selector, int interestOps,
|
||||||
Object attachment)
|
Object attachment)
|
||||||
{
|
{
|
||||||
SelectionKey key = new SelectionKey
|
key = new SelectionKey(this, selector, interestOps, attachment);
|
||||||
(this, selector, interestOps, attachment);
|
|
||||||
selector.add(key);
|
selector.add(key);
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isOpen() {
|
||||||
|
return key != null;
|
||||||
|
}
|
||||||
|
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
if (key != null) {
|
if (key != null) {
|
||||||
key.selector().remove(key);
|
|
||||||
key = null;
|
key = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,8 +36,9 @@ public class SelectionKey {
|
|||||||
return interestOps;
|
return interestOps;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void interestOps(int v) {
|
public SelectionKey interestOps(int v) {
|
||||||
this.interestOps = v;
|
this.interestOps = v;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int readyOps() {
|
public int readyOps() {
|
||||||
|
@ -40,9 +40,9 @@ public abstract class Selector {
|
|||||||
|
|
||||||
public abstract boolean isOpen();
|
public abstract boolean isOpen();
|
||||||
|
|
||||||
public abstract void wakeup();
|
public abstract Selector wakeup();
|
||||||
|
|
||||||
public abstract void select(long interval) throws IOException;
|
public abstract int select(long interval) throws IOException;
|
||||||
|
|
||||||
public abstract void close();
|
public abstract void close();
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,11 @@
|
|||||||
|
|
||||||
package java.nio.channels;
|
package java.nio.channels;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
import java.net.ServerSocket;
|
||||||
|
|
||||||
public class ServerSocketChannel extends SocketChannel {
|
public class ServerSocketChannel extends SocketChannel {
|
||||||
public static ServerSocketChannel open() {
|
public static ServerSocketChannel open() {
|
||||||
@ -24,26 +28,32 @@ public class ServerSocketChannel extends SocketChannel {
|
|||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Handle socket() {
|
public ServerSocket socket() {
|
||||||
return new Handle();
|
return new Handle();
|
||||||
}
|
}
|
||||||
|
|
||||||
private int doAccept() throws Exception {
|
private int doAccept() throws IOException {
|
||||||
return natDoAccept(socket);
|
return natDoAccept(socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int doListen(String host, int port) throws Exception {
|
private int doListen(String host, int port) throws IOException {
|
||||||
return natDoListen(host, port);
|
return natDoListen(host, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Handle {
|
public class Handle extends ServerSocket {
|
||||||
public void bind(InetSocketAddress address)
|
public void bind(SocketAddress address)
|
||||||
throws Exception
|
throws IOException
|
||||||
{
|
{
|
||||||
socket = doListen(address.getHostName(), address.getPort());
|
InetSocketAddress a;
|
||||||
|
try {
|
||||||
|
a = (InetSocketAddress) address;
|
||||||
|
} catch (ClassCastException e) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
socket = doListen(a.getHostName(), a.getPort());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native int natDoAccept(int socket) throws Exception;
|
private static native int natDoAccept(int socket) throws IOException;
|
||||||
private static native int natDoListen(String host, int port) throws Exception;
|
private static native int natDoListen(String host, int port) throws IOException;
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
package java.nio.channels;
|
package java.nio.channels;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.SocketAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
@ -20,30 +21,33 @@ public class SocketChannel extends SelectableChannel
|
|||||||
public static final int InvalidSocket = -1;
|
public static final int InvalidSocket = -1;
|
||||||
|
|
||||||
protected int socket = InvalidSocket;
|
protected int socket = InvalidSocket;
|
||||||
protected boolean open = true;
|
|
||||||
protected boolean connected = false;
|
protected boolean connected = false;
|
||||||
|
|
||||||
public static SocketChannel open() {
|
public static SocketChannel open() {
|
||||||
return new SocketChannel();
|
return new SocketChannel();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void configureBlocking(boolean v) {
|
public SelectableChannel configureBlocking(boolean v) {
|
||||||
if (v) throw new IllegalArgumentException();
|
if (v) throw new IllegalArgumentException();
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void connect(InetSocketAddress address) throws Exception {
|
public boolean connect(SocketAddress address) throws Exception {
|
||||||
socket = doConnect(address.getHostName(), address.getPort());
|
InetSocketAddress a;
|
||||||
|
try {
|
||||||
|
a = (InetSocketAddress) address;
|
||||||
|
} catch (ClassCastException e) {
|
||||||
|
throw new UnsupportedAddressTypeException();
|
||||||
|
}
|
||||||
|
socket = doConnect(a.getHostName(), a.getPort());
|
||||||
|
return connected;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
super.close();
|
if (isOpen()) {
|
||||||
if (! open) return;
|
super.close();
|
||||||
closeSocket();
|
closeSocket();
|
||||||
open = false;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isOpen() {
|
|
||||||
return open;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int doConnect(String host, int port) throws Exception {
|
private int doConnect(String host, int port) throws Exception {
|
||||||
@ -54,7 +58,7 @@ public class SocketChannel extends SelectableChannel
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int read(ByteBuffer b) throws IOException {
|
public int read(ByteBuffer b) throws IOException {
|
||||||
if (! open) return -1;
|
if (! isOpen()) return -1;
|
||||||
if (b.remaining() == 0) return 0;
|
if (b.remaining() == 0) return 0;
|
||||||
int r = natRead(socket, b.array(), b.arrayOffset() + b.position(), b.remaining());
|
int r = natRead(socket, b.array(), b.arrayOffset() + b.position(), b.remaining());
|
||||||
if (r > 0) {
|
if (r > 0) {
|
||||||
|
@ -14,15 +14,10 @@ import java.io.IOException;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
class SocketSelector extends Selector {
|
class SocketSelector extends Selector {
|
||||||
private static final boolean IsWin32;
|
|
||||||
protected long state;
|
protected long state;
|
||||||
protected final Object lock = new Object();
|
protected final Object lock = new Object();
|
||||||
protected boolean woken = false;
|
protected boolean woken = false;
|
||||||
|
|
||||||
static {
|
|
||||||
IsWin32 = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SocketSelector() {
|
public SocketSelector() {
|
||||||
state = natInit();
|
state = natInit();
|
||||||
}
|
}
|
||||||
@ -31,7 +26,7 @@ class SocketSelector extends Selector {
|
|||||||
return state != 0;
|
return state != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void wakeup() {
|
public Selector wakeup() {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
if (! woken) {
|
if (! woken) {
|
||||||
woken = true;
|
woken = true;
|
||||||
@ -39,6 +34,7 @@ class SocketSelector extends Selector {
|
|||||||
natWakeup(state);
|
natWakeup(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean clearWoken() {
|
private boolean clearWoken() {
|
||||||
@ -52,10 +48,11 @@ class SocketSelector extends Selector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void select(long interval) throws IOException {
|
public synchronized int select(long interval) throws IOException {
|
||||||
selectedKeys.clear();
|
selectedKeys.clear();
|
||||||
|
|
||||||
if (clearWoken()) return;
|
if (clearWoken()) return 0;
|
||||||
|
|
||||||
int max=0;
|
int max=0;
|
||||||
for (Iterator<SelectionKey> it = keys.iterator();
|
for (Iterator<SelectionKey> it = keys.iterator();
|
||||||
it.hasNext();)
|
it.hasNext();)
|
||||||
@ -63,14 +60,14 @@ class SocketSelector extends Selector {
|
|||||||
SelectionKey key = it.next();
|
SelectionKey key = it.next();
|
||||||
SocketChannel c = (SocketChannel)key.channel();
|
SocketChannel c = (SocketChannel)key.channel();
|
||||||
int socket = c.socketFD();
|
int socket = c.socketFD();
|
||||||
if (! c.isOpen()) {
|
if (c.isOpen()) {
|
||||||
|
key.readyOps(0);
|
||||||
|
max = natSelectUpdateInterestSet
|
||||||
|
(socket, key.interestOps(), state, max);
|
||||||
|
} else {
|
||||||
natSelectClearAll(socket, state);
|
natSelectClearAll(socket, state);
|
||||||
it.remove();
|
it.remove();
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
key.readyOps(0);
|
|
||||||
max = natSelectUpdateInterestSet(socket, key.interestOps(), state, max);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int r = natDoSocketSelect(state, max, interval);
|
int r = natDoSocketSelect(state, max, interval);
|
||||||
@ -87,6 +84,8 @@ class SocketSelector extends Selector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
clearWoken();
|
clearWoken();
|
||||||
|
|
||||||
|
return selectedKeys.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void close() {
|
public void close() {
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
/* Copyright (c) 2008, 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.nio.channels;
|
||||||
|
|
||||||
|
public class UnsupportedAddressTypeException extends IllegalArgumentException {
|
||||||
|
public UnsupportedAddressTypeException() {
|
||||||
|
super(null, null);
|
||||||
|
}
|
||||||
|
}
|
@ -11,15 +11,54 @@
|
|||||||
package java.util;
|
package java.util;
|
||||||
|
|
||||||
public class Random {
|
public class Random {
|
||||||
public int nextInt(int n) {
|
private static final long Mask = 0x5DEECE66DL;
|
||||||
return nextInt() % n;
|
|
||||||
|
private static long nextSeed = 0;
|
||||||
|
|
||||||
|
private long seed;
|
||||||
|
|
||||||
|
public Random(long seed) {
|
||||||
|
setSeed(seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Random() {
|
||||||
|
setSeed((nextSeed++) ^ System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSeed(long seed) {
|
||||||
|
this.seed = (seed ^ Mask) & ((1L << 48) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int next(int bits) {
|
||||||
|
seed = ((seed * Mask) + 0xBL) & ((1L << 48) - 1);
|
||||||
|
return (int) (seed >>> (48 - bits));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int nextInt(int limit) {
|
||||||
|
if (limit <= 0) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((limit & -limit) == limit) {
|
||||||
|
// limit is a power of two
|
||||||
|
return (int) ((limit * (long) next(31)) >> 31);
|
||||||
|
}
|
||||||
|
|
||||||
|
int bits;
|
||||||
|
int value;
|
||||||
|
do {
|
||||||
|
bits = next(31);
|
||||||
|
value = bits % limit;
|
||||||
|
} while (bits - value + (limit - 1) < 0);
|
||||||
|
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int nextInt() {
|
public int nextInt() {
|
||||||
return (int)(Math.random()*Integer.MAX_VALUE);
|
return next(32);
|
||||||
}
|
}
|
||||||
|
|
||||||
public double nextDouble() {
|
public double nextDouble() {
|
||||||
return Math.random();
|
return (((long) next(26) << 27) + next(27)) / (double) (1L << 53);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,10 @@ public class Vector<T> implements List<T> {
|
|||||||
list.add(index, element);
|
list.add(index, element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void insertElementAt(T element, int index) {
|
||||||
|
add(index, element);
|
||||||
|
}
|
||||||
|
|
||||||
public synchronized boolean add(T element) {
|
public synchronized boolean add(T element) {
|
||||||
return list.add(element);
|
return list.add(element);
|
||||||
}
|
}
|
||||||
@ -57,6 +61,10 @@ public class Vector<T> implements List<T> {
|
|||||||
return list.set(index, value);
|
return list.set(index, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public T setElementAt(T value, int index) {
|
||||||
|
return set(index, value);
|
||||||
|
}
|
||||||
|
|
||||||
public T elementAt(int index) {
|
public T elementAt(int index) {
|
||||||
return get(index);
|
return get(index);
|
||||||
}
|
}
|
||||||
|
85
makefile
85
makefile
@ -52,12 +52,12 @@ strip-all = --strip-all
|
|||||||
|
|
||||||
rdynamic = -rdynamic
|
rdynamic = -rdynamic
|
||||||
|
|
||||||
warnings = -Wall -Wextra -Werror -Wunused-parameter \
|
warnings = -Wall -Wextra -Werror -Wunused-parameter -Winit-self
|
||||||
-Winit-self -Wconversion
|
|
||||||
|
|
||||||
common-cflags = $(warnings) -fno-rtti -fno-exceptions \
|
common-cflags = $(warnings) -fno-rtti -fno-exceptions \
|
||||||
-I$(JAVA_HOME)/include -idirafter $(src) -I$(native-build) \
|
-I$(JAVA_HOME)/include -idirafter $(src) -I$(native-build) \
|
||||||
-D__STDC_LIMIT_MACROS -D_JNI_IMPLEMENTATION_ -DAVIAN_VERSION=\"$(version)\"
|
-D__STDC_LIMIT_MACROS -D_JNI_IMPLEMENTATION_ -DAVIAN_VERSION=\"$(version)\" \
|
||||||
|
-DBOOT_CLASSPATH=\"[classpathJar]\"
|
||||||
|
|
||||||
build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \
|
build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \
|
||||||
-I$(JAVA_HOME)/include/linux -I$(src) -pthread
|
-I$(JAVA_HOME)/include/linux -I$(src) -pthread
|
||||||
@ -66,7 +66,7 @@ cflags = $(build-cflags)
|
|||||||
|
|
||||||
common-lflags = -lm -lz
|
common-lflags = -lm -lz
|
||||||
|
|
||||||
lflags = $(common-lflags) -lpthread -ldl -rdynamic
|
lflags = $(common-lflags) -lpthread -ldl
|
||||||
|
|
||||||
system = posix
|
system = posix
|
||||||
asm = x86
|
asm = x86
|
||||||
@ -75,6 +75,11 @@ object-arch = i386:x86-64
|
|||||||
object-format = elf64-x86-64
|
object-format = elf64-x86-64
|
||||||
pointer-size = 8
|
pointer-size = 8
|
||||||
|
|
||||||
|
so-prefix = lib
|
||||||
|
so-suffix = .so
|
||||||
|
|
||||||
|
shared = -shared
|
||||||
|
|
||||||
ifeq ($(arch),i386)
|
ifeq ($(arch),i386)
|
||||||
object-arch = i386
|
object-arch = i386
|
||||||
object-format = elf32-i386
|
object-format = elf32-i386
|
||||||
@ -85,8 +90,11 @@ ifeq ($(platform),darwin)
|
|||||||
build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \
|
build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \
|
||||||
-I$(JAVA_HOME)/include/linux -I$(src)
|
-I$(JAVA_HOME)/include/linux -I$(src)
|
||||||
lflags = $(common-lflags) -ldl -framework CoreFoundation
|
lflags = $(common-lflags) -ldl -framework CoreFoundation
|
||||||
|
rdynamic =
|
||||||
strip-all = -S -x
|
strip-all = -S -x
|
||||||
binaryToMacho = $(native-build)/binaryToMacho
|
binaryToMacho = $(native-build)/binaryToMacho
|
||||||
|
so-suffix = .jnilib
|
||||||
|
shared = -dynamiclib
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(platform),windows)
|
ifeq ($(platform),windows)
|
||||||
@ -96,6 +104,9 @@ ifeq ($(platform),windows)
|
|||||||
system = windows
|
system = windows
|
||||||
object-format = pe-i386
|
object-format = pe-i386
|
||||||
|
|
||||||
|
so-prefix =
|
||||||
|
so-suffix = .dll
|
||||||
|
|
||||||
cxx = i586-mingw32msvc-g++
|
cxx = i586-mingw32msvc-g++
|
||||||
cc = i586-mingw32msvc-gcc
|
cc = i586-mingw32msvc-gcc
|
||||||
dlltool = i586-mingw32msvc-dlltool
|
dlltool = i586-mingw32msvc-dlltool
|
||||||
@ -104,7 +115,7 @@ ifeq ($(platform),windows)
|
|||||||
objcopy = i586-mingw32msvc-objcopy
|
objcopy = i586-mingw32msvc-objcopy
|
||||||
|
|
||||||
rdynamic = -Wl,--export-dynamic
|
rdynamic = -Wl,--export-dynamic
|
||||||
lflags = -L$(lib) $(common-lflags) -lws2_32 -Wl,--kill-at -mwindows -mconsole
|
lflags = -L$(lib) $(common-lflags) -lws2_32 -mwindows -mconsole
|
||||||
cflags = $(common-cflags) -I$(inc)
|
cflags = $(common-cflags) -I$(inc)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@ -185,9 +196,12 @@ vm-cpp-objects = $(call cpp-objects,$(vm-sources),$(src),$(native-build))
|
|||||||
vm-asm-objects = $(call asm-objects,$(vm-asm-sources),$(src),$(native-build))
|
vm-asm-objects = $(call asm-objects,$(vm-asm-sources),$(src),$(native-build))
|
||||||
vm-objects = $(vm-cpp-objects) $(vm-asm-objects)
|
vm-objects = $(vm-cpp-objects) $(vm-asm-objects)
|
||||||
|
|
||||||
driver-sources = $(src)/main.cpp
|
driver-source = $(src)/main.cpp
|
||||||
|
driver-object = $(native-build)/main.o
|
||||||
|
driver-dynamic-object = $(native-build)/main-dynamic.o
|
||||||
|
|
||||||
driver-object = $(call cpp-objects,$(driver-sources),$(src),$(native-build))
|
boot-source = $(src)/boot.cpp
|
||||||
|
boot-object = $(native-build)/boot.o
|
||||||
|
|
||||||
generator-headers = $(src)/constants.h
|
generator-headers = $(src)/constants.h
|
||||||
generator-sources = $(src)/type-generator.cpp
|
generator-sources = $(src)/type-generator.cpp
|
||||||
@ -195,8 +209,10 @@ generator-objects = \
|
|||||||
$(call cpp-objects,$(generator-sources),$(src),$(native-build))
|
$(call cpp-objects,$(generator-sources),$(src),$(native-build))
|
||||||
generator = $(native-build)/generator
|
generator = $(native-build)/generator
|
||||||
|
|
||||||
libvm = $(native-build)/lib$(name).a
|
static-library = $(native-build)/lib$(name).a
|
||||||
vm = $(native-build)/$(name)
|
executable = $(native-build)/$(name)
|
||||||
|
dynamic-library = $(native-build)/$(so-prefix)$(name)$(so-suffix)
|
||||||
|
executable-dynamic = $(native-build)/$(name)-dynamic
|
||||||
|
|
||||||
classpath-sources = $(shell find $(classpath) -name '*.java')
|
classpath-sources = $(shell find $(classpath) -name '*.java')
|
||||||
classpath-classes = \
|
classpath-classes = \
|
||||||
@ -216,31 +232,36 @@ flags = -cp $(test-build)
|
|||||||
args = $(flags) $(input)
|
args = $(flags) $(input)
|
||||||
|
|
||||||
.PHONY: build
|
.PHONY: build
|
||||||
build: $(vm) $(libvm) $(classpath-dep) $(test-dep)
|
build: $(static-library) $(executable) $(dynamic-library) \
|
||||||
|
$(executable-dynamic) $(classpath-dep) $(test-dep)
|
||||||
|
|
||||||
$(test-classes): $(classpath-dep)
|
$(test-classes): $(classpath-dep)
|
||||||
|
|
||||||
.PHONY: run
|
.PHONY: run
|
||||||
run: build
|
run: build
|
||||||
$(vm) $(args)
|
$(executable) $(args)
|
||||||
|
|
||||||
.PHONY: debug
|
.PHONY: debug
|
||||||
debug: build
|
debug: build
|
||||||
gdb --args $(vm) $(args)
|
gdb --args $(executable) $(args)
|
||||||
|
|
||||||
.PHONY: vg
|
.PHONY: vg
|
||||||
vg: build
|
vg: build
|
||||||
$(vg) $(vm) $(args)
|
$(vg) $(executable) $(args)
|
||||||
|
|
||||||
.PHONY: test
|
.PHONY: test
|
||||||
test: build
|
test: build
|
||||||
/bin/bash $(test)/test.sh 2>/dev/null \
|
/bin/bash $(test)/test.sh 2>/dev/null \
|
||||||
$(vm) $(mode) "$(flags)" \
|
$(executable) $(mode) "$(flags)" \
|
||||||
$(call class-names,$(test-build),$(test-classes))
|
$(call class-names,$(test-build),$(test-classes))
|
||||||
|
|
||||||
.PHONY: javadoc
|
.PHONY: javadoc
|
||||||
javadoc:
|
javadoc:
|
||||||
javadoc -sourcepath classpath -d build/javadoc -subpackages java
|
javadoc -sourcepath classpath -d build/javadoc -subpackages java \
|
||||||
|
-windowtitle "Avian v$(version) Class Library API" \
|
||||||
|
-doctitle "Avian v$(version) Class Library API" \
|
||||||
|
-header "Avian v$(version)" \
|
||||||
|
-bottom "<a href=\"http://oss.readytalk.com/avian/\">http://oss.readytalk.com/avian</a>"
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
@ -293,7 +314,16 @@ $(vm-cpp-objects): $(native-build)/%.o: $(src)/%.cpp $(vm-depends)
|
|||||||
$(vm-asm-objects): $(native-build)/%-asm.o: $(src)/%.S
|
$(vm-asm-objects): $(native-build)/%-asm.o: $(src)/%.S
|
||||||
$(compile-object)
|
$(compile-object)
|
||||||
|
|
||||||
$(driver-object): $(native-build)/%.o: $(src)/%.cpp
|
$(driver-object): $(driver-source)
|
||||||
|
$(compile-object)
|
||||||
|
|
||||||
|
$(driver-dynamic-object): $(driver-source)
|
||||||
|
@echo "compiling $(@)"
|
||||||
|
@mkdir -p $(dir $(@))
|
||||||
|
$(cxx) $(cflags) -DBOOT_LIBRARY=\"$(so-prefix)$(name)$(so-suffix)\" \
|
||||||
|
-c $(<) -o $(@)
|
||||||
|
|
||||||
|
$(boot-object): $(boot-source)
|
||||||
$(compile-object)
|
$(compile-object)
|
||||||
|
|
||||||
$(build)/classpath.jar: $(classpath-dep)
|
$(build)/classpath.jar: $(classpath-dep)
|
||||||
@ -305,9 +335,10 @@ $(binaryToMacho): $(src)/binaryToMacho.cpp
|
|||||||
$(cxx) $(^) -o $(@)
|
$(cxx) $(^) -o $(@)
|
||||||
|
|
||||||
$(classpath-object): $(build)/classpath.jar $(binaryToMacho)
|
$(classpath-object): $(build)/classpath.jar $(binaryToMacho)
|
||||||
|
@echo "creating $(@)"
|
||||||
ifeq ($(platform),darwin)
|
ifeq ($(platform),darwin)
|
||||||
$(binaryToMacho) $(build)/classpath.jar \
|
$(binaryToMacho) $(build)/classpath.jar \
|
||||||
__binary_classpath_jar_start __binary_classpath_jar_size > $(@)
|
__binary_classpath_jar_start __binary_classpath_jar_end > $(@)
|
||||||
else
|
else
|
||||||
(wd=$$(pwd); \
|
(wd=$$(pwd); \
|
||||||
cd $(build); \
|
cd $(build); \
|
||||||
@ -324,23 +355,37 @@ $(generator-objects): $(native-build)/%.o: $(src)/%.cpp
|
|||||||
$(jni-objects): $(native-build)/%.o: $(classpath)/%.cpp
|
$(jni-objects): $(native-build)/%.o: $(classpath)/%.cpp
|
||||||
$(compile-object)
|
$(compile-object)
|
||||||
|
|
||||||
$(libvm): $(vm-objects) $(jni-objects)
|
$(static-library): $(vm-objects) $(jni-objects)
|
||||||
@echo "creating $(@)"
|
@echo "creating $(@)"
|
||||||
rm -rf $(@)
|
rm -rf $(@)
|
||||||
$(ar) cru $(@) $(^)
|
$(ar) cru $(@) $(^)
|
||||||
$(ranlib) $(@)
|
$(ranlib) $(@)
|
||||||
|
|
||||||
$(vm): $(vm-objects) $(classpath-object) $(jni-objects) $(driver-object)
|
$(executable): \
|
||||||
|
$(vm-objects) $(classpath-object) $(jni-objects) $(driver-object) \
|
||||||
|
$(boot-object)
|
||||||
@echo "linking $(@)"
|
@echo "linking $(@)"
|
||||||
ifeq ($(platform),windows)
|
ifeq ($(platform),windows)
|
||||||
$(dlltool) -z $(@).def $(^)
|
$(dlltool) -z $(@).def $(^)
|
||||||
$(dlltool) -k -d $(@).def -e $(@).exp
|
$(dlltool) -k -d $(@).def -e $(@).exp
|
||||||
$(cc) $(@).exp $(^) $(lflags) -o $(@)
|
$(cc) $(@).exp $(^) $(lflags) -o $(@)
|
||||||
else
|
else
|
||||||
$(cc) $(^) $(lflags) -o $(@)
|
$(cc) $(^) $(rdynamic) $(lflags) -o $(@)
|
||||||
endif
|
endif
|
||||||
$(strip) $(strip-all) $(@)
|
$(strip) $(strip-all) $(@)
|
||||||
|
|
||||||
|
$(dynamic-library): \
|
||||||
|
$(vm-objects) $(classpath-object) $(dynamic-object) $(jni-objects) \
|
||||||
|
$(boot-object)
|
||||||
|
@echo "linking $(@)"
|
||||||
|
$(cc) $(^) $(shared) $(lflags) -o $(@)
|
||||||
|
$(strip) $(strip-all) $(@)
|
||||||
|
|
||||||
|
$(executable-dynamic): $(driver-dynamic-object) $(dynamic-library)
|
||||||
|
@echo "linking $(@)"
|
||||||
|
$(cc) $(^) $(lflags) -o $(@)
|
||||||
|
$(strip) $(strip-all) $(@)
|
||||||
|
|
||||||
$(generator): $(generator-objects)
|
$(generator): $(generator-objects)
|
||||||
@echo "linking $(@)"
|
@echo "linking $(@)"
|
||||||
$(build-cc) $(^) -o $(@)
|
$(build-cc) $(^) -o $(@)
|
||||||
|
@ -165,12 +165,12 @@ setting the classpath to "[bootJar]".
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
extern const uint8_t SYMBOL(start)[];
|
extern const uint8_t SYMBOL(start)[];
|
||||||
extern const uint8_t SYMBOL(size)[];
|
extern const uint8_t SYMBOL(end)[];
|
||||||
|
|
||||||
EXPORT const uint8_t*
|
EXPORT const uint8_t*
|
||||||
bootJar(unsigned* size)
|
bootJar(unsigned* size)
|
||||||
{
|
{
|
||||||
*size = reinterpret_cast<uintptr_t>(SYMBOL(size));
|
*size = SYMBOL(end) - SYMBOL(start);
|
||||||
return SYMBOL(start);
|
return SYMBOL(start);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,9 +18,9 @@ namespace vm {
|
|||||||
class Allocator {
|
class Allocator {
|
||||||
public:
|
public:
|
||||||
virtual ~Allocator() { }
|
virtual ~Allocator() { }
|
||||||
virtual void* tryAllocate(unsigned size, bool executable) = 0;
|
virtual void* tryAllocate(unsigned size) = 0;
|
||||||
virtual void* allocate(unsigned size, bool executable) = 0;
|
virtual void* allocate(unsigned size) = 0;
|
||||||
virtual void free(const void* p, unsigned size, bool executable) = 0;
|
virtual void free(const void* p, unsigned size) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace vm
|
} // namespace vm
|
||||||
|
@ -120,17 +120,14 @@ class Assembler {
|
|||||||
|
|
||||||
class Memory: public Operand {
|
class Memory: public Operand {
|
||||||
public:
|
public:
|
||||||
Memory(int base, int offset, int index = NoRegister, unsigned scale = 0,
|
Memory(int base, int offset, int index = NoRegister, unsigned scale = 0):
|
||||||
TraceHandler* traceHandler = 0):
|
base(base), offset(offset), index(index), scale(scale)
|
||||||
base(base), offset(offset), index(index), scale(scale),
|
|
||||||
traceHandler(traceHandler)
|
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
int base;
|
int base;
|
||||||
int offset;
|
int offset;
|
||||||
int index;
|
int index;
|
||||||
unsigned scale;
|
unsigned scale;
|
||||||
TraceHandler* traceHandler;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Client {
|
class Client {
|
||||||
|
@ -30,10 +30,10 @@ pad(unsigned n)
|
|||||||
|
|
||||||
void
|
void
|
||||||
writeObject(FILE* out, const uint8_t* data, unsigned size,
|
writeObject(FILE* out, const uint8_t* data, unsigned size,
|
||||||
const char* dataName, const char* sizeName)
|
const char* startName, const char* endName)
|
||||||
{
|
{
|
||||||
unsigned dataNameLength = strlen(dataName) + 1;
|
unsigned startNameLength = strlen(startName) + 1;
|
||||||
unsigned sizeNameLength = strlen(sizeName) + 1;
|
unsigned endNameLength = strlen(endName) + 1;
|
||||||
|
|
||||||
mach_header header = {
|
mach_header header = {
|
||||||
MH_MAGIC, // magic
|
MH_MAGIC, // magic
|
||||||
@ -96,7 +96,7 @@ writeObject(FILE* out, const uint8_t* data, unsigned size,
|
|||||||
+ sizeof(symtab_command)
|
+ sizeof(symtab_command)
|
||||||
+ pad(size)
|
+ pad(size)
|
||||||
+ (sizeof(struct nlist) * 2), // stroff
|
+ (sizeof(struct nlist) * 2), // stroff
|
||||||
1 + dataNameLength + sizeNameLength, // strsize
|
1 + startNameLength + endNameLength, // strsize
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nlist symbolList[] = {
|
struct nlist symbolList[] = {
|
||||||
@ -108,9 +108,9 @@ writeObject(FILE* out, const uint8_t* data, unsigned size,
|
|||||||
0 // n_value
|
0 // n_value
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
reinterpret_cast<char*>(1 + dataNameLength), // n_un
|
reinterpret_cast<char*>(1 + startNameLength), // n_un
|
||||||
N_ABS | N_EXT, // n_type
|
N_SECT | N_EXT, // n_type
|
||||||
NO_SECT, // n_sect
|
1, // n_sect
|
||||||
0, // n_desc
|
0, // n_desc
|
||||||
size // n_value
|
size // n_value
|
||||||
}
|
}
|
||||||
@ -127,8 +127,8 @@ writeObject(FILE* out, const uint8_t* data, unsigned size,
|
|||||||
fwrite(&symbolList, 1, sizeof(symbolList), out);
|
fwrite(&symbolList, 1, sizeof(symbolList), out);
|
||||||
|
|
||||||
fputc(0, out);
|
fputc(0, out);
|
||||||
fwrite(dataName, 1, dataNameLength, out);
|
fwrite(startName, 1, startNameLength, out);
|
||||||
fwrite(sizeName, 1, sizeNameLength, out);
|
fwrite(endName, 1, endNameLength, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
@ -138,7 +138,7 @@ main(int argc, const char** argv)
|
|||||||
{
|
{
|
||||||
if (argc != 4) {
|
if (argc != 4) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"usage: %s <input file> <data symbol name> <size symbol name>\n",
|
"usage: %s <input file> <start symbol name> <end symbol name>\n",
|
||||||
argv[0]);
|
argv[0]);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
29
src/boot.cpp
Normal file
29
src/boot.cpp
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#include "stdint.h"
|
||||||
|
#include "stdlib.h"
|
||||||
|
|
||||||
|
// since we don't link against libstdc++, we must implement some dummy
|
||||||
|
// functions:
|
||||||
|
extern "C" void __cxa_pure_virtual(void) { abort(); }
|
||||||
|
void operator delete(void*) { abort(); }
|
||||||
|
|
||||||
|
#ifdef __MINGW32__
|
||||||
|
# define EXPORT __declspec(dllexport)
|
||||||
|
# define SYMBOL(x) binary_classpath_jar_##x
|
||||||
|
#else
|
||||||
|
# define EXPORT __attribute__ ((visibility("default")))
|
||||||
|
# define SYMBOL(x) _binary_classpath_jar_##x
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
extern const uint8_t SYMBOL(start)[];
|
||||||
|
extern const uint8_t SYMBOL(end)[];
|
||||||
|
|
||||||
|
EXPORT const uint8_t*
|
||||||
|
classpathJar(unsigned* size)
|
||||||
|
{
|
||||||
|
*size = SYMBOL(end) - SYMBOL(start);
|
||||||
|
return SYMBOL(start);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -47,6 +47,19 @@ search(Thread* t, jstring name, object (*op)(Thread*, object),
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
enumerateThreads(Thread* t, Thread* x, object array, unsigned* index,
|
||||||
|
unsigned limit)
|
||||||
|
{
|
||||||
|
if (*index < limit) {
|
||||||
|
set(t, array, ArrayBody + (*index * BytesPerWord), x->javaThread);
|
||||||
|
|
||||||
|
if (x->peer) enumerateThreads(t, x->peer, array, index, limit);
|
||||||
|
|
||||||
|
if (x->child) enumerateThreads(t, x->child, array, index, limit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
extern "C" JNIEXPORT jstring JNICALL
|
extern "C" JNIEXPORT jstring JNICALL
|
||||||
@ -134,10 +147,10 @@ Java_java_lang_ClassLoader_defineClass
|
|||||||
ENTER(t, Thread::ActiveState);
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
uint8_t* buffer = static_cast<uint8_t*>
|
uint8_t* buffer = static_cast<uint8_t*>
|
||||||
(t->m->heap->allocate(length, false));
|
(t->m->heap->allocate(length));
|
||||||
memcpy(buffer, &byteArrayBody(t, *b, offset), length);
|
memcpy(buffer, &byteArrayBody(t, *b, offset), length);
|
||||||
object c = parseClass(t, buffer, length);
|
object c = parseClass(t, buffer, length);
|
||||||
t->m->heap->free(buffer, length, false);
|
t->m->heap->free(buffer, length);
|
||||||
return makeLocalReference(t, c);
|
return makeLocalReference(t, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -697,6 +710,36 @@ Java_java_lang_Thread_interrupt(Thread* t, jclass, jlong peer)
|
|||||||
interrupt(t, reinterpret_cast<Thread*>(peer));
|
interrupt(t, reinterpret_cast<Thread*>(peer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT jobject JNICALL
|
||||||
|
Java_java_lang_Thread_getTrace(Thread* t, jclass, jlong peer)
|
||||||
|
{
|
||||||
|
if (reinterpret_cast<Thread*>(peer) == t) {
|
||||||
|
return makeLocalReference(t, makeTrace(t));
|
||||||
|
} else {
|
||||||
|
return makeLocalReference
|
||||||
|
(t, t->m->processor->getStackTrace(t, reinterpret_cast<Thread*>(peer)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT jint JNICALL
|
||||||
|
Java_java_lang_Thread_activeCount(Thread* t, jclass)
|
||||||
|
{
|
||||||
|
return t->m->liveCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT jint JNICALL
|
||||||
|
Java_java_lang_Thread_enumerate(Thread* t, jclass, jobjectArray array)
|
||||||
|
{
|
||||||
|
ACQUIRE_RAW(t, t->m->stateLock);
|
||||||
|
|
||||||
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
|
unsigned count = min(t->m->liveCount, objectArrayLength(t, *array));
|
||||||
|
unsigned index = 0;
|
||||||
|
enumerateThreads(t, t->m->rootThread, *array, &index, count);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT jlong JNICALL
|
extern "C" JNIEXPORT jlong JNICALL
|
||||||
Java_java_net_URL_00024ResourceInputStream_open
|
Java_java_net_URL_00024ResourceInputStream_open
|
||||||
(Thread* t, jclass, jstring path)
|
(Thread* t, jclass, jstring path)
|
||||||
|
913
src/compile.cpp
913
src/compile.cpp
File diff suppressed because it is too large
Load Diff
@ -745,9 +745,8 @@ register_(Context* c, int low, int high = NoRegister)
|
|||||||
|
|
||||||
class MemoryValue: public Value {
|
class MemoryValue: public Value {
|
||||||
public:
|
public:
|
||||||
MemoryValue(int base, int offset, int index, unsigned scale,
|
MemoryValue(int base, int offset, int index, unsigned scale):
|
||||||
TraceHandler* traceHandler):
|
value(base, offset, index, scale)
|
||||||
value(base, offset, index, scale, traceHandler)
|
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
virtual OperandType type(Context*) { return Memory; }
|
virtual OperandType type(Context*) { return Memory; }
|
||||||
@ -785,8 +784,8 @@ class MemoryValue: public Value {
|
|||||||
class AbstractMemoryValue: public MemoryValue {
|
class AbstractMemoryValue: public MemoryValue {
|
||||||
public:
|
public:
|
||||||
AbstractMemoryValue(MyOperand* base, int offset, MyOperand* index,
|
AbstractMemoryValue(MyOperand* base, int offset, MyOperand* index,
|
||||||
unsigned scale, TraceHandler* traceHandler):
|
unsigned scale):
|
||||||
MemoryValue(NoRegister, offset, NoRegister, scale, traceHandler),
|
MemoryValue(NoRegister, offset, NoRegister, scale),
|
||||||
base_(base), index_(index)
|
base_(base), index_(index)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
@ -831,10 +830,10 @@ class AbstractMemoryValue: public MemoryValue {
|
|||||||
|
|
||||||
AbstractMemoryValue*
|
AbstractMemoryValue*
|
||||||
memory(Context* c, MyOperand* base, int offset, MyOperand* index,
|
memory(Context* c, MyOperand* base, int offset, MyOperand* index,
|
||||||
unsigned scale, TraceHandler* traceHandler)
|
unsigned scale)
|
||||||
{
|
{
|
||||||
return new (c->zone->allocate(sizeof(AbstractMemoryValue)))
|
return new (c->zone->allocate(sizeof(AbstractMemoryValue)))
|
||||||
AbstractMemoryValue(base, offset, index, scale, traceHandler);
|
AbstractMemoryValue(base, offset, index, scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
class StackValue: public Value {
|
class StackValue: public Value {
|
||||||
@ -1996,13 +1995,12 @@ class MyCompiler: public Compiler {
|
|||||||
virtual Operand* memory(Operand* base,
|
virtual Operand* memory(Operand* base,
|
||||||
int displacement = 0,
|
int displacement = 0,
|
||||||
Operand* index = 0,
|
Operand* index = 0,
|
||||||
unsigned scale = 1,
|
unsigned scale = 1)
|
||||||
TraceHandler* traceHandler = 0)
|
|
||||||
{
|
{
|
||||||
MyOperand* result = operand
|
MyOperand* result = operand
|
||||||
(&c, ::memory
|
(&c, ::memory
|
||||||
(&c, static_cast<MyOperand*>(base), displacement,
|
(&c, static_cast<MyOperand*>(base), displacement,
|
||||||
static_cast<MyOperand*>(index), scale, traceHandler));
|
static_cast<MyOperand*>(index), scale));
|
||||||
|
|
||||||
appendMemory(&c, static_cast<MyOperand*>(base),
|
appendMemory(&c, static_cast<MyOperand*>(base),
|
||||||
static_cast<MyOperand*>(index), result);
|
static_cast<MyOperand*>(index), result);
|
||||||
|
@ -45,8 +45,8 @@ class Compiler {
|
|||||||
virtual Operand* memory(Operand* base,
|
virtual Operand* memory(Operand* base,
|
||||||
int displacement = 0,
|
int displacement = 0,
|
||||||
Operand* index = 0,
|
Operand* index = 0,
|
||||||
unsigned scale = 1,
|
unsigned scale = 1) = 0;
|
||||||
TraceHandler* traceHandler = 0) = 0;
|
|
||||||
virtual Operand* stack() = 0;
|
virtual Operand* stack() = 0;
|
||||||
virtual Operand* base() = 0;
|
virtual Operand* base() = 0;
|
||||||
virtual Operand* thread() = 0;
|
virtual Operand* thread() = 0;
|
||||||
|
@ -19,26 +19,19 @@ namespace {
|
|||||||
void*
|
void*
|
||||||
allocate(System* s, unsigned size)
|
allocate(System* s, unsigned size)
|
||||||
{
|
{
|
||||||
void* p = s->tryAllocate(size, false);
|
void* p = s->tryAllocate(size);
|
||||||
if (p == 0) abort();
|
if (p == 0) abort();
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
free(System* s, const void* p, unsigned size)
|
|
||||||
{
|
|
||||||
s->free(p, size, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char*
|
const char*
|
||||||
append(System* s, unsigned* length, const char* a, const char* b,
|
append(System* s, const char* a, const char* b,
|
||||||
const char* c)
|
const char* c)
|
||||||
{
|
{
|
||||||
unsigned al = strlen(a);
|
unsigned al = strlen(a);
|
||||||
unsigned bl = strlen(b);
|
unsigned bl = strlen(b);
|
||||||
unsigned cl = strlen(c);
|
unsigned cl = strlen(c);
|
||||||
*length = al + bl + cl;
|
char* p = static_cast<char*>(allocate(s, (al + bl + cl) + 1));
|
||||||
char* p = static_cast<char*>(allocate(s, *length + 1));
|
|
||||||
memcpy(p, a, al);
|
memcpy(p, a, al);
|
||||||
memcpy(p + al, b, bl);
|
memcpy(p + al, b, bl);
|
||||||
memcpy(p + al + bl, c, cl + 1);
|
memcpy(p + al + bl, c, cl + 1);
|
||||||
@ -46,11 +39,10 @@ append(System* s, unsigned* length, const char* a, const char* b,
|
|||||||
}
|
}
|
||||||
|
|
||||||
const char*
|
const char*
|
||||||
copy(System* s, unsigned* length, const char* a)
|
copy(System* s, const char* a)
|
||||||
{
|
{
|
||||||
unsigned al = strlen(a);
|
unsigned al = strlen(a);
|
||||||
*length = al;
|
char* p = static_cast<char*>(allocate(s, al + 1));
|
||||||
char* p = static_cast<char*>(allocate(s, *length + 1));
|
|
||||||
memcpy(p, a, al + 1);
|
memcpy(p, a, al + 1);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
@ -78,16 +70,15 @@ class Element {
|
|||||||
|
|
||||||
class DirectoryElement: public Element {
|
class DirectoryElement: public Element {
|
||||||
public:
|
public:
|
||||||
DirectoryElement(System* s, const char* name, unsigned nameLength):
|
DirectoryElement(System* s, const char* name):
|
||||||
s(s), name(name), nameLength(nameLength)
|
s(s), name(name)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
virtual System::Region* find(const char* name) {
|
virtual System::Region* find(const char* name) {
|
||||||
unsigned length;
|
const char* file = append(s, this->name, "/", name);
|
||||||
const char* file = append(s, &length, this->name, "/", name);
|
|
||||||
System::Region* region;
|
System::Region* region;
|
||||||
System::Status status = s->map(®ion, file);
|
System::Status status = s->map(®ion, file);
|
||||||
free(s, file, length + 1);
|
s->free(file);
|
||||||
|
|
||||||
if (s->success(status)) {
|
if (s->success(status)) {
|
||||||
return region;
|
return region;
|
||||||
@ -97,21 +88,19 @@ class DirectoryElement: public Element {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual bool exists(const char* name) {
|
virtual bool exists(const char* name) {
|
||||||
unsigned length;
|
const char* file = append(s, this->name, "/", name);
|
||||||
const char* file = append(s, &length, this->name, "/", name);
|
|
||||||
System::FileType type = s->identify(file);
|
System::FileType type = s->identify(file);
|
||||||
free(s, file, length + 1);
|
s->free(file);
|
||||||
return type != System::DoesNotExist;
|
return type != System::DoesNotExist;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void dispose() {
|
virtual void dispose() {
|
||||||
free(s, name, nameLength + 1);
|
s->free(name);
|
||||||
free(s, this, sizeof(*this));
|
s->free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
const char* name;
|
const char* name;
|
||||||
unsigned nameLength;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class PointerRegion: public System::Region {
|
class PointerRegion: public System::Region {
|
||||||
@ -131,7 +120,7 @@ class PointerRegion: public System::Region {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void dispose() {
|
virtual void dispose() {
|
||||||
free(s, this, sizeof(*this));
|
s->free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
@ -155,7 +144,7 @@ class DataRegion: public System::Region {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void dispose() {
|
virtual void dispose() {
|
||||||
free(s, this, sizeof(*this) + length_);
|
s->free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
@ -376,8 +365,8 @@ class JarIndex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void dispose() {
|
void dispose() {
|
||||||
free(s, nodes, sizeof(Node) * capacity);
|
s->free(nodes);
|
||||||
free(s, this, sizeof(*this) + (sizeof(Node*) * capacity));
|
s->free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
@ -390,8 +379,8 @@ class JarIndex {
|
|||||||
|
|
||||||
class JarElement: public Element {
|
class JarElement: public Element {
|
||||||
public:
|
public:
|
||||||
JarElement(System* s, const char* name, unsigned nameLength):
|
JarElement(System* s, const char* name):
|
||||||
s(s), name(name), nameLength(nameLength), index(0)
|
s(s), name(name), index(0)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
virtual void init() {
|
virtual void init() {
|
||||||
@ -421,33 +410,32 @@ class JarElement: public Element {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void dispose() {
|
virtual void dispose() {
|
||||||
free(s, name, nameLength + 1);
|
s->free(name);
|
||||||
if (index) {
|
if (index) {
|
||||||
index->dispose();
|
index->dispose();
|
||||||
}
|
}
|
||||||
if (region) {
|
if (region) {
|
||||||
region->dispose();
|
region->dispose();
|
||||||
}
|
}
|
||||||
free(s, this, sizeof(*this));
|
s->free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
const char* name;
|
const char* name;
|
||||||
unsigned nameLength;
|
|
||||||
System::Region* region;
|
System::Region* region;
|
||||||
JarIndex* index;
|
JarIndex* index;
|
||||||
};
|
};
|
||||||
|
|
||||||
class BuiltinElement: public JarElement {
|
class BuiltinElement: public JarElement {
|
||||||
public:
|
public:
|
||||||
BuiltinElement(System* s, const char* name, unsigned nameLength):
|
BuiltinElement(System* s, const char* name, const char* libraryName):
|
||||||
JarElement(s, name, nameLength)
|
JarElement(s, name),
|
||||||
|
libraryName(libraryName ? copy(s, libraryName) : 0)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
virtual void init() {
|
virtual void init() {
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
System::Library* library;
|
if (s->success(s->load(&library, libraryName, false))) {
|
||||||
if (s->success(s->load(&library, 0, false))) {
|
|
||||||
void* p = library->resolve(name);
|
void* p = library->resolve(name);
|
||||||
if (p) {
|
if (p) {
|
||||||
uint8_t* (*function)(unsigned*);
|
uint8_t* (*function)(unsigned*);
|
||||||
@ -461,14 +449,22 @@ class BuiltinElement: public JarElement {
|
|||||||
index = JarIndex::open(s, region);
|
index = JarIndex::open(s, region);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
library->disposeAll();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void dispose() {
|
||||||
|
library->disposeAll();
|
||||||
|
s->free(libraryName);
|
||||||
|
JarElement::dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
System::Library* library;
|
||||||
|
const char* libraryName;
|
||||||
};
|
};
|
||||||
|
|
||||||
Element*
|
Element*
|
||||||
parsePath(System* s, const char* path)
|
parsePath(System* s, const char* path, const char* bootLibrary)
|
||||||
{
|
{
|
||||||
class Tokenizer {
|
class Tokenizer {
|
||||||
public:
|
public:
|
||||||
@ -509,7 +505,7 @@ parsePath(System* s, const char* path)
|
|||||||
name[token.length - 2] = 0;
|
name[token.length - 2] = 0;
|
||||||
|
|
||||||
e = new (allocate(s, sizeof(BuiltinElement)))
|
e = new (allocate(s, sizeof(BuiltinElement)))
|
||||||
BuiltinElement(s, name, token.length - 2);
|
BuiltinElement(s, name, bootLibrary);
|
||||||
} else {
|
} else {
|
||||||
char* name = static_cast<char*>(allocate(s, token.length + 1));
|
char* name = static_cast<char*>(allocate(s, token.length + 1));
|
||||||
memcpy(name, token.s, token.length);
|
memcpy(name, token.s, token.length);
|
||||||
@ -517,17 +513,16 @@ parsePath(System* s, const char* path)
|
|||||||
|
|
||||||
switch (s->identify(name)) {
|
switch (s->identify(name)) {
|
||||||
case System::File: {
|
case System::File: {
|
||||||
e = new (allocate(s, sizeof(JarElement)))
|
e = new (allocate(s, sizeof(JarElement))) JarElement(s, name);
|
||||||
JarElement(s, name, token.length);
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case System::Directory: {
|
case System::Directory: {
|
||||||
e = new (allocate(s, sizeof(DirectoryElement)))
|
e = new (allocate(s, sizeof(DirectoryElement)))
|
||||||
DirectoryElement(s, name, token.length);
|
DirectoryElement(s, name);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
free(s, name, token.length + 1);
|
s->free(name);
|
||||||
e = 0;
|
e = 0;
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
@ -548,10 +543,10 @@ parsePath(System* s, const char* path)
|
|||||||
|
|
||||||
class MyFinder: public Finder {
|
class MyFinder: public Finder {
|
||||||
public:
|
public:
|
||||||
MyFinder(System* system, const char* path):
|
MyFinder(System* system, const char* path, const char* bootLibrary):
|
||||||
system(system),
|
system(system),
|
||||||
path_(parsePath(system, path)),
|
path_(parsePath(system, path, bootLibrary)),
|
||||||
pathString(copy(system, &pathStringLength, path))
|
pathString(copy(system, path))
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
virtual System::Region* find(const char* name) {
|
virtual System::Region* find(const char* name) {
|
||||||
@ -585,14 +580,13 @@ class MyFinder: public Finder {
|
|||||||
e = e->next;
|
e = e->next;
|
||||||
t->dispose();
|
t->dispose();
|
||||||
}
|
}
|
||||||
free(system, pathString, pathStringLength + 1);
|
system->free(pathString);
|
||||||
free(system, this, sizeof(*this));
|
system->free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* system;
|
System* system;
|
||||||
Element* path_;
|
Element* path_;
|
||||||
const char* pathString;
|
const char* pathString;
|
||||||
unsigned pathStringLength;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
@ -600,9 +594,9 @@ class MyFinder: public Finder {
|
|||||||
namespace vm {
|
namespace vm {
|
||||||
|
|
||||||
Finder*
|
Finder*
|
||||||
makeFinder(System* s, const char* path)
|
makeFinder(System* s, const char* path, const char* bootLibrary)
|
||||||
{
|
{
|
||||||
return new (allocate(s, sizeof(MyFinder))) MyFinder(s, path);
|
return new (allocate(s, sizeof(MyFinder))) MyFinder(s, path, bootLibrary);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace vm
|
} // namespace vm
|
||||||
|
@ -27,7 +27,7 @@ class Finder {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Finder*
|
Finder*
|
||||||
makeFinder(System* s, const char* path);
|
makeFinder(System* s, const char* path, const char* bootLibrary);
|
||||||
|
|
||||||
} // namespace vm
|
} // namespace vm
|
||||||
|
|
||||||
|
51
src/heap.cpp
51
src/heap.cpp
@ -58,8 +58,8 @@ void assert(Context*, bool);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
System* system(Context*);
|
System* system(Context*);
|
||||||
void* tryAllocate(Context* c, unsigned size, bool executable);
|
void* tryAllocate(Context* c, unsigned size);
|
||||||
void free(Context* c, const void* p, unsigned size, bool executable);
|
void free(Context* c, const void* p, unsigned size);
|
||||||
|
|
||||||
inline void*
|
inline void*
|
||||||
get(void* o, unsigned offsetInWords)
|
get(void* o, unsigned offsetInWords)
|
||||||
@ -78,7 +78,7 @@ set(void** o, void* value)
|
|||||||
{
|
{
|
||||||
*o = reinterpret_cast<void*>
|
*o = reinterpret_cast<void*>
|
||||||
(reinterpret_cast<uintptr_t>(value)
|
(reinterpret_cast<uintptr_t>(value)
|
||||||
| reinterpret_cast<uintptr_t>(*o) & (~PointerMask));
|
| (reinterpret_cast<uintptr_t>(*o) & (~PointerMask)));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
@ -314,8 +314,7 @@ class Segment {
|
|||||||
capacity_ = desired;
|
capacity_ = desired;
|
||||||
while (data == 0) {
|
while (data == 0) {
|
||||||
data = static_cast<uintptr_t*>
|
data = static_cast<uintptr_t*>
|
||||||
(tryAllocate
|
(tryAllocate(context, (footprint(capacity_)) * BytesPerWord));
|
||||||
(context, (footprint(capacity_)) * BytesPerWord, false));
|
|
||||||
|
|
||||||
if (data == 0) {
|
if (data == 0) {
|
||||||
if (capacity_ > minimum) {
|
if (capacity_ > minimum) {
|
||||||
@ -353,7 +352,7 @@ class Segment {
|
|||||||
|
|
||||||
void replaceWith(Segment* s) {
|
void replaceWith(Segment* s) {
|
||||||
if (data) {
|
if (data) {
|
||||||
free(context, data, (footprint(capacity())) * BytesPerWord, false);
|
free(context, data, (footprint(capacity())) * BytesPerWord);
|
||||||
}
|
}
|
||||||
data = s->data;
|
data = s->data;
|
||||||
s->data = 0;
|
s->data = 0;
|
||||||
@ -404,7 +403,7 @@ class Segment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void dispose() {
|
void dispose() {
|
||||||
free(context, data, (footprint(capacity())) * BytesPerWord, false);
|
free(context, data, (footprint(capacity())) * BytesPerWord);
|
||||||
data = 0;
|
data = 0;
|
||||||
map = 0;
|
map = 0;
|
||||||
}
|
}
|
||||||
@ -783,7 +782,7 @@ free(Context* c, Fixie** fixies)
|
|||||||
if (DebugFixies) {
|
if (DebugFixies) {
|
||||||
fprintf(stderr, "free fixie %p\n", f);
|
fprintf(stderr, "free fixie %p\n", f);
|
||||||
}
|
}
|
||||||
free(c, f, f->totalSize(), false);
|
free(c, f, f->totalSize());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1628,12 +1627,12 @@ collect(Context* c)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void* tryAllocate(Context* c, unsigned size, bool executable)
|
void* tryAllocate(Context* c, unsigned size)
|
||||||
{
|
{
|
||||||
ACQUIRE(c->lock);
|
ACQUIRE(c->lock);
|
||||||
|
|
||||||
if (size + c->count < c->limit) {
|
if (size + c->count < c->limit) {
|
||||||
void* p = c->system->tryAllocate(size, executable);
|
void* p = c->system->tryAllocate(size);
|
||||||
if (p) {
|
if (p) {
|
||||||
c->count += size;
|
c->count += size;
|
||||||
return p;
|
return p;
|
||||||
@ -1642,16 +1641,16 @@ void* tryAllocate(Context* c, unsigned size, bool executable)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void free(Context* c, const void* p, unsigned size, bool executable) {
|
void free(Context* c, const void* p, unsigned size) {
|
||||||
ACQUIRE(c->lock);
|
ACQUIRE(c->lock);
|
||||||
|
|
||||||
expect(c->system, c->count >= size);
|
expect(c->system, c->count >= size);
|
||||||
c->system->free(p, size, executable);
|
c->system->free(p);
|
||||||
c->count -= size;
|
c->count -= size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_(Context* c, const void* p, unsigned size, bool executable) {
|
void free_(Context* c, const void* p, unsigned size) {
|
||||||
free(c, p, size, executable);
|
free(c, p, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
class MyHeap: public Heap {
|
class MyHeap: public Heap {
|
||||||
@ -1665,18 +1664,18 @@ class MyHeap: public Heap {
|
|||||||
c.client = client;
|
c.client = client;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void* tryAllocate(unsigned size, bool executable) {
|
virtual void* tryAllocate(unsigned size) {
|
||||||
return ::tryAllocate(&c, size, executable);
|
return ::tryAllocate(&c, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void* allocate(unsigned size, bool executable) {
|
virtual void* allocate(unsigned size) {
|
||||||
void* p = ::tryAllocate(&c, size, executable);
|
void* p = ::tryAllocate(&c, size);
|
||||||
expect(c.system, p);
|
expect(c.system, p);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void free(const void* p, unsigned size, bool executable) {
|
virtual void free(const void* p, unsigned size) {
|
||||||
free_(&c, p, size, executable);
|
free_(&c, p, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void collect(CollectionType type, unsigned incomingFootprint) {
|
virtual void collect(CollectionType type, unsigned incomingFootprint) {
|
||||||
@ -1690,16 +1689,15 @@ class MyHeap: public Heap {
|
|||||||
bool objectMask, unsigned* totalInBytes)
|
bool objectMask, unsigned* totalInBytes)
|
||||||
{
|
{
|
||||||
*totalInBytes = Fixie::totalSize(sizeInWords, objectMask);
|
*totalInBytes = Fixie::totalSize(sizeInWords, objectMask);
|
||||||
return (new (allocator->allocate(*totalInBytes, false))
|
return (new (allocator->allocate(*totalInBytes))
|
||||||
Fixie(sizeInWords, objectMask, &(c.fixies), false))->body();
|
Fixie(sizeInWords, objectMask, &(c.fixies), false))->body();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void* allocateImmortal(Allocator* allocator, unsigned sizeInWords,
|
virtual void* allocateImmortal(Allocator* allocator, unsigned sizeInWords,
|
||||||
bool executable, bool objectMask,
|
bool objectMask, unsigned* totalInBytes)
|
||||||
unsigned* totalInBytes)
|
|
||||||
{
|
{
|
||||||
*totalInBytes = Fixie::totalSize(sizeInWords, objectMask);
|
*totalInBytes = Fixie::totalSize(sizeInWords, objectMask);
|
||||||
return (new (allocator->allocate(*totalInBytes, executable))
|
return (new (allocator->allocate(*totalInBytes))
|
||||||
Fixie(sizeInWords, objectMask, &(c.tenuredFixies), true))->body();
|
Fixie(sizeInWords, objectMask, &(c.tenuredFixies), true))->body();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1809,7 +1807,7 @@ class MyHeap: public Heap {
|
|||||||
virtual void dispose() {
|
virtual void dispose() {
|
||||||
c.dispose();
|
c.dispose();
|
||||||
assert(&c, c.count == 0);
|
assert(&c, c.count == 0);
|
||||||
c.system->free(this, sizeof(*this), false);
|
c.system->free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Context c;
|
Context c;
|
||||||
@ -1822,8 +1820,7 @@ namespace vm {
|
|||||||
Heap*
|
Heap*
|
||||||
makeHeap(System* system, unsigned limit)
|
makeHeap(System* system, unsigned limit)
|
||||||
{
|
{
|
||||||
return new (system->tryAllocate(sizeof(MyHeap), false))
|
return new (system->tryAllocate(sizeof(MyHeap))) MyHeap(system, limit);
|
||||||
MyHeap(system, limit);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace vm
|
} // namespace vm
|
||||||
|
@ -60,8 +60,7 @@ class Heap: public Allocator {
|
|||||||
virtual void* allocateFixed(Allocator* allocator, unsigned sizeInWords,
|
virtual void* allocateFixed(Allocator* allocator, unsigned sizeInWords,
|
||||||
bool objectMask, unsigned* totalInBytes) = 0;
|
bool objectMask, unsigned* totalInBytes) = 0;
|
||||||
virtual void* allocateImmortal(Allocator* allocator, unsigned sizeInWords,
|
virtual void* allocateImmortal(Allocator* allocator, unsigned sizeInWords,
|
||||||
bool executable, bool objectMask,
|
bool objectMask, unsigned* totalInBytes) = 0;
|
||||||
unsigned* totalInBytes) = 0;
|
|
||||||
virtual bool needsMark(void* p) = 0;
|
virtual bool needsMark(void* p) = 0;
|
||||||
virtual void mark(void* p, unsigned offset, unsigned count) = 0;
|
virtual void mark(void* p, unsigned offset, unsigned count) = 0;
|
||||||
virtual void pad(void* p) = 0;
|
virtual void pad(void* p) = 0;
|
||||||
|
@ -704,6 +704,50 @@ store(Thread* t, unsigned index)
|
|||||||
BytesPerWord * 2);
|
BytesPerWord * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExceptionHandler*
|
||||||
|
findExceptionHandler(Thread* t, object method, unsigned ip)
|
||||||
|
{
|
||||||
|
PROTECT(t, method);
|
||||||
|
|
||||||
|
object eht = codeExceptionHandlerTable(t, methodCode(t, method));
|
||||||
|
|
||||||
|
if (eht) {
|
||||||
|
for (unsigned i = 0; i < exceptionHandlerTableLength(t, eht); ++i) {
|
||||||
|
ExceptionHandler* eh = exceptionHandlerTableBody(t, eht, i);
|
||||||
|
|
||||||
|
if (ip - 1 >= exceptionHandlerStart(eh)
|
||||||
|
and ip - 1 < exceptionHandlerEnd(eh))
|
||||||
|
{
|
||||||
|
object catchType = 0;
|
||||||
|
if (exceptionHandlerCatchType(eh)) {
|
||||||
|
object e = t->exception;
|
||||||
|
t->exception = 0;
|
||||||
|
PROTECT(t, e);
|
||||||
|
|
||||||
|
PROTECT(t, eht);
|
||||||
|
catchType = resolveClassInPool
|
||||||
|
(t, codePool(t, methodCode(t, method)),
|
||||||
|
exceptionHandlerCatchType(eh) - 1);
|
||||||
|
|
||||||
|
if (catchType) {
|
||||||
|
eh = exceptionHandlerTableBody(t, eht, i);
|
||||||
|
t->exception = e;
|
||||||
|
} else {
|
||||||
|
// can't find what we're supposed to catch - move on.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (catchType == 0 or instanceOf(t, catchType, t->exception)) {
|
||||||
|
return eh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
ExceptionHandler*
|
ExceptionHandler*
|
||||||
findExceptionHandler(Thread* t, int frame)
|
findExceptionHandler(Thread* t, int frame)
|
||||||
{
|
{
|
||||||
@ -1942,6 +1986,14 @@ interpret(Thread* t)
|
|||||||
ip = (ip - 5) + static_cast<int32_t>(offset);
|
ip = (ip - 5) + static_cast<int32_t>(offset);
|
||||||
} goto loop;
|
} goto loop;
|
||||||
|
|
||||||
|
case l2d: {
|
||||||
|
pushDouble(t, static_cast<double>(static_cast<int64_t>(popLong(t))));
|
||||||
|
} goto loop;
|
||||||
|
|
||||||
|
case l2f: {
|
||||||
|
pushFloat(t, static_cast<float>(static_cast<int64_t>(popLong(t))));
|
||||||
|
} goto loop;
|
||||||
|
|
||||||
case l2i: {
|
case l2i: {
|
||||||
pushInt(t, static_cast<int32_t>(popLong(t)));
|
pushInt(t, static_cast<int32_t>(popLong(t)));
|
||||||
} goto loop;
|
} goto loop;
|
||||||
@ -2999,6 +3051,11 @@ class MyProcessor: public Processor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual object getStackTrace(Thread*, Thread*) {
|
||||||
|
// not implemented
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
virtual void dispose(vm::Thread* t) {
|
virtual void dispose(vm::Thread* t) {
|
||||||
t->m->heap->free(t, sizeof(Thread), false);
|
t->m->heap->free(t, sizeof(Thread), false);
|
||||||
}
|
}
|
||||||
|
188
src/jnienv.cpp
188
src/jnienv.cpp
@ -87,6 +87,35 @@ GetEnv(Machine* m, Thread** t, jint version)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jsize JNICALL
|
||||||
|
GetStringLength(Thread* t, jstring s)
|
||||||
|
{
|
||||||
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
|
return stringLength(t, *s);
|
||||||
|
}
|
||||||
|
|
||||||
|
const jchar* JNICALL
|
||||||
|
GetStringChars(Thread* t, jstring s, jboolean* isCopy)
|
||||||
|
{
|
||||||
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
|
jchar* chars = static_cast<jchar*>
|
||||||
|
(t->m->heap->allocate((stringLength(t, *s) + 1) * sizeof(jchar)));
|
||||||
|
stringChars(t, *s, chars);
|
||||||
|
|
||||||
|
if (isCopy) *isCopy = true;
|
||||||
|
return chars;
|
||||||
|
}
|
||||||
|
|
||||||
|
void JNICALL
|
||||||
|
ReleaseStringChars(Thread* t, jstring s, const jchar* chars)
|
||||||
|
{
|
||||||
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
|
t->m->heap->free(chars, (stringLength(t, *s) + 1) * sizeof(jchar));
|
||||||
|
}
|
||||||
|
|
||||||
jsize JNICALL
|
jsize JNICALL
|
||||||
GetStringUTFLength(Thread* t, jstring s)
|
GetStringUTFLength(Thread* t, jstring s)
|
||||||
{
|
{
|
||||||
@ -101,7 +130,7 @@ GetStringUTFChars(Thread* t, jstring s, jboolean* isCopy)
|
|||||||
ENTER(t, Thread::ActiveState);
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
char* chars = static_cast<char*>
|
char* chars = static_cast<char*>
|
||||||
(t->m->heap->allocate(stringLength(t, *s) + 1, false));
|
(t->m->heap->allocate(stringLength(t, *s) + 1));
|
||||||
stringChars(t, *s, chars);
|
stringChars(t, *s, chars);
|
||||||
|
|
||||||
if (isCopy) *isCopy = true;
|
if (isCopy) *isCopy = true;
|
||||||
@ -111,7 +140,9 @@ GetStringUTFChars(Thread* t, jstring s, jboolean* isCopy)
|
|||||||
void JNICALL
|
void JNICALL
|
||||||
ReleaseStringUTFChars(Thread* t, jstring s, const char* chars)
|
ReleaseStringUTFChars(Thread* t, jstring s, const char* chars)
|
||||||
{
|
{
|
||||||
t->m->heap->free(chars, stringLength(t, *s) + 1, false);
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
|
t->m->heap->free(chars, stringLength(t, *s) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
jsize JNICALL
|
jsize JNICALL
|
||||||
@ -232,15 +263,13 @@ IsInstanceOf(Thread* t, jobject o, jclass c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
object
|
object
|
||||||
findMethod(Thread* t, object c, const char* name, const char* spec)
|
findMethod(Thread* t, jclass c, const char* name, const char* spec)
|
||||||
{
|
{
|
||||||
PROTECT(t, c);
|
|
||||||
|
|
||||||
object n = makeByteArray(t, "%s", name);
|
object n = makeByteArray(t, "%s", name);
|
||||||
PROTECT(t, n);
|
PROTECT(t, n);
|
||||||
|
|
||||||
object s = makeByteArray(t, "%s", spec);
|
object s = makeByteArray(t, "%s", spec);
|
||||||
return vm::findMethod(t, c, n, s);
|
return vm::findMethod(t, *c, n, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
jmethodID JNICALL
|
jmethodID JNICALL
|
||||||
@ -248,7 +277,7 @@ GetMethodID(Thread* t, jclass c, const char* name, const char* spec)
|
|||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
object method = findMethod(t, *c, name, spec);
|
object method = findMethod(t, c, name, spec);
|
||||||
if (UNLIKELY(t->exception)) return 0;
|
if (UNLIKELY(t->exception)) return 0;
|
||||||
|
|
||||||
if (classFlags(t, *c) & ACC_INTERFACE) {
|
if (classFlags(t, *c) & ACC_INTERFACE) {
|
||||||
@ -278,7 +307,7 @@ GetStaticMethodID(Thread* t, jclass c, const char* name, const char* spec)
|
|||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
object method = findMethod(t, *c, name, spec);
|
object method = findMethod(t, c, name, spec);
|
||||||
if (UNLIKELY(t->exception)) return 0;
|
if (UNLIKELY(t->exception)) return 0;
|
||||||
|
|
||||||
return methodOffset(t, method) + 1;
|
return methodOffset(t, method) + 1;
|
||||||
@ -289,11 +318,20 @@ getMethod(Thread* t, object o, jmethodID m)
|
|||||||
{
|
{
|
||||||
if (m & InterfaceMethodID) {
|
if (m & InterfaceMethodID) {
|
||||||
return vectorBody(t, t->m->jniInterfaceTable, m & (~InterfaceMethodID));
|
return vectorBody(t, t->m->jniInterfaceTable, m & (~InterfaceMethodID));
|
||||||
} else if (m & NonVirtualMethodID) {
|
|
||||||
return arrayBody(t, classMethodTable(t, objectClass(t, o)),
|
|
||||||
m & (~NonVirtualMethodID));
|
|
||||||
} else {
|
} else {
|
||||||
return arrayBody(t, classVirtualTable(t, objectClass(t, o)), m - 1);
|
if (classVmFlags(t, objectClass(t, o)) & BootstrapFlag) {
|
||||||
|
PROTECT(t, o);
|
||||||
|
|
||||||
|
resolveClass(t, className(t, objectClass(t, o)));
|
||||||
|
if (UNLIKELY(t->exception)) return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m & NonVirtualMethodID) {
|
||||||
|
return arrayBody(t, classMethodTable(t, objectClass(t, o)),
|
||||||
|
m & (~NonVirtualMethodID));
|
||||||
|
} else {
|
||||||
|
return arrayBody(t, classVirtualTable(t, objectClass(t, o)), m - 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -328,8 +366,9 @@ CallObjectMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
|||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
return makeLocalReference(t, t->m->processor->invokeList
|
object method = getMethod(t, *o, m);
|
||||||
(t, getMethod(t, *o, m), *o, true, a));
|
return makeLocalReference
|
||||||
|
(t, t->m->processor->invokeList(t, method, *o, true, a));
|
||||||
}
|
}
|
||||||
|
|
||||||
jobject JNICALL
|
jobject JNICALL
|
||||||
@ -350,7 +389,8 @@ CallBooleanMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
|||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
object r = t->m->processor->invokeList(t, getMethod(t, *o, m), *o, true, a);
|
object method = getMethod(t, *o, m);
|
||||||
|
object r = t->m->processor->invokeList(t, method, *o, true, a);
|
||||||
return (t->exception ? false : (intValue(t, r) != 0));
|
return (t->exception ? false : (intValue(t, r) != 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -372,7 +412,8 @@ CallByteMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
|||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
object r = t->m->processor->invokeList(t, getMethod(t, *o, m), *o, true, a);
|
object method = getMethod(t, *o, m);
|
||||||
|
object r = t->m->processor->invokeList(t, method, *o, true, a);
|
||||||
return (t->exception ? 0 : intValue(t, r));
|
return (t->exception ? 0 : intValue(t, r));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -394,7 +435,8 @@ CallCharMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
|||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
object r = t->m->processor->invokeList(t, getMethod(t, *o, m), *o, true, a);
|
object method = getMethod(t, *o, m);
|
||||||
|
object r = t->m->processor->invokeList(t, method, *o, true, a);
|
||||||
return (t->exception ? 0 : intValue(t, r));
|
return (t->exception ? 0 : intValue(t, r));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -416,7 +458,8 @@ CallShortMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
|||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
object r = t->m->processor->invokeList(t, getMethod(t, *o, m), *o, true, a);
|
object method = getMethod(t, *o, m);
|
||||||
|
object r = t->m->processor->invokeList(t, method, *o, true, a);
|
||||||
return (t->exception ? 0 : intValue(t, r));
|
return (t->exception ? 0 : intValue(t, r));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -438,7 +481,8 @@ CallIntMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
|||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
object r = t->m->processor->invokeList(t, getMethod(t, *o, m), *o, true, a);
|
object method = getMethod(t, *o, m);
|
||||||
|
object r = t->m->processor->invokeList(t, method, *o, true, a);
|
||||||
return (t->exception ? 0 : intValue(t, r));
|
return (t->exception ? 0 : intValue(t, r));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -460,7 +504,8 @@ CallLongMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
|||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
object r = t->m->processor->invokeList(t, getMethod(t, *o, m), *o, true, a);
|
object method = getMethod(t, *o, m);
|
||||||
|
object r = t->m->processor->invokeList(t, method, *o, true, a);
|
||||||
return (t->exception ? 0 : longValue(t, r));
|
return (t->exception ? 0 : longValue(t, r));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -482,7 +527,8 @@ CallFloatMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
|||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
object r = t->m->processor->invokeList(t, getMethod(t, *o, m), *o, true, a);
|
object method = getMethod(t, *o, m);
|
||||||
|
object r = t->m->processor->invokeList(t, method, *o, true, a);
|
||||||
return (t->exception ? 0 : bitsToFloat(intValue(t, r)));
|
return (t->exception ? 0 : bitsToFloat(intValue(t, r)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -504,7 +550,8 @@ CallDoubleMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
|||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
object r = t->m->processor->invokeList(t, getMethod(t, *o, m), *o, true, a);
|
object method = getMethod(t, *o, m);
|
||||||
|
object r = t->m->processor->invokeList(t, method, *o, true, a);
|
||||||
return (t->exception ? 0 : bitsToDouble(longValue(t, r)));
|
return (t->exception ? 0 : bitsToDouble(longValue(t, r)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -526,7 +573,8 @@ CallVoidMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
|||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
t->m->processor->invokeList(t, getMethod(t, *o, m), *o, true, a);
|
object method = getMethod(t, *o, m);
|
||||||
|
t->m->processor->invokeList(t, method, *o, true, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JNICALL
|
void JNICALL
|
||||||
@ -541,9 +589,16 @@ CallVoidMethod(Thread* t, jobject o, jmethodID m, ...)
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline object
|
inline object
|
||||||
getStaticMethod(Thread* t, object class_, jmethodID m)
|
getStaticMethod(Thread* t, object c, jmethodID m)
|
||||||
{
|
{
|
||||||
return arrayBody(t, classMethodTable(t, class_), m - 1);
|
if (classVmFlags(t, c) & BootstrapFlag) {
|
||||||
|
PROTECT(t, c);
|
||||||
|
|
||||||
|
resolveClass(t, className(t, c));
|
||||||
|
if (UNLIKELY(t->exception)) return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return arrayBody(t, classMethodTable(t, c), m - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
jobject JNICALL
|
jobject JNICALL
|
||||||
@ -772,13 +827,13 @@ CallStaticVoidMethod(Thread* t, jclass c, jmethodID m, ...)
|
|||||||
}
|
}
|
||||||
|
|
||||||
object
|
object
|
||||||
findField(Thread* t, object class_, const char* name, const char* spec)
|
findField(Thread* t, jclass c, const char* name, const char* spec)
|
||||||
{
|
{
|
||||||
object n = makeByteArray(t, "%s", name);
|
object n = makeByteArray(t, "%s", name);
|
||||||
PROTECT(t, n);
|
PROTECT(t, n);
|
||||||
|
|
||||||
object s = makeByteArray(t, "%s", spec);
|
object s = makeByteArray(t, "%s", spec);
|
||||||
return vm::findField(t, class_, n, s);
|
return vm::findField(t, *c, n, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
jfieldID JNICALL
|
jfieldID JNICALL
|
||||||
@ -786,7 +841,7 @@ GetFieldID(Thread* t, jclass c, const char* name, const char* spec)
|
|||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
object field = findField(t, *c, name, spec);
|
object field = findField(t, c, name, spec);
|
||||||
if (UNLIKELY(t->exception)) return 0;
|
if (UNLIKELY(t->exception)) return 0;
|
||||||
|
|
||||||
return fieldOffset(t, field);
|
return fieldOffset(t, field);
|
||||||
@ -797,7 +852,7 @@ GetStaticFieldID(Thread* t, jclass c, const char* name, const char* spec)
|
|||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
object field = findField(t, *c, name, spec);
|
object field = findField(t, c, name, spec);
|
||||||
if (UNLIKELY(t->exception)) return 0;
|
if (UNLIKELY(t->exception)) return 0;
|
||||||
|
|
||||||
return fieldOffset(t, field);
|
return fieldOffset(t, field);
|
||||||
@ -1122,7 +1177,7 @@ NewGlobalRef(Thread* t, jobject o)
|
|||||||
ACQUIRE(t, t->m->referenceLock);
|
ACQUIRE(t, t->m->referenceLock);
|
||||||
|
|
||||||
if (o) {
|
if (o) {
|
||||||
Reference* r = new (t->m->heap->allocate(sizeof(Reference), false))
|
Reference* r = new (t->m->heap->allocate(sizeof(Reference)))
|
||||||
Reference(*o, &(t->m->jniReferences));
|
Reference(*o, &(t->m->jniReferences));
|
||||||
|
|
||||||
return &(r->target);
|
return &(r->target);
|
||||||
@ -1267,7 +1322,7 @@ GetBooleanArrayElements(Thread* t, jbooleanArray array, jboolean* isCopy)
|
|||||||
ENTER(t, Thread::ActiveState);
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
unsigned size = booleanArrayLength(t, *array) * sizeof(jboolean);
|
unsigned size = booleanArrayLength(t, *array) * sizeof(jboolean);
|
||||||
jboolean* p = static_cast<jboolean*>(t->m->heap->allocate(size, false));
|
jboolean* p = static_cast<jboolean*>(t->m->heap->allocate(size));
|
||||||
if (size) {
|
if (size) {
|
||||||
memcpy(p, &booleanArrayBody(t, *array, 0), size);
|
memcpy(p, &booleanArrayBody(t, *array, 0), size);
|
||||||
}
|
}
|
||||||
@ -1285,7 +1340,7 @@ GetByteArrayElements(Thread* t, jbyteArray array, jboolean* isCopy)
|
|||||||
ENTER(t, Thread::ActiveState);
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
unsigned size = byteArrayLength(t, *array) * sizeof(jbyte);
|
unsigned size = byteArrayLength(t, *array) * sizeof(jbyte);
|
||||||
jbyte* p = static_cast<jbyte*>(t->m->heap->allocate(size, false));
|
jbyte* p = static_cast<jbyte*>(t->m->heap->allocate(size));
|
||||||
if (size) {
|
if (size) {
|
||||||
memcpy(p, &byteArrayBody(t, *array, 0), size);
|
memcpy(p, &byteArrayBody(t, *array, 0), size);
|
||||||
}
|
}
|
||||||
@ -1303,7 +1358,7 @@ GetCharArrayElements(Thread* t, jcharArray array, jboolean* isCopy)
|
|||||||
ENTER(t, Thread::ActiveState);
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
unsigned size = charArrayLength(t, *array) * sizeof(jchar);
|
unsigned size = charArrayLength(t, *array) * sizeof(jchar);
|
||||||
jchar* p = static_cast<jchar*>(t->m->heap->allocate(size, false));
|
jchar* p = static_cast<jchar*>(t->m->heap->allocate(size));
|
||||||
if (size) {
|
if (size) {
|
||||||
memcpy(p, &charArrayBody(t, *array, 0), size);
|
memcpy(p, &charArrayBody(t, *array, 0), size);
|
||||||
}
|
}
|
||||||
@ -1321,7 +1376,7 @@ GetShortArrayElements(Thread* t, jshortArray array, jboolean* isCopy)
|
|||||||
ENTER(t, Thread::ActiveState);
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
unsigned size = shortArrayLength(t, *array) * sizeof(jshort);
|
unsigned size = shortArrayLength(t, *array) * sizeof(jshort);
|
||||||
jshort* p = static_cast<jshort*>(t->m->heap->allocate(size, false));
|
jshort* p = static_cast<jshort*>(t->m->heap->allocate(size));
|
||||||
if (size) {
|
if (size) {
|
||||||
memcpy(p, &shortArrayBody(t, *array, 0), size);
|
memcpy(p, &shortArrayBody(t, *array, 0), size);
|
||||||
}
|
}
|
||||||
@ -1339,7 +1394,7 @@ GetIntArrayElements(Thread* t, jintArray array, jboolean* isCopy)
|
|||||||
ENTER(t, Thread::ActiveState);
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
unsigned size = intArrayLength(t, *array) * sizeof(jint);
|
unsigned size = intArrayLength(t, *array) * sizeof(jint);
|
||||||
jint* p = static_cast<jint*>(t->m->heap->allocate(size, false));
|
jint* p = static_cast<jint*>(t->m->heap->allocate(size));
|
||||||
if (size) {
|
if (size) {
|
||||||
memcpy(p, &intArrayBody(t, *array, 0), size);
|
memcpy(p, &intArrayBody(t, *array, 0), size);
|
||||||
}
|
}
|
||||||
@ -1357,7 +1412,7 @@ GetLongArrayElements(Thread* t, jlongArray array, jboolean* isCopy)
|
|||||||
ENTER(t, Thread::ActiveState);
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
unsigned size = longArrayLength(t, *array) * sizeof(jlong);
|
unsigned size = longArrayLength(t, *array) * sizeof(jlong);
|
||||||
jlong* p = static_cast<jlong*>(t->m->heap->allocate(size, false));
|
jlong* p = static_cast<jlong*>(t->m->heap->allocate(size));
|
||||||
if (size) {
|
if (size) {
|
||||||
memcpy(p, &longArrayBody(t, *array, 0), size);
|
memcpy(p, &longArrayBody(t, *array, 0), size);
|
||||||
}
|
}
|
||||||
@ -1375,7 +1430,7 @@ GetFloatArrayElements(Thread* t, jfloatArray array, jboolean* isCopy)
|
|||||||
ENTER(t, Thread::ActiveState);
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
unsigned size = floatArrayLength(t, *array) * sizeof(jfloat);
|
unsigned size = floatArrayLength(t, *array) * sizeof(jfloat);
|
||||||
jfloat* p = static_cast<jfloat*>(t->m->heap->allocate(size, false));
|
jfloat* p = static_cast<jfloat*>(t->m->heap->allocate(size));
|
||||||
if (size) {
|
if (size) {
|
||||||
memcpy(p, &floatArrayBody(t, *array, 0), size);
|
memcpy(p, &floatArrayBody(t, *array, 0), size);
|
||||||
}
|
}
|
||||||
@ -1393,7 +1448,7 @@ GetDoubleArrayElements(Thread* t, jdoubleArray array, jboolean* isCopy)
|
|||||||
ENTER(t, Thread::ActiveState);
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
unsigned size = doubleArrayLength(t, *array) * sizeof(jdouble);
|
unsigned size = doubleArrayLength(t, *array) * sizeof(jdouble);
|
||||||
jdouble* p = static_cast<jdouble*>(t->m->heap->allocate(size, false));
|
jdouble* p = static_cast<jdouble*>(t->m->heap->allocate(size));
|
||||||
if (size) {
|
if (size) {
|
||||||
memcpy(p, &doubleArrayBody(t, *array, 0), size);
|
memcpy(p, &doubleArrayBody(t, *array, 0), size);
|
||||||
}
|
}
|
||||||
@ -1420,7 +1475,7 @@ ReleaseBooleanArrayElements(Thread* t, jbooleanArray array, jboolean* p,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mode == 0 or mode == JNI_ABORT) {
|
if (mode == 0 or mode == JNI_ABORT) {
|
||||||
t->m->heap->free(p, size, false);
|
t->m->heap->free(p, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1438,7 +1493,7 @@ ReleaseByteArrayElements(Thread* t, jbyteArray array, jbyte* p, jint mode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mode == 0 or mode == JNI_ABORT) {
|
if (mode == 0 or mode == JNI_ABORT) {
|
||||||
t->m->heap->free(p, size, false);
|
t->m->heap->free(p, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1456,7 +1511,7 @@ ReleaseCharArrayElements(Thread* t, jcharArray array, jchar* p, jint mode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mode == 0 or mode == JNI_ABORT) {
|
if (mode == 0 or mode == JNI_ABORT) {
|
||||||
t->m->heap->free(p, size, false);
|
t->m->heap->free(p, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1474,7 +1529,7 @@ ReleaseShortArrayElements(Thread* t, jshortArray array, jshort* p, jint mode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mode == 0 or mode == JNI_ABORT) {
|
if (mode == 0 or mode == JNI_ABORT) {
|
||||||
t->m->heap->free(p, size, false);
|
t->m->heap->free(p, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1492,7 +1547,7 @@ ReleaseIntArrayElements(Thread* t, jintArray array, jint* p, jint mode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mode == 0 or mode == JNI_ABORT) {
|
if (mode == 0 or mode == JNI_ABORT) {
|
||||||
t->m->heap->free(p, size, false);
|
t->m->heap->free(p, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1510,7 +1565,7 @@ ReleaseLongArrayElements(Thread* t, jlongArray array, jlong* p, jint mode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mode == 0 or mode == JNI_ABORT) {
|
if (mode == 0 or mode == JNI_ABORT) {
|
||||||
t->m->heap->free(p, size, false);
|
t->m->heap->free(p, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1528,7 +1583,7 @@ ReleaseFloatArrayElements(Thread* t, jfloatArray array, jfloat* p, jint mode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mode == 0 or mode == JNI_ABORT) {
|
if (mode == 0 or mode == JNI_ABORT) {
|
||||||
t->m->heap->free(p, size, false);
|
t->m->heap->free(p, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1547,7 +1602,7 @@ ReleaseDoubleArrayElements(Thread* t, jdoubleArray array, jdouble* p,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mode == 0 or mode == JNI_ABORT) {
|
if (mode == 0 or mode == JNI_ABORT) {
|
||||||
t->m->heap->free(p, size, false);
|
t->m->heap->free(p, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1781,9 +1836,13 @@ GetJavaVM(Thread* t, Machine** m)
|
|||||||
jboolean JNICALL
|
jboolean JNICALL
|
||||||
IsSameObject(Thread* t, jobject a, jobject b)
|
IsSameObject(Thread* t, jobject a, jobject b)
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
if (a and b) {
|
||||||
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
return *a == *b;
|
return *a == *b;
|
||||||
|
} else {
|
||||||
|
return a == b;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct JDK1_1InitArgs {
|
struct JDK1_1InitArgs {
|
||||||
@ -1826,6 +1885,9 @@ populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable)
|
|||||||
|
|
||||||
memset(envTable, 0, sizeof(JNIEnvVTable));
|
memset(envTable, 0, sizeof(JNIEnvVTable));
|
||||||
|
|
||||||
|
envTable->GetStringLength = ::GetStringLength;
|
||||||
|
envTable->GetStringChars = ::GetStringChars;
|
||||||
|
envTable->ReleaseStringChars = ::ReleaseStringChars;
|
||||||
envTable->GetStringUTFLength = ::GetStringUTFLength;
|
envTable->GetStringUTFLength = ::GetStringUTFLength;
|
||||||
envTable->GetStringUTFChars = ::GetStringUTFChars;
|
envTable->GetStringUTFChars = ::GetStringUTFChars;
|
||||||
envTable->ReleaseStringUTFChars = ::ReleaseStringUTFChars;
|
envTable->ReleaseStringUTFChars = ::ReleaseStringUTFChars;
|
||||||
@ -1988,28 +2050,38 @@ JNI_GetDefaultJavaVMInitArgs(void* args)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define BUILTINS_PROPERTY "vm.builtins"
|
#define BUILTINS_PROPERTY "avian.builtins"
|
||||||
|
#define BOOTSTRAP_PROPERTY "avian.bootstrap"
|
||||||
|
|
||||||
extern "C" JNIEXPORT jint JNICALL
|
extern "C" JNIEXPORT jint JNICALL
|
||||||
JNI_CreateJavaVM(Machine** m, Thread** t, void* args)
|
JNI_CreateJavaVM(Machine** m, Thread** t, void* args)
|
||||||
{
|
{
|
||||||
JDK1_1InitArgs* a = static_cast<JDK1_1InitArgs*>(args);
|
JDK1_1InitArgs* a = static_cast<JDK1_1InitArgs*>(args);
|
||||||
|
|
||||||
System* s = makeSystem();
|
const char* builtins = 0;
|
||||||
Heap* h = makeHeap(s, a->maxHeapSize);
|
const char* bootLibrary = 0;
|
||||||
Finder* f = makeFinder(s, a->classpath);
|
|
||||||
Processor* p = makeProcessor(s, h);
|
|
||||||
|
|
||||||
*m = new (h->allocate(sizeof(Machine), false)) Machine(s, h, f, p);
|
|
||||||
|
|
||||||
if (a->properties) {
|
if (a->properties) {
|
||||||
for (const char** p = a->properties; *p; ++p) {
|
for (const char** p = a->properties; *p; ++p) {
|
||||||
if (strncmp(*p, BUILTINS_PROPERTY "=", sizeof(BUILTINS_PROPERTY)) == 0) {
|
if (strncmp(*p, BUILTINS_PROPERTY "=",
|
||||||
(*m)->builtins = (*p) + sizeof(BUILTINS_PROPERTY);
|
sizeof(BUILTINS_PROPERTY)) == 0)
|
||||||
|
{
|
||||||
|
builtins = (*p) + sizeof(BUILTINS_PROPERTY);
|
||||||
|
} else if (strncmp(*p, BOOTSTRAP_PROPERTY "=",
|
||||||
|
sizeof(BOOTSTRAP_PROPERTY)) == 0)
|
||||||
|
{
|
||||||
|
bootLibrary = (*p) + sizeof(BOOTSTRAP_PROPERTY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
System* s = makeSystem();
|
||||||
|
Heap* h = makeHeap(s, a->maxHeapSize);
|
||||||
|
Finder* f = makeFinder(s, a->classpath, bootLibrary);
|
||||||
|
Processor* p = makeProcessor(s, h);
|
||||||
|
|
||||||
|
*m = new (h->allocate(sizeof(Machine)))
|
||||||
|
Machine(s, h, f, p, bootLibrary, builtins);
|
||||||
|
|
||||||
*t = p->makeThread(*m, 0, 0);
|
*t = p->makeThread(*m, 0, 0);
|
||||||
|
|
||||||
enter(*t, Thread::ActiveState);
|
enter(*t, Thread::ActiveState);
|
||||||
|
121
src/machine.cpp
121
src/machine.cpp
@ -22,15 +22,9 @@ namespace {
|
|||||||
bool
|
bool
|
||||||
find(Thread* t, Thread* o)
|
find(Thread* t, Thread* o)
|
||||||
{
|
{
|
||||||
if (t == o) return true;
|
return (t == o)
|
||||||
|
or (t->peer and find(t->peer, o))
|
||||||
for (Thread* p = t->peer; p; p = p->peer) {
|
or (t->child and find(t->child, o));
|
||||||
if (p == o) return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (t->child) return find(t->child, o);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -48,11 +42,7 @@ count(Thread* t, Thread* o)
|
|||||||
unsigned c = 0;
|
unsigned c = 0;
|
||||||
|
|
||||||
if (t != o) ++ c;
|
if (t != o) ++ c;
|
||||||
|
if (t->peer) c += count(t->peer, o);
|
||||||
for (Thread* p = t->peer; p; p = p->peer) {
|
|
||||||
c += count(p, o);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (t->child) c += count(t->child, o);
|
if (t->child) c += count(t->child, o);
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
@ -62,12 +52,8 @@ Thread**
|
|||||||
fill(Thread* t, Thread* o, Thread** array)
|
fill(Thread* t, Thread* o, Thread** array)
|
||||||
{
|
{
|
||||||
if (t != o) *(array++) = t;
|
if (t != o) *(array++) = t;
|
||||||
|
if (t->peer) fill(t->peer, o, array);
|
||||||
for (Thread* p = t->peer; p; p = p->peer) {
|
if (t->child) fill(t->child, o, array);
|
||||||
array = fill(p, o, array);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (t->child) array = fill(t->child, o, array);
|
|
||||||
|
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
@ -492,15 +478,22 @@ void
|
|||||||
postCollect(Thread* t)
|
postCollect(Thread* t)
|
||||||
{
|
{
|
||||||
#ifdef VM_STRESS
|
#ifdef VM_STRESS
|
||||||
t->m->heap->free(t->defaultHeap, Thread::HeapSizeInBytes, false);
|
t->m->heap->free(t->defaultHeap, Thread::HeapSizeInBytes);
|
||||||
t->defaultHeap = static_cast<uintptr_t*>
|
t->defaultHeap = static_cast<uintptr_t*>
|
||||||
(t->m->heap->allocate(Thread::HeapSizeInBytes, false));
|
(t->m->heap->allocate(Thread::HeapSizeInBytes));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
t->heap = t->defaultHeap;
|
t->heap = t->defaultHeap;
|
||||||
t->heapOffset = 0;
|
t->heapOffset = 0;
|
||||||
t->heapIndex = 0;
|
t->heapIndex = 0;
|
||||||
|
|
||||||
|
if (t->backupHeap) {
|
||||||
|
t->m->heap->free
|
||||||
|
(t->backupHeap, t->backupHeapSizeInWords * BytesPerWord);
|
||||||
|
t->backupHeapIndex = 0;
|
||||||
|
t->backupHeapSizeInWords = 0;
|
||||||
|
}
|
||||||
|
|
||||||
for (Thread* c = t->child; c; c = c->peer) {
|
for (Thread* c = t->child; c; c = c->peer) {
|
||||||
postCollect(c);
|
postCollect(c);
|
||||||
}
|
}
|
||||||
@ -660,8 +653,7 @@ parsePool(Thread* t, Stream& s)
|
|||||||
PROTECT(t, pool);
|
PROTECT(t, pool);
|
||||||
|
|
||||||
if (count) {
|
if (count) {
|
||||||
uint32_t* index = static_cast<uint32_t*>
|
uint32_t* index = static_cast<uint32_t*>(t->m->heap->allocate(count * 4));
|
||||||
(t->m->heap->allocate(count * 4, false));
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < count; ++i) {
|
for (unsigned i = 0; i < count; ++i) {
|
||||||
index[i] = s.position();
|
index[i] = s.position();
|
||||||
@ -707,7 +699,7 @@ parsePool(Thread* t, Stream& s)
|
|||||||
i += parsePoolEntry(t, s, index, pool, i);
|
i += parsePoolEntry(t, s, index, pool, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
t->m->heap->free(index, count * 4, false);
|
t->m->heap->free(index, count * 4);
|
||||||
|
|
||||||
s.setPosition(end);
|
s.setPosition(end);
|
||||||
}
|
}
|
||||||
@ -861,7 +853,7 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
|
|||||||
|
|
||||||
if (flags & ACC_STATIC) {
|
if (flags & ACC_STATIC) {
|
||||||
unsigned size = fieldSize(t, code);
|
unsigned size = fieldSize(t, code);
|
||||||
unsigned excess = staticOffset % size;
|
unsigned excess = (staticOffset % size) % BytesPerWord;
|
||||||
if (excess) {
|
if (excess) {
|
||||||
staticOffset += BytesPerWord - excess;
|
staticOffset += BytesPerWord - excess;
|
||||||
}
|
}
|
||||||
@ -878,7 +870,7 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
|
|||||||
abort(t); // todo: handle non-static field initializers
|
abort(t); // todo: handle non-static field initializers
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned excess = memberOffset % fieldSize(t, code);
|
unsigned excess = (memberOffset % fieldSize(t, code)) % BytesPerWord;
|
||||||
if (excess) {
|
if (excess) {
|
||||||
memberOffset += BytesPerWord - excess;
|
memberOffset += BytesPerWord - excess;
|
||||||
}
|
}
|
||||||
@ -1294,7 +1286,9 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
|||||||
object method = arrayBody(t, ivtable, j);
|
object method = arrayBody(t, ivtable, j);
|
||||||
method = hashMapFind
|
method = hashMapFind
|
||||||
(t, virtualMap, method, methodHash, methodEqual);
|
(t, virtualMap, method, methodHash, methodEqual);
|
||||||
assert(t, method);
|
|
||||||
|
// note that method may be null in the case of an abstract
|
||||||
|
// class
|
||||||
|
|
||||||
set(t, vtable, ArrayBody + (j * BytesPerWord), method);
|
set(t, vtable, ArrayBody + (j * BytesPerWord), method);
|
||||||
}
|
}
|
||||||
@ -1630,7 +1624,7 @@ class HeapClient: public Heap::Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void dispose() {
|
void dispose() {
|
||||||
m->heap->free(this, sizeof(*this), false);
|
m->heap->free(this, sizeof(*this));
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -1642,10 +1636,11 @@ class HeapClient: public Heap::Client {
|
|||||||
namespace vm {
|
namespace vm {
|
||||||
|
|
||||||
Machine::Machine(System* system, Heap* heap, Finder* finder,
|
Machine::Machine(System* system, Heap* heap, Finder* finder,
|
||||||
Processor* processor):
|
Processor* processor, const char* bootLibrary,
|
||||||
|
const char* builtins):
|
||||||
vtable(&javaVMVTable),
|
vtable(&javaVMVTable),
|
||||||
system(system),
|
system(system),
|
||||||
heapClient(new (heap->allocate(sizeof(HeapClient), false))
|
heapClient(new (heap->allocate(sizeof(HeapClient)))
|
||||||
HeapClient(this)),
|
HeapClient(this)),
|
||||||
heap(heap),
|
heap(heap),
|
||||||
finder(finder),
|
finder(finder),
|
||||||
@ -1653,7 +1648,7 @@ Machine::Machine(System* system, Heap* heap, Finder* finder,
|
|||||||
rootThread(0),
|
rootThread(0),
|
||||||
exclusive(0),
|
exclusive(0),
|
||||||
jniReferences(0),
|
jniReferences(0),
|
||||||
builtins(0),
|
builtins(builtins),
|
||||||
activeCount(0),
|
activeCount(0),
|
||||||
liveCount(0),
|
liveCount(0),
|
||||||
fixedFootprint(0),
|
fixedFootprint(0),
|
||||||
@ -1686,7 +1681,7 @@ Machine::Machine(System* system, Heap* heap, Finder* finder,
|
|||||||
not system->success(system->make(&heapLock)) or
|
not system->success(system->make(&heapLock)) or
|
||||||
not system->success(system->make(&classLock)) or
|
not system->success(system->make(&classLock)) or
|
||||||
not system->success(system->make(&referenceLock)) or
|
not system->success(system->make(&referenceLock)) or
|
||||||
not system->success(system->load(&libraries, 0, false)))
|
not system->success(system->load(&libraries, bootLibrary, false)))
|
||||||
{
|
{
|
||||||
system->abort();
|
system->abort();
|
||||||
}
|
}
|
||||||
@ -1708,16 +1703,16 @@ Machine::dispose()
|
|||||||
for (Reference* r = jniReferences; r;) {
|
for (Reference* r = jniReferences; r;) {
|
||||||
Reference* tmp = r;
|
Reference* tmp = r;
|
||||||
r = r->next;
|
r = r->next;
|
||||||
heap->free(tmp, sizeof(*tmp), false);
|
heap->free(tmp, sizeof(*tmp));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned i = 0; i < heapPoolIndex; ++i) {
|
for (unsigned i = 0; i < heapPoolIndex; ++i) {
|
||||||
heap->free(heapPool[i], Thread::HeapSizeInBytes, false);
|
heap->free(heapPool[i], Thread::HeapSizeInBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
static_cast<HeapClient*>(heapClient)->dispose();
|
static_cast<HeapClient*>(heapClient)->dispose();
|
||||||
|
|
||||||
heap->free(this, sizeof(*this), false);
|
heap->free(this, sizeof(*this));
|
||||||
}
|
}
|
||||||
|
|
||||||
Thread::Thread(Machine* m, object javaThread, Thread* parent):
|
Thread::Thread(Machine* m, object javaThread, Thread* parent):
|
||||||
@ -1736,8 +1731,11 @@ Thread::Thread(Machine* m, object javaThread, Thread* parent):
|
|||||||
protector(0),
|
protector(0),
|
||||||
runnable(this),
|
runnable(this),
|
||||||
defaultHeap(static_cast<uintptr_t*>
|
defaultHeap(static_cast<uintptr_t*>
|
||||||
(m->heap->allocate(HeapSizeInBytes, false))),
|
(m->heap->allocate(HeapSizeInBytes))),
|
||||||
heap(defaultHeap)
|
heap(defaultHeap),
|
||||||
|
backupHeap(0),
|
||||||
|
backupHeapIndex(0),
|
||||||
|
backupHeapSizeInWords(0)
|
||||||
#ifdef VM_STRESS
|
#ifdef VM_STRESS
|
||||||
, stress(false)
|
, stress(false)
|
||||||
#endif // VM_STRESS
|
#endif // VM_STRESS
|
||||||
@ -1873,7 +1871,7 @@ Thread::dispose()
|
|||||||
systemThread->dispose();
|
systemThread->dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
m->heap->free(defaultHeap, Thread::HeapSizeInBytes, false);
|
m->heap->free(defaultHeap, Thread::HeapSizeInBytes);
|
||||||
|
|
||||||
m->processor->dispose(this);
|
m->processor->dispose(this);
|
||||||
}
|
}
|
||||||
@ -2033,13 +2031,23 @@ allocate2(Thread* t, unsigned sizeInBytes, bool objectMask)
|
|||||||
(t, t->m->heap,
|
(t, t->m->heap,
|
||||||
ceiling(sizeInBytes, BytesPerWord) > Thread::HeapSizeInWords ?
|
ceiling(sizeInBytes, BytesPerWord) > Thread::HeapSizeInWords ?
|
||||||
Machine::FixedAllocation : Machine::MovableAllocation,
|
Machine::FixedAllocation : Machine::MovableAllocation,
|
||||||
sizeInBytes, false, objectMask);
|
sizeInBytes, objectMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
object
|
object
|
||||||
allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type,
|
allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type,
|
||||||
unsigned sizeInBytes, bool executable, bool objectMask)
|
unsigned sizeInBytes, bool objectMask)
|
||||||
{
|
{
|
||||||
|
if (t->backupHeap) {
|
||||||
|
expect(t, t->backupHeapIndex + ceiling(sizeInBytes, BytesPerWord)
|
||||||
|
<= t->backupHeapSizeInWords);
|
||||||
|
|
||||||
|
object o = reinterpret_cast<object>(t->backupHeap + t->backupHeapIndex);
|
||||||
|
t->backupHeapIndex += ceiling(sizeInBytes, BytesPerWord);
|
||||||
|
cast<object>(o, 0) = 0;
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
ACQUIRE_RAW(t, t->m->stateLock);
|
ACQUIRE_RAW(t, t->m->stateLock);
|
||||||
|
|
||||||
while (t->m->exclusive and t->m->exclusive != t) {
|
while (t->m->exclusive and t->m->exclusive != t) {
|
||||||
@ -2055,12 +2063,12 @@ allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type,
|
|||||||
t->heap = 0;
|
t->heap = 0;
|
||||||
}
|
}
|
||||||
} else if (t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
|
} else if (t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
|
||||||
>= Thread::HeapSizeInWords)
|
> Thread::HeapSizeInWords)
|
||||||
{
|
{
|
||||||
t->heap = 0;
|
t->heap = 0;
|
||||||
if (t->m->heapPoolIndex < Machine::HeapPoolSize) {
|
if (t->m->heapPoolIndex < Machine::HeapPoolSize) {
|
||||||
t->heap = static_cast<uintptr_t*>
|
t->heap = static_cast<uintptr_t*>
|
||||||
(t->m->heap->tryAllocate(Thread::HeapSizeInBytes, false));
|
(t->m->heap->tryAllocate(Thread::HeapSizeInBytes));
|
||||||
if (t->heap) {
|
if (t->heap) {
|
||||||
t->m->heapPool[t->m->heapPoolIndex++] = t->heap;
|
t->m->heapPool[t->m->heapPoolIndex++] = t->heap;
|
||||||
t->heapOffset += t->heapIndex;
|
t->heapOffset += t->heapIndex;
|
||||||
@ -2098,8 +2106,7 @@ allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type,
|
|||||||
unsigned total;
|
unsigned total;
|
||||||
object o = static_cast<object>
|
object o = static_cast<object>
|
||||||
(t->m->heap->allocateImmortal
|
(t->m->heap->allocateImmortal
|
||||||
(allocator, ceiling(sizeInBytes, BytesPerWord),
|
(allocator, ceiling(sizeInBytes, BytesPerWord), objectMask, &total));
|
||||||
executable, objectMask, &total));
|
|
||||||
|
|
||||||
cast<uintptr_t>(o, 0) = FixedMark;
|
cast<uintptr_t>(o, 0) = FixedMark;
|
||||||
|
|
||||||
@ -2150,6 +2157,24 @@ stringChars(Thread* t, object string, char* chars)
|
|||||||
chars[stringLength(t, string)] = 0;
|
chars[stringLength(t, string)] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
stringChars(Thread* t, object string, uint16_t* chars)
|
||||||
|
{
|
||||||
|
object data = stringData(t, string);
|
||||||
|
if (objectClass(t, data)
|
||||||
|
== arrayBody(t, t->m->types, Machine::ByteArrayType))
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < stringLength(t, string); ++i) {
|
||||||
|
chars[i] = byteArrayBody(t, data, stringOffset(t, string) + i);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
memcpy(chars,
|
||||||
|
&charArrayBody(t, data, stringOffset(t, string)),
|
||||||
|
stringLength(t, string) * sizeof(uint16_t));
|
||||||
|
}
|
||||||
|
chars[stringLength(t, string)] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
isAssignableFrom(Thread* t, object a, object b)
|
isAssignableFrom(Thread* t, object a, object b)
|
||||||
{
|
{
|
||||||
@ -2727,7 +2752,7 @@ collect(Thread* t, Heap::CollectionType type)
|
|||||||
killZombies(t, m->rootThread);
|
killZombies(t, m->rootThread);
|
||||||
|
|
||||||
for (unsigned i = 0; i < m->heapPoolIndex; ++i) {
|
for (unsigned i = 0; i < m->heapPoolIndex; ++i) {
|
||||||
m->heap->free(m->heapPool[i], Thread::HeapSizeInBytes, false);
|
m->heap->free(m->heapPool[i], Thread::HeapSizeInBytes);
|
||||||
}
|
}
|
||||||
m->heapPoolIndex = 0;
|
m->heapPoolIndex = 0;
|
||||||
|
|
||||||
@ -2818,7 +2843,7 @@ makeTrace(Thread* t, Processor::StackWalker* walker)
|
|||||||
}
|
}
|
||||||
|
|
||||||
object
|
object
|
||||||
makeTrace(Thread* t)
|
makeTrace(Thread* t, Thread* target)
|
||||||
{
|
{
|
||||||
class Visitor: public Processor::StackVisitor {
|
class Visitor: public Processor::StackVisitor {
|
||||||
public:
|
public:
|
||||||
@ -2833,7 +2858,7 @@ makeTrace(Thread* t)
|
|||||||
object trace;
|
object trace;
|
||||||
} v(t);
|
} v(t);
|
||||||
|
|
||||||
t->m->processor->walkStack(t, &v);
|
t->m->processor->walkStack(target, &v);
|
||||||
|
|
||||||
return v.trace ? v.trace : makeArray(t, 0, true);
|
return v.trace ? v.trace : makeArray(t, 0, true);
|
||||||
}
|
}
|
||||||
|
@ -1121,7 +1121,8 @@ class Machine {
|
|||||||
ImmortalAllocation
|
ImmortalAllocation
|
||||||
};
|
};
|
||||||
|
|
||||||
Machine(System* system, Heap* heap, Finder* finder, Processor* processor);
|
Machine(System* system, Heap* heap, Finder* finder, Processor* processor,
|
||||||
|
const char* bootLibrary, const char* builtins);
|
||||||
|
|
||||||
~Machine() {
|
~Machine() {
|
||||||
dispose();
|
dispose();
|
||||||
@ -1287,6 +1288,9 @@ class Thread {
|
|||||||
Runnable runnable;
|
Runnable runnable;
|
||||||
uintptr_t* defaultHeap;
|
uintptr_t* defaultHeap;
|
||||||
uintptr_t* heap;
|
uintptr_t* heap;
|
||||||
|
uintptr_t* backupHeap;
|
||||||
|
unsigned backupHeapIndex;
|
||||||
|
unsigned backupHeapSizeInWords;
|
||||||
#ifdef VM_STRESS
|
#ifdef VM_STRESS
|
||||||
bool stress;
|
bool stress;
|
||||||
#endif // VM_STRESS
|
#endif // VM_STRESS
|
||||||
@ -1327,7 +1331,7 @@ dispose(Thread* t, Reference* r)
|
|||||||
if (r->next) {
|
if (r->next) {
|
||||||
r->next->handle = r->handle;
|
r->next->handle = r->handle;
|
||||||
}
|
}
|
||||||
t->m->heap->free(r, sizeof(*r), false);
|
t->m->heap->free(r, sizeof(*r));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -1425,12 +1429,26 @@ expect(Thread* t, bool v)
|
|||||||
expect(t->m->system, v);
|
expect(t->m->system, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
ensure(Thread* t, unsigned sizeInBytes)
|
||||||
|
{
|
||||||
|
if (t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
|
||||||
|
> Thread::HeapSizeInWords)
|
||||||
|
{
|
||||||
|
expect(t, t->backupHeap == 0);
|
||||||
|
t->backupHeap = static_cast<uintptr_t*>
|
||||||
|
(t->m->heap->allocate(pad(sizeInBytes)));
|
||||||
|
t->backupHeapIndex = 0;
|
||||||
|
t->backupHeapSizeInWords = ceiling(sizeInBytes, BytesPerWord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
object
|
object
|
||||||
allocate2(Thread* t, unsigned sizeInBytes, bool objectMask);
|
allocate2(Thread* t, unsigned sizeInBytes, bool objectMask);
|
||||||
|
|
||||||
object
|
object
|
||||||
allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type,
|
allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type,
|
||||||
unsigned sizeInBytes, bool executable, bool objectMask);
|
unsigned sizeInBytes, bool objectMask);
|
||||||
|
|
||||||
inline object
|
inline object
|
||||||
allocateSmall(Thread* t, unsigned sizeInBytes)
|
allocateSmall(Thread* t, unsigned sizeInBytes)
|
||||||
@ -1447,7 +1465,7 @@ allocate(Thread* t, unsigned sizeInBytes, bool objectMask)
|
|||||||
stress(t);
|
stress(t);
|
||||||
|
|
||||||
if (UNLIKELY(t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
|
if (UNLIKELY(t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
|
||||||
>= Thread::HeapSizeInWords
|
> Thread::HeapSizeInWords
|
||||||
or t->m->exclusive))
|
or t->m->exclusive))
|
||||||
{
|
{
|
||||||
return allocate2(t, sizeInBytes, objectMask);
|
return allocate2(t, sizeInBytes, objectMask);
|
||||||
@ -1484,7 +1502,7 @@ setObjectClass(Thread*, object o, object value)
|
|||||||
cast<object>(o, 0)
|
cast<object>(o, 0)
|
||||||
= reinterpret_cast<object>
|
= reinterpret_cast<object>
|
||||||
(reinterpret_cast<uintptr_t>(value)
|
(reinterpret_cast<uintptr_t>(value)
|
||||||
| reinterpret_cast<uintptr_t>(cast<object>(o, 0)) & (~PointerMask));
|
| (reinterpret_cast<uintptr_t>(cast<object>(o, 0)) & (~PointerMask)));
|
||||||
}
|
}
|
||||||
|
|
||||||
object&
|
object&
|
||||||
@ -1526,7 +1544,13 @@ object
|
|||||||
makeTrace(Thread* t, Processor::StackWalker* walker);
|
makeTrace(Thread* t, Processor::StackWalker* walker);
|
||||||
|
|
||||||
object
|
object
|
||||||
makeTrace(Thread* t);
|
makeTrace(Thread* t, Thread* target);
|
||||||
|
|
||||||
|
inline object
|
||||||
|
makeTrace(Thread* t)
|
||||||
|
{
|
||||||
|
return makeTrace(t, t);
|
||||||
|
}
|
||||||
|
|
||||||
inline object
|
inline object
|
||||||
makeRuntimeException(Thread* t, object message)
|
makeRuntimeException(Thread* t, object message)
|
||||||
@ -1702,6 +1726,9 @@ makeString(Thread* t, const char* format, ...);
|
|||||||
void
|
void
|
||||||
stringChars(Thread* t, object string, char* chars);
|
stringChars(Thread* t, object string, char* chars);
|
||||||
|
|
||||||
|
void
|
||||||
|
stringChars(Thread* t, object string, uint16_t* chars);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
isAssignableFrom(Thread* t, object a, object b);
|
isAssignableFrom(Thread* t, object a, object b);
|
||||||
|
|
||||||
@ -2231,6 +2258,7 @@ inline object
|
|||||||
makeSingleton(Thread* t, unsigned count)
|
makeSingleton(Thread* t, unsigned count)
|
||||||
{
|
{
|
||||||
object o = makeSingleton(t, count + singletonMaskSize(count), true);
|
object o = makeSingleton(t, count + singletonMaskSize(count), true);
|
||||||
|
assert(t, singletonLength(t, o) == count + singletonMaskSize(t, o));
|
||||||
if (count) {
|
if (count) {
|
||||||
singletonMask(t, o)[0] = 1;
|
singletonMask(t, o)[0] = 1;
|
||||||
}
|
}
|
||||||
|
40
src/main.cpp
40
src/main.cpp
@ -14,37 +14,12 @@
|
|||||||
#include "stdint.h"
|
#include "stdint.h"
|
||||||
#include "jni.h"
|
#include "jni.h"
|
||||||
|
|
||||||
// since we don't link against libstdc++, we must implement some dummy
|
|
||||||
// functions:
|
|
||||||
extern "C" void __cxa_pure_virtual(void) { abort(); }
|
|
||||||
void operator delete(void*) { abort(); }
|
|
||||||
|
|
||||||
#ifdef __MINGW32__
|
#ifdef __MINGW32__
|
||||||
# define PATH_SEPARATOR ';'
|
# define PATH_SEPARATOR ';'
|
||||||
# define EXPORT __declspec(dllexport)
|
|
||||||
# define SYMBOL(x) binary_classpath_jar_##x
|
|
||||||
#else
|
#else
|
||||||
# define PATH_SEPARATOR ':'
|
# define PATH_SEPARATOR ':'
|
||||||
# define EXPORT __attribute__ ((visibility("default")))
|
|
||||||
# define SYMBOL(x) _binary_classpath_jar_##x
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define BOOT_CLASSPATH "[classpathJar]"
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
|
|
||||||
extern const uint8_t SYMBOL(start)[];
|
|
||||||
extern const uint8_t SYMBOL(size)[];
|
|
||||||
|
|
||||||
EXPORT const uint8_t*
|
|
||||||
classpathJar(unsigned* size)
|
|
||||||
{
|
|
||||||
*size = reinterpret_cast<uintptr_t>(SYMBOL(size));
|
|
||||||
return SYMBOL(start);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef JNI_VERSION_1_6
|
#ifdef JNI_VERSION_1_6
|
||||||
// todo: use JavaVMInitArgs instead
|
// todo: use JavaVMInitArgs instead
|
||||||
typedef struct JDK1_1InitArgs {
|
typedef struct JDK1_1InitArgs {
|
||||||
@ -121,14 +96,25 @@ main(int ac, const char** av)
|
|||||||
vmArgs.classpath = classpath;
|
vmArgs.classpath = classpath;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const char* properties[propertyCount + 1];
|
#ifdef BOOT_LIBRARY
|
||||||
properties[propertyCount] = 0;
|
const int BootPropertyCount = 1;
|
||||||
|
#else
|
||||||
|
const int BootPropertyCount = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const char* properties[propertyCount + BootPropertyCount + 1];
|
||||||
|
properties[propertyCount + BootPropertyCount] = 0;
|
||||||
for (int i = 1; i < ac; ++i) {
|
for (int i = 1; i < ac; ++i) {
|
||||||
if (strncmp(av[i], "-D", 2) == 0) {
|
if (strncmp(av[i], "-D", 2) == 0) {
|
||||||
properties[--propertyCount] = av[i] + 2;
|
properties[--propertyCount] = av[i] + 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef BOOT_LIBRARY
|
||||||
|
properties[propertyCount + BootPropertyCount - 1]
|
||||||
|
= "avian.bootstrap=" BOOT_LIBRARY;
|
||||||
|
#endif
|
||||||
|
|
||||||
vmArgs.properties = const_cast<char**>(properties);
|
vmArgs.properties = const_cast<char**>(properties);
|
||||||
|
|
||||||
if (class_ == 0) {
|
if (class_ == 0) {
|
||||||
|
293
src/posix.cpp
293
src/posix.cpp
@ -35,9 +35,6 @@ using namespace vm;
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
System::SignalHandler* segFaultHandler = 0;
|
|
||||||
struct sigaction oldSegFaultHandler;
|
|
||||||
|
|
||||||
class MutexResource {
|
class MutexResource {
|
||||||
public:
|
public:
|
||||||
MutexResource(pthread_mutex_t& m): m(&m) {
|
MutexResource(pthread_mutex_t& m): m(&m) {
|
||||||
@ -52,12 +49,22 @@ class MutexResource {
|
|||||||
pthread_mutex_t* m;
|
pthread_mutex_t* m;
|
||||||
};
|
};
|
||||||
|
|
||||||
const int InterruptSignal = SIGUSR2;
|
const int VisitSignal = SIGUSR1;
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
const int SegFaultSignal = SIGBUS;
|
const int SegFaultSignal = SIGBUS;
|
||||||
#else
|
#else
|
||||||
const int SegFaultSignal = SIGSEGV;
|
const int SegFaultSignal = SIGSEGV;
|
||||||
#endif
|
#endif
|
||||||
|
const int InterruptSignal = SIGUSR2;
|
||||||
|
|
||||||
|
const unsigned VisitSignalIndex = 0;
|
||||||
|
const unsigned SegFaultSignalIndex = 1;
|
||||||
|
const unsigned InterruptSignalIndex = 2;
|
||||||
|
|
||||||
|
class MySystem;
|
||||||
|
MySystem* system;
|
||||||
|
|
||||||
|
const int signals[] = { VisitSignal, SegFaultSignal, InterruptSignal };
|
||||||
|
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
# define IP_REGISTER(context) (context->uc_mcontext.gregs[REG_RIP])
|
# define IP_REGISTER(context) (context->uc_mcontext.gregs[REG_RIP])
|
||||||
@ -65,10 +72,17 @@ const int SegFaultSignal = SIGSEGV;
|
|||||||
# define STACK_REGISTER(context) (context->uc_mcontext.gregs[REG_RSP])
|
# define STACK_REGISTER(context) (context->uc_mcontext.gregs[REG_RSP])
|
||||||
# define THREAD_REGISTER(context) (context->uc_mcontext.gregs[REG_RBX])
|
# define THREAD_REGISTER(context) (context->uc_mcontext.gregs[REG_RBX])
|
||||||
#elif defined __APPLE__
|
#elif defined __APPLE__
|
||||||
# define IP_REGISTER(context) (context->uc_mcontext->__ss.__eip)
|
# if __DARWIN_UNIX03 && defined(_STRUCT_X86_EXCEPTION_STATE32)
|
||||||
# define BASE_REGISTER(context) (context->uc_mcontext->__ss.__ebp)
|
# define IP_REGISTER(context) (context->uc_mcontext->__ss.__eip)
|
||||||
# define STACK_REGISTER(context) (context->uc_mcontext->__ss.__esp)
|
# define BASE_REGISTER(context) (context->uc_mcontext->__ss.__ebp)
|
||||||
# define THREAD_REGISTER(context) (context->uc_mcontext->__ss.__ebx)
|
# define STACK_REGISTER(context) (context->uc_mcontext->__ss.__esp)
|
||||||
|
# define THREAD_REGISTER(context) (context->uc_mcontext->__ss.__ebx)
|
||||||
|
# else
|
||||||
|
# define IP_REGISTER(context) (context->uc_mcontext->ss.eip)
|
||||||
|
# define BASE_REGISTER(context) (context->uc_mcontext->ss.ebp)
|
||||||
|
# define STACK_REGISTER(context) (context->uc_mcontext->ss.esp)
|
||||||
|
# define THREAD_REGISTER(context) (context->uc_mcontext->ss.ebx)
|
||||||
|
# endif
|
||||||
#elif defined __i386__
|
#elif defined __i386__
|
||||||
# define IP_REGISTER(context) (context->uc_mcontext.gregs[REG_EIP])
|
# define IP_REGISTER(context) (context->uc_mcontext.gregs[REG_EIP])
|
||||||
# define BASE_REGISTER(context) (context->uc_mcontext.gregs[REG_EBP])
|
# define BASE_REGISTER(context) (context->uc_mcontext.gregs[REG_EBP])
|
||||||
@ -79,41 +93,7 @@ const int SegFaultSignal = SIGSEGV;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
void
|
void
|
||||||
handleSignal(int signal, siginfo_t* info, void* context)
|
handleSignal(int signal, siginfo_t* info, void* context);
|
||||||
{
|
|
||||||
if (signal == SegFaultSignal) {
|
|
||||||
ucontext_t* c = static_cast<ucontext_t*>(context);
|
|
||||||
|
|
||||||
void* ip = reinterpret_cast<void*>(IP_REGISTER(c));
|
|
||||||
void* base = reinterpret_cast<void*>(BASE_REGISTER(c));
|
|
||||||
void* stack = reinterpret_cast<void*>(STACK_REGISTER(c));
|
|
||||||
void* thread = reinterpret_cast<void*>(THREAD_REGISTER(c));
|
|
||||||
|
|
||||||
bool jump = segFaultHandler->handleSignal
|
|
||||||
(&ip, &base, &stack, &thread);
|
|
||||||
|
|
||||||
if (jump) {
|
|
||||||
// I'd like to use setcontext here (and get rid of the
|
|
||||||
// sigprocmask call), but it doesn't work on my Linux x86_64
|
|
||||||
// system, and I can't tell from the documentation if it's even
|
|
||||||
// supposed to work.
|
|
||||||
|
|
||||||
sigset_t set;
|
|
||||||
|
|
||||||
sigemptyset(&set);
|
|
||||||
sigaddset(&set, SegFaultSignal);
|
|
||||||
sigprocmask(SIG_UNBLOCK, &set, 0);
|
|
||||||
|
|
||||||
vmJump(ip, base, stack, thread);
|
|
||||||
} else if (oldSegFaultHandler.sa_flags & SA_SIGINFO) {
|
|
||||||
oldSegFaultHandler.sa_sigaction(signal, info, context);
|
|
||||||
} else if (oldSegFaultHandler.sa_handler) {
|
|
||||||
oldSegFaultHandler.sa_handler(signal);
|
|
||||||
} else {
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void*
|
void*
|
||||||
run(void* r)
|
run(void* r)
|
||||||
@ -125,7 +105,7 @@ run(void* r)
|
|||||||
void*
|
void*
|
||||||
allocate(System* s, unsigned size)
|
allocate(System* s, unsigned size)
|
||||||
{
|
{
|
||||||
void* p = s->tryAllocate(size, false);
|
void* p = s->tryAllocate(size);
|
||||||
if (p == 0) abort();
|
if (p == 0) abort();
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
@ -187,7 +167,7 @@ class MySystem: public System {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void dispose() {
|
virtual void dispose() {
|
||||||
s->free(this, sizeof(*this), false);
|
s->free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_t thread;
|
pthread_t thread;
|
||||||
@ -215,7 +195,7 @@ class MySystem: public System {
|
|||||||
|
|
||||||
virtual void dispose() {
|
virtual void dispose() {
|
||||||
pthread_mutex_destroy(&mutex);
|
pthread_mutex_destroy(&mutex);
|
||||||
s->free(this, sizeof(*this), false);
|
s->free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
@ -414,7 +394,7 @@ class MySystem: public System {
|
|||||||
virtual void dispose() {
|
virtual void dispose() {
|
||||||
expect(s, owner_ == 0);
|
expect(s, owner_ == 0);
|
||||||
pthread_mutex_destroy(&mutex);
|
pthread_mutex_destroy(&mutex);
|
||||||
s->free(this, sizeof(*this), false);
|
s->free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
@ -445,7 +425,7 @@ class MySystem: public System {
|
|||||||
int r UNUSED = pthread_key_delete(key);
|
int r UNUSED = pthread_key_delete(key);
|
||||||
expect(s, r == 0);
|
expect(s, r == 0);
|
||||||
|
|
||||||
s->free(this, sizeof(*this), false);
|
s->free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
@ -472,7 +452,7 @@ class MySystem: public System {
|
|||||||
if (start_) {
|
if (start_) {
|
||||||
munmap(start_, length_);
|
munmap(start_, length_);
|
||||||
}
|
}
|
||||||
s->free(this, sizeof(*this), false);
|
s->free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
@ -525,10 +505,10 @@ class MySystem: public System {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (name_) {
|
if (name_) {
|
||||||
s->free(name_, nameLength + 1, false);
|
s->free(name_);
|
||||||
}
|
}
|
||||||
|
|
||||||
s->free(this, sizeof(*this), false);
|
s->free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
@ -540,49 +520,63 @@ class MySystem: public System {
|
|||||||
System::Library* next_;
|
System::Library* next_;
|
||||||
};
|
};
|
||||||
|
|
||||||
MySystem() {
|
MySystem(): threadVisitor(0), visitTarget(0) {
|
||||||
struct sigaction sa;
|
expect(this, system == 0);
|
||||||
memset(&sa, 0, sizeof(struct sigaction));
|
system = this;
|
||||||
sigemptyset(&(sa.sa_mask));
|
|
||||||
sa.sa_flags = SA_SIGINFO;
|
registerHandler(&nullHandler, InterruptSignalIndex);
|
||||||
sa.sa_sigaction = handleSignal;
|
registerHandler(&nullHandler, VisitSignalIndex);
|
||||||
|
|
||||||
|
expect(this, make(&visitLock) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int registerHandler(System::SignalHandler* handler, int index) {
|
||||||
|
if (handler) {
|
||||||
|
handlers[index] = handler;
|
||||||
|
|
||||||
|
struct sigaction sa;
|
||||||
|
memset(&sa, 0, sizeof(struct sigaction));
|
||||||
|
sigemptyset(&(sa.sa_mask));
|
||||||
|
sa.sa_flags = SA_SIGINFO;
|
||||||
|
sa.sa_sigaction = handleSignal;
|
||||||
|
|
||||||
int rv UNUSED = sigaction(InterruptSignal, &sa, 0);
|
return sigaction(signals[index], &sa, oldHandlers + index);
|
||||||
expect(this, rv == 0);
|
} else if (handlers[index]) {
|
||||||
}
|
handlers[index] = 0;
|
||||||
|
return sigaction(signals[index], oldHandlers + index, 0);
|
||||||
virtual void* tryAllocate(unsigned size, bool executable) {
|
|
||||||
assert(this, (not executable) or (size % LikelyPageSizeInBytes == 0));
|
|
||||||
|
|
||||||
#ifndef MAP_32BIT
|
|
||||||
#define MAP_32BIT 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (executable) {
|
|
||||||
void* p = mmap(0, size, PROT_EXEC | PROT_READ | PROT_WRITE,
|
|
||||||
MAP_PRIVATE | MAP_ANON | MAP_32BIT, -1, 0);
|
|
||||||
|
|
||||||
if (p == MAP_FAILED) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return malloc(size);
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void free(const void* p, unsigned size, bool executable) {
|
virtual void* tryAllocate(unsigned sizeInBytes) {
|
||||||
if (p) {
|
return malloc(sizeInBytes);
|
||||||
if (executable) {
|
}
|
||||||
int r UNUSED = munmap(const_cast<void*>(p), size);
|
|
||||||
assert(this, r == 0);
|
virtual void free(const void* p) {
|
||||||
} else {
|
if (p) ::free(const_cast<void*>(p));
|
||||||
::free(const_cast<void*>(p));
|
}
|
||||||
}
|
|
||||||
|
virtual void* tryAllocateExecutable(unsigned sizeInBytes) {
|
||||||
|
assert(this, sizeInBytes % LikelyPageSizeInBytes == 0);
|
||||||
|
|
||||||
|
void* p = mmap(0, sizeInBytes, PROT_EXEC | PROT_READ | PROT_WRITE,
|
||||||
|
MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||||
|
|
||||||
|
if (p == MAP_FAILED) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return p;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void freeExecutable(const void* p, unsigned sizeInBytes) {
|
||||||
|
assert(this, sizeInBytes % LikelyPageSizeInBytes == 0);
|
||||||
|
|
||||||
|
int r UNUSED = munmap(const_cast<void*>(p), sizeInBytes);
|
||||||
|
assert(this, r == 0);
|
||||||
|
}
|
||||||
|
|
||||||
virtual bool success(Status s) {
|
virtual bool success(Status s) {
|
||||||
return s == 0;
|
return s == 0;
|
||||||
}
|
}
|
||||||
@ -618,22 +612,32 @@ class MySystem: public System {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual Status handleSegFault(SignalHandler* handler) {
|
virtual Status handleSegFault(SignalHandler* handler) {
|
||||||
if (handler) {
|
return registerHandler(handler, SegFaultSignalIndex);
|
||||||
segFaultHandler = handler;
|
}
|
||||||
|
|
||||||
struct sigaction sa;
|
virtual Status visit(System::Thread* st, System::Thread* sTarget,
|
||||||
memset(&sa, 0, sizeof(struct sigaction));
|
ThreadVisitor* visitor)
|
||||||
sigemptyset(&(sa.sa_mask));
|
{
|
||||||
sa.sa_flags = SA_SIGINFO;
|
assert(this, st != sTarget);
|
||||||
sa.sa_sigaction = handleSignal;
|
|
||||||
|
Thread* t = static_cast<Thread*>(st);
|
||||||
return sigaction(SegFaultSignal, &sa, &oldSegFaultHandler);
|
Thread* target = static_cast<Thread*>(sTarget);
|
||||||
} else if (segFaultHandler) {
|
|
||||||
segFaultHandler = 0;
|
ACQUIRE_MONITOR(t, visitLock);
|
||||||
return sigaction(SegFaultSignal, &oldSegFaultHandler, 0);
|
|
||||||
} else {
|
while (threadVisitor) visitLock->wait(t, 0);
|
||||||
return 1;
|
|
||||||
}
|
threadVisitor = visitor;
|
||||||
|
visitTarget = target;
|
||||||
|
|
||||||
|
int rv = pthread_kill(target->thread, VisitSignal);
|
||||||
|
expect(this, rv == 0);
|
||||||
|
|
||||||
|
while (visitTarget) visitLock->wait(t, 0);
|
||||||
|
|
||||||
|
threadVisitor = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual uint64_t call(void* function, uintptr_t* arguments, uint8_t* types,
|
virtual uint64_t call(void* function, uintptr_t* arguments, uint8_t* types,
|
||||||
@ -687,18 +691,18 @@ class MySystem: public System {
|
|||||||
bool alreadyAllocated = false;
|
bool alreadyAllocated = false;
|
||||||
bool isMain = false;
|
bool isMain = false;
|
||||||
unsigned nameLength = (name ? strlen(name) : 0);
|
unsigned nameLength = (name ? strlen(name) : 0);
|
||||||
if (mapName) {
|
if (mapName and name) {
|
||||||
unsigned size = nameLength + 3 + sizeof(SO_SUFFIX);
|
unsigned size = nameLength + 3 + sizeof(SO_SUFFIX);
|
||||||
char buffer[size];
|
char buffer[size];
|
||||||
snprintf(buffer, size, "lib%s" SO_SUFFIX, name);
|
snprintf(buffer, size, "lib%s" SO_SUFFIX, name);
|
||||||
p = dlopen(buffer, RTLD_LAZY);
|
p = dlopen(buffer, RTLD_LAZY | RTLD_LOCAL);
|
||||||
} else {
|
} else {
|
||||||
if (!name) {
|
if (!name) {
|
||||||
pathOfExecutable(this, &name, &nameLength);
|
pathOfExecutable(this, &name, &nameLength);
|
||||||
alreadyAllocated = true;
|
alreadyAllocated = true;
|
||||||
isMain = true;
|
isMain = true;
|
||||||
}
|
}
|
||||||
p = dlopen(name, RTLD_LAZY);
|
p = dlopen(name, RTLD_LAZY | RTLD_LOCAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p) {
|
if (p) {
|
||||||
@ -711,7 +715,7 @@ class MySystem: public System {
|
|||||||
n = static_cast<char*>(allocate(this, nameLength + 1));
|
n = static_cast<char*>(allocate(this, nameLength + 1));
|
||||||
memcpy(n, name, nameLength + 1);
|
memcpy(n, name, nameLength + 1);
|
||||||
if (alreadyAllocated) {
|
if (alreadyAllocated) {
|
||||||
free(name, nameLength, false);
|
free(name);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
n = 0;
|
n = 0;
|
||||||
@ -747,10 +751,89 @@ class MySystem: public System {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void dispose() {
|
virtual void dispose() {
|
||||||
|
visitLock->dispose();
|
||||||
|
|
||||||
|
registerHandler(0, InterruptSignalIndex);
|
||||||
|
registerHandler(0, VisitSignalIndex);
|
||||||
|
system = 0;
|
||||||
|
|
||||||
::free(this);
|
::free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class NullSignalHandler: public SignalHandler {
|
||||||
|
virtual bool handleSignal(void**, void**, void**, void**) { return false; }
|
||||||
|
} nullHandler;
|
||||||
|
|
||||||
|
SignalHandler* handlers[3];
|
||||||
|
struct sigaction oldHandlers[3];
|
||||||
|
|
||||||
|
ThreadVisitor* threadVisitor;
|
||||||
|
Thread* visitTarget;
|
||||||
|
System::Monitor* visitLock;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
handleSignal(int signal, siginfo_t* info, void* context)
|
||||||
|
{
|
||||||
|
ucontext_t* c = static_cast<ucontext_t*>(context);
|
||||||
|
|
||||||
|
void* ip = reinterpret_cast<void*>(IP_REGISTER(c));
|
||||||
|
void* base = reinterpret_cast<void*>(BASE_REGISTER(c));
|
||||||
|
void* stack = reinterpret_cast<void*>(STACK_REGISTER(c));
|
||||||
|
void* thread = reinterpret_cast<void*>(THREAD_REGISTER(c));
|
||||||
|
|
||||||
|
unsigned index;
|
||||||
|
|
||||||
|
switch (signal) {
|
||||||
|
case VisitSignal: {
|
||||||
|
index = VisitSignalIndex;
|
||||||
|
|
||||||
|
system->threadVisitor->visit(ip, base, stack);
|
||||||
|
|
||||||
|
System::Thread* t = system->visitTarget;
|
||||||
|
system->visitTarget = 0;
|
||||||
|
system->visitLock->notifyAll(t);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case SegFaultSignal: {
|
||||||
|
index = SegFaultSignalIndex;
|
||||||
|
|
||||||
|
bool jump = system->handlers[index]->handleSignal
|
||||||
|
(&ip, &base, &stack, &thread);
|
||||||
|
|
||||||
|
if (jump) {
|
||||||
|
// I'd like to use setcontext here (and get rid of the
|
||||||
|
// sigprocmask call), but it doesn't work on my Linux x86_64
|
||||||
|
// system, and I can't tell from the documentation if it's even
|
||||||
|
// supposed to work.
|
||||||
|
|
||||||
|
sigset_t set;
|
||||||
|
|
||||||
|
sigemptyset(&set);
|
||||||
|
sigaddset(&set, SegFaultSignal);
|
||||||
|
sigprocmask(SIG_UNBLOCK, &set, 0);
|
||||||
|
|
||||||
|
vmJump(ip, base, stack, thread);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case InterruptSignal: {
|
||||||
|
index = InterruptSignalIndex;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default: abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (system->oldHandlers[index].sa_flags & SA_SIGINFO) {
|
||||||
|
system->oldHandlers[index].sa_sigaction(signal, info, context);
|
||||||
|
} else if (system->oldHandlers[index].sa_handler) {
|
||||||
|
system->oldHandlers[index].sa_handler(signal);
|
||||||
|
} else {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace vm {
|
namespace vm {
|
||||||
|
@ -191,50 +191,6 @@ resolveNativeMethod2(Thread* t, object method)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExceptionHandler*
|
|
||||||
findExceptionHandler(Thread* t, object method, unsigned ip)
|
|
||||||
{
|
|
||||||
PROTECT(t, method);
|
|
||||||
|
|
||||||
object eht = codeExceptionHandlerTable(t, methodCode(t, method));
|
|
||||||
|
|
||||||
if (eht) {
|
|
||||||
for (unsigned i = 0; i < exceptionHandlerTableLength(t, eht); ++i) {
|
|
||||||
ExceptionHandler* eh = exceptionHandlerTableBody(t, eht, i);
|
|
||||||
|
|
||||||
if (ip - 1 >= exceptionHandlerStart(eh)
|
|
||||||
and ip - 1 < exceptionHandlerEnd(eh))
|
|
||||||
{
|
|
||||||
object catchType = 0;
|
|
||||||
if (exceptionHandlerCatchType(eh)) {
|
|
||||||
object e = t->exception;
|
|
||||||
t->exception = 0;
|
|
||||||
PROTECT(t, e);
|
|
||||||
|
|
||||||
PROTECT(t, eht);
|
|
||||||
catchType = resolveClassInPool
|
|
||||||
(t, codePool(t, methodCode(t, method)),
|
|
||||||
exceptionHandlerCatchType(eh) - 1);
|
|
||||||
|
|
||||||
if (catchType) {
|
|
||||||
eh = exceptionHandlerTableBody(t, eht, i);
|
|
||||||
t->exception = e;
|
|
||||||
} else {
|
|
||||||
// can't find what we're supposed to catch - move on.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (catchType == 0 or instanceOf(t, catchType, t->exception)) {
|
|
||||||
return eh;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
findLineNumber(Thread* t, object method, unsigned ip)
|
findLineNumber(Thread* t, object method, unsigned ip)
|
||||||
{
|
{
|
||||||
|
@ -40,8 +40,7 @@ inline object
|
|||||||
resolveClassInObject(Thread* t, object container, unsigned classOffset)
|
resolveClassInObject(Thread* t, object container, unsigned classOffset)
|
||||||
{
|
{
|
||||||
object o = cast<object>(container, classOffset);
|
object o = cast<object>(container, classOffset);
|
||||||
if (objectClass(t, o) == arrayBody(t, t->m->types, Machine::ByteArrayType))
|
if (objectClass(t, o) == arrayBody(t, t->m->types, Machine::ByteArrayType)) {
|
||||||
{
|
|
||||||
PROTECT(t, container);
|
PROTECT(t, container);
|
||||||
|
|
||||||
o = resolveClass(t, o);
|
o = resolveClass(t, o);
|
||||||
@ -56,8 +55,7 @@ inline object
|
|||||||
resolveClassInPool(Thread* t, object pool, unsigned index)
|
resolveClassInPool(Thread* t, object pool, unsigned index)
|
||||||
{
|
{
|
||||||
object o = singletonObject(t, pool, index);
|
object o = singletonObject(t, pool, index);
|
||||||
if (objectClass(t, o) == arrayBody(t, t->m->types, Machine::ByteArrayType))
|
if (objectClass(t, o) == arrayBody(t, t->m->types, Machine::ByteArrayType)) {
|
||||||
{
|
|
||||||
PROTECT(t, pool);
|
PROTECT(t, pool);
|
||||||
|
|
||||||
o = resolveClass(t, o);
|
o = resolveClass(t, o);
|
||||||
@ -194,9 +192,6 @@ populateMultiArray(Thread* t, object array, int32_t* counts,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ExceptionHandler*
|
|
||||||
findExceptionHandler(Thread* t, object method, unsigned ip);
|
|
||||||
|
|
||||||
int
|
int
|
||||||
findLineNumber(Thread* t, object method, unsigned ip);
|
findLineNumber(Thread* t, object method, unsigned ip);
|
||||||
|
|
||||||
|
@ -115,6 +115,9 @@ class Processor {
|
|||||||
virtual void
|
virtual void
|
||||||
dispose() = 0;
|
dispose() = 0;
|
||||||
|
|
||||||
|
virtual object
|
||||||
|
getStackTrace(Thread* t, Thread* target) = 0;
|
||||||
|
|
||||||
object
|
object
|
||||||
invoke(Thread* t, object method, object this_, ...)
|
invoke(Thread* t, object method, object this_, ...)
|
||||||
{
|
{
|
||||||
|
32
src/system.h
32
src/system.h
@ -34,6 +34,12 @@ class System {
|
|||||||
virtual void dispose() = 0;
|
virtual void dispose() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ThreadVisitor {
|
||||||
|
public:
|
||||||
|
virtual ~ThreadVisitor() { }
|
||||||
|
virtual void visit(void* ip, void* base, void* stack) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
class Runnable {
|
class Runnable {
|
||||||
public:
|
public:
|
||||||
virtual ~Runnable() { }
|
virtual ~Runnable() { }
|
||||||
@ -99,17 +105,36 @@ class System {
|
|||||||
void** thread) = 0;
|
void** thread) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class MonitorResource {
|
||||||
|
public:
|
||||||
|
MonitorResource(System::Thread* t, System::Monitor* m): t(t), m(m) {
|
||||||
|
m->acquire(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
~MonitorResource() {
|
||||||
|
m->release(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
System::Thread* t;
|
||||||
|
System::Monitor* m;
|
||||||
|
};
|
||||||
|
|
||||||
virtual ~System() { }
|
virtual ~System() { }
|
||||||
|
|
||||||
virtual bool success(Status) = 0;
|
virtual bool success(Status) = 0;
|
||||||
virtual void* tryAllocate(unsigned size, bool executable) = 0;
|
virtual void* tryAllocate(unsigned sizeInBytes) = 0;
|
||||||
virtual void free(const void* p, unsigned size, bool executable) = 0;
|
virtual void free(const void* p) = 0;
|
||||||
|
virtual void* tryAllocateExecutable(unsigned sizeInBytes) = 0;
|
||||||
|
virtual void freeExecutable(const void* p, unsigned sizeInBytes) = 0;
|
||||||
virtual Status attach(Runnable*) = 0;
|
virtual Status attach(Runnable*) = 0;
|
||||||
virtual Status start(Runnable*) = 0;
|
virtual Status start(Runnable*) = 0;
|
||||||
virtual Status make(Mutex**) = 0;
|
virtual Status make(Mutex**) = 0;
|
||||||
virtual Status make(Monitor**) = 0;
|
virtual Status make(Monitor**) = 0;
|
||||||
virtual Status make(Local**) = 0;
|
virtual Status make(Local**) = 0;
|
||||||
virtual Status handleSegFault(SignalHandler* handler) = 0;
|
virtual Status handleSegFault(SignalHandler* handler) = 0;
|
||||||
|
virtual Status visit(Thread* thread, Thread* target,
|
||||||
|
ThreadVisitor* visitor) = 0;
|
||||||
virtual uint64_t call(void* function, uintptr_t* arguments, uint8_t* types,
|
virtual uint64_t call(void* function, uintptr_t* arguments, uint8_t* types,
|
||||||
unsigned count, unsigned size,
|
unsigned count, unsigned size,
|
||||||
unsigned returnType) = 0;
|
unsigned returnType) = 0;
|
||||||
@ -123,6 +148,9 @@ class System {
|
|||||||
virtual void dispose() = 0;
|
virtual void dispose() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define ACQUIRE_MONITOR(t, m) \
|
||||||
|
System::MonitorResource MAKE_NAME(monitorResource_) (t, m)
|
||||||
|
|
||||||
inline void NO_RETURN
|
inline void NO_RETURN
|
||||||
abort(System* s)
|
abort(System* s)
|
||||||
{
|
{
|
||||||
|
@ -1507,7 +1507,7 @@ writeOffset(Output* out, Object* offset, bool allocationStyle = false)
|
|||||||
out->write("length");
|
out->write("length");
|
||||||
} else {
|
} else {
|
||||||
out->write(typeName(memberOwner(o)));
|
out->write(typeName(memberOwner(o)));
|
||||||
out->write(capitalize("length"));
|
out->write("Length");
|
||||||
out->write("(o)");
|
out->write("(o)");
|
||||||
}
|
}
|
||||||
out->write(" * ");
|
out->write(" * ");
|
||||||
@ -1762,6 +1762,49 @@ typeFixedSize(Object* type)
|
|||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned
|
||||||
|
typeArrayElementSize(Object* type)
|
||||||
|
{
|
||||||
|
for (MemberIterator it(type); it.hasMore();) {
|
||||||
|
Object* m = it.next();
|
||||||
|
switch (m->type) {
|
||||||
|
case Object::Scalar: break;
|
||||||
|
|
||||||
|
case Object::Array: {
|
||||||
|
return memberElementSize(m);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default: UNREACHABLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
writeSizes(Output* out, Object* declarations)
|
||||||
|
{
|
||||||
|
for (Object* p = declarations; p; p = cdr(p)) {
|
||||||
|
Object* o = car(p);
|
||||||
|
switch (o->type) {
|
||||||
|
case Object::Type: {
|
||||||
|
out->write("const unsigned FixedSizeOf");
|
||||||
|
out->write(capitalize(typeName(o)));
|
||||||
|
out->write(" = ");
|
||||||
|
out->write(typeFixedSize(o));
|
||||||
|
out->write(";\n\n");
|
||||||
|
|
||||||
|
out->write("const unsigned ArrayElementSizeOf");
|
||||||
|
out->write(capitalize(typeName(o)));
|
||||||
|
out->write(" = ");
|
||||||
|
out->write(typeArrayElementSize(o));
|
||||||
|
out->write(";\n\n");
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const char*
|
const char*
|
||||||
obfuscate(const char* s)
|
obfuscate(const char* s)
|
||||||
{
|
{
|
||||||
@ -2049,24 +2092,6 @@ set(uint32_t* mask, unsigned index)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned
|
|
||||||
typeArrayElementSize(Object* type)
|
|
||||||
{
|
|
||||||
for (MemberIterator it(type); it.hasMore();) {
|
|
||||||
Object* m = it.next();
|
|
||||||
switch (m->type) {
|
|
||||||
case Object::Scalar: break;
|
|
||||||
|
|
||||||
case Object::Array: {
|
|
||||||
return memberElementSize(m);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
default: UNREACHABLE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t
|
uint32_t
|
||||||
typeObjectMask(Object* type)
|
typeObjectMask(Object* type)
|
||||||
{
|
{
|
||||||
@ -2274,6 +2299,7 @@ main(int ac, char** av)
|
|||||||
|
|
||||||
writePods(&out, declarations);
|
writePods(&out, declarations);
|
||||||
writeAccessors(&out, declarations);
|
writeAccessors(&out, declarations);
|
||||||
|
writeSizes(&out, declarations);
|
||||||
writeInitializerDeclarations(&out, declarations);
|
writeInitializerDeclarations(&out, declarations);
|
||||||
writeConstructorDeclarations(&out, declarations);
|
writeConstructorDeclarations(&out, declarations);
|
||||||
}
|
}
|
||||||
|
@ -24,10 +24,10 @@
|
|||||||
(void* value))
|
(void* value))
|
||||||
|
|
||||||
(pod exceptionHandler
|
(pod exceptionHandler
|
||||||
(uint32_t start)
|
(uint16_t start)
|
||||||
(uint32_t end)
|
(uint16_t end)
|
||||||
(uint32_t ip)
|
(uint16_t ip)
|
||||||
(uint32_t catchType))
|
(uint16_t catchType))
|
||||||
|
|
||||||
(type exceptionHandlerTable
|
(type exceptionHandlerTable
|
||||||
(array exceptionHandler body))
|
(array exceptionHandler body))
|
||||||
@ -91,13 +91,22 @@
|
|||||||
(object method)
|
(object method)
|
||||||
(int ip))
|
(int ip))
|
||||||
|
|
||||||
(type traceNode
|
(type treeNode
|
||||||
|
(object value)
|
||||||
|
(object left)
|
||||||
|
(object right))
|
||||||
|
|
||||||
|
(type treePath
|
||||||
|
(uintptr_t fresh)
|
||||||
|
(object node)
|
||||||
|
(object root)
|
||||||
|
(object ancestors))
|
||||||
|
|
||||||
|
(type callNode
|
||||||
(intptr_t address)
|
(intptr_t address)
|
||||||
(object next)
|
|
||||||
(object method)
|
|
||||||
(object target)
|
(object target)
|
||||||
(uintptr_t virtualCall)
|
(uintptr_t virtualCall)
|
||||||
(array uintptr_t map))
|
(object next))
|
||||||
|
|
||||||
(type array
|
(type array
|
||||||
(noassert array object body))
|
(noassert array object body))
|
||||||
|
277
src/util.cpp
277
src/util.cpp
@ -14,18 +14,241 @@ using namespace vm;
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
object
|
inline object
|
||||||
clone(Thread* t, object o)
|
getTreeNodeValue(Thread*, object n)
|
||||||
{
|
{
|
||||||
object class_ = objectClass(t, o);
|
return reinterpret_cast<object>
|
||||||
unsigned size = baseSize(t, o, class_) * BytesPerWord;
|
(cast<intptr_t>(n, TreeNodeValue) & PointerMask);
|
||||||
|
}
|
||||||
|
|
||||||
object clone = make(t, class_);
|
inline void
|
||||||
memcpy(reinterpret_cast<void**>(clone) + 1,
|
setTreeNodeValue(Thread* t, object n, object value)
|
||||||
reinterpret_cast<void**>(o) + 1,
|
{
|
||||||
size - BytesPerWord);
|
intptr_t red = cast<intptr_t>(n, TreeNodeValue) & (~PointerMask);
|
||||||
|
|
||||||
return clone;
|
set(t, n, TreeNodeValue, value);
|
||||||
|
|
||||||
|
cast<intptr_t>(n, TreeNodeValue) |= red;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool
|
||||||
|
treeNodeRed(Thread*, object n)
|
||||||
|
{
|
||||||
|
return (cast<intptr_t>(n, TreeNodeValue) & (~PointerMask)) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
setTreeNodeRed(Thread*, object n, bool red)
|
||||||
|
{
|
||||||
|
if (red) {
|
||||||
|
cast<intptr_t>(n, TreeNodeValue) |= 1;
|
||||||
|
} else {
|
||||||
|
cast<intptr_t>(n, TreeNodeValue) &= PointerMask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline object
|
||||||
|
cloneTreeNode(Thread* t, object n)
|
||||||
|
{
|
||||||
|
PROTECT(t, n);
|
||||||
|
|
||||||
|
object newNode = makeTreeNode
|
||||||
|
(t, getTreeNodeValue(t, n), treeNodeLeft(t, n), treeNodeRight(t, n));
|
||||||
|
setTreeNodeRed(t, newNode, treeNodeRed(t, n));
|
||||||
|
return newNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
object
|
||||||
|
treeFind(Thread* t, object old, object node, object sentinal,
|
||||||
|
intptr_t (*compare)(Thread* t, object a, object b))
|
||||||
|
{
|
||||||
|
PROTECT(t, old);
|
||||||
|
PROTECT(t, node);
|
||||||
|
PROTECT(t, sentinal);
|
||||||
|
|
||||||
|
object newRoot = cloneTreeNode(t, old);
|
||||||
|
PROTECT(t, newRoot);
|
||||||
|
|
||||||
|
object new_ = newRoot;
|
||||||
|
PROTECT(t, new_);
|
||||||
|
|
||||||
|
object ancestors = 0;
|
||||||
|
PROTECT(t, ancestors);
|
||||||
|
|
||||||
|
while (old != sentinal) {
|
||||||
|
ancestors = makePair(t, new_, ancestors);
|
||||||
|
|
||||||
|
intptr_t difference = compare
|
||||||
|
(t, getTreeNodeValue(t, node), getTreeNodeValue(t, old));
|
||||||
|
|
||||||
|
if (difference < 0) {
|
||||||
|
old = treeNodeLeft(t, old);
|
||||||
|
object n = cloneTreeNode(t, old);
|
||||||
|
set(t, new_, TreeNodeLeft, n);
|
||||||
|
new_ = n;
|
||||||
|
} else if (difference > 0) {
|
||||||
|
old = treeNodeRight(t, old);
|
||||||
|
object n = cloneTreeNode(t, old);
|
||||||
|
set(t, new_, TreeNodeRight, n);
|
||||||
|
new_ = n;
|
||||||
|
} else {
|
||||||
|
return makeTreePath(t, false, new_, newRoot, pairSecond(t, ancestors));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setTreeNodeValue(t, new_, getTreeNodeValue(t, node));
|
||||||
|
|
||||||
|
return makeTreePath(t, true, new_, newRoot, ancestors);
|
||||||
|
}
|
||||||
|
|
||||||
|
object
|
||||||
|
leftRotate(Thread* t, object n)
|
||||||
|
{
|
||||||
|
PROTECT(t, n);
|
||||||
|
|
||||||
|
object child = cloneTreeNode(t, treeNodeRight(t, n));
|
||||||
|
set(t, n, TreeNodeRight, treeNodeLeft(t, child));
|
||||||
|
set(t, child, TreeNodeLeft, n);
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
|
object
|
||||||
|
rightRotate(Thread* t, object n)
|
||||||
|
{
|
||||||
|
PROTECT(t, n);
|
||||||
|
|
||||||
|
object child = cloneTreeNode(t, treeNodeLeft(t, n));
|
||||||
|
set(t, n, TreeNodeLeft, treeNodeRight(t, child));
|
||||||
|
set(t, child, TreeNodeRight, n);
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
|
object
|
||||||
|
treeAdd(Thread* t, object path)
|
||||||
|
{
|
||||||
|
object new_ = treePathNode(t, path);
|
||||||
|
PROTECT(t, new_);
|
||||||
|
|
||||||
|
object newRoot = treePathRoot(t, path);
|
||||||
|
PROTECT(t, newRoot);
|
||||||
|
|
||||||
|
object ancestors = treePathAncestors(t, path);
|
||||||
|
PROTECT(t, ancestors);
|
||||||
|
|
||||||
|
// rebalance
|
||||||
|
setTreeNodeRed(t, new_, true);
|
||||||
|
while (ancestors != 0 and treeNodeRed(t, pairFirst(t, ancestors))) {
|
||||||
|
if (pairFirst(t, ancestors)
|
||||||
|
== treeNodeLeft(t, pairFirst(t, pairSecond(t, ancestors))))
|
||||||
|
{
|
||||||
|
if (treeNodeRed
|
||||||
|
(t, treeNodeRight(t, pairFirst(t, pairSecond(t, ancestors)))))
|
||||||
|
{
|
||||||
|
setTreeNodeRed(t, pairFirst(t, ancestors), true);
|
||||||
|
|
||||||
|
object n = cloneTreeNode
|
||||||
|
(t, treeNodeRight(t, pairFirst(t, pairSecond(t, ancestors))));
|
||||||
|
|
||||||
|
set(t, pairFirst(t, pairSecond(t, ancestors)), TreeNodeRight, n);
|
||||||
|
|
||||||
|
setTreeNodeRed
|
||||||
|
(t, treeNodeRight
|
||||||
|
(t, pairFirst(t, pairSecond(t, ancestors))), false);
|
||||||
|
|
||||||
|
setTreeNodeRed(t, pairFirst(t, pairSecond(t, ancestors)), false);
|
||||||
|
|
||||||
|
new_ = pairFirst(t, pairSecond(t, ancestors));
|
||||||
|
ancestors = pairSecond(t, pairSecond(t, ancestors));
|
||||||
|
} else {
|
||||||
|
if (new_ == treeNodeRight(t, pairFirst(t, ancestors))) {
|
||||||
|
new_ = pairFirst(t, ancestors);
|
||||||
|
ancestors = pairSecond(t, ancestors);
|
||||||
|
|
||||||
|
object n = leftRotate(t, new_);
|
||||||
|
|
||||||
|
if (new_ == treeNodeRight(t, pairFirst(t, ancestors))) {
|
||||||
|
set(t, pairFirst(t, ancestors), TreeNodeRight, n);
|
||||||
|
} else {
|
||||||
|
set(t, pairFirst(t, ancestors), TreeNodeLeft, n);
|
||||||
|
}
|
||||||
|
ancestors = makePair(t, n, ancestors);
|
||||||
|
}
|
||||||
|
setTreeNodeRed(t, pairFirst(t, ancestors), false);
|
||||||
|
setTreeNodeRed(t, pairFirst(t, pairSecond(t, ancestors)), true);
|
||||||
|
|
||||||
|
object n = rightRotate(t, pairFirst(t, pairSecond(t, ancestors)));
|
||||||
|
if (pairSecond(t, pairSecond(t, ancestors)) == 0) {
|
||||||
|
newRoot = n;
|
||||||
|
} else if (treeNodeRight
|
||||||
|
(t, pairFirst(t, pairSecond(t, pairSecond(t, ancestors))))
|
||||||
|
== pairFirst(t, pairSecond(t, ancestors)))
|
||||||
|
{
|
||||||
|
set(t, pairFirst(t, pairSecond(t, pairSecond(t, ancestors))),
|
||||||
|
TreeNodeRight, n);
|
||||||
|
} else {
|
||||||
|
set(t, pairFirst(t, pairSecond(t, pairSecond(t, ancestors))),
|
||||||
|
TreeNodeLeft, n);
|
||||||
|
}
|
||||||
|
// done
|
||||||
|
}
|
||||||
|
} else { // this is just the reverse of the code above (right and
|
||||||
|
// left swapped):
|
||||||
|
if (treeNodeRed
|
||||||
|
(t, treeNodeLeft(t, pairFirst(t, pairSecond(t, ancestors)))))
|
||||||
|
{
|
||||||
|
setTreeNodeRed(t, pairFirst(t, ancestors), true);
|
||||||
|
|
||||||
|
object n = cloneTreeNode
|
||||||
|
(t, treeNodeLeft(t, pairFirst(t, pairSecond(t, ancestors))));
|
||||||
|
|
||||||
|
set(t, pairFirst(t, pairSecond(t, ancestors)), TreeNodeLeft, n);
|
||||||
|
|
||||||
|
setTreeNodeRed
|
||||||
|
(t, treeNodeLeft
|
||||||
|
(t, pairFirst(t, pairSecond(t, ancestors))), false);
|
||||||
|
|
||||||
|
setTreeNodeRed(t, pairFirst(t, pairSecond(t, ancestors)), false);
|
||||||
|
|
||||||
|
new_ = pairFirst(t, pairSecond(t, ancestors));
|
||||||
|
ancestors = pairSecond(t, pairSecond(t, ancestors));
|
||||||
|
} else {
|
||||||
|
if (new_ == treeNodeLeft(t, pairFirst(t, ancestors))) {
|
||||||
|
new_ = pairFirst(t, ancestors);
|
||||||
|
ancestors = pairSecond(t, ancestors);
|
||||||
|
|
||||||
|
object n = rightRotate(t, new_);
|
||||||
|
|
||||||
|
if (new_ == treeNodeLeft(t, pairFirst(t, ancestors))) {
|
||||||
|
set(t, pairFirst(t, ancestors), TreeNodeLeft, n);
|
||||||
|
} else {
|
||||||
|
set(t, pairFirst(t, ancestors), TreeNodeRight, n);
|
||||||
|
}
|
||||||
|
ancestors = makePair(t, n, ancestors);
|
||||||
|
}
|
||||||
|
setTreeNodeRed(t, pairFirst(t, ancestors), false);
|
||||||
|
setTreeNodeRed(t, pairFirst(t, pairSecond(t, ancestors)), true);
|
||||||
|
|
||||||
|
object n = leftRotate(t, pairFirst(t, pairSecond(t, ancestors)));
|
||||||
|
if (pairSecond(t, pairSecond(t, ancestors)) == 0) {
|
||||||
|
newRoot = n;
|
||||||
|
} else if (treeNodeLeft
|
||||||
|
(t, pairFirst(t, pairSecond(t, pairSecond(t, ancestors))))
|
||||||
|
== pairFirst(t, pairSecond(t, ancestors)))
|
||||||
|
{
|
||||||
|
set(t, pairFirst(t, pairSecond(t, pairSecond(t, ancestors))),
|
||||||
|
TreeNodeLeft, n);
|
||||||
|
} else {
|
||||||
|
set(t, pairFirst(t, pairSecond(t, pairSecond(t, ancestors))),
|
||||||
|
TreeNodeRight, n);
|
||||||
|
}
|
||||||
|
// done
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setTreeNodeRed(t, newRoot, false);
|
||||||
|
|
||||||
|
return newRoot;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
@ -293,4 +516,40 @@ vectorAppend(Thread* t, object vector, object value)
|
|||||||
return vector;
|
return vector;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object
|
||||||
|
treeQuery(Thread* t, object tree, intptr_t key, object sentinal,
|
||||||
|
intptr_t (*compare)(Thread* t, intptr_t key, object b))
|
||||||
|
{
|
||||||
|
object node = tree;
|
||||||
|
while (node != sentinal) {
|
||||||
|
intptr_t difference = compare(t, key, getTreeNodeValue(t, node));
|
||||||
|
if (difference < 0) {
|
||||||
|
node = treeNodeLeft(t, node);
|
||||||
|
} else if (difference > 0) {
|
||||||
|
node = treeNodeRight(t, node);
|
||||||
|
} else {
|
||||||
|
return getTreeNodeValue(t, node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
object
|
||||||
|
treeInsert(Thread* t, object tree, object value, object sentinal,
|
||||||
|
intptr_t (*compare)(Thread* t, object a, object b))
|
||||||
|
{
|
||||||
|
PROTECT(t, tree);
|
||||||
|
PROTECT(t, sentinal);
|
||||||
|
|
||||||
|
object node = makeTreeNode(t, value, sentinal, sentinal);
|
||||||
|
|
||||||
|
object path = treeFind(t, tree, node, sentinal, compare);
|
||||||
|
if (treePathFresh(t, path)) {
|
||||||
|
return treeAdd(t, path);
|
||||||
|
} else {
|
||||||
|
return tree;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace vm
|
} // namespace vm
|
||||||
|
@ -83,6 +83,14 @@ listAppend(Thread* t, object list, object value);
|
|||||||
object
|
object
|
||||||
vectorAppend(Thread* t, object vector, object value);
|
vectorAppend(Thread* t, object vector, object value);
|
||||||
|
|
||||||
|
object
|
||||||
|
treeQuery(Thread* t, object tree, intptr_t key, object sentinal,
|
||||||
|
intptr_t (*compare)(Thread* t, intptr_t key, object b));
|
||||||
|
|
||||||
|
object
|
||||||
|
treeInsert(Thread* t, object tree, object value, object sentinal,
|
||||||
|
intptr_t (*compare)(Thread* t, object a, object b));
|
||||||
|
|
||||||
} // vm
|
} // vm
|
||||||
|
|
||||||
#endif//UTIL_H
|
#endif//UTIL_H
|
||||||
|
@ -32,7 +32,7 @@ class Vector {
|
|||||||
|
|
||||||
void dispose() {
|
void dispose() {
|
||||||
if (data and minimumCapacity >= 0) {
|
if (data and minimumCapacity >= 0) {
|
||||||
allocator->free(data, capacity, false);
|
allocator->free(data, capacity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,10 +52,10 @@ class Vector {
|
|||||||
unsigned newCapacity = max
|
unsigned newCapacity = max
|
||||||
(position + space, max(minimumCapacity, capacity * 2));
|
(position + space, max(minimumCapacity, capacity * 2));
|
||||||
uint8_t* newData = static_cast<uint8_t*>
|
uint8_t* newData = static_cast<uint8_t*>
|
||||||
(allocator->allocate(newCapacity, false));
|
(allocator->allocate(newCapacity));
|
||||||
if (data) {
|
if (data) {
|
||||||
memcpy(newData, data, position);
|
memcpy(newData, data, position);
|
||||||
allocator->free(data, capacity, false);
|
allocator->free(data, capacity);
|
||||||
}
|
}
|
||||||
data = newData;
|
data = newData;
|
||||||
capacity = newCapacity;
|
capacity = newCapacity;
|
||||||
|
103
src/windows.cpp
103
src/windows.cpp
@ -23,6 +23,23 @@ using namespace vm;
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
class MutexResource {
|
||||||
|
public:
|
||||||
|
MutexResource(System* s, HANDLE m): s(s), m(m) {
|
||||||
|
int r UNUSED = WaitForSingleObject(m, INFINITE);
|
||||||
|
assert(s, r == WAIT_OBJECT_0);
|
||||||
|
}
|
||||||
|
|
||||||
|
~MutexResource() {
|
||||||
|
bool success UNUSED = ReleaseMutex(m);
|
||||||
|
assert(s, success);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
System* s;
|
||||||
|
HANDLE m;
|
||||||
|
};
|
||||||
|
|
||||||
System::SignalHandler* segFaultHandler = 0;
|
System::SignalHandler* segFaultHandler = 0;
|
||||||
LPTOP_LEVEL_EXCEPTION_FILTER oldSegFaultHandler = 0;
|
LPTOP_LEVEL_EXCEPTION_FILTER oldSegFaultHandler = 0;
|
||||||
|
|
||||||
@ -43,23 +60,6 @@ handleException(LPEXCEPTION_POINTERS e)
|
|||||||
return EXCEPTION_CONTINUE_SEARCH;
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
class MutexResource {
|
|
||||||
public:
|
|
||||||
MutexResource(System* s, HANDLE m): s(s), m(m) {
|
|
||||||
int r UNUSED = WaitForSingleObject(m, INFINITE);
|
|
||||||
assert(s, r == WAIT_OBJECT_0);
|
|
||||||
}
|
|
||||||
|
|
||||||
~MutexResource() {
|
|
||||||
bool success UNUSED = ReleaseMutex(m);
|
|
||||||
assert(s, success);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
System* s;
|
|
||||||
HANDLE m;
|
|
||||||
};
|
|
||||||
|
|
||||||
DWORD WINAPI
|
DWORD WINAPI
|
||||||
run(void* r)
|
run(void* r)
|
||||||
{
|
{
|
||||||
@ -70,7 +70,7 @@ run(void* r)
|
|||||||
void*
|
void*
|
||||||
allocate(System* s, unsigned size)
|
allocate(System* s, unsigned size)
|
||||||
{
|
{
|
||||||
void* p = s->tryAllocate(size, false);
|
void* p = s->tryAllocate(size);
|
||||||
if (p == 0) abort();
|
if (p == 0) abort();
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
@ -117,7 +117,7 @@ class MySystem: public System {
|
|||||||
CloseHandle(event);
|
CloseHandle(event);
|
||||||
CloseHandle(mutex);
|
CloseHandle(mutex);
|
||||||
CloseHandle(thread);
|
CloseHandle(thread);
|
||||||
s->free(this, sizeof(*this), false);
|
s->free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
HANDLE thread;
|
HANDLE thread;
|
||||||
@ -148,7 +148,7 @@ class MySystem: public System {
|
|||||||
|
|
||||||
virtual void dispose() {
|
virtual void dispose() {
|
||||||
CloseHandle(mutex);
|
CloseHandle(mutex);
|
||||||
s->free(this, sizeof(*this), false);
|
s->free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
@ -362,7 +362,7 @@ class MySystem: public System {
|
|||||||
virtual void dispose() {
|
virtual void dispose() {
|
||||||
assert(s, owner_ == 0);
|
assert(s, owner_ == 0);
|
||||||
CloseHandle(mutex);
|
CloseHandle(mutex);
|
||||||
s->free(this, sizeof(*this), false);
|
s->free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
@ -393,7 +393,7 @@ class MySystem: public System {
|
|||||||
bool r UNUSED = TlsFree(key);
|
bool r UNUSED = TlsFree(key);
|
||||||
assert(s, r);
|
assert(s, r);
|
||||||
|
|
||||||
s->free(this, sizeof(*this), false);
|
s->free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
@ -425,7 +425,7 @@ class MySystem: public System {
|
|||||||
if (mapping) CloseHandle(mapping);
|
if (mapping) CloseHandle(mapping);
|
||||||
if (file) CloseHandle(file);
|
if (file) CloseHandle(file);
|
||||||
}
|
}
|
||||||
system->free(this, sizeof(*this), false);
|
system->free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* system;
|
System* system;
|
||||||
@ -437,12 +437,10 @@ class MySystem: public System {
|
|||||||
|
|
||||||
class Library: public System::Library {
|
class Library: public System::Library {
|
||||||
public:
|
public:
|
||||||
Library(System* s, HMODULE handle, const char* name, size_t nameLength,
|
Library(System* s, HMODULE handle, const char* name, bool mapName):
|
||||||
bool mapName):
|
|
||||||
s(s),
|
s(s),
|
||||||
handle(handle),
|
handle(handle),
|
||||||
name_(name),
|
name_(name),
|
||||||
nameLength(nameLength),
|
|
||||||
mapName_(mapName),
|
mapName_(mapName),
|
||||||
next_(0)
|
next_(0)
|
||||||
{ }
|
{ }
|
||||||
@ -484,16 +482,15 @@ class MySystem: public System {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (name_) {
|
if (name_) {
|
||||||
s->free(name_, nameLength + 1, false);
|
s->free(name_);
|
||||||
}
|
}
|
||||||
|
|
||||||
s->free(this, sizeof(*this), false);
|
s->free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
HMODULE handle;
|
HMODULE handle;
|
||||||
const char* name_;
|
const char* name_;
|
||||||
size_t nameLength;
|
|
||||||
bool mapName_;
|
bool mapName_;
|
||||||
System::Library* next_;
|
System::Library* next_;
|
||||||
};
|
};
|
||||||
@ -503,14 +500,26 @@ class MySystem: public System {
|
|||||||
assert(this, mutex);
|
assert(this, mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void* tryAllocate(unsigned size, bool) {
|
virtual void* tryAllocate(unsigned sizeInBytes) {
|
||||||
return malloc(size);
|
return malloc(sizeInBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void free(const void* p, unsigned, bool) {
|
virtual void free(const void* p) {
|
||||||
if (p) ::free(const_cast<void*>(p));
|
if (p) ::free(const_cast<void*>(p));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void* tryAllocateExecutable(unsigned sizeInBytes) {
|
||||||
|
assert(this, sizeInBytes % LikelyPageSizeInBytes == 0);
|
||||||
|
|
||||||
|
return VirtualAlloc
|
||||||
|
(0, sizeInBytes, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void freeExecutable(const void* p, unsigned) {
|
||||||
|
int r UNUSED = VirtualFree(const_cast<void*>(p), 0, MEM_RELEASE);
|
||||||
|
assert(this, r);
|
||||||
|
}
|
||||||
|
|
||||||
virtual bool success(Status s) {
|
virtual bool success(Status s) {
|
||||||
return s == 0;
|
return s == 0;
|
||||||
}
|
}
|
||||||
@ -564,6 +573,32 @@ class MySystem: public System {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual Status visit(System::Thread* st UNUSED, System::Thread* sTarget,
|
||||||
|
ThreadVisitor* visitor)
|
||||||
|
{
|
||||||
|
assert(this, st != sTarget);
|
||||||
|
|
||||||
|
Thread* target = static_cast<Thread*>(sTarget);
|
||||||
|
|
||||||
|
ACQUIRE(this, mutex);
|
||||||
|
|
||||||
|
int rv = SuspendThread(target->thread);
|
||||||
|
expect(this, rv != -1);
|
||||||
|
|
||||||
|
CONTEXT context;
|
||||||
|
rv = GetThreadContext(target->thread, &context);
|
||||||
|
expect(this, rv);
|
||||||
|
|
||||||
|
visitor->visit(reinterpret_cast<void*>(context.Eip),
|
||||||
|
reinterpret_cast<void*>(context.Ebp),
|
||||||
|
reinterpret_cast<void*>(context.Esp));
|
||||||
|
|
||||||
|
rv = ResumeThread(target->thread);
|
||||||
|
expect(this, rv != -1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
virtual uint64_t call(void* function, uintptr_t* arguments, uint8_t* types,
|
virtual uint64_t call(void* function, uintptr_t* arguments, uint8_t* types,
|
||||||
unsigned count, unsigned size, unsigned returnType)
|
unsigned count, unsigned size, unsigned returnType)
|
||||||
{
|
{
|
||||||
@ -623,7 +658,7 @@ class MySystem: public System {
|
|||||||
{
|
{
|
||||||
HMODULE handle;
|
HMODULE handle;
|
||||||
unsigned nameLength = (name ? strlen(name) : 0);
|
unsigned nameLength = (name ? strlen(name) : 0);
|
||||||
if (mapName) {
|
if (mapName and name) {
|
||||||
unsigned size = sizeof(SO_PREFIX) + nameLength + sizeof(SO_SUFFIX);
|
unsigned size = sizeof(SO_PREFIX) + nameLength + sizeof(SO_SUFFIX);
|
||||||
char buffer[size];
|
char buffer[size];
|
||||||
snprintf(buffer, size, SO_PREFIX "%s" SO_SUFFIX, name);
|
snprintf(buffer, size, SO_PREFIX "%s" SO_SUFFIX, name);
|
||||||
@ -648,7 +683,7 @@ class MySystem: public System {
|
|||||||
}
|
}
|
||||||
|
|
||||||
*lib = new (allocate(this, sizeof(Library)))
|
*lib = new (allocate(this, sizeof(Library)))
|
||||||
Library(this, handle, n, nameLength, mapName);
|
Library(this, handle, n, mapName);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
|
69
src/x86.cpp
69
src/x86.cpp
@ -214,21 +214,22 @@ encode(Context* c, uint8_t* instruction, unsigned length, int a, int b,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
rex(Context* c)
|
rex(Context* c, uint8_t mask, int r)
|
||||||
{
|
{
|
||||||
if (BytesPerWord == 8) {
|
if (BytesPerWord == 8) {
|
||||||
c->code.append(0x48);
|
c->code.append(mask | ((r & 8) >> 3));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rex(Context* c)
|
||||||
|
{
|
||||||
|
rex(c, 0x48, rax);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
encode(Context* c, uint8_t instruction, int a, Assembler::Memory* b, bool rex)
|
encode(Context* c, uint8_t instruction, int a, Assembler::Memory* b, bool rex)
|
||||||
{
|
{
|
||||||
if (b->traceHandler) {
|
|
||||||
fprintf(stderr, "handle trace %p\n", b->traceHandler);
|
|
||||||
b->traceHandler->handleTrace(codePromise(c, c->code.length()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rex) {
|
if (rex) {
|
||||||
::rex(c);
|
::rex(c);
|
||||||
}
|
}
|
||||||
@ -240,11 +241,6 @@ void
|
|||||||
encode2(Context* c, uint16_t instruction, int a, Assembler::Memory* b,
|
encode2(Context* c, uint16_t instruction, int a, Assembler::Memory* b,
|
||||||
bool rex)
|
bool rex)
|
||||||
{
|
{
|
||||||
if (b->traceHandler) {
|
|
||||||
fprintf(stderr, "handle trace %p\n", b->traceHandler);
|
|
||||||
b->traceHandler->handleTrace(codePromise(c, c->code.length()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rex) {
|
if (rex) {
|
||||||
::rex(c);
|
::rex(c);
|
||||||
}
|
}
|
||||||
@ -292,18 +288,31 @@ conditional(Context* c, unsigned condition, Assembler::Constant* a)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
callC(Context* c, unsigned size UNUSED, Assembler::Constant* a)
|
callC(Context* c, unsigned size, Assembler::Constant* a)
|
||||||
{
|
{
|
||||||
assert(c, size == BytesPerWord);
|
assert(c, size == BytesPerWord);
|
||||||
|
|
||||||
unconditional(c, 0xe8, a);
|
if (BytesPerWord == 8) {
|
||||||
|
Assembler::Register r(r10);
|
||||||
|
moveCR(c, size, a, &r);
|
||||||
|
callR(c, size, &r);
|
||||||
|
c->client->releaseTemporary(r.low);
|
||||||
|
} else {
|
||||||
|
unconditional(c, 0xe8, a);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
alignedCallC(Context* c, unsigned size, Assembler::Constant* a)
|
alignedCallC(Context* c, unsigned size, Assembler::Constant* a)
|
||||||
{
|
{
|
||||||
while ((c->code.length() + 1) % 4) {
|
if (BytesPerWord == 8) {
|
||||||
c->code.append(0x90);
|
while ((c->code.length() + 2) % 8) {
|
||||||
|
c->code.append(0x90);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while ((c->code.length() + 1) % 4) {
|
||||||
|
c->code.append(0x90);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
callC(c, size, a);
|
callC(c, size, a);
|
||||||
}
|
}
|
||||||
@ -313,6 +322,7 @@ callR(Context* c, unsigned size UNUSED, Assembler::Register* a)
|
|||||||
{
|
{
|
||||||
assert(c, size == BytesPerWord);
|
assert(c, size == BytesPerWord);
|
||||||
|
|
||||||
|
if (a->low & 8) rex(c, 0x40, a->low);
|
||||||
c->code.append(0xff);
|
c->code.append(0xff);
|
||||||
c->code.append(0xd0 | a->low);
|
c->code.append(0xd0 | a->low);
|
||||||
}
|
}
|
||||||
@ -521,7 +531,7 @@ moveCR(Context* c, unsigned size UNUSED, Assembler::Constant* a,
|
|||||||
{
|
{
|
||||||
assert(c, BytesPerWord == 8 or size == 4); // todo
|
assert(c, BytesPerWord == 8 or size == 4); // todo
|
||||||
|
|
||||||
rex(c);
|
rex(c, 0x48, b->low);
|
||||||
c->code.append(0xb8 | b->low);
|
c->code.append(0xb8 | b->low);
|
||||||
if (a->value->resolved()) {
|
if (a->value->resolved()) {
|
||||||
c->code.appendAddress(a->value->value());
|
c->code.appendAddress(a->value->value());
|
||||||
@ -1131,13 +1141,26 @@ class MyAssembler: public Assembler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void updateCall(void* returnAddress, void* newTarget) {
|
virtual void updateCall(void* returnAddress, void* newTarget) {
|
||||||
uint8_t* instruction = static_cast<uint8_t*>(returnAddress) - 5;
|
if (BytesPerWord == 8) {
|
||||||
assert(&c, *instruction == 0xE8);
|
uint8_t* instruction = static_cast<uint8_t*>(returnAddress) - 13;
|
||||||
assert(&c, reinterpret_cast<uintptr_t>(instruction + 1) % 4 == 0);
|
assert(&c, instruction[0] == 0x49);
|
||||||
|
assert(&c, instruction[1] == 0xba);
|
||||||
|
assert(&c, instruction[10] == 0x41);
|
||||||
|
assert(&c, instruction[11] == 0xff);
|
||||||
|
assert(&c, instruction[12] == 0xd2);
|
||||||
|
assert(&c, reinterpret_cast<uintptr_t>(instruction + 2) % 8 == 0);
|
||||||
|
|
||||||
int32_t v = static_cast<uint8_t*>(newTarget)
|
intptr_t v = reinterpret_cast<intptr_t>(newTarget);
|
||||||
- static_cast<uint8_t*>(returnAddress);
|
memcpy(instruction + 2, &v, 8);
|
||||||
memcpy(instruction + 1, &v, 4);
|
} else {
|
||||||
|
uint8_t* instruction = static_cast<uint8_t*>(returnAddress) - 5;
|
||||||
|
assert(&c, *instruction == 0xE8);
|
||||||
|
assert(&c, reinterpret_cast<uintptr_t>(instruction + 1) % 4 == 0);
|
||||||
|
|
||||||
|
int32_t v = static_cast<uint8_t*>(newTarget)
|
||||||
|
- static_cast<uint8_t*>(returnAddress);
|
||||||
|
memcpy(instruction + 1, &v, 4);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void dispose() {
|
virtual void dispose() {
|
||||||
|
31
src/zone.h
31
src/zone.h
@ -27,11 +27,9 @@ class Zone: public Allocator {
|
|||||||
uint8_t data[0];
|
uint8_t data[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
Zone(System* s, Allocator* allocator, bool executable,
|
Zone(System* s, Allocator* allocator, unsigned minimumFootprint):
|
||||||
unsigned minimumFootprint):
|
|
||||||
s(s),
|
s(s),
|
||||||
allocator(allocator),
|
allocator(allocator),
|
||||||
executable(executable),
|
|
||||||
segment(0),
|
segment(0),
|
||||||
position(0),
|
position(0),
|
||||||
minimumFootprint(minimumFootprint < sizeof(Segment) ? 0 :
|
minimumFootprint(minimumFootprint < sizeof(Segment) ? 0 :
|
||||||
@ -45,11 +43,11 @@ class Zone: public Allocator {
|
|||||||
void dispose() {
|
void dispose() {
|
||||||
for (Segment* seg = segment, *next; seg; seg = next) {
|
for (Segment* seg = segment, *next; seg; seg = next) {
|
||||||
next = seg->next;
|
next = seg->next;
|
||||||
allocator->free(seg, sizeof(Segment) + seg->size, executable);
|
allocator->free(seg, sizeof(Segment) + seg->size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ensure(unsigned space, bool executable) {
|
bool ensure(unsigned space) {
|
||||||
if (segment == 0 or position + space > segment->size) {
|
if (segment == 0 or position + space > segment->size) {
|
||||||
unsigned size = max
|
unsigned size = max
|
||||||
(space, max
|
(space, max
|
||||||
@ -60,10 +58,10 @@ class Zone: public Allocator {
|
|||||||
size = (size + (LikelyPageSizeInBytes - 1))
|
size = (size + (LikelyPageSizeInBytes - 1))
|
||||||
& ~(LikelyPageSizeInBytes - 1);
|
& ~(LikelyPageSizeInBytes - 1);
|
||||||
|
|
||||||
void* p = allocator->tryAllocate(size, executable);
|
void* p = allocator->tryAllocate(size);
|
||||||
if (p == 0) {
|
if (p == 0) {
|
||||||
size = space + sizeof(Segment);
|
size = space + sizeof(Segment);
|
||||||
void* p = allocator->tryAllocate(size, executable);
|
void* p = allocator->tryAllocate(size);
|
||||||
if (p == 0) {
|
if (p == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -75,11 +73,9 @@ class Zone: public Allocator {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void* tryAllocate(unsigned size, bool executable) {
|
virtual void* tryAllocate(unsigned size) {
|
||||||
assert(s, executable == this->executable);
|
|
||||||
|
|
||||||
size = pad(size);
|
size = pad(size);
|
||||||
if (ensure(size, executable)) {
|
if (ensure(size)) {
|
||||||
void* r = segment->data + position;
|
void* r = segment->data + position;
|
||||||
position += size;
|
position += size;
|
||||||
return r;
|
return r;
|
||||||
@ -88,27 +84,20 @@ class Zone: public Allocator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void* allocate(unsigned size, bool executable) {
|
virtual void* allocate(unsigned size) {
|
||||||
assert(s, executable == this->executable);
|
void* p = tryAllocate(size);
|
||||||
|
|
||||||
void* p = tryAllocate(size, executable);
|
|
||||||
expect(s, p);
|
expect(s, p);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void free(const void*, unsigned, bool) {
|
virtual void free(const void*, unsigned) {
|
||||||
// not supported
|
// not supported
|
||||||
abort(s);
|
abort(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* allocate(unsigned size) {
|
|
||||||
return allocate(size, executable);
|
|
||||||
}
|
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
Allocator* allocator;
|
Allocator* allocator;
|
||||||
void* context;
|
void* context;
|
||||||
bool executable;
|
|
||||||
Segment* segment;
|
Segment* segment;
|
||||||
unsigned position;
|
unsigned position;
|
||||||
unsigned minimumFootprint;
|
unsigned minimumFootprint;
|
||||||
|
@ -2,7 +2,22 @@ public class Misc {
|
|||||||
private static int alpha;
|
private static int alpha;
|
||||||
private static int beta;
|
private static int beta;
|
||||||
private static byte byte1, byte2, byte3;
|
private static byte byte1, byte2, byte3;
|
||||||
|
|
||||||
private int gamma;
|
private int gamma;
|
||||||
|
private int pajama;
|
||||||
|
private boolean boolean1;
|
||||||
|
private boolean boolean2;
|
||||||
|
private long time;
|
||||||
|
|
||||||
|
public Misc() {
|
||||||
|
expect(! boolean1);
|
||||||
|
expect(! boolean2);
|
||||||
|
|
||||||
|
time = 0xffffffffffffffffL;
|
||||||
|
|
||||||
|
expect(! boolean1);
|
||||||
|
expect(! boolean2);
|
||||||
|
}
|
||||||
|
|
||||||
private String foo(String s) {
|
private String foo(String s) {
|
||||||
return s;
|
return s;
|
||||||
|
Loading…
Reference in New Issue
Block a user