mirror of
https://github.com/corda/corda.git
synced 2024-12-28 16:58:55 +00:00
preliminary support for using OpenJDK's class library
Whereas the GNU Classpath port used the strategy of patching Classpath with core classes from Avian so as to minimize changes to the VM, this port uses the opposite strategy: abstract and isolate classpath-specific features in the VM similar to how we abstract away platform-specific features in system.h. This allows us to use an unmodified copy of OpenJDK's class library, including its core classes and augmented by a few VM-specific classes in the "avian" package.
This commit is contained in:
parent
17c1a552d5
commit
cddea7187d
@ -12,5 +12,5 @@ package avian;
|
||||
|
||||
public class Addendum {
|
||||
public Object pool;
|
||||
public Object annotationTable;
|
||||
public Object annotationTable;
|
||||
}
|
||||
|
268
classpath/avian/Classes.java
Normal file
268
classpath/avian/Classes.java
Normal file
@ -0,0 +1,268 @@
|
||||
/* Copyright (c) 2010, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
package avian;
|
||||
|
||||
import static avian.Stream.read1;
|
||||
import static avian.Stream.read2;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Field;
|
||||
import java.io.InputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class Classes {
|
||||
private static final int LinkFlag = 1 << 8;
|
||||
|
||||
public static native VMClass defineVMClass
|
||||
(ClassLoader loader, byte[] b, int offset, int length);
|
||||
|
||||
public static native VMClass vmClass(Object o);
|
||||
|
||||
public static native VMClass primitiveClass(char name);
|
||||
|
||||
public static native void initialize(VMClass vmClass);
|
||||
|
||||
public static native boolean isAssignableFrom(VMClass a, VMClass b);
|
||||
|
||||
public static native VMClass getVMClass(Object o);
|
||||
|
||||
private static native VMClass resolveVMClass(ClassLoader loader, byte[] spec)
|
||||
throws ClassNotFoundException;
|
||||
|
||||
private static VMClass loadVMClass(ClassLoader loader,
|
||||
byte[] nameBytes, int offset, int length)
|
||||
{
|
||||
byte[] spec = new byte[length + 1];
|
||||
System.arraycopy(nameBytes, offset, spec, 0, length);
|
||||
|
||||
try {
|
||||
VMClass c = resolveVMClass(loader, spec);
|
||||
if (c == null) {
|
||||
throw new NoClassDefFoundError();
|
||||
}
|
||||
return c;
|
||||
} catch (ClassNotFoundException e) {
|
||||
NoClassDefFoundError error = new NoClassDefFoundError
|
||||
(new String(nameBytes, offset, length, false));
|
||||
error.initCause(e);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
private static Object parseAnnotationValue(ClassLoader loader,
|
||||
Object pool,
|
||||
InputStream in)
|
||||
throws IOException
|
||||
{
|
||||
switch (read1(in)) {
|
||||
case 'Z':
|
||||
return Boolean.valueOf(Singleton.getInt(pool, read2(in) - 1) != 0);
|
||||
|
||||
case 'B':
|
||||
return Byte.valueOf((byte) Singleton.getInt(pool, read2(in) - 1));
|
||||
|
||||
case 'C':
|
||||
return Character.valueOf((char) Singleton.getInt(pool, read2(in) - 1));
|
||||
|
||||
case 'S':
|
||||
return Short.valueOf((short) Singleton.getInt(pool, read2(in) - 1));
|
||||
|
||||
case 'I':
|
||||
return Integer.valueOf(Singleton.getInt(pool, read2(in) - 1));
|
||||
|
||||
case 'F':
|
||||
return Float.valueOf
|
||||
(Float.intBitsToFloat(Singleton.getInt(pool, read2(in) - 1)));
|
||||
|
||||
case 'J': {
|
||||
return Long.valueOf(Singleton.getLong(pool, read2(in) - 1));
|
||||
}
|
||||
|
||||
case 'D': {
|
||||
return Double.valueOf
|
||||
(Double.longBitsToDouble(Singleton.getLong(pool, read2(in) - 1)));
|
||||
}
|
||||
|
||||
case 's': {
|
||||
byte[] data = (byte[]) Singleton.getObject(pool, read2(in) - 1);
|
||||
|
||||
return new String(data, 0, data.length - 1, false);
|
||||
}
|
||||
|
||||
case 'e': {
|
||||
byte[] typeName = (byte[]) Singleton.getObject(pool, read2(in) - 1);
|
||||
byte[] name = (byte[]) Singleton.getObject(pool, read2(in) - 1);
|
||||
|
||||
return Enum.valueOf
|
||||
(getClass(loadVMClass(loader, typeName, 1, typeName.length - 3)),
|
||||
new String(name, 0, name.length - 1, false));
|
||||
}
|
||||
|
||||
case 'c':{
|
||||
byte[] name = (byte[]) Singleton.getObject(pool, read2(in) - 1);
|
||||
|
||||
return getClass(loadVMClass(loader, name, 1, name.length - 3));
|
||||
}
|
||||
|
||||
case '@':
|
||||
return parseAnnotation(loader, pool, in);
|
||||
|
||||
case '[': {
|
||||
Object[] array = new Object[read2(in)];
|
||||
for (int i = 0; i < array.length; ++i) {
|
||||
array[i] = parseAnnotationValue(loader, pool, in);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
default: throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
private static Object[] parseAnnotation(ClassLoader loader,
|
||||
Object pool,
|
||||
InputStream in)
|
||||
throws IOException
|
||||
{
|
||||
byte[] typeName = (byte[]) Singleton.getObject(pool, read2(in) - 1);
|
||||
Object[] annotation = new Object[(read2(in) + 1) * 2];
|
||||
annotation[1] = getClass
|
||||
(loadVMClass(loader, typeName, 1, typeName.length - 3));
|
||||
|
||||
for (int i = 2; i < annotation.length; i += 2) {
|
||||
byte[] name = (byte[]) Singleton.getObject(pool, read2(in) - 1);
|
||||
annotation[i] = new String(name, 0, name.length - 1, false);
|
||||
annotation[i + 1] = parseAnnotationValue(loader, pool, in);
|
||||
}
|
||||
|
||||
return annotation;
|
||||
}
|
||||
|
||||
private static Object[] parseAnnotationTable(ClassLoader loader,
|
||||
Object pool,
|
||||
InputStream in)
|
||||
throws IOException
|
||||
{
|
||||
Object[] table = new Object[read2(in)];
|
||||
for (int i = 0; i < table.length; ++i) {
|
||||
table[i] = parseAnnotation(loader, pool, in);
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
private static void parseAnnotationTable(ClassLoader loader,
|
||||
Addendum addendum)
|
||||
{
|
||||
if (addendum != null && addendum.annotationTable instanceof byte[]) {
|
||||
try {
|
||||
addendum.annotationTable = parseAnnotationTable
|
||||
(loader, addendum.pool, new ByteArrayInputStream
|
||||
((byte[]) addendum.annotationTable));
|
||||
} catch (IOException e) {
|
||||
AssertionError error = new AssertionError();
|
||||
error.initCause(e);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int resolveSpec(ClassLoader loader, byte[] spec, int start) {
|
||||
int result;
|
||||
int end;
|
||||
switch (spec[start]) {
|
||||
case 'L':
|
||||
++ start;
|
||||
end = start;
|
||||
while (spec[end] != ';') ++ end;
|
||||
result = end + 1;
|
||||
break;
|
||||
|
||||
case '[':
|
||||
end = start + 1;
|
||||
while (spec[end] == '[') ++ end;
|
||||
switch (spec[end]) {
|
||||
case 'L':
|
||||
++ end;
|
||||
while (spec[end] != ';') ++ end;
|
||||
++ end;
|
||||
break;
|
||||
|
||||
default:
|
||||
++ end;
|
||||
}
|
||||
result = end;
|
||||
break;
|
||||
|
||||
default:
|
||||
return start + 1;
|
||||
}
|
||||
|
||||
loadVMClass(loader, spec, start, end - start);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void link(VMClass c, ClassLoader loader) {
|
||||
acquireClassLock();
|
||||
try {
|
||||
if ((c.vmFlags & LinkFlag) == 0) {
|
||||
if (c.super_ != null) {
|
||||
link(c.super_, loader);
|
||||
}
|
||||
|
||||
parseAnnotationTable(loader, c.addendum);
|
||||
|
||||
if (c.interfaceTable != null) {
|
||||
int stride = ((c.flags & Modifier.INTERFACE) != 0 ? 1 : 2);
|
||||
for (int i = 0; i < c.interfaceTable.length; i += stride) {
|
||||
link((VMClass) c.interfaceTable[i], loader);
|
||||
}
|
||||
}
|
||||
|
||||
if (c.methodTable != null) {
|
||||
for (int i = 0; i < c.methodTable.length; ++i) {
|
||||
VMMethod m = c.methodTable[i];
|
||||
|
||||
for (int j = 1; j < m.spec.length;) {
|
||||
j = resolveSpec(loader, m.spec, j);
|
||||
}
|
||||
|
||||
parseAnnotationTable(loader, m.addendum);
|
||||
}
|
||||
}
|
||||
|
||||
if (c.fieldTable != null) {
|
||||
for (int i = 0; i < c.fieldTable.length; ++i) {
|
||||
VMField f = c.fieldTable[i];
|
||||
|
||||
resolveSpec(loader, f.spec, 0);
|
||||
|
||||
parseAnnotationTable(loader, f.addendum);
|
||||
}
|
||||
}
|
||||
|
||||
c.vmFlags |= LinkFlag;
|
||||
}
|
||||
} finally {
|
||||
releaseClassLock();
|
||||
}
|
||||
}
|
||||
|
||||
public static void link(VMClass c) {
|
||||
link(c, c.loader);
|
||||
}
|
||||
|
||||
private static native void acquireClassLock();
|
||||
|
||||
private static native void releaseClassLock();
|
||||
}
|
13
classpath/avian/FieldAddendum.java
Normal file
13
classpath/avian/FieldAddendum.java
Normal file
@ -0,0 +1,13 @@
|
||||
/* Copyright (c) 2010, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
package avian;
|
||||
|
||||
public class FieldAddendum extends Addendum { }
|
15
classpath/avian/MethodAddendum.java
Normal file
15
classpath/avian/MethodAddendum.java
Normal file
@ -0,0 +1,15 @@
|
||||
/* Copyright (c) 2009-2010, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
package avian;
|
||||
|
||||
public class MethodAddendum extends Addendum {
|
||||
public Object exceptionTable;
|
||||
}
|
@ -10,24 +10,10 @@
|
||||
|
||||
package avian;
|
||||
|
||||
import static avian.Stream.read1;
|
||||
import static avian.Stream.read2;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.URL;
|
||||
import java.net.MalformedURLException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class SystemClassLoader extends ClassLoader {
|
||||
private static final int LinkFlag = 1 << 8;
|
||||
|
||||
public static native VMClass defineVMClass
|
||||
(ClassLoader loader, byte[] b, int offset, int length);
|
||||
|
||||
private static native VMClass findVMClass(String name)
|
||||
throws ClassNotFoundException;
|
||||
|
||||
@ -35,6 +21,8 @@ public class SystemClassLoader extends ClassLoader {
|
||||
return getClass(findVMClass(name));
|
||||
}
|
||||
|
||||
public static native Class getClass(VMClass vmClass);
|
||||
|
||||
private static native VMClass findLoadedVMClass(String name);
|
||||
|
||||
protected Class reallyFindLoadedClass(String name){
|
||||
@ -44,9 +32,6 @@ public class SystemClassLoader extends ClassLoader {
|
||||
|
||||
private static native boolean resourceExists(String name);
|
||||
|
||||
private static native VMClass resolveVMClass(ClassLoader loader, byte[] spec)
|
||||
throws ClassNotFoundException;
|
||||
|
||||
protected URL findResource(String name) {
|
||||
if (resourceExists(name)) {
|
||||
try {
|
||||
@ -55,261 +40,4 @@ public class SystemClassLoader extends ClassLoader {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static VMClass loadVMClass(ClassLoader loader,
|
||||
byte[] nameBytes, int offset, int length)
|
||||
{
|
||||
byte[] spec = new byte[length + 1];
|
||||
System.arraycopy(nameBytes, offset, spec, 0, length);
|
||||
|
||||
try {
|
||||
VMClass c = resolveVMClass(loader, spec);
|
||||
if (c == null) {
|
||||
throw new NoClassDefFoundError();
|
||||
}
|
||||
return c;
|
||||
} catch (ClassNotFoundException e) {
|
||||
NoClassDefFoundError error = new NoClassDefFoundError
|
||||
(new String(nameBytes, offset, length, false));
|
||||
error.initCause(e);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
private static Object parseAnnotationValue(ClassLoader loader,
|
||||
Object pool,
|
||||
InputStream in)
|
||||
throws IOException
|
||||
{
|
||||
switch (read1(in)) {
|
||||
case 'Z':
|
||||
return Boolean.valueOf(Singleton.getInt(pool, read2(in) - 1) != 0);
|
||||
|
||||
case 'B':
|
||||
return Byte.valueOf((byte) Singleton.getInt(pool, read2(in) - 1));
|
||||
|
||||
case 'C':
|
||||
return Character.valueOf((char) Singleton.getInt(pool, read2(in) - 1));
|
||||
|
||||
case 'S':
|
||||
return Short.valueOf((short) Singleton.getInt(pool, read2(in) - 1));
|
||||
|
||||
case 'I':
|
||||
return Integer.valueOf(Singleton.getInt(pool, read2(in) - 1));
|
||||
|
||||
case 'F':
|
||||
return Float.valueOf
|
||||
(Float.intBitsToFloat(Singleton.getInt(pool, read2(in) - 1)));
|
||||
|
||||
case 'J': {
|
||||
return Long.valueOf(Singleton.getLong(pool, read2(in) - 1));
|
||||
}
|
||||
|
||||
case 'D': {
|
||||
return Double.valueOf
|
||||
(Double.longBitsToDouble(Singleton.getLong(pool, read2(in) - 1)));
|
||||
}
|
||||
|
||||
case 's': {
|
||||
byte[] data = (byte[]) Singleton.getObject(pool, read2(in) - 1);
|
||||
|
||||
return new String(data, 0, data.length - 1, false);
|
||||
}
|
||||
|
||||
case 'e': {
|
||||
byte[] typeName = (byte[]) Singleton.getObject(pool, read2(in) - 1);
|
||||
byte[] name = (byte[]) Singleton.getObject(pool, read2(in) - 1);
|
||||
|
||||
return Enum.valueOf
|
||||
(getClass(loadVMClass(loader, typeName, 1, typeName.length - 3)),
|
||||
new String(name, 0, name.length - 1, false));
|
||||
}
|
||||
|
||||
case 'c':{
|
||||
byte[] name = (byte[]) Singleton.getObject(pool, read2(in) - 1);
|
||||
|
||||
return getClass(loadVMClass(loader, name, 1, name.length - 3));
|
||||
}
|
||||
|
||||
case '@':
|
||||
return parseAnnotation(loader, pool, in);
|
||||
|
||||
case '[': {
|
||||
Object[] array = new Object[read2(in)];
|
||||
for (int i = 0; i < array.length; ++i) {
|
||||
array[i] = parseAnnotationValue(loader, pool, in);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
default: throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
private static Object[] parseAnnotation(ClassLoader loader,
|
||||
Object pool,
|
||||
InputStream in)
|
||||
throws IOException
|
||||
{
|
||||
byte[] typeName = (byte[]) Singleton.getObject(pool, read2(in) - 1);
|
||||
Object[] annotation = new Object[(read2(in) + 1) * 2];
|
||||
annotation[1] = getClass
|
||||
(loadVMClass(loader, typeName, 1, typeName.length - 3));
|
||||
|
||||
for (int i = 2; i < annotation.length; i += 2) {
|
||||
byte[] name = (byte[]) Singleton.getObject(pool, read2(in) - 1);
|
||||
annotation[i] = new String(name, 0, name.length - 1, false);
|
||||
annotation[i + 1] = parseAnnotationValue(loader, pool, in);
|
||||
}
|
||||
|
||||
return annotation;
|
||||
}
|
||||
|
||||
private static Object[] parseAnnotationTable(ClassLoader loader,
|
||||
Object pool,
|
||||
InputStream in)
|
||||
throws IOException
|
||||
{
|
||||
Object[] table = new Object[read2(in)];
|
||||
for (int i = 0; i < table.length; ++i) {
|
||||
table[i] = parseAnnotation(loader, pool, in);
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
private static void parseAnnotationTable(ClassLoader loader,
|
||||
Addendum addendum)
|
||||
{
|
||||
if (addendum != null && addendum.annotationTable instanceof byte[]) {
|
||||
try {
|
||||
addendum.annotationTable = parseAnnotationTable
|
||||
(loader, addendum.pool, new ByteArrayInputStream
|
||||
((byte[]) addendum.annotationTable));
|
||||
} catch (IOException e) {
|
||||
AssertionError error = new AssertionError();
|
||||
error.initCause(e);
|
||||
throw error;
|
||||
}
|
||||
|
||||
addendum.pool = null;
|
||||
}
|
||||
}
|
||||
|
||||
private static int resolveSpec(ClassLoader loader, byte[] spec, int start) {
|
||||
int result;
|
||||
int end;
|
||||
switch (spec[start]) {
|
||||
case 'L':
|
||||
++ start;
|
||||
end = start;
|
||||
while (spec[end] != ';') ++ end;
|
||||
result = end + 1;
|
||||
break;
|
||||
|
||||
case '[':
|
||||
end = start + 1;
|
||||
while (spec[end] == '[') ++ end;
|
||||
switch (spec[end]) {
|
||||
case 'L':
|
||||
++ end;
|
||||
while (spec[end] != ';') ++ end;
|
||||
++ end;
|
||||
break;
|
||||
|
||||
default:
|
||||
++ end;
|
||||
}
|
||||
result = end;
|
||||
break;
|
||||
|
||||
default:
|
||||
return start + 1;
|
||||
}
|
||||
|
||||
loadVMClass(loader, spec, start, end - start);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static native void acquireClassLock();
|
||||
|
||||
private static native void releaseClassLock();
|
||||
|
||||
public static Class getClass(VMClass vmClass) {
|
||||
if (vmClass.addendum == null) {
|
||||
SystemClassLoader.acquireClassLock();
|
||||
try {
|
||||
if (vmClass.addendum == null) {
|
||||
vmClass.addendum = new ClassAddendum();
|
||||
}
|
||||
} finally {
|
||||
SystemClassLoader.releaseClassLock();
|
||||
}
|
||||
}
|
||||
|
||||
if (vmClass.addendum.class_ == null) {
|
||||
SystemClassLoader.acquireClassLock();
|
||||
try {
|
||||
if (vmClass.addendum.class_ == null) {
|
||||
vmClass.addendum.class_ = new Class(vmClass);
|
||||
}
|
||||
} finally {
|
||||
SystemClassLoader.releaseClassLock();
|
||||
}
|
||||
}
|
||||
|
||||
return vmClass.addendum.class_;
|
||||
}
|
||||
|
||||
public static native VMClass getVMClass(Object o);
|
||||
|
||||
public static void link(VMClass c, ClassLoader loader) {
|
||||
acquireClassLock();
|
||||
try {
|
||||
if ((c.vmFlags & LinkFlag) == 0) {
|
||||
if (c.super_ != null) {
|
||||
link(c.super_, loader);
|
||||
}
|
||||
|
||||
parseAnnotationTable(loader, c.addendum);
|
||||
|
||||
if (c.interfaceTable != null) {
|
||||
int stride = ((c.flags & Modifier.INTERFACE) != 0 ? 1 : 2);
|
||||
for (int i = 0; i < c.interfaceTable.length; i += stride) {
|
||||
link((VMClass) c.interfaceTable[i], loader);
|
||||
}
|
||||
}
|
||||
|
||||
if (c.methodTable != null) {
|
||||
for (int i = 0; i < c.methodTable.length; ++i) {
|
||||
VMMethod m = c.methodTable[i];
|
||||
|
||||
for (int j = 1; j < m.spec.length;) {
|
||||
j = resolveSpec(loader, m.spec, j);
|
||||
}
|
||||
|
||||
parseAnnotationTable(loader, m.addendum);
|
||||
}
|
||||
}
|
||||
|
||||
if (c.fieldTable != null) {
|
||||
for (int i = 0; i < c.fieldTable.length; ++i) {
|
||||
VMField f = c.fieldTable[i];
|
||||
|
||||
resolveSpec(loader, f.spec, 0);
|
||||
|
||||
parseAnnotationTable(loader, f.addendum);
|
||||
}
|
||||
}
|
||||
|
||||
c.vmFlags |= LinkFlag;
|
||||
}
|
||||
} finally {
|
||||
releaseClassLock();
|
||||
}
|
||||
}
|
||||
|
||||
public static void link(VMClass c) {
|
||||
link(c, c.loader);
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,6 @@ public class VMField {
|
||||
public short offset;
|
||||
public byte[] name;
|
||||
public byte[] spec;
|
||||
public avian.Addendum addendum;
|
||||
public FieldAddendum addendum;
|
||||
public VMClass class_;
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ public class VMMethod {
|
||||
public int nativeID;
|
||||
public byte[] name;
|
||||
public byte[] spec;
|
||||
public avian.Addendum addendum;
|
||||
public MethodAddendum addendum;
|
||||
public VMClass class_;
|
||||
public Object code;
|
||||
}
|
||||
|
@ -34,6 +34,10 @@ public class Handler extends URLStreamHandler {
|
||||
public InputStream getInputStream() throws IOException {
|
||||
return new ResourceInputStream(url.getFile());
|
||||
}
|
||||
|
||||
public void connect() {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
private static class ResourceInputStream extends InputStream {
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include "math.h"
|
||||
#include "stdlib.h"
|
||||
#include "time.h"
|
||||
#include "time.h"
|
||||
#include "string.h"
|
||||
#include "stdio.h"
|
||||
#include "jni.h"
|
||||
|
@ -47,8 +47,6 @@ public final class Class <T>
|
||||
this.vmClass = vmClass;
|
||||
}
|
||||
|
||||
public static native VMClass vmClass(Object o);
|
||||
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
@ -71,23 +69,23 @@ public final class Class <T>
|
||||
public static String getName(VMClass c) {
|
||||
if (c.name == null) {
|
||||
if ((c.vmFlags & PrimitiveFlag) != 0) {
|
||||
if (c == primitiveClass('V')) {
|
||||
if (c == SystemClassLoader.primitiveClass('V')) {
|
||||
c.name = "void\0".getBytes();
|
||||
} else if (c == primitiveClass('Z')) {
|
||||
} else if (c == SystemClassLoader.primitiveClass('Z')) {
|
||||
c.name = "boolean\0".getBytes();
|
||||
} else if (c == primitiveClass('B')) {
|
||||
} else if (c == SystemClassLoader.primitiveClass('B')) {
|
||||
c.name = "byte\0".getBytes();
|
||||
} else if (c == primitiveClass('C')) {
|
||||
} else if (c == SystemClassLoader.primitiveClass('C')) {
|
||||
c.name = "char\0".getBytes();
|
||||
} else if (c == primitiveClass('S')) {
|
||||
} else if (c == SystemClassLoader.primitiveClass('S')) {
|
||||
c.name = "short\0".getBytes();
|
||||
} else if (c == primitiveClass('I')) {
|
||||
} else if (c == SystemClassLoader.primitiveClass('I')) {
|
||||
c.name = "int\0".getBytes();
|
||||
} else if (c == primitiveClass('F')) {
|
||||
} else if (c == SystemClassLoader.primitiveClass('F')) {
|
||||
c.name = "float\0".getBytes();
|
||||
} else if (c == primitiveClass('J')) {
|
||||
} else if (c == SystemClassLoader.primitiveClass('J')) {
|
||||
c.name = "long\0".getBytes();
|
||||
} else if (c == primitiveClass('D')) {
|
||||
} else if (c == SystemClassLoader.primitiveClass('D')) {
|
||||
c.name = "double\0".getBytes();
|
||||
} else {
|
||||
throw new AssertionError();
|
||||
@ -154,15 +152,11 @@ public final class Class <T>
|
||||
Class c = loader.loadClass(name);
|
||||
SystemClassLoader.link(c.vmClass, loader);
|
||||
if (initialize) {
|
||||
initialize(c.vmClass);
|
||||
SystemClassLoader.initialize(c.vmClass);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
private static native VMClass primitiveClass(char name);
|
||||
|
||||
private static native void initialize(VMClass vmClass);
|
||||
|
||||
public static Class forCanonicalName(String name) {
|
||||
return forCanonicalName(null, name);
|
||||
}
|
||||
@ -175,7 +169,8 @@ public final class Class <T>
|
||||
return forName(name.substring(1, name.length() - 1), true, loader);
|
||||
} else {
|
||||
if (name.length() == 1) {
|
||||
return SystemClassLoader.getClass(primitiveClass(name.charAt(0)));
|
||||
return SystemClassLoader.getClass
|
||||
(SystemClassLoader.primitiveClass(name.charAt(0)));
|
||||
} else {
|
||||
throw new ClassNotFoundException(name);
|
||||
}
|
||||
@ -189,21 +184,29 @@ public final class Class <T>
|
||||
if (isArray()) {
|
||||
String n = getName();
|
||||
if ("[Z".equals(n)) {
|
||||
return SystemClassLoader.getClass(primitiveClass('Z'));
|
||||
return SystemClassLoader.getClass
|
||||
(SystemClassLoader.primitiveClass('Z'));
|
||||
} else if ("[B".equals(n)) {
|
||||
return SystemClassLoader.getClass(primitiveClass('B'));
|
||||
return SystemClassLoader.getClass
|
||||
(SystemClassLoader.primitiveClass('B'));
|
||||
} else if ("[S".equals(n)) {
|
||||
return SystemClassLoader.getClass(primitiveClass('S'));
|
||||
return SystemClassLoader.getClass
|
||||
(SystemClassLoader.primitiveClass('S'));
|
||||
} else if ("[C".equals(n)) {
|
||||
return SystemClassLoader.getClass(primitiveClass('C'));
|
||||
return SystemClassLoader.getClass
|
||||
(SystemClassLoader.primitiveClass('C'));
|
||||
} else if ("[I".equals(n)) {
|
||||
return SystemClassLoader.getClass(primitiveClass('I'));
|
||||
return SystemClassLoader.getClass
|
||||
(SystemClassLoader.primitiveClass('I'));
|
||||
} else if ("[F".equals(n)) {
|
||||
return SystemClassLoader.getClass(primitiveClass('F'));
|
||||
return SystemClassLoader.getClass
|
||||
(SystemClassLoader.primitiveClass('F'));
|
||||
} else if ("[J".equals(n)) {
|
||||
return SystemClassLoader.getClass(primitiveClass('J'));
|
||||
return SystemClassLoader.getClass
|
||||
(SystemClassLoader.primitiveClass('J'));
|
||||
} else if ("[D".equals(n)) {
|
||||
return SystemClassLoader.getClass(primitiveClass('D'));
|
||||
return SystemClassLoader.getClass
|
||||
(SystemClassLoader.primitiveClass('D'));
|
||||
}
|
||||
|
||||
if (vmClass.staticTable == null) throw new AssertionError();
|
||||
@ -213,10 +216,8 @@ public final class Class <T>
|
||||
}
|
||||
}
|
||||
|
||||
public static native boolean isAssignableFrom(VMClass a, VMClass b);
|
||||
|
||||
public boolean isAssignableFrom(Class c) {
|
||||
return isAssignableFrom(vmClass, c.vmClass);
|
||||
return SystemClassLoader.isAssignableFrom(vmClass, c.vmClass);
|
||||
}
|
||||
|
||||
private static Field findField(VMClass vmClass, String name) {
|
||||
@ -533,7 +534,8 @@ public final class Class <T>
|
||||
}
|
||||
|
||||
public static boolean isInstance(VMClass c, Object o) {
|
||||
return o != null && isAssignableFrom(c, SystemClassLoader.getVMClass(o));
|
||||
return o != null && SystemClassLoader.isAssignableFrom
|
||||
(c, SystemClassLoader.getVMClass(o));
|
||||
}
|
||||
|
||||
public boolean isInstance(Object o) {
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
package java.lang;
|
||||
|
||||
public class OutOfMemoryError extends Error {
|
||||
public class OutOfMemoryError extends VirtualMachineError {
|
||||
public OutOfMemoryError(String message) {
|
||||
super(message, null);
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ public class StackTraceElement {
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
return class_.replace('/', '.');
|
||||
return class_;
|
||||
}
|
||||
|
||||
public String getMethodName() {
|
||||
|
@ -12,13 +12,12 @@ package java.lang.ref;
|
||||
|
||||
public class ReferenceQueue<T> {
|
||||
private Reference<? extends T> front;
|
||||
private Reference<? extends T> rear;
|
||||
|
||||
public Reference<? extends T> poll() {
|
||||
Reference<? extends T> r = front;
|
||||
if (front != null) {
|
||||
if (front == front.jNext) {
|
||||
front = rear = null;
|
||||
front = null;
|
||||
} else {
|
||||
front = front.jNext;
|
||||
}
|
||||
@ -27,12 +26,11 @@ public class ReferenceQueue<T> {
|
||||
}
|
||||
|
||||
void add(Reference<? extends T> r) {
|
||||
r.jNext = r;
|
||||
if (front == null) {
|
||||
front = r;
|
||||
r.jNext = r;
|
||||
} else {
|
||||
rear.jNext = r;
|
||||
r.jNext = front;
|
||||
}
|
||||
rear = r;
|
||||
front = r;
|
||||
}
|
||||
}
|
||||
|
@ -204,7 +204,7 @@ public class Field<T> extends AccessibleObject {
|
||||
} else {
|
||||
throw new IllegalArgumentException
|
||||
("needed " + getType() + ", got "
|
||||
+ Class.getName(Class.vmClass(target)) +
|
||||
+ Class.getName(SystemClassLoader.vmClass(target)) +
|
||||
" when setting " + Class.getName(vmField.class_) + "." + getName());
|
||||
}
|
||||
break;
|
||||
|
203
makefile
203
makefile
@ -1,4 +1,4 @@
|
||||
MAKEFLAGS = -s
|
||||
#MAKEFLAGS = -s
|
||||
|
||||
name = avian
|
||||
version = 0.3
|
||||
@ -39,11 +39,17 @@ endif
|
||||
ifeq ($(continuations),true)
|
||||
options := $(options)-continuations
|
||||
endif
|
||||
|
||||
classpath = avian
|
||||
|
||||
test-library-path = .
|
||||
test-executable = $(executable)
|
||||
|
||||
ifdef gnu
|
||||
classpath = gnu
|
||||
options := $(options)-gnu
|
||||
gnu-sources = $(src)/gnu.cpp
|
||||
gnu-jar = $(gnu)/share/classpath/glibj.zip
|
||||
gnu-libraries = \
|
||||
classapth-jar = $(gnu)/share/classpath/glibj.zip
|
||||
classpath-libraries = \
|
||||
$(gnu)/lib/classpath/libjavaio.a \
|
||||
$(gnu)/lib/classpath/libjavalang.a \
|
||||
$(gnu)/lib/classpath/libjavalangreflect.a \
|
||||
@ -51,10 +57,20 @@ ifdef gnu
|
||||
$(gnu)/lib/classpath/libjavanet.a \
|
||||
$(gnu)/lib/classpath/libjavanio.a \
|
||||
$(gnu)/lib/classpath/libjavautil.a
|
||||
gnu-object-dep = $(build)/gnu-object.dep
|
||||
gnu-cflags = -DBOOT_BUILTINS=\"javaio,javalang,javalangreflect,javamath,javanet,javanio,javautil\" -DAVIAN_GNU
|
||||
gnu-lflags = -lgmp
|
||||
gnu-objects = $(shell find $(build)/gnu-objects -name "*.o")
|
||||
classpath-cflags = -DBOOT_BUILTINS=\"javaio,javalang,javalangreflect,javamath,javanet,javanio,javautil\" -DAVIAN_GNU
|
||||
classpath-lflags = -lgmp
|
||||
endif
|
||||
ifdef openjdk
|
||||
classpath = openjdk
|
||||
options := $(options)-openjdk
|
||||
ifeq ($(arch),x86_64)
|
||||
openjdk-lib-dir = $(openjdk)/jre/lib/amd64
|
||||
else
|
||||
openjdk-lib-dir = $(openjdk)/jre/lib
|
||||
endif
|
||||
classpath-jar = $(openjdk)/jre/lib/rt.jar
|
||||
test-library-path = $(openjdk-lib-dir):$(native-build)
|
||||
test-executable = $(executable-dynamic)
|
||||
endif
|
||||
|
||||
root := $(shell (cd .. && pwd))
|
||||
@ -63,13 +79,16 @@ native-build = $(build)/$(platform)-$(arch)$(options)
|
||||
classpath-build = $(build)/classpath
|
||||
test-build = $(build)/test
|
||||
src = src
|
||||
classpath = classpath
|
||||
classpath-src = classpath
|
||||
test = test
|
||||
|
||||
ifdef gnu
|
||||
avian-classpath-build = $(build)/avian-classpath
|
||||
ifneq ($(classpath),avian)
|
||||
classpath-object-dep = $(build)/classpath-object.dep
|
||||
classpath-objects = $(shell find $(build)/classpath-objects -name "*.o")
|
||||
else
|
||||
avian-classpath-build = $(classpath-build)
|
||||
jni-sources := $(shell find $(classpath-src) -name '*.cpp')
|
||||
jni-objects = \
|
||||
$(call cpp-objects,$(jni-sources),$(classpath-src),$(native-build))
|
||||
endif
|
||||
|
||||
input = List
|
||||
@ -79,12 +98,12 @@ build-cc = gcc
|
||||
|
||||
mflag =
|
||||
ifneq ($(platform),darwin)
|
||||
ifeq ($(arch),i386)
|
||||
mflag = -m32
|
||||
endif
|
||||
ifeq ($(arch),x86_64)
|
||||
mflag = -m64
|
||||
endif
|
||||
ifeq ($(arch),i386)
|
||||
mflag = -m32
|
||||
endif
|
||||
ifeq ($(arch),x86_64)
|
||||
mflag = -m64
|
||||
endif
|
||||
endif
|
||||
|
||||
cxx = $(build-cxx) $(mflag)
|
||||
@ -112,14 +131,14 @@ warnings = -Wall -Wextra -Werror -Wunused-parameter -Winit-self \
|
||||
common-cflags = $(warnings) -fno-rtti -fno-exceptions -fno-omit-frame-pointer \
|
||||
"-I$(JAVA_HOME)/include" -idirafter $(src) -I$(native-build) \
|
||||
-D__STDC_LIMIT_MACROS -D_JNI_IMPLEMENTATION_ -DAVIAN_VERSION=\"$(version)\" \
|
||||
-DUSE_ATOMIC_OPERATIONS $(gnu-cflags)
|
||||
-DUSE_ATOMIC_OPERATIONS $(classpath-cflags)
|
||||
|
||||
build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \
|
||||
"-I$(JAVA_HOME)/include/linux" -I$(src) -pthread
|
||||
|
||||
cflags = $(build-cflags)
|
||||
|
||||
common-lflags = -lm -lz $(gnu-lflags)
|
||||
common-lflags = -lm -lz $(classpath-lflags)
|
||||
|
||||
build-lflags =
|
||||
|
||||
@ -297,9 +316,6 @@ cpp-objects = $(foreach x,$(1),$(patsubst $(2)/%.cpp,$(3)/%.o,$(x)))
|
||||
asm-objects = $(foreach x,$(1),$(patsubst $(2)/%.S,$(3)/%-asm.o,$(x)))
|
||||
java-classes = $(foreach x,$(1),$(patsubst $(2)/%.java,$(3)/%.class,$(x)))
|
||||
|
||||
jni-sources := $(shell find $(classpath) -name '*.cpp')
|
||||
jni-objects = $(call cpp-objects,$(jni-sources),$(classpath),$(native-build))
|
||||
|
||||
generated-code = \
|
||||
$(native-build)/type-enums.cpp \
|
||||
$(native-build)/type-declarations.cpp \
|
||||
@ -307,26 +323,7 @@ generated-code = \
|
||||
$(native-build)/type-initializations.cpp \
|
||||
$(native-build)/type-java-initializations.cpp
|
||||
|
||||
vm-depends = \
|
||||
$(generated-code) \
|
||||
$(src)/allocator.h \
|
||||
$(src)/common.h \
|
||||
$(src)/system.h \
|
||||
$(src)/heap.h \
|
||||
$(src)/finder.h \
|
||||
$(src)/processor.h \
|
||||
$(src)/process.h \
|
||||
$(src)/stream.h \
|
||||
$(src)/constants.h \
|
||||
$(src)/jnienv.h \
|
||||
$(src)/machine.h \
|
||||
$(src)/util.h \
|
||||
$(src)/zone.h \
|
||||
$(src)/assembler.h \
|
||||
$(src)/compiler.h \
|
||||
$(src)/$(asm).h \
|
||||
$(src)/heapwalk.h \
|
||||
$(src)/bootimage.h
|
||||
vm-depends := $(generated-code) $(wildcard $(src)/*.h)
|
||||
|
||||
vm-sources = \
|
||||
$(src)/$(system).cpp \
|
||||
@ -335,10 +332,10 @@ vm-sources = \
|
||||
$(src)/util.cpp \
|
||||
$(src)/heap.cpp \
|
||||
$(src)/$(process).cpp \
|
||||
$(src)/classpath-$(classpath).cpp \
|
||||
$(src)/builtin.cpp \
|
||||
$(src)/jnienv.cpp \
|
||||
$(src)/process.cpp \
|
||||
$(gnu-sources)
|
||||
$(src)/process.cpp
|
||||
|
||||
vm-asm-sources = $(src)/$(asm).S
|
||||
|
||||
@ -428,48 +425,37 @@ converter = $(native-build)/binaryToObject
|
||||
|
||||
static-library = $(native-build)/lib$(name).a
|
||||
executable = $(native-build)/$(name)${exe-suffix}
|
||||
dynamic-library = $(native-build)/$(so-prefix)$(name)$(so-suffix)
|
||||
dynamic-library = $(native-build)/$(so-prefix)jvm$(so-suffix)
|
||||
executable-dynamic = $(native-build)/$(name)-dynamic${exe-suffix}
|
||||
|
||||
classpath-sources := $(shell find $(classpath) -name '*.java')
|
||||
ifneq ($(classpath),avian)
|
||||
classpath-sources := \
|
||||
$(classpath-src)/avian/Continuations.java \
|
||||
$(classpath-src)/avian/Callback.java \
|
||||
$(classpath-src)/avian/CallbackReceiver.java \
|
||||
$(classpath-src)/avian/IncompatibleContinuationException.java \
|
||||
$(classpath-src)/avian/SystemClassLoader.java \
|
||||
$(classpath-src)/avian/Machine.java \
|
||||
$(classpath-src)/avian/Addendum.java \
|
||||
$(classpath-src)/avian/ClassAddendum.java \
|
||||
$(classpath-src)/avian/MethodAddendum.java \
|
||||
$(classpath-src)/avian/FieldAddendum.java \
|
||||
$(classpath-src)/avian/VMClass.java \
|
||||
$(classpath-src)/avian/VMField.java \
|
||||
$(classpath-src)/avian/VMMethod.java \
|
||||
$(classpath-src)/avian/resource/Handler.java
|
||||
else
|
||||
classpath-sources := $(shell find $(classpath-src) -name '*.java')
|
||||
endif
|
||||
|
||||
classpath-classes = \
|
||||
$(call java-classes,$(classpath-sources),$(classpath),$(classpath-build))
|
||||
$(call java-classes,$(classpath-sources),$(classpath-src),$(classpath-build))
|
||||
classpath-object = $(native-build)/classpath-jar.o
|
||||
classpath-dep = $(classpath-build).dep
|
||||
|
||||
gnu-blacklist = \
|
||||
java/lang/AbstractStringBuffer.class \
|
||||
java/lang/reflect/Proxy.class
|
||||
|
||||
gnu-overrides = \
|
||||
vm-classes = \
|
||||
avian/*.class \
|
||||
avian/resource/*.class \
|
||||
java/lang/Class.class \
|
||||
java/lang/Enum.class \
|
||||
java/lang/InheritableThreadLocal.class \
|
||||
java/lang/Object.class \
|
||||
java/lang/StackTraceElement.class \
|
||||
java/lang/String.class \
|
||||
java/lang/String\$$*.class \
|
||||
java/lang/StringBuffer.class \
|
||||
java/lang/StringBuilder.class \
|
||||
java/lang/StringBuilder\$$*.class \
|
||||
java/lang/Thread.class \
|
||||
java/lang/Thread\$$*.class \
|
||||
java/lang/ThreadGroup.class \
|
||||
java/lang/ThreadLocal.class \
|
||||
java/lang/Throwable.class \
|
||||
java/lang/ref/PhantomReference.class \
|
||||
java/lang/ref/Reference.class \
|
||||
java/lang/ref/ReferenceQueue.class \
|
||||
java/lang/ref/SoftReference.class \
|
||||
java/lang/ref/WeakReference.class \
|
||||
java/lang/reflect/AccessibleObject.class \
|
||||
java/lang/reflect/Constructor.class \
|
||||
java/lang/reflect/Field.class \
|
||||
java/lang/reflect/Method.class \
|
||||
java/lang/reflect/Proxy.class \
|
||||
java/lang/reflect/Proxy\$$*.class
|
||||
avian/resource/*.class
|
||||
|
||||
test-sources = $(wildcard $(test)/*.java)
|
||||
test-classes = $(call java-classes,$(test-sources),$(test),$(test-build))
|
||||
@ -510,7 +496,7 @@ vg: build
|
||||
.PHONY: test
|
||||
test: build
|
||||
/bin/sh $(test)/test.sh 2>/dev/null \
|
||||
$(executable) $(mode) "$(flags)" \
|
||||
$(test-library-path) $(test-executable) $(mode) "$(flags)" \
|
||||
$(call class-names,$(test-build),$(test-classes))
|
||||
|
||||
.PHONY: tarball
|
||||
@ -549,27 +535,20 @@ $(generated-code): %.cpp: $(src)/types.def $(generator) $(classpath-dep)
|
||||
$(native-build)/type-generator.o: \
|
||||
$(generator-headers)
|
||||
|
||||
$(classpath-build)/%.class: $(classpath)/%.java
|
||||
$(classpath-build)/%.class: $(classpath-src)/%.java
|
||||
@echo $(<)
|
||||
|
||||
$(classpath-dep): $(classpath-sources) $(gnu-jar)
|
||||
$(classpath-dep): $(classpath-sources) $(classpath-jar)
|
||||
@echo "compiling classpath classes"
|
||||
@mkdir -p $(avian-classpath-build)
|
||||
$(javac) -d $(avian-classpath-build) \
|
||||
-bootclasspath $(avian-classpath-build) \
|
||||
$(shell $(MAKE) -s --no-print-directory $(classpath-classes))
|
||||
ifdef gnu
|
||||
(wd=$$(pwd) && \
|
||||
cd $(avian-classpath-build) && \
|
||||
$(jar) c0f "$$($(native-path) "$${wd}/$(build)/overrides.jar")" \
|
||||
$(gnu-overrides))
|
||||
@mkdir -p $(classpath-build)
|
||||
ifneq ($(classpath),avian)
|
||||
(wd=$$(pwd) && \
|
||||
cd $(classpath-build) && \
|
||||
$(jar) xf $(gnu-jar) && \
|
||||
rm $(gnu-blacklist) && \
|
||||
jar xf "$$($(native-path) "$${wd}/$(build)/overrides.jar")")
|
||||
$(jar) xf $(classpath-jar))
|
||||
endif
|
||||
$(javac) -d $(classpath-build) \
|
||||
-bootclasspath $(classpath-build) \
|
||||
$(shell $(MAKE) -s --no-print-directory $(classpath-classes))
|
||||
@touch $(@)
|
||||
|
||||
$(test-build)/%.class: $(test)/%.java
|
||||
@ -625,7 +604,7 @@ $(driver-object): $(driver-source)
|
||||
$(driver-dynamic-object): $(driver-source)
|
||||
@echo "compiling $(@)"
|
||||
@mkdir -p $(dir $(@))
|
||||
$(cxx) $(cflags) -DBOOT_LIBRARY=\"$(so-prefix)$(name)$(so-suffix)\" \
|
||||
$(cxx) $(cflags) -DBOOT_LIBRARY=\"$(so-prefix)jvm$(so-suffix)\" \
|
||||
-c $(<) $(call output,$(@))
|
||||
|
||||
$(boot-object): $(boot-source)
|
||||
@ -668,14 +647,14 @@ $(generator-objects): $(native-build)/%.o: $(src)/%.cpp
|
||||
$(build-cxx) -DPOINTER_SIZE=$(pointer-size) -O0 -g3 $(build-cflags) \
|
||||
-c $(<) -o $(@)
|
||||
|
||||
$(jni-objects): $(native-build)/%.o: $(classpath)/%.cpp
|
||||
$(jni-objects): $(native-build)/%.o: $(classpath-src)/%.cpp
|
||||
$(compile-object)
|
||||
|
||||
$(static-library): $(gnu-object-dep)
|
||||
$(static-library): $(classpath-object-dep)
|
||||
$(static-library): $(vm-objects) $(jni-objects) $(vm-heapwalk-objects)
|
||||
@echo "creating $(@)"
|
||||
rm -rf $(@)
|
||||
$(ar) cru $(@) $(^) $(call gnu-objects)
|
||||
$(ar) cru $(@) $(^) $(call classpath-objects)
|
||||
$(ranlib) $(@)
|
||||
|
||||
$(bootimage-bin): $(bootimage-generator)
|
||||
@ -687,13 +666,13 @@ $(bootimage-object): $(bootimage-bin) $(converter)
|
||||
_binary_bootimage_bin_end $(platform) $(arch) $(pointer-size) \
|
||||
writable executable
|
||||
|
||||
$(gnu-object-dep): $(gnu-libraries)
|
||||
@mkdir -p $(build)/gnu-objects
|
||||
(cd $(build)/gnu-objects && \
|
||||
for x in $(gnu-libraries); do ar x $${x}; done)
|
||||
$(classpath-object-dep): $(classpath-libraries)
|
||||
@mkdir -p $(build)/classpath-objects
|
||||
(cd $(build)/classpath-objects && \
|
||||
for x in $(classpath-libraries); do ar x $${x}; done)
|
||||
@touch $(@)
|
||||
|
||||
$(executable): $(gnu-object-dep)
|
||||
$(executable): $(classpath-object-dep)
|
||||
$(executable): \
|
||||
$(vm-objects) $(jni-objects) $(driver-object) $(vm-heapwalk-objects) \
|
||||
$(boot-object) $(vm-classpath-object)
|
||||
@ -704,13 +683,13 @@ ifdef msvc
|
||||
-MANIFESTFILE:$(@).manifest
|
||||
$(mt) -manifest $(@).manifest -outputresource:"$(@);1"
|
||||
else
|
||||
$(dlltool) -z $(@).def $(^) $(call gnu-objects)
|
||||
$(dlltool) -z $(@).def $(^) $(call classpath-objects)
|
||||
$(dlltool) -d $(@).def -e $(@).exp
|
||||
$(ld) $(@).exp $(^) $(call gnu-objects) $(lflags) -o $(@)
|
||||
$(ld) $(@).exp $(^) $(call classpath-objects) $(lflags) -o $(@)
|
||||
endif
|
||||
else
|
||||
$(ld) $(^) $(call gnu-objects) $(rdynamic) $(lflags) $(bootimage-lflags) \
|
||||
-o $(@)
|
||||
$(ld) $(^) $(call classpath-objects) $(rdynamic) $(lflags) \
|
||||
$(bootimage-lflags) -o $(@)
|
||||
endif
|
||||
$(strip) $(strip-all) $(@)
|
||||
|
||||
@ -740,18 +719,18 @@ else
|
||||
$(ld) $(^) $(rdynamic) $(lflags) -o $(@)
|
||||
endif
|
||||
|
||||
$(dynamic-library): $(gnu-object-dep)
|
||||
$(dynamic-library): $(classpath-object-dep)
|
||||
$(dynamic-library): \
|
||||
$(vm-objects) $(dynamic-object) $(jni-objects) $(vm-heapwalk-objects) \
|
||||
$(boot-object) $(vm-classpath-object) $(gnu-libraries)
|
||||
$(boot-object) $(vm-classpath-object) $(classpath-libraries)
|
||||
@echo "linking $(@)"
|
||||
ifdef msvc
|
||||
$(ld) $(shared) $(lflags) $(^) -out:$(@) -PDB:$(@).pdb \
|
||||
-IMPLIB:$(native-build)/$(name).lib -MANIFESTFILE:$(@).manifest
|
||||
$(mt) -manifest $(@).manifest -outputresource:"$(@);2"
|
||||
else
|
||||
$(ld) $(^) $(call gnu-objects) $(shared) $(lflags) $(bootimage-lflags) \
|
||||
-o $(@)
|
||||
$(ld) $(^) -Wl,--version-script=openjdk.ld \
|
||||
$(call classpath-objects) $(shared) $(lflags) $(bootimage-lflags) -o $(@)
|
||||
endif
|
||||
$(strip) $(strip-all) $(@)
|
||||
|
||||
|
288
openjdk.ld
Normal file
288
openjdk.ld
Normal file
@ -0,0 +1,288 @@
|
||||
#
|
||||
# @(#)mapfile-vers-product 1.19 08/02/12 10:56:37
|
||||
#
|
||||
|
||||
#
|
||||
# Copyright 2002-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
# CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
# have any questions.
|
||||
#
|
||||
#
|
||||
|
||||
# Define public interface.
|
||||
|
||||
SUNWprivate_1.1 {
|
||||
global:
|
||||
# JNI
|
||||
JNI_CreateJavaVM;
|
||||
JNI_GetCreatedJavaVMs;
|
||||
JNI_GetDefaultJavaVMInitArgs;
|
||||
|
||||
# JVM
|
||||
JVM_Accept;
|
||||
JVM_ActiveProcessorCount;
|
||||
JVM_AllocateNewArray;
|
||||
JVM_AllocateNewObject;
|
||||
JVM_ArrayCopy;
|
||||
JVM_AssertionStatusDirectives;
|
||||
JVM_Available;
|
||||
JVM_Bind;
|
||||
JVM_ClassDepth;
|
||||
JVM_ClassLoaderDepth;
|
||||
JVM_Clone;
|
||||
JVM_Close;
|
||||
JVM_CX8Field;
|
||||
JVM_CompileClass;
|
||||
JVM_CompileClasses;
|
||||
JVM_CompilerCommand;
|
||||
JVM_Connect;
|
||||
JVM_ConstantPoolGetClassAt;
|
||||
JVM_ConstantPoolGetClassAtIfLoaded;
|
||||
JVM_ConstantPoolGetDoubleAt;
|
||||
JVM_ConstantPoolGetFieldAt;
|
||||
JVM_ConstantPoolGetFieldAtIfLoaded;
|
||||
JVM_ConstantPoolGetFloatAt;
|
||||
JVM_ConstantPoolGetIntAt;
|
||||
JVM_ConstantPoolGetLongAt;
|
||||
JVM_ConstantPoolGetMethodAt;
|
||||
JVM_ConstantPoolGetMethodAtIfLoaded;
|
||||
JVM_ConstantPoolGetMemberRefInfoAt;
|
||||
JVM_ConstantPoolGetSize;
|
||||
JVM_ConstantPoolGetStringAt;
|
||||
JVM_ConstantPoolGetUTF8At;
|
||||
JVM_CountStackFrames;
|
||||
JVM_CurrentClassLoader;
|
||||
JVM_CurrentLoadedClass;
|
||||
JVM_CurrentThread;
|
||||
JVM_CurrentTimeMillis;
|
||||
JVM_DefineClass;
|
||||
JVM_DefineClassWithSource;
|
||||
JVM_DesiredAssertionStatus;
|
||||
JVM_DisableCompiler;
|
||||
JVM_DoPrivileged;
|
||||
JVM_DTraceGetVersion;
|
||||
JVM_DTraceActivate;
|
||||
JVM_DTraceIsProbeEnabled;
|
||||
JVM_DTraceIsSupported;
|
||||
JVM_DTraceDispose;
|
||||
JVM_DumpAllStacks;
|
||||
JVM_DumpThreads;
|
||||
JVM_EnableCompiler;
|
||||
JVM_Exit;
|
||||
JVM_FillInStackTrace;
|
||||
JVM_FindClassFromClass;
|
||||
JVM_FindClassFromClassLoader;
|
||||
JVM_FindClassFromBootLoader;
|
||||
JVM_FindLibraryEntry;
|
||||
JVM_FindLoadedClass;
|
||||
JVM_FindPrimitiveClass;
|
||||
JVM_FindSignal;
|
||||
JVM_FreeMemory;
|
||||
JVM_GC;
|
||||
JVM_GetAllThreads;
|
||||
JVM_GetArrayElement;
|
||||
JVM_GetArrayLength;
|
||||
JVM_GetCPClassNameUTF;
|
||||
JVM_GetCPFieldClassNameUTF;
|
||||
JVM_GetCPFieldModifiers;
|
||||
JVM_GetCPFieldNameUTF;
|
||||
JVM_GetCPFieldSignatureUTF;
|
||||
JVM_GetCPMethodClassNameUTF;
|
||||
JVM_GetCPMethodModifiers;
|
||||
JVM_GetCPMethodNameUTF;
|
||||
JVM_GetCPMethodSignatureUTF;
|
||||
JVM_GetCallerClass;
|
||||
JVM_GetClassAccessFlags;
|
||||
JVM_GetClassAnnotations;
|
||||
JVM_GetClassCPEntriesCount;
|
||||
JVM_GetClassCPTypes;
|
||||
JVM_GetClassConstantPool;
|
||||
JVM_GetClassContext;
|
||||
JVM_GetClassDeclaredConstructors;
|
||||
JVM_GetClassDeclaredFields;
|
||||
JVM_GetClassDeclaredMethods;
|
||||
JVM_GetClassFieldsCount;
|
||||
JVM_GetClassInterfaces;
|
||||
JVM_GetClassLoader;
|
||||
JVM_GetClassMethodsCount;
|
||||
JVM_GetClassModifiers;
|
||||
JVM_GetClassName;
|
||||
JVM_GetClassNameUTF;
|
||||
JVM_GetClassSignature;
|
||||
JVM_GetClassSigners;
|
||||
JVM_GetComponentType;
|
||||
JVM_GetDeclaredClasses;
|
||||
JVM_GetDeclaringClass;
|
||||
JVM_GetEnclosingMethodInfo;
|
||||
JVM_GetFieldAnnotations;
|
||||
JVM_GetFieldIxModifiers;
|
||||
JVM_GetHostName;
|
||||
JVM_GetInheritedAccessControlContext;
|
||||
JVM_GetInterfaceVersion;
|
||||
JVM_GetLastErrorString;
|
||||
JVM_GetManagement;
|
||||
JVM_GetMethodAnnotations;
|
||||
JVM_GetMethodDefaultAnnotationValue;
|
||||
JVM_GetMethodIxArgsSize;
|
||||
JVM_GetMethodIxByteCode;
|
||||
JVM_GetMethodIxByteCodeLength;
|
||||
JVM_GetMethodIxExceptionIndexes;
|
||||
JVM_GetMethodIxExceptionTableEntry;
|
||||
JVM_GetMethodIxExceptionTableLength;
|
||||
JVM_GetMethodIxExceptionsCount;
|
||||
JVM_GetMethodIxLocalsCount;
|
||||
JVM_GetMethodIxMaxStack;
|
||||
JVM_GetMethodIxModifiers;
|
||||
JVM_GetMethodIxNameUTF;
|
||||
JVM_GetMethodIxSignatureUTF;
|
||||
JVM_GetMethodParameterAnnotations;
|
||||
JVM_GetPrimitiveArrayElement;
|
||||
JVM_GetProtectionDomain;
|
||||
JVM_GetSockName;
|
||||
JVM_GetSockOpt;
|
||||
JVM_GetStackAccessControlContext;
|
||||
JVM_GetStackTraceDepth;
|
||||
JVM_GetStackTraceElement;
|
||||
JVM_GetSystemPackage;
|
||||
JVM_GetSystemPackages;
|
||||
JVM_GetThreadStateNames;
|
||||
JVM_GetThreadStateValues;
|
||||
JVM_GetVersionInfo;
|
||||
JVM_Halt;
|
||||
JVM_HoldsLock;
|
||||
JVM_IHashCode;
|
||||
JVM_InitAgentProperties;
|
||||
JVM_InitProperties;
|
||||
JVM_InitializeCompiler;
|
||||
JVM_InitializeSocketLibrary;
|
||||
JVM_InternString;
|
||||
JVM_Interrupt;
|
||||
JVM_InvokeMethod;
|
||||
JVM_IsArrayClass;
|
||||
JVM_IsConstructorIx;
|
||||
JVM_IsInterface;
|
||||
JVM_IsInterrupted;
|
||||
JVM_IsNaN;
|
||||
JVM_IsPrimitiveClass;
|
||||
JVM_IsSameClassPackage;
|
||||
JVM_IsSilentCompiler;
|
||||
JVM_IsSupportedJNIVersion;
|
||||
JVM_IsThreadAlive;
|
||||
JVM_LatestUserDefinedLoader;
|
||||
JVM_Listen;
|
||||
JVM_LoadClass0;
|
||||
JVM_LoadLibrary;
|
||||
JVM_Lseek;
|
||||
JVM_MaxObjectInspectionAge;
|
||||
JVM_MaxMemory;
|
||||
JVM_MonitorNotify;
|
||||
JVM_MonitorNotifyAll;
|
||||
JVM_MonitorWait;
|
||||
JVM_NanoTime;
|
||||
JVM_NativePath;
|
||||
JVM_NewArray;
|
||||
JVM_NewInstanceFromConstructor;
|
||||
JVM_NewMultiArray;
|
||||
JVM_OnExit;
|
||||
JVM_Open;
|
||||
JVM_PrintStackTrace;
|
||||
JVM_RaiseSignal;
|
||||
JVM_RawMonitorCreate;
|
||||
JVM_RawMonitorDestroy;
|
||||
JVM_RawMonitorEnter;
|
||||
JVM_RawMonitorExit;
|
||||
JVM_Read;
|
||||
JVM_Recv;
|
||||
JVM_RecvFrom;
|
||||
JVM_RegisterSignal;
|
||||
JVM_ReleaseUTF;
|
||||
JVM_ResolveClass;
|
||||
JVM_ResumeThread;
|
||||
JVM_Send;
|
||||
JVM_SendTo;
|
||||
JVM_SetArrayElement;
|
||||
JVM_SetClassSigners;
|
||||
JVM_SetLength;
|
||||
JVM_SetPrimitiveArrayElement;
|
||||
JVM_SetProtectionDomain;
|
||||
JVM_SetSockOpt;
|
||||
JVM_SetThreadPriority;
|
||||
JVM_Sleep;
|
||||
JVM_Socket;
|
||||
JVM_SocketAvailable;
|
||||
JVM_SocketClose;
|
||||
JVM_SocketShutdown;
|
||||
JVM_StartThread;
|
||||
JVM_StopThread;
|
||||
JVM_SuspendThread;
|
||||
JVM_SupportsCX8;
|
||||
JVM_Sync;
|
||||
JVM_Timeout;
|
||||
JVM_TotalMemory;
|
||||
JVM_TraceInstructions;
|
||||
JVM_TraceMethodCalls;
|
||||
JVM_UnloadLibrary;
|
||||
JVM_Write;
|
||||
JVM_Yield;
|
||||
JVM_handle_linux_signal;
|
||||
|
||||
# Old reflection routines
|
||||
# These do not need to be present in the product build in JDK 1.4
|
||||
# but their code has not been removed yet because there will not
|
||||
# be a substantial code savings until JVM_InvokeMethod and
|
||||
# JVM_NewInstanceFromConstructor can also be removed; see
|
||||
# reflectionCompat.hpp.
|
||||
JVM_GetClassConstructor;
|
||||
JVM_GetClassConstructors;
|
||||
JVM_GetClassField;
|
||||
JVM_GetClassFields;
|
||||
JVM_GetClassMethod;
|
||||
JVM_GetClassMethods;
|
||||
JVM_GetField;
|
||||
JVM_GetPrimitiveField;
|
||||
JVM_NewInstance;
|
||||
JVM_SetField;
|
||||
JVM_SetPrimitiveField;
|
||||
|
||||
# Needed for dropping VM into JDK 1.3.x, 1.4
|
||||
_JVM_native_threads;
|
||||
jdk_sem_init;
|
||||
jdk_sem_post;
|
||||
jdk_sem_wait;
|
||||
jdk_pthread_sigmask;
|
||||
jdk_waitpid;
|
||||
|
||||
# miscellaneous functions
|
||||
jio_fprintf;
|
||||
jio_printf;
|
||||
jio_snprintf;
|
||||
jio_vfprintf;
|
||||
jio_vsnprintf;
|
||||
fork1;
|
||||
numa_warn;
|
||||
numa_error;
|
||||
|
||||
# Needed because there is no JVM interface for this.
|
||||
sysThreadAvailableStackWithSlack;
|
||||
|
||||
# This is for Forte Analyzer profiling support.
|
||||
AsyncGetCallTrace;
|
||||
};
|
||||
|
767
src/builtin.cpp
767
src/builtin.cpp
@ -39,135 +39,14 @@ search(Thread* t, object name, object (*op)(Thread*, object),
|
||||
|
||||
return reinterpret_cast<int64_t>(r);
|
||||
} else {
|
||||
t->exception = makeNullPointerException(t);
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
enumerateThreads(Thread* t, Thread* x, object array, unsigned* index,
|
||||
unsigned limit)
|
||||
{
|
||||
if (*index < limit) {
|
||||
set(t, array, ArrayBody + (*index * BytesPerWord), x->javaThread);
|
||||
++ (*index);
|
||||
|
||||
if (x->peer) enumerateThreads(t, x->peer, array, index, limit);
|
||||
|
||||
if (x->child) enumerateThreads(t, x->child, array, index, limit);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
compatibleArrayTypes(Thread* t, object a, object b)
|
||||
{
|
||||
return classArrayElementSize(t, a)
|
||||
and classArrayElementSize(t, b)
|
||||
and (a == b
|
||||
or (not ((classVmFlags(t, a) & PrimitiveFlag)
|
||||
or (classVmFlags(t, b) & PrimitiveFlag))));
|
||||
}
|
||||
|
||||
void
|
||||
runOnLoadIfFound(Thread* t, System::Library* library)
|
||||
{
|
||||
void* p = library->resolve("JNI_OnLoad");
|
||||
if (p) {
|
||||
jint (JNICALL * JNI_OnLoad)(Machine*, void*);
|
||||
memcpy(&JNI_OnLoad, &p, sizeof(void*));
|
||||
JNI_OnLoad(t->m, 0);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Object_toString
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object this_ = reinterpret_cast<object>(arguments[0]);
|
||||
|
||||
unsigned hash = objectHash(t, this_);
|
||||
object s = makeString
|
||||
(t, "%s@0x%x",
|
||||
&byteArrayBody(t, className(t, objectClass(t, this_)), 0),
|
||||
hash);
|
||||
|
||||
return reinterpret_cast<int64_t>(s);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Object_getVMClass
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object o = reinterpret_cast<object>(arguments[0]);
|
||||
|
||||
return reinterpret_cast<int64_t>(objectClass(t, o));
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Avian_java_lang_Object_wait
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object this_ = reinterpret_cast<object>(arguments[0]);
|
||||
int64_t milliseconds; memcpy(&milliseconds, arguments + 1, 8);
|
||||
|
||||
vm::wait(t, this_, milliseconds);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Avian_java_lang_Object_notify
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object this_ = reinterpret_cast<object>(arguments[0]);
|
||||
|
||||
notify(t, this_);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Avian_java_lang_Object_notifyAll
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object this_ = reinterpret_cast<object>(arguments[0]);
|
||||
|
||||
notifyAll(t, this_);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Object_hashCode
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object this_ = reinterpret_cast<object>(arguments[0]);
|
||||
|
||||
return objectHash(t, this_);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Object_clone
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object o = reinterpret_cast<object>(arguments[0]);
|
||||
PROTECT(t, o);
|
||||
|
||||
object class_ = objectClass(t, o);
|
||||
unsigned size = baseSize(t, o, class_) * BytesPerWord;
|
||||
object clone;
|
||||
|
||||
if (classArrayElementSize(t, class_)) {
|
||||
clone = static_cast<object>(allocate(t, size, classObjectMask(t, class_)));
|
||||
memcpy(clone, o, size);
|
||||
// clear any object header flags:
|
||||
setObjectClass(t, o, objectClass(t, o));
|
||||
} else {
|
||||
clone = make(t, class_);
|
||||
memcpy(reinterpret_cast<void**>(clone) + 1,
|
||||
reinterpret_cast<void**>(o) + 1,
|
||||
size - BytesPerWord);
|
||||
}
|
||||
|
||||
return reinterpret_cast<int64_t>(clone);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Avian_avian_SystemClassLoader_acquireClassLock
|
||||
(Thread* t, object, uintptr_t*)
|
||||
@ -195,8 +74,6 @@ Avian_avian_SystemClassLoader_defineVMClass
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object loader = reinterpret_cast<object>(arguments[0]);
|
||||
PROTECT(t, loader);
|
||||
|
||||
object b = reinterpret_cast<object>(arguments[1]);
|
||||
int offset = arguments[2];
|
||||
int length = arguments[3];
|
||||
@ -204,20 +81,9 @@ Avian_avian_SystemClassLoader_defineVMClass
|
||||
uint8_t* buffer = static_cast<uint8_t*>
|
||||
(t->m->heap->allocate(length));
|
||||
memcpy(buffer, &byteArrayBody(t, b, offset), length);
|
||||
object c = parseClass(t, loader, buffer, length);
|
||||
object c = defineClass(t, loader, buffer, length);
|
||||
t->m->heap->free(buffer, length);
|
||||
|
||||
if (c) {
|
||||
PROTECT(t, c);
|
||||
if (getClassLoaderMap(t, loader) == 0) {
|
||||
object map = makeHashMap(t, 0, 0);
|
||||
set(t, loader, ClassLoaderMap, map);
|
||||
}
|
||||
|
||||
hashMapInsert(t, getClassLoaderMap(t, loader), className(t, c), c,
|
||||
byteArrayHash);
|
||||
}
|
||||
|
||||
return reinterpret_cast<int64_t>(c);
|
||||
}
|
||||
|
||||
@ -260,62 +126,21 @@ Avian_avian_SystemClassLoader_resourceExists
|
||||
stringChars(t, name, RUNTIME_ARRAY_BODY(n));
|
||||
return t->m->finder->exists(RUNTIME_ARRAY_BODY(n));
|
||||
} else {
|
||||
t->exception = makeNullPointerException(t);
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_io_ObjectInputStream_makeInstance
|
||||
Avian_avian_SystemClassLoader_primitiveClass
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object c = reinterpret_cast<object>(arguments[0]);
|
||||
|
||||
return reinterpret_cast<int64_t>(make(t, c));
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Class_primitiveClass
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
char name = arguments[0];
|
||||
|
||||
switch (name) {
|
||||
case 'B':
|
||||
return reinterpret_cast<int64_t>
|
||||
(arrayBody(t, t->m->types, Machine::JbyteType));
|
||||
case 'C':
|
||||
return reinterpret_cast<int64_t>
|
||||
(arrayBody(t, t->m->types, Machine::JcharType));
|
||||
case 'D':
|
||||
return reinterpret_cast<int64_t>
|
||||
(arrayBody(t, t->m->types, Machine::JdoubleType));
|
||||
case 'F':
|
||||
return reinterpret_cast<int64_t>
|
||||
(arrayBody(t, t->m->types, Machine::JfloatType));
|
||||
case 'I':
|
||||
return reinterpret_cast<int64_t>
|
||||
(arrayBody(t, t->m->types, Machine::JintType));
|
||||
case 'J':
|
||||
return reinterpret_cast<int64_t>
|
||||
(arrayBody(t, t->m->types, Machine::JlongType));
|
||||
case 'S':
|
||||
return reinterpret_cast<int64_t>
|
||||
(arrayBody(t, t->m->types, Machine::JshortType));
|
||||
case 'V':
|
||||
return reinterpret_cast<int64_t>
|
||||
(arrayBody(t, t->m->types, Machine::JvoidType));
|
||||
case 'Z':
|
||||
return reinterpret_cast<int64_t>
|
||||
(arrayBody(t, t->m->types, Machine::JbooleanType));
|
||||
default:
|
||||
t->exception = makeIllegalArgumentException(t);
|
||||
return 0;
|
||||
}
|
||||
return reinterpret_cast<int64_t>(primitiveClass(t, arguments[0]));
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Avian_java_lang_Class_initialize
|
||||
Avian_avian_SystemClassLoader_initialize
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object this_ = reinterpret_cast<object>(arguments[0]);
|
||||
@ -324,7 +149,7 @@ Avian_java_lang_Class_initialize
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Class_isAssignableFrom
|
||||
Avian_avian_SystemClassLoader_isAssignableFrom
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object this_ = reinterpret_cast<object>(arguments[0]);
|
||||
@ -333,392 +158,12 @@ Avian_java_lang_Class_isAssignableFrom
|
||||
if (LIKELY(that)) {
|
||||
return vm::isAssignableFrom(t, this_, that);
|
||||
} else {
|
||||
t->exception = makeNullPointerException(t);
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_reflect_Field_getPrimitive
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object instance = reinterpret_cast<object>(arguments[0]);
|
||||
int code = arguments[1];
|
||||
int offset = arguments[2];
|
||||
|
||||
switch (code) {
|
||||
case ByteField:
|
||||
return cast<int8_t>(instance, offset);
|
||||
case BooleanField:
|
||||
return cast<uint8_t>(instance, offset);
|
||||
case CharField:
|
||||
return cast<uint16_t>(instance, offset);
|
||||
case ShortField:
|
||||
return cast<int16_t>(instance, offset);
|
||||
case IntField:
|
||||
return cast<int32_t>(instance, offset);
|
||||
case LongField:
|
||||
return cast<int64_t>(instance, offset);
|
||||
case FloatField:
|
||||
return cast<uint32_t>(instance, offset);
|
||||
case DoubleField:
|
||||
return cast<uint64_t>(instance, offset);
|
||||
default:
|
||||
abort(t);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_reflect_Field_getObject
|
||||
(Thread*, object, uintptr_t* arguments)
|
||||
{
|
||||
object instance = reinterpret_cast<object>(arguments[0]);
|
||||
int offset = arguments[1];
|
||||
|
||||
return reinterpret_cast<int64_t>(cast<object>(instance, offset));
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Avian_java_lang_reflect_Field_setPrimitive
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object instance = reinterpret_cast<object>(arguments[0]);
|
||||
int code = arguments[1];
|
||||
int offset = arguments[2];
|
||||
int64_t value; memcpy(&value, arguments + 3, 8);
|
||||
|
||||
switch (code) {
|
||||
case ByteField:
|
||||
cast<int8_t>(instance, offset) = static_cast<int8_t>(value);
|
||||
break;
|
||||
case BooleanField:
|
||||
cast<uint8_t>(instance, offset) = static_cast<uint8_t>(value);
|
||||
break;
|
||||
case CharField:
|
||||
cast<uint16_t>(instance, offset) = static_cast<uint16_t>(value);
|
||||
break;
|
||||
case ShortField:
|
||||
cast<int16_t>(instance, offset) = static_cast<int16_t>(value);
|
||||
break;
|
||||
case IntField:
|
||||
cast<int32_t>(instance, offset) = static_cast<int32_t>(value);
|
||||
break;
|
||||
case LongField:
|
||||
cast<int64_t>(instance, offset) = static_cast<int64_t>(value);
|
||||
break;
|
||||
case FloatField:
|
||||
cast<uint32_t>(instance, offset) = static_cast<uint32_t>(value);
|
||||
break;
|
||||
case DoubleField:
|
||||
cast<uint64_t>(instance, offset) = static_cast<uint64_t>(value);
|
||||
break;
|
||||
default:
|
||||
abort(t);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Avian_java_lang_reflect_Field_setObject
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object instance = reinterpret_cast<object>(arguments[0]);
|
||||
int offset = arguments[1];
|
||||
object value = reinterpret_cast<object>(arguments[2]);
|
||||
|
||||
set(t, instance, offset, value);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_reflect_Constructor_make
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object c = reinterpret_cast<object>(arguments[0]);
|
||||
|
||||
return reinterpret_cast<int64_t>(make(t, c));
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_reflect_Method_getCaller
|
||||
(Thread* t, object, uintptr_t*)
|
||||
{
|
||||
class Visitor: public Processor::StackVisitor {
|
||||
public:
|
||||
Visitor(Thread* t): t(t), method(0), count(0) { }
|
||||
|
||||
virtual bool visit(Processor::StackWalker* walker) {
|
||||
if (count == 2) {
|
||||
method = walker->method();
|
||||
return false;
|
||||
} else {
|
||||
++ count;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Thread* t;
|
||||
object method;
|
||||
unsigned count;
|
||||
} v(t);
|
||||
|
||||
t->m->processor->walkStack(t, &v);
|
||||
|
||||
return reinterpret_cast<int64_t>(v.method);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_reflect_Method_invoke
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object method = reinterpret_cast<object>(arguments[0]);
|
||||
object instance = reinterpret_cast<object>(arguments[1]);
|
||||
object args = reinterpret_cast<object>(arguments[2]);
|
||||
|
||||
object v = t->m->processor->invokeArray(t, method, instance, args);
|
||||
if (t->exception) {
|
||||
t->exception = makeInvocationTargetException(t, t->exception);
|
||||
}
|
||||
return reinterpret_cast<int64_t>(v);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_reflect_Array_getLength
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object array = reinterpret_cast<object>(arguments[0]);
|
||||
|
||||
if (LIKELY(array)) {
|
||||
unsigned elementSize = classArrayElementSize(t, objectClass(t, array));
|
||||
|
||||
if (LIKELY(elementSize)) {
|
||||
return cast<uintptr_t>(array, BytesPerWord);
|
||||
} else {
|
||||
t->exception = makeIllegalArgumentException(t);
|
||||
}
|
||||
} else {
|
||||
t->exception = makeNullPointerException(t);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_reflect_Array_makeObjectArray
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object elementType = reinterpret_cast<object>(arguments[0]);
|
||||
int length = arguments[1];
|
||||
|
||||
return reinterpret_cast<int64_t>
|
||||
(makeObjectArray(t, classLoader(t, elementType), elementType, length));
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Float_floatToRawIntBits
|
||||
(Thread*, object, uintptr_t* arguments)
|
||||
{
|
||||
return static_cast<int32_t>(*arguments);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Float_intBitsToFloat
|
||||
(Thread*, object, uintptr_t* arguments)
|
||||
{
|
||||
return static_cast<int32_t>(*arguments);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Double_doubleToRawLongBits
|
||||
(Thread*, object, uintptr_t* arguments)
|
||||
{
|
||||
int64_t v; memcpy(&v, arguments, 8);
|
||||
return v;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Double_longBitsToDouble
|
||||
(Thread*, object, uintptr_t* arguments)
|
||||
{
|
||||
int64_t v; memcpy(&v, arguments, 8);
|
||||
return v;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_String_intern
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object this_ = reinterpret_cast<object>(arguments[0]);
|
||||
|
||||
return reinterpret_cast<int64_t>(intern(t, this_));
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_System_getVMProperty
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object name = reinterpret_cast<object>(arguments[0]);
|
||||
object found = reinterpret_cast<object>(arguments[1]);
|
||||
PROTECT(t, found);
|
||||
|
||||
unsigned length = stringLength(t, name);
|
||||
RUNTIME_ARRAY(char, n, length + 1);
|
||||
stringChars(t, name, RUNTIME_ARRAY_BODY(n));
|
||||
|
||||
int64_t r = 0;
|
||||
if (::strcmp(RUNTIME_ARRAY_BODY(n), "java.lang.classpath") == 0) {
|
||||
r = reinterpret_cast<int64_t>(makeString(t, "%s", t->m->finder->path()));
|
||||
} else if (::strcmp(RUNTIME_ARRAY_BODY(n), "avian.version") == 0) {
|
||||
r = reinterpret_cast<int64_t>(makeString(t, AVIAN_VERSION));
|
||||
} else if (::strcmp(RUNTIME_ARRAY_BODY(n), "file.encoding") == 0) {
|
||||
r = reinterpret_cast<int64_t>(makeString(t, "ASCII"));
|
||||
} else {
|
||||
const char* v = findProperty(t, RUNTIME_ARRAY_BODY(n));
|
||||
if (v) {
|
||||
r = reinterpret_cast<int64_t>(makeString(t, v));
|
||||
}
|
||||
}
|
||||
|
||||
if (r) {
|
||||
booleanArrayBody(t, found, 0) = true;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Avian_java_lang_System_arraycopy
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object src = reinterpret_cast<object>(arguments[0]);
|
||||
int32_t srcOffset = arguments[1];
|
||||
object dst = reinterpret_cast<object>(arguments[2]);
|
||||
int32_t dstOffset = arguments[3];
|
||||
int32_t length = arguments[4];
|
||||
|
||||
if (LIKELY(src and dst)) {
|
||||
if (LIKELY(compatibleArrayTypes
|
||||
(t, objectClass(t, src), objectClass(t, dst))))
|
||||
{
|
||||
unsigned elementSize = classArrayElementSize(t, objectClass(t, src));
|
||||
|
||||
if (LIKELY(elementSize)) {
|
||||
intptr_t sl = cast<uintptr_t>(src, BytesPerWord);
|
||||
intptr_t dl = cast<uintptr_t>(dst, BytesPerWord);
|
||||
if (LIKELY(length > 0)) {
|
||||
if (LIKELY(srcOffset >= 0 and srcOffset + length <= sl and
|
||||
dstOffset >= 0 and dstOffset + length <= dl))
|
||||
{
|
||||
uint8_t* sbody = &cast<uint8_t>(src, ArrayBody);
|
||||
uint8_t* dbody = &cast<uint8_t>(dst, ArrayBody);
|
||||
if (src == dst) {
|
||||
memmove(dbody + (dstOffset * elementSize),
|
||||
sbody + (srcOffset * elementSize),
|
||||
length * elementSize);
|
||||
} else {
|
||||
memcpy(dbody + (dstOffset * elementSize),
|
||||
sbody + (srcOffset * elementSize),
|
||||
length * elementSize);
|
||||
}
|
||||
|
||||
if (classObjectMask(t, objectClass(t, dst))) {
|
||||
mark(t, dst, ArrayBody + (dstOffset * BytesPerWord), length);
|
||||
}
|
||||
|
||||
return;
|
||||
} else {
|
||||
t->exception = makeIndexOutOfBoundsException(t);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
t->exception = makeNullPointerException(t);
|
||||
return;
|
||||
}
|
||||
|
||||
t->exception = makeArrayStoreException(t);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_System_identityHashCode
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object o = reinterpret_cast<object>(arguments[0]);
|
||||
|
||||
if (LIKELY(o)) {
|
||||
return objectHash(t, o);
|
||||
} else {
|
||||
t->exception = makeNullPointerException(t);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Avian_java_lang_Runtime_load
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object name = reinterpret_cast<object>(arguments[0]);
|
||||
bool mapName = arguments[1];
|
||||
|
||||
unsigned length = stringLength(t, name);
|
||||
RUNTIME_ARRAY(char, n, length + 1);
|
||||
stringChars(t, name, RUNTIME_ARRAY_BODY(n));
|
||||
|
||||
ACQUIRE(t, t->m->classLock);
|
||||
|
||||
const char* builtins = findProperty(t, "avian.builtins");
|
||||
if (mapName and builtins) {
|
||||
const char* s = builtins;
|
||||
while (*s) {
|
||||
if (::strncmp(s, RUNTIME_ARRAY_BODY(n), length) == 0
|
||||
and (s[length] == ',' or s[length] == 0))
|
||||
{
|
||||
// library is built in to this executable
|
||||
if (not t->m->triedBuiltinOnLoad) {
|
||||
t->m->triedBuiltinOnLoad = true;
|
||||
runOnLoadIfFound(t, t->m->libraries);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
while (*s and *s != ',') ++ s;
|
||||
if (*s) ++ s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
System::Library* last = t->m->libraries;
|
||||
for (System::Library* lib = t->m->libraries; lib; lib = lib->next()) {
|
||||
if (lib->name()
|
||||
and ::strcmp(lib->name(), RUNTIME_ARRAY_BODY(n)) == 0
|
||||
and lib->mapName() == mapName)
|
||||
{
|
||||
// already loaded
|
||||
return;
|
||||
}
|
||||
last = lib;
|
||||
}
|
||||
|
||||
System::Library* lib;
|
||||
if (LIKELY(t->m->system->success
|
||||
(t->m->system->load(&lib, RUNTIME_ARRAY_BODY(n), mapName))))
|
||||
{
|
||||
last->setNext(lib);
|
||||
runOnLoadIfFound(t, lib);
|
||||
} else {
|
||||
object message = makeString
|
||||
(t, "library not found: %s", RUNTIME_ARRAY_BODY(n));
|
||||
t->exception = makeUnsatisfiedLinkError(t, message);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Avian_java_lang_Runtime_gc
|
||||
(Thread* t, object, uintptr_t*)
|
||||
{
|
||||
collect(t, Heap::MajorCollection);
|
||||
}
|
||||
|
||||
#ifdef AVIAN_HEAPDUMP
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
@ -753,193 +198,6 @@ Avian_java_lang_Runtime_exit
|
||||
t->m->system->exit(arguments[1]);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Runtime_freeMemory
|
||||
(Thread*, object, uintptr_t*)
|
||||
{
|
||||
// todo
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Runtime_totalMemory
|
||||
(Thread*, object, uintptr_t*)
|
||||
{
|
||||
// todo
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Avian_java_lang_Runtime_addShutdownHook
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object hook = reinterpret_cast<object>(arguments[1]);
|
||||
PROTECT(t, hook);
|
||||
|
||||
ACQUIRE(t, t->m->shutdownLock);
|
||||
|
||||
t->m->shutdownHooks = makePair(t, hook, t->m->shutdownHooks);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Throwable_trace
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
int32_t skipCount = arguments[0];
|
||||
|
||||
class Visitor: public Processor::StackVisitor {
|
||||
public:
|
||||
Visitor(Thread* t, int skipCount):
|
||||
t(t), trace(0), skipCount(skipCount)
|
||||
{ }
|
||||
|
||||
virtual bool visit(Processor::StackWalker* walker) {
|
||||
if (skipCount == 0) {
|
||||
object method = walker->method();
|
||||
if (isAssignableFrom
|
||||
(t, arrayBody(t, t->m->types, Machine::ThrowableType),
|
||||
methodClass(t, method))
|
||||
and vm::strcmp(reinterpret_cast<const int8_t*>("<init>"),
|
||||
&byteArrayBody(t, methodName(t, method), 0))
|
||||
== 0)
|
||||
{
|
||||
return true;
|
||||
} else {
|
||||
trace = makeTrace(t, walker);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
-- skipCount;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Thread* t;
|
||||
object trace;
|
||||
unsigned skipCount;
|
||||
} v(t, skipCount);
|
||||
|
||||
t->m->processor->walkStack(t, &v);
|
||||
|
||||
if (v.trace == 0) v.trace = makeArray(t, 0);
|
||||
|
||||
return reinterpret_cast<int64_t>(v.trace);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Throwable_resolveTrace
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object trace = reinterpret_cast<object>(*arguments);
|
||||
PROTECT(t, trace);
|
||||
|
||||
unsigned length = arrayLength(t, trace);
|
||||
object elementType = arrayBody
|
||||
(t, t->m->types, Machine::StackTraceElementType);
|
||||
object array = makeObjectArray
|
||||
(t, classLoader(t, elementType), elementType, length);
|
||||
PROTECT(t, array);
|
||||
|
||||
object e = 0;
|
||||
PROTECT(t, e);
|
||||
|
||||
object class_ = 0;
|
||||
PROTECT(t, class_);
|
||||
|
||||
object method = 0;
|
||||
PROTECT(t, method);
|
||||
|
||||
for (unsigned i = 0; i < length; ++i) {
|
||||
e = arrayBody(t, trace, i);
|
||||
|
||||
class_ = className(t, methodClass(t, traceElementMethod(t, e)));
|
||||
class_ = makeString(t, class_, 0, byteArrayLength(t, class_) - 1, 0);
|
||||
|
||||
method = methodName(t, traceElementMethod(t, e));
|
||||
method = makeString(t, method, 0, byteArrayLength(t, method) - 1, 0);
|
||||
|
||||
unsigned line = t->m->processor->lineNumber
|
||||
(t, traceElementMethod(t, e), traceElementIp(t, e));
|
||||
|
||||
object file = classSourceFile(t, methodClass(t, traceElementMethod(t, e)));
|
||||
file = file ? makeString(t, file, 0, byteArrayLength(t, file) - 1, 0) : 0;
|
||||
|
||||
object ste = makeStackTraceElement(t, class_, method, file, line);
|
||||
set(t, array, ArrayBody + (i * BytesPerWord), ste);
|
||||
}
|
||||
|
||||
return reinterpret_cast<int64_t>(array);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Thread_currentThread
|
||||
(Thread* t, object, uintptr_t*)
|
||||
{
|
||||
return reinterpret_cast<int64_t>(t->javaThread);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Thread_doStart
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
return reinterpret_cast<int64_t>
|
||||
(startThread(t, reinterpret_cast<object>(*arguments)));
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Avian_java_lang_Thread_interrupt
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
int64_t peer; memcpy(&peer, arguments, 8);
|
||||
|
||||
interrupt(t, reinterpret_cast<Thread*>(peer));
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Thread_getStackTrace
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
int64_t peer; memcpy(&peer, arguments, 8);
|
||||
|
||||
if (reinterpret_cast<Thread*>(peer) == t) {
|
||||
return reinterpret_cast<int64_t>(makeTrace(t));
|
||||
} else {
|
||||
return reinterpret_cast<int64_t>
|
||||
(t->m->processor->getStackTrace(t, reinterpret_cast<Thread*>(peer)));
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Thread_activeCount
|
||||
(Thread* t, object, uintptr_t*)
|
||||
{
|
||||
return t->m->liveCount;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Thread_enumerate
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object array = reinterpret_cast<object>(*arguments);
|
||||
|
||||
ACQUIRE_RAW(t, t->m->stateLock);
|
||||
|
||||
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 void JNICALL
|
||||
Avian_java_lang_Thread_setDaemon
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object thread = reinterpret_cast<object>(arguments[0]);
|
||||
bool daemon = arguments[1] != 0;
|
||||
|
||||
setDaemon(t, thread, daemon);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_avian_resource_Handler_00024ResourceInputStream_getContentLength
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
@ -973,7 +231,8 @@ Avian_avian_resource_Handler_00024ResourceInputStream_open
|
||||
return reinterpret_cast<int64_t>
|
||||
(t->m->finder->find(RUNTIME_ARRAY_BODY(p)));
|
||||
} else {
|
||||
t->exception = makeNullPointerException(t);
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
601
src/classpath-avian.cpp
Normal file
601
src/classpath-avian.cpp
Normal file
@ -0,0 +1,601 @@
|
||||
/* Copyright (c) 2010, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
#include "machine.h"
|
||||
#include "classpath-common.h"
|
||||
|
||||
using namespace vm;
|
||||
|
||||
namespace {
|
||||
|
||||
namespace local {
|
||||
|
||||
class MyClasspath : public Classpath {
|
||||
public:
|
||||
MyClasspath(Allocator* allocator):
|
||||
allocator(allocator)
|
||||
{ }
|
||||
|
||||
virtual object
|
||||
makeJclass(Thread* t, object class_)
|
||||
{
|
||||
return vm::makeJclass(t, class_);
|
||||
}
|
||||
|
||||
virtual object
|
||||
makeString(Thread* t, object array, int32_t offset, int32_t length)
|
||||
{
|
||||
return vm::makeString(t, array, offset, length, 0);
|
||||
}
|
||||
|
||||
virtual object
|
||||
makeThread(Thread* t, Thread* parent)
|
||||
{
|
||||
object group;
|
||||
if (parent) {
|
||||
group = threadGroup(t, parent->javaThread);
|
||||
} else {
|
||||
group = makeThreadGroup(t, 0, 0, 0);
|
||||
}
|
||||
|
||||
const unsigned NewState = 0;
|
||||
const unsigned NormalPriority = 5;
|
||||
|
||||
return vm::makeThread
|
||||
(t, 0, 0, 0, NewState, NormalPriority, 0, 0, 0, t->m->loader, 0, 0,
|
||||
group);
|
||||
}
|
||||
|
||||
virtual void
|
||||
runThread(Thread* t)
|
||||
{
|
||||
object method = resolveMethod
|
||||
(t, t->m->loader, "java/lang/Thread", "run", "(Ljava/lang/Thread;)V");
|
||||
|
||||
if (t->exception == 0) {
|
||||
t->m->processor->invoke(t, method, 0, t->javaThread);
|
||||
}
|
||||
}
|
||||
|
||||
virtual object
|
||||
makeThrowable
|
||||
(Thread* t, Machine::Type type, object message, object trace, object cause)
|
||||
{
|
||||
PROTECT(t, message);
|
||||
PROTECT(t, cause);
|
||||
|
||||
if (trace == 0) {
|
||||
trace = makeTrace(t);
|
||||
}
|
||||
|
||||
object result = make(t, arrayBody(t, t->m->types, type));
|
||||
|
||||
set(t, result, ThrowableMessage, message);
|
||||
set(t, result, ThrowableTrace, trace);
|
||||
set(t, result, ThrowableCause, cause);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual void
|
||||
dispose()
|
||||
{
|
||||
allocator->free(this, sizeof(*this));
|
||||
}
|
||||
|
||||
Allocator* allocator;
|
||||
};
|
||||
|
||||
void
|
||||
enumerateThreads(Thread* t, Thread* x, object array, unsigned* index,
|
||||
unsigned limit)
|
||||
{
|
||||
if (*index < limit) {
|
||||
set(t, array, ArrayBody + (*index * BytesPerWord), x->javaThread);
|
||||
++ (*index);
|
||||
|
||||
if (x->peer) enumerateThreads(t, x->peer, array, index, limit);
|
||||
|
||||
if (x->child) enumerateThreads(t, x->child, array, index, limit);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace local
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace vm {
|
||||
|
||||
Classpath*
|
||||
makeClasspath(System*, Allocator* allocator)
|
||||
{
|
||||
return new (allocator->allocate(sizeof(local::MyClasspath)))
|
||||
local::MyClasspath(allocator);
|
||||
}
|
||||
|
||||
} // namespace vm
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Object_toString
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object this_ = reinterpret_cast<object>(arguments[0]);
|
||||
|
||||
unsigned hash = objectHash(t, this_);
|
||||
object s = makeString
|
||||
(t, "%s@0x%x",
|
||||
&byteArrayBody(t, className(t, objectClass(t, this_)), 0),
|
||||
hash);
|
||||
|
||||
return reinterpret_cast<int64_t>(s);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Object_getVMClass
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object o = reinterpret_cast<object>(arguments[0]);
|
||||
|
||||
return reinterpret_cast<int64_t>(objectClass(t, o));
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Avian_java_lang_Object_wait
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object this_ = reinterpret_cast<object>(arguments[0]);
|
||||
int64_t milliseconds; memcpy(&milliseconds, arguments + 1, 8);
|
||||
|
||||
vm::wait(t, this_, milliseconds);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Avian_java_lang_Object_notify
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object this_ = reinterpret_cast<object>(arguments[0]);
|
||||
|
||||
notify(t, this_);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Avian_java_lang_Object_notifyAll
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object this_ = reinterpret_cast<object>(arguments[0]);
|
||||
|
||||
notifyAll(t, this_);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Object_hashCode
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object this_ = reinterpret_cast<object>(arguments[0]);
|
||||
|
||||
return objectHash(t, this_);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Object_clone
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
return reinterpret_cast<int64_t>
|
||||
(clone(t, reinterpret_cast<object>(arguments[0])));
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_io_ObjectInputStream_makeInstance
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object c = reinterpret_cast<object>(arguments[0]);
|
||||
|
||||
return reinterpret_cast<int64_t>(make(t, c));
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_reflect_Field_getPrimitive
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object instance = reinterpret_cast<object>(arguments[0]);
|
||||
int code = arguments[1];
|
||||
int offset = arguments[2];
|
||||
|
||||
switch (code) {
|
||||
case ByteField:
|
||||
return cast<int8_t>(instance, offset);
|
||||
case BooleanField:
|
||||
return cast<uint8_t>(instance, offset);
|
||||
case CharField:
|
||||
return cast<uint16_t>(instance, offset);
|
||||
case ShortField:
|
||||
return cast<int16_t>(instance, offset);
|
||||
case IntField:
|
||||
return cast<int32_t>(instance, offset);
|
||||
case LongField:
|
||||
return cast<int64_t>(instance, offset);
|
||||
case FloatField:
|
||||
return cast<uint32_t>(instance, offset);
|
||||
case DoubleField:
|
||||
return cast<uint64_t>(instance, offset);
|
||||
default:
|
||||
abort(t);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_reflect_Field_getObject
|
||||
(Thread*, object, uintptr_t* arguments)
|
||||
{
|
||||
object instance = reinterpret_cast<object>(arguments[0]);
|
||||
int offset = arguments[1];
|
||||
|
||||
return reinterpret_cast<int64_t>(cast<object>(instance, offset));
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Avian_java_lang_reflect_Field_setPrimitive
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object instance = reinterpret_cast<object>(arguments[0]);
|
||||
int code = arguments[1];
|
||||
int offset = arguments[2];
|
||||
int64_t value; memcpy(&value, arguments + 3, 8);
|
||||
|
||||
switch (code) {
|
||||
case ByteField:
|
||||
cast<int8_t>(instance, offset) = static_cast<int8_t>(value);
|
||||
break;
|
||||
case BooleanField:
|
||||
cast<uint8_t>(instance, offset) = static_cast<uint8_t>(value);
|
||||
break;
|
||||
case CharField:
|
||||
cast<uint16_t>(instance, offset) = static_cast<uint16_t>(value);
|
||||
break;
|
||||
case ShortField:
|
||||
cast<int16_t>(instance, offset) = static_cast<int16_t>(value);
|
||||
break;
|
||||
case IntField:
|
||||
cast<int32_t>(instance, offset) = static_cast<int32_t>(value);
|
||||
break;
|
||||
case LongField:
|
||||
cast<int64_t>(instance, offset) = static_cast<int64_t>(value);
|
||||
break;
|
||||
case FloatField:
|
||||
cast<uint32_t>(instance, offset) = static_cast<uint32_t>(value);
|
||||
break;
|
||||
case DoubleField:
|
||||
cast<uint64_t>(instance, offset) = static_cast<uint64_t>(value);
|
||||
break;
|
||||
default:
|
||||
abort(t);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Avian_java_lang_reflect_Field_setObject
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object instance = reinterpret_cast<object>(arguments[0]);
|
||||
int offset = arguments[1];
|
||||
object value = reinterpret_cast<object>(arguments[2]);
|
||||
|
||||
set(t, instance, offset, value);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_reflect_Constructor_make
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object c = reinterpret_cast<object>(arguments[0]);
|
||||
|
||||
return reinterpret_cast<int64_t>(make(t, c));
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_reflect_Method_getCaller
|
||||
(Thread* t, object, uintptr_t*)
|
||||
{
|
||||
return reinterpret_cast<int64_t>(getCaller(t, 2));
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_reflect_Method_invoke
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object method = reinterpret_cast<object>(arguments[0]);
|
||||
object instance = reinterpret_cast<object>(arguments[1]);
|
||||
object args = reinterpret_cast<object>(arguments[2]);
|
||||
|
||||
object v = t->m->processor->invokeArray(t, method, instance, args);
|
||||
if (t->exception) {
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::InvocationTargetExceptionType, 0, 0, t->exception);
|
||||
}
|
||||
return reinterpret_cast<int64_t>(v);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_reflect_Array_getLength
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object array = reinterpret_cast<object>(arguments[0]);
|
||||
|
||||
if (LIKELY(array)) {
|
||||
unsigned elementSize = classArrayElementSize(t, objectClass(t, array));
|
||||
|
||||
if (LIKELY(elementSize)) {
|
||||
return cast<uintptr_t>(array, BytesPerWord);
|
||||
} else {
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::IllegalArgumentExceptionType);
|
||||
}
|
||||
} else {
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_reflect_Array_makeObjectArray
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object elementType = reinterpret_cast<object>(arguments[0]);
|
||||
int length = arguments[1];
|
||||
|
||||
return reinterpret_cast<int64_t>
|
||||
(makeObjectArray(t, classLoader(t, elementType), elementType, length));
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Float_floatToRawIntBits
|
||||
(Thread*, object, uintptr_t* arguments)
|
||||
{
|
||||
return static_cast<int32_t>(*arguments);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Float_intBitsToFloat
|
||||
(Thread*, object, uintptr_t* arguments)
|
||||
{
|
||||
return static_cast<int32_t>(*arguments);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Double_doubleToRawLongBits
|
||||
(Thread*, object, uintptr_t* arguments)
|
||||
{
|
||||
int64_t v; memcpy(&v, arguments, 8);
|
||||
return v;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Double_longBitsToDouble
|
||||
(Thread*, object, uintptr_t* arguments)
|
||||
{
|
||||
int64_t v; memcpy(&v, arguments, 8);
|
||||
return v;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_String_intern
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object this_ = reinterpret_cast<object>(arguments[0]);
|
||||
|
||||
return reinterpret_cast<int64_t>(intern(t, this_));
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_System_getVMProperty
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object name = reinterpret_cast<object>(arguments[0]);
|
||||
object found = reinterpret_cast<object>(arguments[1]);
|
||||
PROTECT(t, found);
|
||||
|
||||
unsigned length = stringLength(t, name);
|
||||
RUNTIME_ARRAY(char, n, length + 1);
|
||||
stringChars(t, name, RUNTIME_ARRAY_BODY(n));
|
||||
|
||||
int64_t r = 0;
|
||||
if (::strcmp(RUNTIME_ARRAY_BODY(n), "java.lang.classpath") == 0) {
|
||||
r = reinterpret_cast<int64_t>(makeString(t, "%s", t->m->finder->path()));
|
||||
} else if (::strcmp(RUNTIME_ARRAY_BODY(n), "avian.version") == 0) {
|
||||
r = reinterpret_cast<int64_t>(makeString(t, AVIAN_VERSION));
|
||||
} else if (::strcmp(RUNTIME_ARRAY_BODY(n), "file.encoding") == 0) {
|
||||
r = reinterpret_cast<int64_t>(makeString(t, "ASCII"));
|
||||
} else {
|
||||
const char* v = findProperty(t, RUNTIME_ARRAY_BODY(n));
|
||||
if (v) {
|
||||
r = reinterpret_cast<int64_t>(makeString(t, v));
|
||||
}
|
||||
}
|
||||
|
||||
if (r) {
|
||||
booleanArrayBody(t, found, 0) = true;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Avian_java_lang_System_arraycopy
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
arrayCopy(t, reinterpret_cast<object>(arguments[0]),
|
||||
arguments[1],
|
||||
reinterpret_cast<object>(arguments[2]),
|
||||
arguments[3],
|
||||
arguments[4]);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_System_identityHashCode
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object o = reinterpret_cast<object>(arguments[0]);
|
||||
|
||||
if (LIKELY(o)) {
|
||||
return objectHash(t, o);
|
||||
} else {
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Avian_java_lang_Runtime_load
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object name = reinterpret_cast<object>(arguments[0]);
|
||||
bool mapName = arguments[1];
|
||||
|
||||
unsigned length = stringLength(t, name);
|
||||
RUNTIME_ARRAY(char, n, length + 1);
|
||||
stringChars(t, name, RUNTIME_ARRAY_BODY(n));
|
||||
|
||||
loadLibrary(t, RUNTIME_ARRAY_BODY(n), mapName, true);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Avian_java_lang_Runtime_gc
|
||||
(Thread* t, object, uintptr_t*)
|
||||
{
|
||||
collect(t, Heap::MajorCollection);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Runtime_freeMemory
|
||||
(Thread*, object, uintptr_t*)
|
||||
{
|
||||
// todo
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Runtime_totalMemory
|
||||
(Thread*, object, uintptr_t*)
|
||||
{
|
||||
// todo
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Avian_java_lang_Runtime_addShutdownHook
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object hook = reinterpret_cast<object>(arguments[1]);
|
||||
PROTECT(t, hook);
|
||||
|
||||
ACQUIRE(t, t->m->shutdownLock);
|
||||
|
||||
t->m->shutdownHooks = makePair(t, hook, t->m->shutdownHooks);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Throwable_trace
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
return reinterpret_cast<int64_t>(getTrace(t, arguments[0]));
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Throwable_resolveTrace
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object trace = reinterpret_cast<object>(*arguments);
|
||||
PROTECT(t, trace);
|
||||
|
||||
unsigned length = arrayLength(t, trace);
|
||||
object elementType = arrayBody
|
||||
(t, t->m->types, Machine::StackTraceElementType);
|
||||
object array = makeObjectArray
|
||||
(t, classLoader(t, elementType), elementType, length);
|
||||
PROTECT(t, array);
|
||||
|
||||
for (unsigned i = 0; i < length; ++i) {
|
||||
object ste = makeStackTraceElement(t, arrayBody(t, trace, i));
|
||||
set(t, array, ArrayBody + (i * BytesPerWord), ste);
|
||||
}
|
||||
|
||||
return reinterpret_cast<int64_t>(array);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Thread_currentThread
|
||||
(Thread* t, object, uintptr_t*)
|
||||
{
|
||||
return reinterpret_cast<int64_t>(t->javaThread);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Thread_doStart
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
return reinterpret_cast<int64_t>
|
||||
(startThread(t, reinterpret_cast<object>(*arguments)));
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Avian_java_lang_Thread_interrupt
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
int64_t peer; memcpy(&peer, arguments, 8);
|
||||
|
||||
interrupt(t, reinterpret_cast<Thread*>(peer));
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Thread_getStackTrace
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
int64_t peer; memcpy(&peer, arguments, 8);
|
||||
|
||||
if (reinterpret_cast<Thread*>(peer) == t) {
|
||||
return reinterpret_cast<int64_t>(makeTrace(t));
|
||||
} else {
|
||||
return reinterpret_cast<int64_t>
|
||||
(t->m->processor->getStackTrace(t, reinterpret_cast<Thread*>(peer)));
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Thread_activeCount
|
||||
(Thread* t, object, uintptr_t*)
|
||||
{
|
||||
return t->m->liveCount;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Thread_enumerate
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object array = reinterpret_cast<object>(*arguments);
|
||||
|
||||
ACQUIRE_RAW(t, t->m->stateLock);
|
||||
|
||||
unsigned count = min(t->m->liveCount, objectArrayLength(t, array));
|
||||
unsigned index = 0;
|
||||
local::enumerateThreads(t, t->m->rootThread, array, &index, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Avian_java_lang_Thread_setDaemon
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object thread = reinterpret_cast<object>(arguments[0]);
|
||||
bool daemon = arguments[1] != 0;
|
||||
|
||||
setDaemon(t, thread, daemon);
|
||||
}
|
271
src/classpath-common.h
Normal file
271
src/classpath-common.h
Normal file
@ -0,0 +1,271 @@
|
||||
/* Copyright (c) 2010, 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. */
|
||||
|
||||
#ifndef CLASSPATH_COMMON_H
|
||||
#define CLASSPATH_COMMON_H
|
||||
|
||||
namespace vm {
|
||||
|
||||
inline object
|
||||
getCaller(Thread* t, unsigned target)
|
||||
{
|
||||
class Visitor: public Processor::StackVisitor {
|
||||
public:
|
||||
Visitor(Thread* t, unsigned target):
|
||||
t(t), method(0), count(0), target(target)
|
||||
{ }
|
||||
|
||||
virtual bool visit(Processor::StackWalker* walker) {
|
||||
if (count == target) {
|
||||
method = walker->method();
|
||||
return false;
|
||||
} else {
|
||||
++ count;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Thread* t;
|
||||
object method;
|
||||
unsigned count;
|
||||
unsigned target;
|
||||
} v(t, target);
|
||||
|
||||
t->m->processor->walkStack(t, &v);
|
||||
|
||||
return v.method;
|
||||
}
|
||||
|
||||
inline object
|
||||
getTrace(Thread* t, unsigned skipCount)
|
||||
{
|
||||
class Visitor: public Processor::StackVisitor {
|
||||
public:
|
||||
Visitor(Thread* t, int skipCount):
|
||||
t(t), trace(0), skipCount(skipCount)
|
||||
{ }
|
||||
|
||||
virtual bool visit(Processor::StackWalker* walker) {
|
||||
if (skipCount == 0) {
|
||||
object method = walker->method();
|
||||
if (isAssignableFrom
|
||||
(t, arrayBody(t, t->m->types, Machine::ThrowableType),
|
||||
methodClass(t, method))
|
||||
and vm::strcmp(reinterpret_cast<const int8_t*>("<init>"),
|
||||
&byteArrayBody(t, methodName(t, method), 0))
|
||||
== 0)
|
||||
{
|
||||
return true;
|
||||
} else {
|
||||
trace = makeTrace(t, walker);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
-- skipCount;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Thread* t;
|
||||
object trace;
|
||||
unsigned skipCount;
|
||||
} v(t, skipCount);
|
||||
|
||||
t->m->processor->walkStack(t, &v);
|
||||
|
||||
if (v.trace == 0) v.trace = makeArray(t, 0);
|
||||
|
||||
return v.trace;
|
||||
}
|
||||
|
||||
inline bool
|
||||
compatibleArrayTypes(Thread* t, object a, object b)
|
||||
{
|
||||
return classArrayElementSize(t, a)
|
||||
and classArrayElementSize(t, b)
|
||||
and (a == b
|
||||
or (not ((classVmFlags(t, a) & PrimitiveFlag)
|
||||
or (classVmFlags(t, b) & PrimitiveFlag))));
|
||||
}
|
||||
|
||||
inline void
|
||||
arrayCopy(Thread* t, object src, int32_t srcOffset, object dst,
|
||||
int32_t dstOffset, int32_t length)
|
||||
{
|
||||
if (LIKELY(src and dst)) {
|
||||
if (LIKELY(compatibleArrayTypes
|
||||
(t, objectClass(t, src), objectClass(t, dst))))
|
||||
{
|
||||
unsigned elementSize = classArrayElementSize(t, objectClass(t, src));
|
||||
|
||||
if (LIKELY(elementSize)) {
|
||||
intptr_t sl = cast<uintptr_t>(src, BytesPerWord);
|
||||
intptr_t dl = cast<uintptr_t>(dst, BytesPerWord);
|
||||
if (LIKELY(length > 0)) {
|
||||
if (LIKELY(srcOffset >= 0 and srcOffset + length <= sl and
|
||||
dstOffset >= 0 and dstOffset + length <= dl))
|
||||
{
|
||||
uint8_t* sbody = &cast<uint8_t>(src, ArrayBody);
|
||||
uint8_t* dbody = &cast<uint8_t>(dst, ArrayBody);
|
||||
if (src == dst) {
|
||||
memmove(dbody + (dstOffset * elementSize),
|
||||
sbody + (srcOffset * elementSize),
|
||||
length * elementSize);
|
||||
} else {
|
||||
memcpy(dbody + (dstOffset * elementSize),
|
||||
sbody + (srcOffset * elementSize),
|
||||
length * elementSize);
|
||||
}
|
||||
|
||||
if (classObjectMask(t, objectClass(t, dst))) {
|
||||
mark(t, dst, ArrayBody + (dstOffset * BytesPerWord), length);
|
||||
}
|
||||
|
||||
return;
|
||||
} else {
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::IndexOutOfBoundsExceptionType);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
return;
|
||||
}
|
||||
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::ArrayStoreExceptionType);
|
||||
}
|
||||
|
||||
void
|
||||
runOnLoadIfFound(Thread* t, System::Library* library)
|
||||
{
|
||||
void* p = library->resolve("JNI_OnLoad");
|
||||
if (p) {
|
||||
jint (JNICALL * JNI_OnLoad)(Machine*, void*);
|
||||
memcpy(&JNI_OnLoad, &p, sizeof(void*));
|
||||
JNI_OnLoad(t->m, 0);
|
||||
}
|
||||
}
|
||||
|
||||
System::Library*
|
||||
loadLibrary(Thread* t, const char* name, bool mapName, bool runOnLoad)
|
||||
{
|
||||
ACQUIRE(t, t->m->classLock);
|
||||
|
||||
const char* builtins = findProperty(t, "avian.builtins");
|
||||
if (mapName and builtins) {
|
||||
const char* s = builtins;
|
||||
while (*s) {
|
||||
unsigned length = strlen(name);
|
||||
if (::strncmp(s, name, length) == 0
|
||||
and (s[length] == ',' or s[length] == 0))
|
||||
{
|
||||
// library is built in to this executable
|
||||
if (runOnLoad and not t->m->triedBuiltinOnLoad) {
|
||||
t->m->triedBuiltinOnLoad = true;
|
||||
runOnLoadIfFound(t, t->m->libraries);
|
||||
}
|
||||
return t->m->libraries;
|
||||
} else {
|
||||
while (*s and *s != ',') ++ s;
|
||||
if (*s) ++ s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
System::Library* last = t->m->libraries;
|
||||
for (System::Library* lib = t->m->libraries; lib; lib = lib->next()) {
|
||||
if (lib->name()
|
||||
and ::strcmp(lib->name(), name) == 0
|
||||
and lib->mapName() == mapName)
|
||||
{
|
||||
// already loaded
|
||||
return lib;
|
||||
}
|
||||
last = lib;
|
||||
}
|
||||
|
||||
System::Library* lib;
|
||||
if (LIKELY(t->m->system->success(t->m->system->load(&lib, name, mapName)))) {
|
||||
last->setNext(lib);
|
||||
if (runOnLoad) {
|
||||
runOnLoadIfFound(t, lib);
|
||||
}
|
||||
return lib;
|
||||
} else {
|
||||
object message = makeString(t, "library not found: %s", name);
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::UnsatisfiedLinkErrorType, message);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
object
|
||||
clone(Thread* t, object o)
|
||||
{
|
||||
PROTECT(t, o);
|
||||
|
||||
object class_ = objectClass(t, o);
|
||||
unsigned size = baseSize(t, o, class_) * BytesPerWord;
|
||||
object clone;
|
||||
|
||||
if (classArrayElementSize(t, class_)) {
|
||||
clone = static_cast<object>(allocate(t, size, classObjectMask(t, class_)));
|
||||
memcpy(clone, o, size);
|
||||
// clear any object header flags:
|
||||
setObjectClass(t, o, objectClass(t, o));
|
||||
} else {
|
||||
clone = make(t, class_);
|
||||
memcpy(reinterpret_cast<void**>(clone) + 1,
|
||||
reinterpret_cast<void**>(o) + 1,
|
||||
size - BytesPerWord);
|
||||
}
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
object
|
||||
makeStackTraceElement(Thread* t, object e)
|
||||
{
|
||||
PROTECT(t, e);
|
||||
|
||||
object class_ = className(t, methodClass(t, traceElementMethod(t, e)));
|
||||
PROTECT(t, class_);
|
||||
|
||||
RUNTIME_ARRAY(char, s, byteArrayLength(t, class_));
|
||||
replace('/', '.', RUNTIME_ARRAY_BODY(s),
|
||||
reinterpret_cast<char*>(&byteArrayBody(t, class_, 0)));
|
||||
class_ = makeString(t, "%s", s);
|
||||
|
||||
object method = methodName(t, traceElementMethod(t, e));
|
||||
PROTECT(t, method);
|
||||
|
||||
method = t->m->classpath->makeString
|
||||
(t, method, 0, byteArrayLength(t, method) - 1);
|
||||
|
||||
unsigned line = t->m->processor->lineNumber
|
||||
(t, traceElementMethod(t, e), traceElementIp(t, e));
|
||||
|
||||
object file = classSourceFile(t, methodClass(t, traceElementMethod(t, e)));
|
||||
file = file ? t->m->classpath->makeString
|
||||
(t, file, 0, byteArrayLength(t, file) - 1) : 0;
|
||||
|
||||
return makeStackTraceElement(t, class_, method, file, line);
|
||||
}
|
||||
|
||||
} // namespace vm
|
||||
|
||||
#endif//CLASSPATH_COMMON_H
|
2096
src/classpath-openjdk.cpp
Normal file
2096
src/classpath-openjdk.cpp
Normal file
File diff suppressed because it is too large
Load Diff
10
src/common.h
10
src/common.h
@ -465,6 +465,16 @@ replace(char a, char b, char* c)
|
||||
for (; *c; ++c) if (*c == a) *c = b;
|
||||
}
|
||||
|
||||
inline void
|
||||
replace(char a, char b, char* dst, const char* src)
|
||||
{
|
||||
unsigned i = 0;
|
||||
for (; src[i]; ++ i) {
|
||||
dst[i] = src[i] == a ? b : src[i];
|
||||
}
|
||||
dst[i] = 0;
|
||||
}
|
||||
|
||||
class Machine;
|
||||
class Thread;
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
#ifdef __x86_64__
|
||||
|
||||
#define THREAD_STACK 2216
|
||||
#define THREAD_STACK 2224
|
||||
|
||||
#if defined __MINGW32__ || defined __CYGWIN32__
|
||||
|
||||
|
110
src/compile.cpp
110
src/compile.cpp
@ -40,7 +40,7 @@ namespace {
|
||||
|
||||
namespace local {
|
||||
|
||||
const bool DebugCompile = false;
|
||||
const bool DebugCompile = true;
|
||||
const bool DebugNatives = false;
|
||||
const bool DebugCallTable = false;
|
||||
const bool DebugMethodTree = false;
|
||||
@ -259,10 +259,10 @@ object
|
||||
findMethod(Thread* t, object method, object instance)
|
||||
{
|
||||
if ((methodFlags(t, method) & ACC_STATIC) == 0) {
|
||||
if (methodVirtual(t, method)) {
|
||||
return findVirtualMethod(t, method, objectClass(t, instance));
|
||||
} else if (classFlags(t, methodClass(t, method)) & ACC_INTERFACE) {
|
||||
if (classFlags(t, methodClass(t, method)) & ACC_INTERFACE) {
|
||||
return findInterfaceMethod(t, method, objectClass(t, instance));
|
||||
} else if (methodVirtual(t, method)) {
|
||||
return findVirtualMethod(t, method, objectClass(t, instance));
|
||||
}
|
||||
}
|
||||
return method;
|
||||
@ -2142,7 +2142,8 @@ findInterfaceMethodFromInstance(MyThread* t, object method, object instance)
|
||||
return methodAddress(t, target);
|
||||
}
|
||||
} else {
|
||||
t->exception = makeNullPointerException(t);
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
unwind(t);
|
||||
}
|
||||
}
|
||||
@ -2414,7 +2415,8 @@ makeBlankObjectArray(MyThread* t, object loader, object class_, int32_t length)
|
||||
(makeObjectArray(t, loader, class_, length));
|
||||
} else {
|
||||
object message = makeString(t, "%d", length);
|
||||
t->exception = makeNegativeArraySizeException(t, message);
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NegativeArraySizeExceptionType, message);
|
||||
unwind(t);
|
||||
}
|
||||
}
|
||||
@ -2463,7 +2465,8 @@ makeBlankArray(MyThread* t, unsigned type, int32_t length)
|
||||
return reinterpret_cast<uintptr_t>(constructor(t, length));
|
||||
} else {
|
||||
object message = makeString(t, "%d", length);
|
||||
t->exception = makeNegativeArraySizeException(t, message);
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NegativeArraySizeExceptionType, message);
|
||||
unwind(t);
|
||||
}
|
||||
}
|
||||
@ -2497,7 +2500,8 @@ setMaybeNull(MyThread* t, object o, unsigned offset, object value)
|
||||
if (LIKELY(o)) {
|
||||
set(t, o, offset, value);
|
||||
} else {
|
||||
t->exception = makeNullPointerException(t);
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
unwind(t);
|
||||
}
|
||||
}
|
||||
@ -2508,7 +2512,8 @@ acquireMonitorForObject(MyThread* t, object o)
|
||||
if (LIKELY(o)) {
|
||||
acquire(t, o);
|
||||
} else {
|
||||
t->exception = makeNullPointerException(t);
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
unwind(t);
|
||||
}
|
||||
}
|
||||
@ -2519,7 +2524,8 @@ releaseMonitorForObject(MyThread* t, object o)
|
||||
if (LIKELY(o)) {
|
||||
release(t, o);
|
||||
} else {
|
||||
t->exception = makeNullPointerException(t);
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
unwind(t);
|
||||
}
|
||||
}
|
||||
@ -2535,7 +2541,8 @@ makeMultidimensionalArray2(MyThread* t, object class_, uintptr_t* countStack,
|
||||
RUNTIME_ARRAY_BODY(counts)[i] = countStack[dimensions - i - 1];
|
||||
if (UNLIKELY(RUNTIME_ARRAY_BODY(counts)[i] < 0)) {
|
||||
object message = makeString(t, "%d", RUNTIME_ARRAY_BODY(counts)[i]);
|
||||
t->exception = makeNegativeArraySizeException(t, message);
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NegativeArraySizeExceptionType, message);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -2589,7 +2596,8 @@ throwArrayIndexOutOfBounds(MyThread* t)
|
||||
{
|
||||
if (ensure(t, FixedSizeOfArrayIndexOutOfBoundsException + traceSize(t))) {
|
||||
t->tracing = true;
|
||||
t->exception = makeArrayIndexOutOfBoundsException(t, 0);
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::ArrayIndexOutOfBoundsExceptionType);
|
||||
t->tracing = false;
|
||||
} else {
|
||||
// not enough memory available for a new exception and stack trace
|
||||
@ -2606,7 +2614,8 @@ throw_(MyThread* t, object o)
|
||||
if (LIKELY(o)) {
|
||||
t->exception = o;
|
||||
} else {
|
||||
t->exception = makeNullPointerException(t);
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
}
|
||||
|
||||
// printTrace(t, t->exception);
|
||||
@ -2622,7 +2631,8 @@ checkCast(MyThread* t, object class_, object o)
|
||||
(t, "%s as %s",
|
||||
&byteArrayBody(t, className(t, objectClass(t, o)), 0),
|
||||
&byteArrayBody(t, className(t, class_), 0));
|
||||
t->exception = makeClassCastException(t, message);
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::ClassCastExceptionType, message);
|
||||
unwind(t);
|
||||
}
|
||||
}
|
||||
@ -6125,34 +6135,32 @@ resolveNative(MyThread* t, object method)
|
||||
|
||||
initClass(t, methodClass(t, method));
|
||||
|
||||
if (LIKELY(t->exception == 0)
|
||||
and unresolved(t, methodCompiled(t, method)))
|
||||
{
|
||||
void* function = resolveNativeMethod(t, method);
|
||||
if (UNLIKELY(function == 0)) {
|
||||
if (LIKELY(t->exception == 0) and methodCode(t, method) == 0) {
|
||||
object native = resolveNativeMethod(t, method);
|
||||
if (UNLIKELY(native == 0)) {
|
||||
object message = makeString
|
||||
(t, "%s.%s%s",
|
||||
&byteArrayBody(t, className(t, methodClass(t, method)), 0),
|
||||
&byteArrayBody(t, methodName(t, method), 0),
|
||||
&byteArrayBody(t, methodSpec(t, method), 0));
|
||||
t->exception = makeUnsatisfiedLinkError(t, message);
|
||||
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::UnsatisfiedLinkErrorType, message);
|
||||
return;
|
||||
}
|
||||
|
||||
// ensure other threads see updated methodVmFlags before
|
||||
// methodCompiled, since we don't want them using the slow calling
|
||||
// convention on a function that expects the fast calling
|
||||
// convention:
|
||||
// ensure other threads only see the methodCode field populated
|
||||
// once the object it points do has been populated:
|
||||
storeStoreMemoryBarrier();
|
||||
|
||||
methodCompiled(t, method) = reinterpret_cast<uintptr_t>(function);
|
||||
set(t, method, MethodCode, native);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t
|
||||
invokeNativeFast(MyThread* t, object method)
|
||||
invokeNativeFast(MyThread* t, object method, void* function)
|
||||
{
|
||||
return reinterpret_cast<FastNativeFunction>(methodCompiled(t, method))
|
||||
return reinterpret_cast<FastNativeFunction>(function)
|
||||
(t, method,
|
||||
static_cast<uintptr_t*>(t->stack)
|
||||
+ t->arch->frameFooterSize()
|
||||
@ -6160,7 +6168,7 @@ invokeNativeFast(MyThread* t, object method)
|
||||
}
|
||||
|
||||
uint64_t
|
||||
invokeNativeSlow(MyThread* t, object method)
|
||||
invokeNativeSlow(MyThread* t, object method, void* function)
|
||||
{
|
||||
PROTECT(t, method);
|
||||
|
||||
@ -6232,7 +6240,6 @@ invokeNativeSlow(MyThread* t, object method)
|
||||
}
|
||||
}
|
||||
|
||||
void* function = reinterpret_cast<void*>(methodCompiled(t, method));
|
||||
unsigned returnCode = methodReturnCode(t, method);
|
||||
unsigned returnType = fieldType(t, returnCode);
|
||||
uint64_t result;
|
||||
@ -6247,7 +6254,7 @@ invokeNativeSlow(MyThread* t, object method)
|
||||
if (methodFlags(t, method) & ACC_STATIC) {
|
||||
acquire(t, methodClass(t, method));
|
||||
} else {
|
||||
acquire(t, *reinterpret_cast<object*>(RUNTIME_ARRAY_BODY(args)[0]));
|
||||
acquire(t, *reinterpret_cast<object*>(RUNTIME_ARRAY_BODY(args)[1]));
|
||||
}
|
||||
}
|
||||
|
||||
@ -6268,7 +6275,7 @@ invokeNativeSlow(MyThread* t, object method)
|
||||
if (methodFlags(t, method) & ACC_STATIC) {
|
||||
release(t, methodClass(t, method));
|
||||
} else {
|
||||
release(t, *reinterpret_cast<object*>(RUNTIME_ARRAY_BODY(args)[0]));
|
||||
release(t, *reinterpret_cast<object*>(RUNTIME_ARRAY_BODY(args)[1]));
|
||||
}
|
||||
}
|
||||
|
||||
@ -6327,10 +6334,11 @@ invokeNativeSlow(MyThread* t, object method)
|
||||
uint64_t
|
||||
invokeNative2(MyThread* t, object method)
|
||||
{
|
||||
if (methodVmFlags(t, method) & FastNative) {
|
||||
return invokeNativeFast(t, method);
|
||||
object native = methodCode(t, method);
|
||||
if (nativeFast(t, native)) {
|
||||
return invokeNativeFast(t, method, nativeFunction(t, native));
|
||||
} else {
|
||||
return invokeNativeSlow(t, method);
|
||||
return invokeNativeSlow(t, method, nativeFunction(t, native));
|
||||
}
|
||||
}
|
||||
|
||||
@ -6829,7 +6837,8 @@ callContinuation(MyThread* t, object continuation, object result,
|
||||
action = Call;
|
||||
}
|
||||
} else {
|
||||
t->exception = makeIncompatibleContinuationException(t);
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::IncompatibleContinuationExceptionType);
|
||||
action = Throw;
|
||||
}
|
||||
} else {
|
||||
@ -7165,7 +7174,8 @@ class SegFaultHandler: public System::SignalHandler {
|
||||
|
||||
if (ensure(t, FixedSizeOfNullPointerException + traceSize(t))) {
|
||||
t->tracing = true;
|
||||
t->exception = makeNullPointerException(t);
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
t->tracing = false;
|
||||
} else {
|
||||
// not enough memory available for a new NPE and stack trace
|
||||
@ -7269,6 +7279,7 @@ class MyProcessor: public Processor {
|
||||
t->init();
|
||||
|
||||
if (false) {
|
||||
fprintf(stderr, "%d\n", difference(&(t->stack), t));
|
||||
fprintf(stderr, "%d\n", difference(&(t->continuation), t));
|
||||
fprintf(stderr, "%d\n", difference(&(t->exception), t));
|
||||
fprintf(stderr, "%d\n", difference(&(t->exceptionStackAdjustment), t));
|
||||
@ -7518,7 +7529,7 @@ class MyProcessor: public Processor {
|
||||
assert(t, t->state == Thread::ActiveState
|
||||
or t->state == Thread::ExclusiveState);
|
||||
|
||||
unsigned size = parameterFootprint(t, methodSpec, false);
|
||||
unsigned size = parameterFootprint(t, methodSpec, this_ == 0);
|
||||
RUNTIME_ARRAY(uintptr_t, array, size);
|
||||
RUNTIME_ARRAY(bool, objectMask, size);
|
||||
ArgumentList list
|
||||
@ -7765,6 +7776,31 @@ class MyProcessor: public Processor {
|
||||
abort(t);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void registerNative(Thread* t, object method, void* function) {
|
||||
PROTECT(t, method);
|
||||
|
||||
expect(t, methodFlags(t, method) & ACC_NATIVE);
|
||||
|
||||
object native = makeNative(t, function, false);
|
||||
|
||||
// ensure other threads only see the methodCode field populated
|
||||
// once the object it points do has been populated:
|
||||
storeStoreMemoryBarrier();
|
||||
|
||||
set(t, method, MethodCode, native);
|
||||
}
|
||||
|
||||
virtual void unregisterNatives(Thread* t, object c) {
|
||||
if (classMethodTable(t, c)) {
|
||||
for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, c)); ++i) {
|
||||
object method = arrayBody(t, classMethodTable(t, c), i);
|
||||
if (methodFlags(t, method) & ACC_NATIVE) {
|
||||
set(t, method, MethodCode, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
System* s;
|
||||
Allocator* allocator;
|
||||
|
@ -10,11 +10,11 @@
|
||||
|
||||
#ifdef __x86_64__
|
||||
|
||||
#define THREAD_CONTINUATION 2224
|
||||
#define THREAD_CONTINUATION 2232
|
||||
#define THREAD_EXCEPTION 80
|
||||
#define THREAD_EXCEPTION_STACK_ADJUSTMENT 2232
|
||||
#define THREAD_EXCEPTION_OFFSET 2240
|
||||
#define THREAD_EXCEPTION_HANDLER 2248
|
||||
#define THREAD_EXCEPTION_STACK_ADJUSTMENT 2240
|
||||
#define THREAD_EXCEPTION_OFFSET 2248
|
||||
#define THREAD_EXCEPTION_HANDLER 2256
|
||||
|
||||
#define CONTINUATION_NEXT 8
|
||||
#define CONTINUATION_ADDRESS 32
|
||||
|
@ -509,7 +509,9 @@ resolveNativeMethodData(Thread* t, object method)
|
||||
&byteArrayBody(t, className(t, methodClass(t, method)), 0),
|
||||
&byteArrayBody(t, methodName(t, method), 0),
|
||||
&byteArrayBody(t, methodSpec(t, method), 0));
|
||||
t->exception = makeUnsatisfiedLinkError(t, message);
|
||||
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::UnsatisfiedLinkErrorType, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -524,7 +526,8 @@ checkStack(Thread* t, object method)
|
||||
+ codeMaxStack(t, methodCode(t, method))
|
||||
> Thread::StackSizeInWords / 2))
|
||||
{
|
||||
t->exception = makeStackOverflowError(t);
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::StackOverflowErrorType);
|
||||
}
|
||||
}
|
||||
|
||||
@ -680,15 +683,15 @@ invokeNativeSlow(Thread* t, object method)
|
||||
&byteArrayBody(t, methodName(t, method), 0));
|
||||
}
|
||||
|
||||
// if (strcmp(reinterpret_cast<const char*>
|
||||
// (&byteArrayBody(t, className(t, methodClass(t, method)), 0)),
|
||||
// "org/eclipse/swt/internal/C") == 0
|
||||
// and strcmp(reinterpret_cast<const char*>
|
||||
// (&byteArrayBody(t, methodName(t, method), 0)),
|
||||
// "memmove") == 0)
|
||||
// {
|
||||
// asm("int3");
|
||||
// }
|
||||
// if (strcmp(reinterpret_cast<const char*>
|
||||
// (&byteArrayBody(t, className(t, methodClass(t, method)), 0)),
|
||||
// "org/eclipse/swt/internal/C") == 0
|
||||
// and strcmp(reinterpret_cast<const char*>
|
||||
// (&byteArrayBody(t, methodName(t, method), 0)),
|
||||
// "memmove") == 0)
|
||||
// {
|
||||
// asm("int3");
|
||||
// }
|
||||
|
||||
{ ENTER(t, Thread::IdleState);
|
||||
|
||||
@ -931,13 +934,15 @@ interpret(Thread* t)
|
||||
{
|
||||
pushObject(t, objectArrayBody(t, array, index));
|
||||
} else {
|
||||
object message = makeString(t, "%d not in [0,%d)", index,
|
||||
objectArrayLength(t, array));
|
||||
exception = makeArrayIndexOutOfBoundsException(t, message);
|
||||
object message = makeString
|
||||
(t, "%d not in [0,%d)", index, objectArrayLength(t, array));
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
|
||||
goto throw_;
|
||||
}
|
||||
} else {
|
||||
exception = makeNullPointerException(t);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
goto throw_;
|
||||
}
|
||||
} goto loop;
|
||||
@ -953,13 +958,15 @@ interpret(Thread* t)
|
||||
{
|
||||
set(t, array, ArrayBody + (index * BytesPerWord), value);
|
||||
} else {
|
||||
object message = makeString(t, "%d not in [0,%d)", index,
|
||||
objectArrayLength(t, array));
|
||||
exception = makeArrayIndexOutOfBoundsException(t, message);
|
||||
object message = makeString
|
||||
(t, "%d not in [0,%d)", index, objectArrayLength(t, array));
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
|
||||
goto throw_;
|
||||
}
|
||||
} else {
|
||||
exception = makeNullPointerException(t);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
goto throw_;
|
||||
}
|
||||
} goto loop;
|
||||
@ -1002,7 +1009,8 @@ interpret(Thread* t)
|
||||
class_, count));
|
||||
} else {
|
||||
object message = makeString(t, "%d", count);
|
||||
exception = makeNegativeArraySizeException(t, message);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NegativeArraySizeExceptionType, message);
|
||||
goto throw_;
|
||||
}
|
||||
} goto loop;
|
||||
@ -1023,7 +1031,8 @@ interpret(Thread* t)
|
||||
if (LIKELY(array)) {
|
||||
pushInt(t, cast<uintptr_t>(array, BytesPerWord));
|
||||
} else {
|
||||
exception = makeNullPointerException(t);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
goto throw_;
|
||||
}
|
||||
} goto loop;
|
||||
@ -1051,7 +1060,8 @@ interpret(Thread* t)
|
||||
case athrow: {
|
||||
exception = popObject(t);
|
||||
if (UNLIKELY(exception == 0)) {
|
||||
exception = makeNullPointerException(t);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
}
|
||||
} goto throw_;
|
||||
|
||||
@ -1071,7 +1081,8 @@ interpret(Thread* t)
|
||||
} else {
|
||||
object message = makeString(t, "%d not in [0,%d)", index,
|
||||
booleanArrayLength(t, array));
|
||||
exception = makeArrayIndexOutOfBoundsException(t, message);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
|
||||
goto throw_;
|
||||
}
|
||||
} else {
|
||||
@ -1083,12 +1094,15 @@ interpret(Thread* t)
|
||||
} else {
|
||||
object message = makeString(t, "%d not in [0,%d)", index,
|
||||
byteArrayLength(t, array));
|
||||
exception = makeArrayIndexOutOfBoundsException(t, message);
|
||||
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
|
||||
goto throw_;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
exception = makeNullPointerException(t);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
goto throw_;
|
||||
}
|
||||
} goto loop;
|
||||
@ -1110,7 +1124,8 @@ interpret(Thread* t)
|
||||
} else {
|
||||
object message = makeString(t, "%d not in [0,%d)", index,
|
||||
booleanArrayLength(t, array));
|
||||
exception = makeArrayIndexOutOfBoundsException(t, message);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
|
||||
goto throw_;
|
||||
}
|
||||
} else {
|
||||
@ -1121,12 +1136,14 @@ interpret(Thread* t)
|
||||
} else {
|
||||
object message = makeString(t, "%d not in [0,%d)", index,
|
||||
byteArrayLength(t, array));
|
||||
exception = makeArrayIndexOutOfBoundsException(t, message);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
|
||||
goto throw_;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
exception = makeNullPointerException(t);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
goto throw_;
|
||||
}
|
||||
} goto loop;
|
||||
@ -1147,11 +1164,13 @@ interpret(Thread* t)
|
||||
} else {
|
||||
object message = makeString(t, "%d not in [0,%d)", index,
|
||||
charArrayLength(t, array));
|
||||
exception = makeArrayIndexOutOfBoundsException(t, message);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
|
||||
goto throw_;
|
||||
}
|
||||
} else {
|
||||
exception = makeNullPointerException(t);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
goto throw_;
|
||||
}
|
||||
} goto loop;
|
||||
@ -1169,11 +1188,13 @@ interpret(Thread* t)
|
||||
} else {
|
||||
object message = makeString(t, "%d not in [0,%d)", index,
|
||||
charArrayLength(t, array));
|
||||
exception = makeArrayIndexOutOfBoundsException(t, message);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
|
||||
goto throw_;
|
||||
}
|
||||
} else {
|
||||
exception = makeNullPointerException(t);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
goto throw_;
|
||||
}
|
||||
} goto loop;
|
||||
@ -1191,7 +1212,8 @@ interpret(Thread* t)
|
||||
&byteArrayBody
|
||||
(t, className(t, objectClass(t, peekObject(t, sp - 1))), 0),
|
||||
&byteArrayBody(t, className(t, class_), 0));
|
||||
exception = makeClassCastException(t, message);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::ClassCastExceptionType, message);
|
||||
goto throw_;
|
||||
}
|
||||
}
|
||||
@ -1228,11 +1250,13 @@ interpret(Thread* t)
|
||||
} else {
|
||||
object message = makeString(t, "%d not in [0,%d)", index,
|
||||
doubleArrayLength(t, array));
|
||||
exception = makeArrayIndexOutOfBoundsException(t, message);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
|
||||
goto throw_;
|
||||
}
|
||||
} else {
|
||||
exception = makeNullPointerException(t);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
goto throw_;
|
||||
}
|
||||
} goto loop;
|
||||
@ -1250,11 +1274,13 @@ interpret(Thread* t)
|
||||
} else {
|
||||
object message = makeString(t, "%d not in [0,%d)", index,
|
||||
doubleArrayLength(t, array));
|
||||
exception = makeArrayIndexOutOfBoundsException(t, message);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
|
||||
goto throw_;
|
||||
}
|
||||
} else {
|
||||
exception = makeNullPointerException(t);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
goto throw_;
|
||||
}
|
||||
} goto loop;
|
||||
@ -1428,11 +1454,13 @@ interpret(Thread* t)
|
||||
} else {
|
||||
object message = makeString(t, "%d not in [0,%d)", index,
|
||||
floatArrayLength(t, array));
|
||||
exception = makeArrayIndexOutOfBoundsException(t, message);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
|
||||
goto throw_;
|
||||
}
|
||||
} else {
|
||||
exception = makeNullPointerException(t);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
goto throw_;
|
||||
}
|
||||
} goto loop;
|
||||
@ -1450,11 +1478,13 @@ interpret(Thread* t)
|
||||
} else {
|
||||
object message = makeString(t, "%d not in [0,%d)", index,
|
||||
floatArrayLength(t, array));
|
||||
exception = makeArrayIndexOutOfBoundsException(t, message);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
|
||||
goto throw_;
|
||||
}
|
||||
} else {
|
||||
exception = makeNullPointerException(t);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
goto throw_;
|
||||
}
|
||||
} goto loop;
|
||||
@ -1566,7 +1596,8 @@ interpret(Thread* t)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
exception = makeNullPointerException(t);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
goto throw_;
|
||||
}
|
||||
} goto loop;
|
||||
@ -1658,11 +1689,13 @@ interpret(Thread* t)
|
||||
} else {
|
||||
object message = makeString(t, "%d not in [0,%d)", index,
|
||||
intArrayLength(t, array));
|
||||
exception = makeArrayIndexOutOfBoundsException(t, message);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
|
||||
goto throw_;
|
||||
}
|
||||
} else {
|
||||
exception = makeNullPointerException(t);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
goto throw_;
|
||||
}
|
||||
} goto loop;
|
||||
@ -1687,11 +1720,13 @@ interpret(Thread* t)
|
||||
} else {
|
||||
object message = makeString(t, "%d not in [0,%d)", index,
|
||||
intArrayLength(t, array));
|
||||
exception = makeArrayIndexOutOfBoundsException(t, message);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
|
||||
goto throw_;
|
||||
}
|
||||
} else {
|
||||
exception = makeNullPointerException(t);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
goto throw_;
|
||||
}
|
||||
} goto loop;
|
||||
@ -1958,7 +1993,8 @@ interpret(Thread* t)
|
||||
(t, method, objectClass(t, peekObject(t, sp - parameterFootprint)));
|
||||
goto invoke;
|
||||
} else {
|
||||
exception = makeNullPointerException(t);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
goto throw_;
|
||||
}
|
||||
} goto loop;
|
||||
@ -1983,7 +2019,8 @@ interpret(Thread* t)
|
||||
|
||||
goto invoke;
|
||||
} else {
|
||||
exception = makeNullPointerException(t);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
goto throw_;
|
||||
}
|
||||
} goto loop;
|
||||
@ -2014,7 +2051,8 @@ interpret(Thread* t)
|
||||
code = findVirtualMethod(t, method, class_);
|
||||
goto invoke;
|
||||
} else {
|
||||
exception = makeNullPointerException(t);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
goto throw_;
|
||||
}
|
||||
} goto loop;
|
||||
@ -2150,11 +2188,13 @@ interpret(Thread* t)
|
||||
} else {
|
||||
object message = makeString(t, "%d not in [0,%d)", index,
|
||||
longArrayLength(t, array));
|
||||
exception = makeArrayIndexOutOfBoundsException(t, message);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
|
||||
goto throw_;
|
||||
}
|
||||
} else {
|
||||
exception = makeNullPointerException(t);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
goto throw_;
|
||||
}
|
||||
} goto loop;
|
||||
@ -2179,11 +2219,13 @@ interpret(Thread* t)
|
||||
} else {
|
||||
object message = makeString(t, "%d not in [0,%d)", index,
|
||||
longArrayLength(t, array));
|
||||
exception = makeArrayIndexOutOfBoundsException(t, message);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
|
||||
goto throw_;
|
||||
}
|
||||
} else {
|
||||
exception = makeNullPointerException(t);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
goto throw_;
|
||||
}
|
||||
} goto loop;
|
||||
@ -2413,7 +2455,8 @@ interpret(Thread* t)
|
||||
if (LIKELY(o)) {
|
||||
acquire(t, o);
|
||||
} else {
|
||||
exception = makeNullPointerException(t);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
goto throw_;
|
||||
}
|
||||
} goto loop;
|
||||
@ -2423,7 +2466,8 @@ interpret(Thread* t)
|
||||
if (LIKELY(o)) {
|
||||
release(t, o);
|
||||
} else {
|
||||
exception = makeNullPointerException(t);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
goto throw_;
|
||||
}
|
||||
} goto loop;
|
||||
@ -2441,7 +2485,8 @@ interpret(Thread* t)
|
||||
counts[i] = popInt(t);
|
||||
if (UNLIKELY(counts[i] < 0)) {
|
||||
object message = makeString(t, "%d", counts[i]);
|
||||
exception = makeNegativeArraySizeException(t, message);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NegativeArraySizeExceptionType, message);
|
||||
goto throw_;
|
||||
}
|
||||
}
|
||||
@ -2514,7 +2559,8 @@ interpret(Thread* t)
|
||||
pushObject(t, array);
|
||||
} else {
|
||||
object message = makeString(t, "%d", count);
|
||||
exception = makeNegativeArraySizeException(t, message);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NegativeArraySizeExceptionType, message);
|
||||
goto throw_;
|
||||
}
|
||||
} goto loop;
|
||||
@ -2576,7 +2622,8 @@ interpret(Thread* t)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
exception = makeNullPointerException(t);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
}
|
||||
} break;
|
||||
|
||||
@ -2587,7 +2634,8 @@ interpret(Thread* t)
|
||||
if (LIKELY(o)) {
|
||||
cast<int64_t>(o, fieldOffset(t, field)) = value;
|
||||
} else {
|
||||
exception = makeNullPointerException(t);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
}
|
||||
} break;
|
||||
|
||||
@ -2597,7 +2645,8 @@ interpret(Thread* t)
|
||||
if (LIKELY(o)) {
|
||||
set(t, o, fieldOffset(t, field), value);
|
||||
} else {
|
||||
exception = makeNullPointerException(t);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
}
|
||||
} break;
|
||||
|
||||
@ -2727,11 +2776,13 @@ interpret(Thread* t)
|
||||
} else {
|
||||
object message = makeString(t, "%d not in [0,%d)", index,
|
||||
shortArrayLength(t, array));
|
||||
exception = makeArrayIndexOutOfBoundsException(t, message);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
|
||||
goto throw_;
|
||||
}
|
||||
} else {
|
||||
exception = makeNullPointerException(t);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
goto throw_;
|
||||
}
|
||||
} goto loop;
|
||||
@ -2749,11 +2800,13 @@ interpret(Thread* t)
|
||||
} else {
|
||||
object message = makeString(t, "%d not in [0,%d)", index,
|
||||
shortArrayLength(t, array));
|
||||
exception = makeArrayIndexOutOfBoundsException(t, message);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::ArrayIndexOutOfBoundsExceptionType, message);
|
||||
goto throw_;
|
||||
}
|
||||
} else {
|
||||
exception = makeNullPointerException(t);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
goto throw_;
|
||||
}
|
||||
} goto loop;
|
||||
@ -3195,7 +3248,8 @@ class MyProcessor: public Processor {
|
||||
if (UNLIKELY(t->sp + methodParameterFootprint(t, method) + 1
|
||||
> Thread::StackSizeInWords / 2))
|
||||
{
|
||||
t->exception = makeStackOverflowError(t);
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::StackOverflowErrorType);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -3220,7 +3274,8 @@ class MyProcessor: public Processor {
|
||||
if (UNLIKELY(t->sp + methodParameterFootprint(t, method) + 1
|
||||
> Thread::StackSizeInWords / 2))
|
||||
{
|
||||
t->exception = makeStackOverflowError(t);
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::StackOverflowErrorType);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -3244,7 +3299,8 @@ class MyProcessor: public Processor {
|
||||
if (UNLIKELY(t->sp + parameterFootprint(vmt, methodSpec, false)
|
||||
> Thread::StackSizeInWords / 2))
|
||||
{
|
||||
t->exception = makeStackOverflowError(t);
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::StackOverflowErrorType);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
159
src/jnienv.cpp
159
src/jnienv.cpp
@ -156,6 +156,49 @@ ReleaseStringChars(Thread* t, jstring s, const jchar* chars)
|
||||
t->m->heap->free(chars, (stringLength(t, *s) + 1) * sizeof(jchar));
|
||||
}
|
||||
|
||||
void JNICALL
|
||||
GetStringRegion(Thread* t, jstring s, jsize start, jsize length, jchar* dst)
|
||||
{
|
||||
ENTER(t, Thread::ActiveState);
|
||||
|
||||
stringChars(t, *s, start, length, dst);
|
||||
}
|
||||
|
||||
const jchar* JNICALL
|
||||
GetStringCritical(Thread* t, jstring s, jboolean* isCopy)
|
||||
{
|
||||
if ((t->criticalLevel ++) == 0) {
|
||||
enter(t, Thread::ActiveState);
|
||||
}
|
||||
|
||||
if (isCopy) {
|
||||
*isCopy = true;
|
||||
}
|
||||
|
||||
object data = stringData(t, *s);
|
||||
if (objectClass(t, data)
|
||||
== arrayBody(t, t->m->types, Machine::ByteArrayType))
|
||||
{
|
||||
return GetStringChars(t, s, isCopy);
|
||||
} else {
|
||||
return &charArrayBody(t, data, stringOffset(t, *s));
|
||||
}
|
||||
}
|
||||
|
||||
void JNICALL
|
||||
ReleaseStringCritical(Thread* t, jstring s, const jchar* chars)
|
||||
{
|
||||
if (objectClass(t, stringData(t, *s))
|
||||
== arrayBody(t, t->m->types, Machine::ByteArrayType))
|
||||
{
|
||||
ReleaseStringChars(t, s, chars);
|
||||
}
|
||||
|
||||
if ((-- t->criticalLevel) == 0) {
|
||||
enter(t, Thread::IdleState);
|
||||
}
|
||||
}
|
||||
|
||||
jsize JNICALL
|
||||
GetStringUTFLength(Thread* t, jstring s)
|
||||
{
|
||||
@ -186,6 +229,15 @@ ReleaseStringUTFChars(Thread* t, jstring s, const char* chars)
|
||||
t->m->heap->free(chars, stringLength(t, *s) + 1);
|
||||
}
|
||||
|
||||
void JNICALL
|
||||
GetStringUTFRegion(Thread* t, jstring s, jsize start, jsize length, char* dst)
|
||||
{
|
||||
ENTER(t, Thread::ActiveState);
|
||||
|
||||
stringUTFChars
|
||||
(t, *s, start, length, dst, stringUTFLength(t, *s, start, length));
|
||||
}
|
||||
|
||||
jsize JNICALL
|
||||
GetArrayLength(Thread* t, jarray array)
|
||||
{
|
||||
@ -206,9 +258,8 @@ NewString(Thread* t, const jchar* chars, jsize size)
|
||||
a = makeCharArray(t, size);
|
||||
memcpy(&charArrayBody(t, a, 0), chars, size * sizeof(jchar));
|
||||
}
|
||||
object s = makeString(t, a, 0, size, 0);
|
||||
|
||||
return makeLocalReference(t, s);
|
||||
return makeLocalReference(t, t->m->classpath->makeString(t, a, 0, size));
|
||||
}
|
||||
|
||||
jstring JNICALL
|
||||
@ -218,15 +269,11 @@ NewStringUTF(Thread* t, const char* chars)
|
||||
|
||||
ENTER(t, Thread::ActiveState);
|
||||
|
||||
object a = 0;
|
||||
unsigned size = strlen(chars);
|
||||
if (size) {
|
||||
a = makeByteArray(t, size);
|
||||
memcpy(&byteArrayBody(t, a, 0), chars, size);
|
||||
}
|
||||
object s = makeString(t, a, 0, size, 0);
|
||||
object array = parseUtf8(t, chars, strlen(chars));
|
||||
|
||||
return makeLocalReference(t, s);
|
||||
return makeLocalReference
|
||||
(t, t->m->classpath->makeString
|
||||
(t, array, 0, cast<uintptr_t>(array, BytesPerWord) - 1));
|
||||
}
|
||||
|
||||
void
|
||||
@ -240,6 +287,19 @@ replace(int a, int b, const char* in, int8_t* out)
|
||||
*out = 0;
|
||||
}
|
||||
|
||||
jclass JNICALL
|
||||
DefineClass(Thread* t, const char*, jobject loader, const jbyte* buffer,
|
||||
jsize length)
|
||||
{
|
||||
ENTER(t, Thread::ActiveState);
|
||||
|
||||
object c = defineClass
|
||||
(t, loader ? *loader : t->m->loader,
|
||||
reinterpret_cast<const uint8_t*>(buffer), length);
|
||||
|
||||
return makeLocalReference(t, c == 0 ? 0 : getJClass(t, c));
|
||||
}
|
||||
|
||||
jclass JNICALL
|
||||
FindClass(Thread* t, const char* name)
|
||||
{
|
||||
@ -279,6 +339,20 @@ ThrowNew(Thread* t, jclass c, const char* message)
|
||||
return 0;
|
||||
}
|
||||
|
||||
jint JNICALL
|
||||
Throw(Thread* t, jthrowable throwable)
|
||||
{
|
||||
if (t->exception) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ENTER(t, Thread::ActiveState);
|
||||
|
||||
t->exception = *throwable;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void JNICALL
|
||||
DeleteLocalRef(Thread* t, jobject r)
|
||||
{
|
||||
@ -329,6 +403,14 @@ IsInstanceOf(Thread* t, jobject o, jclass c)
|
||||
return instanceOf(t, jclassVmClass(t, *c), *o);
|
||||
}
|
||||
|
||||
jboolean JNICALL
|
||||
IsAssignableFrom(Thread* t, jclass a, jclass b)
|
||||
{
|
||||
ENTER(t, Thread::ActiveState);
|
||||
|
||||
return isAssignableFrom(t, jclassVmClass(t, *a), jclassVmClass(t, *b));
|
||||
}
|
||||
|
||||
object
|
||||
findMethod(Thread* t, jclass c, const char* name, const char* spec)
|
||||
{
|
||||
@ -362,7 +444,10 @@ GetMethodID(Thread* t, jclass c, const char* name, const char* spec)
|
||||
ENTER(t, Thread::ActiveState);
|
||||
|
||||
object method = findMethod(t, c, name, spec);
|
||||
if (UNLIKELY(t->exception)) return 0;
|
||||
if (UNLIKELY(t->exception)) {
|
||||
printTrace(t, t->exception);
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(t, (methodFlags(t, method) & ACC_STATIC) == 0);
|
||||
|
||||
@ -1116,7 +1201,7 @@ SetStaticObjectField(Thread* t, jclass c, jfieldID field, jobject v)
|
||||
{
|
||||
ENTER(t, Thread::ActiveState);
|
||||
|
||||
set(t, classStaticTable(t, *c), field, (v ? *v : 0));
|
||||
set(t, classStaticTable(t, jclassVmClass(t, *c)), field, (v ? *v : 0));
|
||||
}
|
||||
|
||||
void JNICALL
|
||||
@ -1222,6 +1307,12 @@ DeleteGlobalRef(Thread* t, jobject r)
|
||||
}
|
||||
}
|
||||
|
||||
jint JNICALL
|
||||
EnsureLocalCapacity(Thread*, jint)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
jthrowable JNICALL
|
||||
ExceptionOccurred(Thread* t)
|
||||
{
|
||||
@ -1832,6 +1923,34 @@ ReleasePrimitiveArrayCritical(Thread* t, jarray, void*, jint)
|
||||
}
|
||||
}
|
||||
|
||||
jint JNICALL
|
||||
RegisterNatives(Thread* t, jclass c, const JNINativeMethod* methods,
|
||||
jint methodCount)
|
||||
{
|
||||
ENTER(t, Thread::ActiveState);
|
||||
|
||||
for (int i = 0; i < methodCount; ++i) {
|
||||
if (methods[i].function) {
|
||||
object method = findMethod(t, c, methods[i].name, methods[i].signature);
|
||||
if (UNLIKELY(t->exception)) return -1;
|
||||
|
||||
t->m->processor->registerNative(t, method, methods[i].function);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
jint JNICALL
|
||||
UnregisterNatives(Thread* t, jclass c)
|
||||
{
|
||||
ENTER(t, Thread::ActiveState);
|
||||
|
||||
t->m->processor->unregisterNatives(t, *c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
jint JNICALL
|
||||
MonitorEnter(Thread* t, jobject o)
|
||||
{
|
||||
@ -1948,14 +2067,20 @@ populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable)
|
||||
envTable->GetStringLength = local::GetStringLength;
|
||||
envTable->GetStringChars = local::GetStringChars;
|
||||
envTable->ReleaseStringChars = local::ReleaseStringChars;
|
||||
envTable->GetStringRegion = local::GetStringRegion;
|
||||
envTable->GetStringCritical = local::GetStringCritical;
|
||||
envTable->ReleaseStringCritical = local::ReleaseStringCritical;
|
||||
envTable->GetStringUTFLength = local::GetStringUTFLength;
|
||||
envTable->GetStringUTFChars = local::GetStringUTFChars;
|
||||
envTable->ReleaseStringUTFChars = local::ReleaseStringUTFChars;
|
||||
envTable->GetStringUTFRegion = local::GetStringUTFRegion;
|
||||
envTable->GetArrayLength = local::GetArrayLength;
|
||||
envTable->NewString = local::NewString;
|
||||
envTable->NewStringUTF = local::NewStringUTF;
|
||||
envTable->DefineClass = local::DefineClass;
|
||||
envTable->FindClass = local::FindClass;
|
||||
envTable->ThrowNew = local::ThrowNew;
|
||||
envTable->Throw = local::Throw;
|
||||
envTable->ExceptionCheck = local::ExceptionCheck;
|
||||
#ifdef AVIAN_GNU
|
||||
envTable->NewDirectByteBuffer = vm::NewDirectByteBuffer;
|
||||
@ -1969,6 +2094,7 @@ populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable)
|
||||
envTable->DeleteLocalRef = local::DeleteLocalRef;
|
||||
envTable->GetObjectClass = local::GetObjectClass;
|
||||
envTable->IsInstanceOf = local::IsInstanceOf;
|
||||
envTable->IsAssignableFrom = local::IsAssignableFrom;
|
||||
envTable->GetFieldID = local::GetFieldID;
|
||||
envTable->GetMethodID = local::GetMethodID;
|
||||
envTable->GetStaticMethodID = local::GetStaticMethodID;
|
||||
@ -2054,6 +2180,7 @@ populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable)
|
||||
envTable->NewGlobalRef = local::NewGlobalRef;
|
||||
envTable->NewWeakGlobalRef = local::NewGlobalRef;
|
||||
envTable->DeleteGlobalRef = local::DeleteGlobalRef;
|
||||
envTable->EnsureLocalCapacity = local::EnsureLocalCapacity;
|
||||
envTable->ExceptionOccurred = local::ExceptionOccurred;
|
||||
envTable->ExceptionDescribe = local::ExceptionDescribe;
|
||||
envTable->ExceptionClear = local::ExceptionClear;
|
||||
@ -2103,6 +2230,8 @@ populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable)
|
||||
envTable->GetPrimitiveArrayCritical = local::GetPrimitiveArrayCritical;
|
||||
envTable->ReleasePrimitiveArrayCritical
|
||||
= local::ReleasePrimitiveArrayCritical;
|
||||
envTable->RegisterNatives = local::RegisterNatives;
|
||||
envTable->UnregisterNatives = local::UnregisterNatives;
|
||||
envTable->MonitorEnter = local::MonitorEnter;
|
||||
envTable->MonitorExit = local::MonitorExit;
|
||||
envTable->GetJavaVM = local::GetJavaVM;
|
||||
@ -2201,6 +2330,7 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args)
|
||||
Heap* h = makeHeap(s, heapLimit);
|
||||
Finder* f = makeFinder(s, RUNTIME_ARRAY_BODY(classpathBuffer), bootLibrary);
|
||||
Processor* p = makeProcessor(s, h, true);
|
||||
Classpath* c = makeClasspath(s, h);
|
||||
|
||||
const char** properties = static_cast<const char**>
|
||||
(h->allocate(sizeof(const char*) * propertyCount));
|
||||
@ -2212,11 +2342,14 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args)
|
||||
}
|
||||
|
||||
*m = new (h->allocate(sizeof(Machine)))
|
||||
Machine(s, h, f, p, properties, propertyCount);
|
||||
Machine(s, h, f, p, c, properties, propertyCount);
|
||||
|
||||
*t = p->makeThread(*m, 0, 0);
|
||||
|
||||
enter(*t, Thread::ActiveState);
|
||||
|
||||
c->boot(*t);
|
||||
|
||||
enter(*t, Thread::IdleState);
|
||||
|
||||
return 0;
|
||||
|
261
src/machine.cpp
261
src/machine.cpp
@ -196,10 +196,12 @@ turnOffTheLights(Thread* t)
|
||||
System* s = m->system;
|
||||
Heap* h = m->heap;
|
||||
Processor* p = m->processor;
|
||||
Classpath* c = m->classpath;
|
||||
Finder* f = m->finder;
|
||||
|
||||
m->dispose();
|
||||
h->disposeFixies();
|
||||
c->dispose();
|
||||
p->dispose();
|
||||
h->dispose();
|
||||
f->dispose();
|
||||
@ -227,23 +229,6 @@ killZombies(Thread* t, Thread* o)
|
||||
}
|
||||
}
|
||||
|
||||
object
|
||||
makeJavaThread(Thread* t, Thread* parent)
|
||||
{
|
||||
object group;
|
||||
if (parent) {
|
||||
group = threadGroup(t, parent->javaThread);
|
||||
} else {
|
||||
group = makeThreadGroup(t, 0, 0, 0);
|
||||
}
|
||||
|
||||
const unsigned NewState = 0;
|
||||
const unsigned NormalPriority = 5;
|
||||
|
||||
return makeThread
|
||||
(t, 0, 0, 0, NewState, NormalPriority, 0, 0, 0, t->m->loader, 0, 0, group);
|
||||
}
|
||||
|
||||
unsigned
|
||||
footprint(Thread* t)
|
||||
{
|
||||
@ -377,13 +362,12 @@ referenceTargetUnreachable(Thread* t, Heap::Visitor* v, object* p)
|
||||
|
||||
object q = jreferenceQueue(t, *p);
|
||||
|
||||
set(t, *p, JreferenceJNext, *p);
|
||||
if (referenceQueueFront(t, q)) {
|
||||
set(t, referenceQueueRear(t, q), JreferenceJNext, *p);
|
||||
set(t, *p, JreferenceJNext, referenceQueueFront(t, q));
|
||||
} else {
|
||||
set(t, q, ReferenceQueueFront, *p);
|
||||
set(t, *p, JreferenceJNext, *p);
|
||||
}
|
||||
set(t, q, ReferenceQueueRear, *p);
|
||||
set(t, q, ReferenceQueueFront, *p);
|
||||
|
||||
jreferenceQueue(t, *p) = 0;
|
||||
}
|
||||
@ -793,8 +777,8 @@ parsePoolEntry(Thread* t, Stream& s, uint32_t* index, object pool, unsigned i)
|
||||
parsePoolEntry(t, s, index, pool, si);
|
||||
|
||||
object value = singletonObject(t, pool, si);
|
||||
value = makeString
|
||||
(t, value, 0, cast<uintptr_t>(value, BytesPerWord) - 1, 0);
|
||||
value = t->m->classpath->makeString
|
||||
(t, value, 0, cast<uintptr_t>(value, BytesPerWord) - 1);
|
||||
value = intern(t, value);
|
||||
set(t, pool, SingletonBody + (i * BytesPerWord), value);
|
||||
}
|
||||
@ -1046,7 +1030,7 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
|
||||
object body = makeByteArray(t, length);
|
||||
s.read(reinterpret_cast<uint8_t*>(&byteArrayBody(t, body, 0)),
|
||||
length);
|
||||
addendum = makeAddendum(t, pool, body);
|
||||
addendum = makeFieldAddendum(t, pool, body);
|
||||
} else {
|
||||
s.skip(length);
|
||||
}
|
||||
@ -1082,9 +1066,8 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
|
||||
classVmFlags(t, class_) |= HasFinalMemberFlag;
|
||||
}
|
||||
|
||||
unsigned excess = (memberOffset % fieldSize(t, code)) % BytesPerWord;
|
||||
if (excess) {
|
||||
memberOffset += BytesPerWord - excess;
|
||||
while (memberOffset % fieldSize(t, code)) {
|
||||
++ memberOffset;
|
||||
}
|
||||
|
||||
fieldOffset(t, field) = memberOffset;
|
||||
@ -1392,14 +1375,29 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
||||
&byteArrayBody(t, name, 0)) == 0)
|
||||
{
|
||||
code = parseCode(t, s, pool);
|
||||
} else if (vm::strcmp(reinterpret_cast<const int8_t*>("Exceptions"),
|
||||
&byteArrayBody(t, name, 0)) == 0)
|
||||
{
|
||||
if (addendum == 0) {
|
||||
addendum = makeMethodAddendum(t, pool, 0, 0);
|
||||
}
|
||||
unsigned exceptionCount = s.read2();
|
||||
object body = makeShortArray(t, exceptionCount);
|
||||
for (unsigned i = 0; i < exceptionCount; ++i) {
|
||||
shortArrayBody(t, body, i) = s.read2();
|
||||
}
|
||||
set(t, addendum, MethodAddendumExceptionTable, body);
|
||||
} else if (vm::strcmp(reinterpret_cast<const int8_t*>
|
||||
("RuntimeVisibleAnnotations"),
|
||||
&byteArrayBody(t, name, 0)) == 0)
|
||||
{
|
||||
if (addendum == 0) {
|
||||
addendum = makeMethodAddendum(t, pool, 0, 0);
|
||||
}
|
||||
object body = makeByteArray(t, length);
|
||||
s.read(reinterpret_cast<uint8_t*>(&byteArrayBody(t, body, 0)),
|
||||
length);
|
||||
addendum = makeAddendum(t, pool, body);
|
||||
set(t, addendum, AddendumAnnotationTable, body);
|
||||
} else {
|
||||
s.skip(length);
|
||||
}
|
||||
@ -1549,7 +1547,6 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
||||
|
||||
if (abstractVirtuals) {
|
||||
PROTECT(t, vtable);
|
||||
PROTECT(t, abstractVirtuals);
|
||||
|
||||
unsigned oldLength = arrayLength(t, classMethodTable(t, class_));
|
||||
object newMethodTable = makeArray
|
||||
@ -1673,8 +1670,7 @@ updateBootstrapClass(Thread* t, object bootstrapClass, object class_)
|
||||
// verify that the classes have the same layout
|
||||
expect(t, classSuper(t, bootstrapClass) == classSuper(t, class_));
|
||||
|
||||
expect(t, bootstrapClass == arrayBody(t, t->m->types, Machine::ClassType)
|
||||
or classFixedSize(t, bootstrapClass) >= classFixedSize(t, class_));
|
||||
expect(t, classFixedSize(t, bootstrapClass) >= classFixedSize(t, class_));
|
||||
|
||||
expect(t, (classVmFlags(t, class_) & HasFinalizerFlag) == 0);
|
||||
|
||||
@ -2079,8 +2075,8 @@ class HeapClient: public Heap::Client {
|
||||
namespace vm {
|
||||
|
||||
Machine::Machine(System* system, Heap* heap, Finder* finder,
|
||||
Processor* processor, const char** properties,
|
||||
unsigned propertyCount):
|
||||
Processor* processor, Classpath* classpath,
|
||||
const char** properties, unsigned propertyCount):
|
||||
vtable(&javaVMVTable),
|
||||
system(system),
|
||||
heapClient(new (heap->allocate(sizeof(HeapClient)))
|
||||
@ -2088,6 +2084,7 @@ Machine::Machine(System* system, Heap* heap, Finder* finder,
|
||||
heap(heap),
|
||||
finder(finder),
|
||||
processor(processor),
|
||||
classpath(classpath),
|
||||
rootThread(0),
|
||||
exclusive(0),
|
||||
finalizeThread(0),
|
||||
@ -2199,7 +2196,8 @@ Thread::Thread(Machine* m, object javaThread, Thread* parent):
|
||||
backupHeapIndex(0),
|
||||
useBackupHeap(false),
|
||||
waiting(false),
|
||||
tracing(false)
|
||||
tracing(false),
|
||||
daemon(false)
|
||||
#ifdef VM_STRESS
|
||||
, stress(false)
|
||||
#endif // VM_STRESS
|
||||
@ -2248,10 +2246,11 @@ Thread::init()
|
||||
|
||||
m->jniMethodTable = makeVector(this, 0, 0);
|
||||
|
||||
m->nullPointerException = makeNullPointerException(this);
|
||||
m->nullPointerException = m->classpath->makeThrowable
|
||||
(this, Machine::NullPointerExceptionType);
|
||||
|
||||
m->arrayIndexOutOfBoundsException
|
||||
= makeArrayIndexOutOfBoundsException(this, 0);
|
||||
m->arrayIndexOutOfBoundsException = m->classpath->makeThrowable
|
||||
(this, Machine::IndexOutOfBoundsExceptionType);
|
||||
|
||||
m->localThread->set(this);
|
||||
} else {
|
||||
@ -2262,7 +2261,7 @@ Thread::init()
|
||||
expect(this, m->system->success(m->system->make(&lock)));
|
||||
|
||||
if (javaThread == 0) {
|
||||
this->javaThread = makeJavaThread(this, parent);
|
||||
this->javaThread = m->classpath->makeThread(this, parent);
|
||||
}
|
||||
|
||||
threadPeer(this, javaThread) = reinterpret_cast<jlong>(this);
|
||||
@ -2365,6 +2364,7 @@ enter(Thread* t, Thread::State s)
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
#ifdef USE_ATOMIC_OPERATIONS
|
||||
# define INCREMENT atomicIncrement
|
||||
# define ACQUIRE_LOCK ACQUIRE_RAW(t, t->m->stateLock)
|
||||
@ -2408,6 +2408,24 @@ enter(Thread* t, Thread::State s)
|
||||
} break;
|
||||
|
||||
case Thread::IdleState:
|
||||
// The java.lang.Thread implementation may or may not notify the
|
||||
// VM when the daemon field in the Java object changes, so we sync
|
||||
// up the native field whenever the thread transitions to idle:
|
||||
if (t->daemon != threadDaemon(t, t->javaThread)) {
|
||||
ACQUIRE_LOCK;
|
||||
|
||||
t->daemon = threadDaemon(t, t->javaThread);
|
||||
|
||||
if (t->daemon) {
|
||||
++ t->m->daemonCount;
|
||||
} else {
|
||||
expect(t, t->m->daemonCount);
|
||||
-- t->m->daemonCount;
|
||||
}
|
||||
|
||||
t->m->stateLock->notifyAll(t->systemThread);
|
||||
}
|
||||
|
||||
if (t->state == Thread::ActiveState) {
|
||||
// fast path
|
||||
assert(t, t->m->activeCount > 0);
|
||||
@ -2420,6 +2438,7 @@ enter(Thread* t, Thread::State s)
|
||||
|
||||
t->m->stateLock->notifyAll(t->systemThread);
|
||||
}
|
||||
|
||||
break;
|
||||
} else {
|
||||
// fall through to slow path
|
||||
@ -2692,91 +2711,98 @@ makeString(Thread* t, const char* format, ...)
|
||||
object s = ::makeByteArray(t, format, a);
|
||||
va_end(a);
|
||||
|
||||
return makeString(t, s, 0, byteArrayLength(t, s) - 1, 0);
|
||||
return t->m->classpath->makeString(t, s, 0, byteArrayLength(t, s) - 1);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
stringUTFLength(Thread* t, object string) {
|
||||
int length = 0;
|
||||
stringUTFLength(Thread* t, object string, unsigned start, unsigned length)
|
||||
{
|
||||
unsigned result = 0;
|
||||
|
||||
if (stringLength(t, string)) {
|
||||
if (length) {
|
||||
object data = stringData(t, string);
|
||||
if (objectClass(t, data)
|
||||
== arrayBody(t, t->m->types, Machine::ByteArrayType)) {
|
||||
length = stringLength(t, string);
|
||||
== arrayBody(t, t->m->types, Machine::ByteArrayType))
|
||||
{
|
||||
result = length;
|
||||
} else {
|
||||
for (unsigned i = 0; i < stringLength(t, string); ++i) {
|
||||
uint16_t c = charArrayBody(t, data, stringOffset(t, string) + i);
|
||||
if (!c) length += 1; // null char (was 2 bytes in Java)
|
||||
else if (c < 0x80) length += 1; // ASCII char
|
||||
else if (c < 0x800) length += 2; // two-byte char
|
||||
else length += 3; // three-byte char
|
||||
for (unsigned i = 0; i < length; ++i) {
|
||||
uint16_t c = charArrayBody
|
||||
(t, data, stringOffset(t, string) + start + i);
|
||||
if (c == 0) result += 1; // null char (was 2 bytes in Java)
|
||||
else if (c < 0x80) result += 1; // ASCII char
|
||||
else if (c < 0x800) result += 2; // two-byte char
|
||||
else result += 3; // three-byte char
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
stringChars(Thread* t, object string, char* chars)
|
||||
stringChars(Thread* t, object string, unsigned start, unsigned length,
|
||||
char* chars)
|
||||
{
|
||||
if (stringLength(t, string)) {
|
||||
if (length) {
|
||||
object data = stringData(t, string);
|
||||
if (objectClass(t, data)
|
||||
== arrayBody(t, t->m->types, Machine::ByteArrayType))
|
||||
{
|
||||
memcpy(chars,
|
||||
&byteArrayBody(t, data, stringOffset(t, string)),
|
||||
stringLength(t, string));
|
||||
&byteArrayBody(t, data, stringOffset(t, string) + start),
|
||||
length);
|
||||
} else {
|
||||
for (unsigned i = 0; i < stringLength(t, string); ++i) {
|
||||
chars[i] = charArrayBody(t, data, stringOffset(t, string) + i);
|
||||
for (unsigned i = 0; i < length; ++i) {
|
||||
chars[i] = charArrayBody(t, data, stringOffset(t, string) + start + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
chars[stringLength(t, string)] = 0;
|
||||
chars[length] = 0;
|
||||
}
|
||||
|
||||
void
|
||||
stringChars(Thread* t, object string, uint16_t* chars)
|
||||
stringChars(Thread* t, object string, unsigned start, unsigned length,
|
||||
uint16_t* chars)
|
||||
{
|
||||
if (stringLength(t, string)) {
|
||||
if (length) {
|
||||
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);
|
||||
for (unsigned i = 0; i < length; ++i) {
|
||||
chars[i] = byteArrayBody(t, data, stringOffset(t, string) + start + i);
|
||||
}
|
||||
} else {
|
||||
memcpy(chars,
|
||||
&charArrayBody(t, data, stringOffset(t, string)),
|
||||
stringLength(t, string) * sizeof(uint16_t));
|
||||
&charArrayBody(t, data, stringOffset(t, string) + start),
|
||||
length * sizeof(uint16_t));
|
||||
}
|
||||
}
|
||||
chars[stringLength(t, string)] = 0;
|
||||
chars[length] = 0;
|
||||
}
|
||||
|
||||
void
|
||||
stringUTFChars(Thread* t, object string, char* chars, unsigned length UNUSED)
|
||||
stringUTFChars(Thread* t, object string, unsigned start, unsigned length,
|
||||
char* chars, unsigned charsLength UNUSED)
|
||||
{
|
||||
assert(t, static_cast<unsigned>(stringUTFLength(t, string)) == length);
|
||||
assert(t, static_cast<unsigned>
|
||||
(stringUTFLength(t, string, start, length)) == charsLength);
|
||||
|
||||
if (stringLength(t, string)) {
|
||||
if (length) {
|
||||
object data = stringData(t, string);
|
||||
if (objectClass(t, data)
|
||||
== arrayBody(t, t->m->types, Machine::ByteArrayType))
|
||||
{
|
||||
memcpy(chars,
|
||||
&byteArrayBody(t, data, stringOffset(t, string)),
|
||||
stringLength(t, string));
|
||||
chars[stringLength(t, string)] = 0;
|
||||
&byteArrayBody(t, data, stringOffset(t, string) + start),
|
||||
length);
|
||||
chars[length] = 0;
|
||||
} else {
|
||||
int j = 0;
|
||||
for (unsigned i = 0; i < stringLength(t, string); ++i) {
|
||||
uint16_t c = charArrayBody(t, data, stringOffset(t, string) + i);
|
||||
for (unsigned i = 0; i < length; ++i) {
|
||||
uint16_t c = charArrayBody
|
||||
(t, data, stringOffset(t, string) + start + i);
|
||||
if(!c) { // null char
|
||||
chars[j++] = 0;
|
||||
} else if (c < 0x80) { // ASCII char
|
||||
@ -3118,7 +3144,8 @@ resolveSystemClass(Thread* t, object spec)
|
||||
hashMapInsert(t, t->m->classMap, spec, class_, byteArrayHash);
|
||||
} else if (t->exception == 0) {
|
||||
object message = makeString(t, "%s", &byteArrayBody(t, spec, 0));
|
||||
t->exception = makeClassNotFoundException(t, message);
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::ClassNotFoundExceptionType, message);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3191,7 +3218,8 @@ resolveClass(Thread* t, object loader, object spec)
|
||||
byteArrayHash);
|
||||
} else if (t->exception == 0) {
|
||||
object message = makeString(t, "%s", &byteArrayBody(t, spec, 0));
|
||||
t->exception = makeClassNotFoundException(t, message);
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::ClassNotFoundExceptionType, message);
|
||||
}
|
||||
|
||||
return class_;
|
||||
@ -3216,7 +3244,8 @@ resolveMethod(Thread* t, object class_, const char* methodName,
|
||||
(t, "%s %s not found in %s", methodName, methodSpec,
|
||||
&byteArrayBody(t, className(t, class_), 0));
|
||||
|
||||
t->exception = makeNoSuchMethodError(t, message);
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NoSuchMethodErrorType, message);
|
||||
return 0;
|
||||
} else {
|
||||
return method;
|
||||
@ -3246,7 +3275,8 @@ resolveField(Thread* t, object class_, const char* fieldName,
|
||||
(t, "%s %s not found in %s", fieldName, fieldSpec,
|
||||
&byteArrayBody(t, className(t, class_), 0));
|
||||
|
||||
t->exception = makeNoSuchFieldError(t, message);
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NoSuchFieldErrorType, message);
|
||||
return 0;
|
||||
} else {
|
||||
return field;
|
||||
@ -3324,7 +3354,9 @@ preInitClass(Thread* t, object c)
|
||||
} else if (classVmFlags(t, c) & InitErrorFlag) {
|
||||
object message = makeString
|
||||
(t, "%s", &byteArrayBody(t, className(t, c), 0));
|
||||
t->exception = makeNoClassDefFoundError(t, message);
|
||||
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NoClassDefFoundErrorType, message);
|
||||
} else {
|
||||
classVmFlags(t, c) |= InitFlag;
|
||||
return true;
|
||||
@ -3341,7 +3373,9 @@ postInitClass(Thread* t, object c)
|
||||
|
||||
ACQUIRE(t, t->m->classLock);
|
||||
if (t->exception) {
|
||||
t->exception = makeExceptionInInitializerError(t, t->exception);
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::ExceptionInInitializerErrorType, 0, 0, t->exception);
|
||||
|
||||
classVmFlags(t, c) |= NeedInitFlag | InitErrorFlag;
|
||||
classVmFlags(t, c) &= ~InitFlag;
|
||||
} else {
|
||||
@ -3412,7 +3446,7 @@ findInTable(Thread* t, object table, object name, object spec,
|
||||
object
|
||||
findInHierarchy(Thread* t, object class_, object name, object spec,
|
||||
object (*find)(Thread*, object, object, object),
|
||||
object (*makeError)(Thread*, object))
|
||||
Machine::Type errorType)
|
||||
{
|
||||
object originalClass = class_;
|
||||
|
||||
@ -3440,7 +3474,7 @@ findInHierarchy(Thread* t, object class_, object name, object spec,
|
||||
&byteArrayBody(t, name, 0),
|
||||
&byteArrayBody(t, spec, 0),
|
||||
&byteArrayBody(t, className(t, originalClass), 0));
|
||||
t->exception = makeError(t, message);
|
||||
t->exception = t->m->classpath->makeThrowable(t, errorType, message);
|
||||
}
|
||||
|
||||
return o;
|
||||
@ -3596,7 +3630,7 @@ collect(Thread* t, Heap::CollectionType type)
|
||||
|
||||
if (m->objectsToFinalize and m->finalizeThread == 0) {
|
||||
m->finalizeThread = m->processor->makeThread
|
||||
(m, makeJavaThread(t, m->rootThread), m->rootThread);
|
||||
(m, t->m->classpath->makeThread(t, m->rootThread), m->rootThread);
|
||||
|
||||
if (not t->m->system->success
|
||||
(m->system->start(&(m->finalizeThread->runnable))))
|
||||
@ -3695,7 +3729,8 @@ void
|
||||
printTrace(Thread* t, object exception)
|
||||
{
|
||||
if (exception == 0) {
|
||||
exception = makeNullPointerException(t, 0, makeTrace(t), 0);
|
||||
exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::NullPointerExceptionType);
|
||||
}
|
||||
|
||||
for (object e = exception; e; e = throwableCause(t, e)) {
|
||||
@ -3738,6 +3773,10 @@ printTrace(Thread* t, object exception)
|
||||
fprintf(stderr, "(line %d)\n", line);
|
||||
}
|
||||
}
|
||||
|
||||
if (e == throwableCause(t, e)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3792,17 +3831,6 @@ makeTrace(Thread* t, Thread* target)
|
||||
return v.trace ? v.trace : makeArray(t, 0);
|
||||
}
|
||||
|
||||
void
|
||||
runJavaThread(Thread* t)
|
||||
{
|
||||
object method = resolveMethod
|
||||
(t, t->m->loader, "java/lang/Thread", "run", "(Ljava/lang/Thread;)V");
|
||||
|
||||
if (t->exception == 0) {
|
||||
t->m->processor->invoke(t, method, 0, t->javaThread);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
runFinalizeThread(Thread* t)
|
||||
{
|
||||
@ -3833,6 +3861,47 @@ runFinalizeThread(Thread* t)
|
||||
}
|
||||
}
|
||||
|
||||
object
|
||||
parseUtf8(Thread* t, const char* data, unsigned length)
|
||||
{
|
||||
class Client: public Stream::Client {
|
||||
public:
|
||||
Client(Thread* t): t(t) { }
|
||||
|
||||
virtual void NO_RETURN handleError() {
|
||||
vm::abort(t);
|
||||
}
|
||||
|
||||
private:
|
||||
Thread* t;
|
||||
} client(t);
|
||||
|
||||
Stream s(&client, reinterpret_cast<const uint8_t*>(data), length);
|
||||
|
||||
return ::parseUtf8(t, s, length);
|
||||
}
|
||||
|
||||
object
|
||||
defineClass(Thread* t, object loader, const uint8_t* buffer, unsigned length)
|
||||
{
|
||||
PROTECT(t, loader);
|
||||
|
||||
object c = parseClass(t, loader, buffer, length);
|
||||
|
||||
if (c) {
|
||||
PROTECT(t, c);
|
||||
if (getClassLoaderMap(t, loader) == 0) {
|
||||
object map = makeHashMap(t, 0, 0);
|
||||
set(t, loader, ClassLoaderMap, map);
|
||||
}
|
||||
|
||||
hashMapInsert(t, getClassLoaderMap(t, loader), className(t, c), c,
|
||||
byteArrayHash);
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
void
|
||||
noop()
|
||||
{ }
|
||||
@ -3857,7 +3926,7 @@ vmPrintTrace(Thread* t)
|
||||
int line = t->m->processor->lineNumber
|
||||
(t, walker->method(), walker->ip());
|
||||
|
||||
fprintf(stderr, " at %s.%s ", class_, method);
|
||||
fprintf(stderr, " at %s.%s (%x) ", class_, method, walker->ip());
|
||||
|
||||
switch (line) {
|
||||
case NativeLine:
|
||||
|
289
src/machine.h
289
src/machine.h
@ -97,7 +97,6 @@ const unsigned ContinuationFlag = 1 << 11;
|
||||
const unsigned ClassInitFlag = 1 << 0;
|
||||
const unsigned CompiledFlag = 1 << 1;
|
||||
const unsigned ConstructorFlag = 1 << 2;
|
||||
const unsigned FastNative = 1 << 3;
|
||||
|
||||
#ifndef JNI_VERSION_1_6
|
||||
#define JNI_VERSION_1_6 0x00010006
|
||||
@ -1151,6 +1150,8 @@ class Reference {
|
||||
unsigned count;
|
||||
};
|
||||
|
||||
class Classpath;
|
||||
|
||||
class Machine {
|
||||
public:
|
||||
enum Type {
|
||||
@ -1164,7 +1165,8 @@ class Machine {
|
||||
};
|
||||
|
||||
Machine(System* system, Heap* heap, Finder* finder, Processor* processor,
|
||||
const char** properties, unsigned propertyCount);
|
||||
Classpath* classpath, const char** properties,
|
||||
unsigned propertyCount);
|
||||
|
||||
~Machine() {
|
||||
dispose();
|
||||
@ -1178,6 +1180,7 @@ class Machine {
|
||||
Heap* heap;
|
||||
Finder* finder;
|
||||
Processor* processor;
|
||||
Classpath* classpath;
|
||||
Thread* rootThread;
|
||||
Thread* exclusive;
|
||||
Thread* finalizeThread;
|
||||
@ -1371,11 +1374,45 @@ class Thread {
|
||||
bool useBackupHeap;
|
||||
bool waiting;
|
||||
bool tracing;
|
||||
#ifdef VM_STRESS
|
||||
bool daemon;
|
||||
bool stress;
|
||||
#endif // VM_STRESS
|
||||
};
|
||||
|
||||
class Classpath {
|
||||
public:
|
||||
virtual object
|
||||
makeJclass(Thread* t, object class_) = 0;
|
||||
|
||||
virtual object
|
||||
makeString(Thread* t, object array, int32_t offset, int32_t length) = 0;
|
||||
|
||||
virtual object
|
||||
makeThread(Thread* t, Thread* parent) = 0;
|
||||
|
||||
virtual void
|
||||
runThread(Thread* t) = 0;
|
||||
|
||||
virtual object
|
||||
makeThrowable
|
||||
(Thread* t, Machine::Type type, object message = 0, object trace = 0,
|
||||
object cause = 0) = 0;
|
||||
|
||||
virtual void
|
||||
boot(Thread* t) = 0;
|
||||
|
||||
virtual void
|
||||
dispose() = 0;
|
||||
};
|
||||
|
||||
inline void
|
||||
runJavaThread(Thread* t)
|
||||
{
|
||||
t->m->classpath->runThread(t);
|
||||
}
|
||||
|
||||
Classpath*
|
||||
makeClasspath(System* system, Allocator* allocator);
|
||||
|
||||
typedef uint64_t (JNICALL *FastNativeFunction)(Thread*, object, uintptr_t*);
|
||||
|
||||
inline object
|
||||
@ -1731,160 +1768,10 @@ makeTrace(Thread* t)
|
||||
return makeTrace(t, t);
|
||||
}
|
||||
|
||||
inline object
|
||||
makeRuntimeException(Thread* t, object message)
|
||||
{
|
||||
PROTECT(t, message);
|
||||
object trace = makeTrace(t);
|
||||
return makeRuntimeException(t, message, trace, 0);
|
||||
}
|
||||
|
||||
inline object
|
||||
makeIllegalStateException(Thread* t, object message)
|
||||
{
|
||||
PROTECT(t, message);
|
||||
object trace = makeTrace(t);
|
||||
return makeIllegalStateException(t, message, trace, 0);
|
||||
}
|
||||
|
||||
inline object
|
||||
makeIllegalArgumentException(Thread* t)
|
||||
{
|
||||
return makeIllegalArgumentException(t, 0, makeTrace(t), 0);
|
||||
}
|
||||
|
||||
inline object
|
||||
makeIllegalMonitorStateException(Thread* t)
|
||||
{
|
||||
return makeIllegalMonitorStateException(t, 0, makeTrace(t), 0);
|
||||
}
|
||||
|
||||
inline object
|
||||
makeIndexOutOfBoundsException(Thread* t)
|
||||
{
|
||||
return makeIndexOutOfBoundsException(t, 0, makeTrace(t), 0);
|
||||
}
|
||||
|
||||
inline object
|
||||
makeArrayIndexOutOfBoundsException(Thread* t, object message)
|
||||
{
|
||||
PROTECT(t, message);
|
||||
object trace = makeTrace(t);
|
||||
return makeArrayIndexOutOfBoundsException(t, message, trace, 0);
|
||||
}
|
||||
|
||||
inline object
|
||||
makeArrayStoreException(Thread* t)
|
||||
{
|
||||
return makeArrayStoreException(t, 0, makeTrace(t), 0);
|
||||
}
|
||||
|
||||
inline object
|
||||
makeNegativeArraySizeException(Thread* t, object message)
|
||||
{
|
||||
PROTECT(t, message);
|
||||
object trace = makeTrace(t);
|
||||
return makeNegativeArraySizeException(t, message, trace, 0);
|
||||
}
|
||||
|
||||
inline object
|
||||
makeClassCastException(Thread* t, object message)
|
||||
{
|
||||
PROTECT(t, message);
|
||||
object trace = makeTrace(t);
|
||||
return makeClassCastException(t, message, trace, 0);
|
||||
}
|
||||
|
||||
inline object
|
||||
makeClassNotFoundException(Thread* t, object message)
|
||||
{
|
||||
PROTECT(t, message);
|
||||
object trace = makeTrace(t);
|
||||
return makeClassNotFoundException(t, message, trace, 0, 0);
|
||||
}
|
||||
|
||||
inline object
|
||||
makeNullPointerException(Thread* t)
|
||||
{
|
||||
return makeNullPointerException(t, 0, makeTrace(t), 0);
|
||||
}
|
||||
|
||||
inline object
|
||||
makeInvocationTargetException(Thread* t, object targetException)
|
||||
{
|
||||
PROTECT(t, targetException);
|
||||
object trace = makeTrace(t);
|
||||
return makeRuntimeException(t, 0, trace, targetException);
|
||||
}
|
||||
|
||||
inline object
|
||||
makeInterruptedException(Thread* t)
|
||||
{
|
||||
return makeInterruptedException(t, 0, makeTrace(t), 0);
|
||||
}
|
||||
|
||||
inline object
|
||||
makeIncompatibleContinuationException(Thread* t)
|
||||
{
|
||||
return makeIncompatibleContinuationException(t, 0, makeTrace(t), 0);
|
||||
}
|
||||
|
||||
inline object
|
||||
makeStackOverflowError(Thread* t)
|
||||
{
|
||||
return makeStackOverflowError(t, 0, makeTrace(t), 0);
|
||||
}
|
||||
|
||||
inline object
|
||||
makeNoSuchFieldError(Thread* t, object message)
|
||||
{
|
||||
PROTECT(t, message);
|
||||
object trace = makeTrace(t);
|
||||
return makeNoSuchFieldError(t, message, trace, 0);
|
||||
}
|
||||
|
||||
inline object
|
||||
makeNoSuchMethodError(Thread* t, object message)
|
||||
{
|
||||
PROTECT(t, message);
|
||||
object trace = makeTrace(t);
|
||||
return makeNoSuchMethodError(t, message, trace, 0);
|
||||
}
|
||||
|
||||
inline object
|
||||
makeNoClassDefFoundError(Thread* t, object message)
|
||||
{
|
||||
PROTECT(t, message);
|
||||
object trace = makeTrace(t);
|
||||
return makeNoClassDefFoundError(t, message, trace, 0);
|
||||
}
|
||||
|
||||
inline object
|
||||
makeUnsatisfiedLinkError(Thread* t, object message)
|
||||
{
|
||||
PROTECT(t, message);
|
||||
object trace = makeTrace(t);
|
||||
return makeUnsatisfiedLinkError(t, message, trace, 0);
|
||||
}
|
||||
|
||||
inline object
|
||||
makeExceptionInInitializerError(Thread* t, object cause)
|
||||
{
|
||||
PROTECT(t, cause);
|
||||
object trace = makeTrace(t);
|
||||
return makeExceptionInInitializerError(t, 0, trace, cause, cause);
|
||||
}
|
||||
|
||||
inline object
|
||||
makeIncompatibleClassChangeError(Thread* t)
|
||||
{
|
||||
return makeIncompatibleClassChangeError(t, 0, makeTrace(t), 0);
|
||||
}
|
||||
|
||||
inline object
|
||||
makeNew(Thread* t, object class_)
|
||||
{
|
||||
assert(t, t->state == Thread::ActiveState);
|
||||
assert(t, t->state == Thread::NoState or t->state == Thread::ActiveState);
|
||||
|
||||
PROTECT(t, class_);
|
||||
unsigned sizeInBytes = pad(classFixedSize(t, class_));
|
||||
@ -1917,16 +1804,43 @@ object
|
||||
makeString(Thread* t, const char* format, ...);
|
||||
|
||||
int
|
||||
stringUTFLength(Thread* t, object string);
|
||||
stringUTFLength(Thread* t, object string, unsigned start, unsigned length);
|
||||
|
||||
inline int
|
||||
stringUTFLength(Thread* t, object string)
|
||||
{
|
||||
return stringUTFLength(t, string, 0, stringLength(t, string));
|
||||
}
|
||||
|
||||
void
|
||||
stringChars(Thread* t, object string, char* chars);
|
||||
stringChars(Thread* t, object string, unsigned start, unsigned length,
|
||||
char* chars);
|
||||
|
||||
inline void
|
||||
stringChars(Thread* t, object string, char* chars)
|
||||
{
|
||||
stringChars(t, string, 0, stringLength(t, string), chars);
|
||||
}
|
||||
|
||||
void
|
||||
stringChars(Thread* t, object string, uint16_t* chars);
|
||||
stringChars(Thread* t, object string, unsigned start, unsigned length,
|
||||
uint16_t* chars);
|
||||
|
||||
inline void
|
||||
stringChars(Thread* t, object string, uint16_t* chars)
|
||||
{
|
||||
stringChars(t, string, 0, stringLength(t, string), chars);
|
||||
}
|
||||
|
||||
void
|
||||
stringUTFChars(Thread* t, object string, char* chars, unsigned length);
|
||||
stringUTFChars(Thread* t, object string, unsigned start, unsigned length,
|
||||
char* chars, unsigned charsLength);
|
||||
|
||||
inline void
|
||||
stringUTFChars(Thread* t, object string, char* chars, unsigned charsLength)
|
||||
{
|
||||
stringUTFChars(t, string, 0, stringLength(t, string), chars, charsLength);
|
||||
}
|
||||
|
||||
bool
|
||||
isAssignableFrom(Thread* t, object a, object b);
|
||||
@ -2159,6 +2073,9 @@ emptyMethod(Thread* t, object method)
|
||||
and (codeBody(t, methodCode(t, method), 0) == return_);
|
||||
}
|
||||
|
||||
object
|
||||
parseUtf8(Thread* t, const char* data, unsigned length);
|
||||
|
||||
object
|
||||
parseClass(Thread* t, object loader, const uint8_t* data, unsigned length);
|
||||
|
||||
@ -2264,13 +2181,13 @@ findMethodInClass(Thread* t, object class_, object name, object spec)
|
||||
object
|
||||
findInHierarchy(Thread* t, object class_, object name, object spec,
|
||||
object (*find)(Thread*, object, object, object),
|
||||
object (*makeError)(Thread*, object));
|
||||
Machine::Type errorType);
|
||||
|
||||
inline object
|
||||
findMethod(Thread* t, object class_, object name, object spec)
|
||||
{
|
||||
return findInHierarchy
|
||||
(t, class_, name, spec, findMethodInClass, makeNoSuchMethodError);
|
||||
(t, class_, name, spec, findMethodInClass, Machine::NoSuchMethodErrorType);
|
||||
}
|
||||
|
||||
inline object
|
||||
@ -2690,10 +2607,12 @@ wait(Thread* t, object o, int64_t milliseconds)
|
||||
bool interrupted = monitorWait(t, m, milliseconds);
|
||||
|
||||
if (interrupted) {
|
||||
t->exception = makeInterruptedException(t);
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::InterruptedExceptionType);
|
||||
}
|
||||
} else {
|
||||
t->exception = makeIllegalMonitorStateException(t);
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::IllegalMonitorStateExceptionType);
|
||||
}
|
||||
|
||||
if (DebugMonitors) {
|
||||
@ -2722,7 +2641,8 @@ notify(Thread* t, object o)
|
||||
if (m and monitorOwner(t, m) == t) {
|
||||
monitorNotify(t, m);
|
||||
} else {
|
||||
t->exception = makeIllegalMonitorStateException(t);
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::IllegalMonitorStateExceptionType);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2739,7 +2659,8 @@ notifyAll(Thread* t, object o)
|
||||
if (m and monitorOwner(t, m) == t) {
|
||||
monitorNotifyAll(t, m);
|
||||
} else {
|
||||
t->exception = makeIllegalMonitorStateException(t);
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::IllegalMonitorStateExceptionType);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2756,6 +2677,7 @@ setDaemon(Thread* t, object thread, bool daemon)
|
||||
|
||||
if ((threadDaemon(t, thread) != 0) != daemon) {
|
||||
threadDaemon(t, thread) = daemon;
|
||||
t->daemon = daemon;
|
||||
|
||||
if (daemon) {
|
||||
++ t->m->daemonCount;
|
||||
@ -2947,7 +2869,7 @@ resolveClassInPool(Thread* t, object method, unsigned index)
|
||||
inline object
|
||||
resolve(Thread* t, object loader, object method, unsigned index,
|
||||
object (*find)(vm::Thread*, object, object, object),
|
||||
object (*makeError)(vm::Thread*, object))
|
||||
Machine::Type errorType)
|
||||
{
|
||||
object o = singletonObject(t, codePool(t, methodCode(t, method)), index);
|
||||
if (objectClass(t, o) == arrayBody(t, t->m->types, Machine::ReferenceType))
|
||||
@ -2962,7 +2884,7 @@ resolve(Thread* t, object loader, object method, unsigned index,
|
||||
|
||||
o = findInHierarchy
|
||||
(t, class_, referenceName(t, reference), referenceSpec(t, reference),
|
||||
find, makeError);
|
||||
find, errorType);
|
||||
if (UNLIKELY(t->exception)) return 0;
|
||||
|
||||
set(t, codePool(t, methodCode(t, method)),
|
||||
@ -2976,7 +2898,7 @@ inline object
|
||||
resolveField(Thread* t, object loader, object method, unsigned index)
|
||||
{
|
||||
return resolve(t, loader, method, index, findFieldInClass,
|
||||
makeNoSuchFieldError);
|
||||
Machine::NoSuchFieldErrorType);
|
||||
}
|
||||
|
||||
inline object
|
||||
@ -2990,7 +2912,7 @@ inline object
|
||||
resolveMethod(Thread* t, object loader, object method, unsigned index)
|
||||
{
|
||||
return resolve(t, loader, method, index, findMethodInClass,
|
||||
makeNoSuchMethodError);
|
||||
Machine::NoSuchMethodErrorType);
|
||||
}
|
||||
|
||||
inline object
|
||||
@ -3004,6 +2926,8 @@ inline object
|
||||
getJClass(Thread* t, object c)
|
||||
{
|
||||
if (classAddendum(t, c) == 0) {
|
||||
PROTECT(t, c);
|
||||
|
||||
ACQUIRE(t, t->m->classLock);
|
||||
|
||||
object addendum = makeClassAddendum(t, 0, 0, 0, 0);
|
||||
@ -3013,9 +2937,11 @@ getJClass(Thread* t, object c)
|
||||
|
||||
object jclass = classAddendumClass(t, classAddendum(t, c));
|
||||
if (jclass == 0) {
|
||||
PROTECT(t, c);
|
||||
|
||||
ACQUIRE(t, t->m->classLock);
|
||||
|
||||
jclass = makeJclass(t, c);
|
||||
jclass = t->m->classpath->makeJclass(t, c);
|
||||
|
||||
set(t, classAddendum(t, c), ClassAddendumClass, jclass);
|
||||
}
|
||||
@ -3023,6 +2949,29 @@ getJClass(Thread* t, object c)
|
||||
return jclass;
|
||||
}
|
||||
|
||||
inline object
|
||||
primitiveClass(Thread* t, char name)
|
||||
{
|
||||
switch (name) {
|
||||
case 'B': return arrayBody(t, t->m->types, Machine::JbyteType);
|
||||
case 'C': return arrayBody(t, t->m->types, Machine::JcharType);
|
||||
case 'D': return arrayBody(t, t->m->types, Machine::JdoubleType);
|
||||
case 'F': return arrayBody(t, t->m->types, Machine::JfloatType);
|
||||
case 'I': return arrayBody(t, t->m->types, Machine::JintType);
|
||||
case 'J': return arrayBody(t, t->m->types, Machine::JlongType);
|
||||
case 'S': return arrayBody(t, t->m->types, Machine::JshortType);
|
||||
case 'V': return arrayBody(t, t->m->types, Machine::JvoidType);
|
||||
case 'Z': return arrayBody(t, t->m->types, Machine::JbooleanType);
|
||||
default:
|
||||
t->exception = t->m->classpath->makeThrowable
|
||||
(t, Machine::IllegalArgumentExceptionType);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
object
|
||||
defineClass(Thread* t, object loader, const uint8_t* buffer, unsigned length);
|
||||
|
||||
void
|
||||
dumpHeap(Thread* t, FILE* out);
|
||||
|
||||
|
@ -755,7 +755,7 @@ class MySystem: public System {
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
// fprintf(stderr, "dlerror: %s\n", dlerror());
|
||||
fprintf(stderr, "dlerror: %s\n", dlerror());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -207,18 +207,17 @@ resolveNativeMethod(Thread* t, object method, const char* prefix,
|
||||
|
||||
namespace vm {
|
||||
|
||||
void*
|
||||
object
|
||||
resolveNativeMethod(Thread* t, object method)
|
||||
{
|
||||
void* p = ::resolveNativeMethod(t, method, "Avian_", 6, 3);
|
||||
if (p) {
|
||||
methodVmFlags(t, method) |= FastNative;
|
||||
return p;
|
||||
return makeNative(t, p, true);
|
||||
}
|
||||
|
||||
p = ::resolveNativeMethod(t, method, "Java_", 5, -1);
|
||||
if (p) {
|
||||
return p;
|
||||
return makeNative(t, p, false);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -56,7 +56,7 @@ isSpecialMethod(Thread* t, object method, object class_)
|
||||
and isSuperclass(t, methodClass(t, method), class_);
|
||||
}
|
||||
|
||||
void*
|
||||
object
|
||||
resolveNativeMethod(Thread* t, object method);
|
||||
|
||||
inline void
|
||||
|
@ -153,6 +153,10 @@ class Processor {
|
||||
walkContinuationBody(Thread* t, Heap::Walker* w, object o, unsigned start)
|
||||
= 0;
|
||||
|
||||
virtual void registerNative(Thread* t, object method, void* function) = 0;
|
||||
|
||||
virtual void unregisterNatives(Thread* t, object c) = 0;
|
||||
|
||||
object
|
||||
invoke(Thread* t, object method, object this_, ...)
|
||||
{
|
||||
|
@ -87,7 +87,7 @@ class System {
|
||||
|
||||
class Library {
|
||||
public:
|
||||
virtual void* resolve(const char* function) = 0;
|
||||
virtual void* resolve(const char* symbol) = 0;
|
||||
virtual const char* name() = 0;
|
||||
virtual bool mapName() = 0;
|
||||
virtual Library* next() = 0;
|
||||
|
@ -400,6 +400,8 @@ class Array : public Scalar {
|
||||
o->typeName = typeName;
|
||||
o->name = name;
|
||||
o->elementSize = elementSize;
|
||||
o->noassert = false;
|
||||
o->nogc = false;
|
||||
return o;
|
||||
}
|
||||
};
|
||||
@ -455,7 +457,7 @@ memberTypeName(Object* o)
|
||||
}
|
||||
}
|
||||
|
||||
const char*
|
||||
const char*&
|
||||
memberName(Object* o)
|
||||
{
|
||||
switch (o->type) {
|
||||
@ -987,8 +989,11 @@ class MemberIterator {
|
||||
|
||||
offset_ += padding_;
|
||||
|
||||
// printf("size: %d; padding: %d; alignment: %d; offset: %d;\n",
|
||||
// size_, padding_, alignment_, offset_);
|
||||
// fprintf(stderr,
|
||||
// "type: %s; member: %s; size: %d; padding: %d; alignment: %d;"
|
||||
// " offset: %d;\n",
|
||||
// typeName(type), memberName(member), size_, padding_, alignment_,
|
||||
// offset_);
|
||||
|
||||
return member;
|
||||
}
|
||||
@ -1087,6 +1092,27 @@ parseArray(Object* t, Object* p, Object* declarations)
|
||||
typeName, name, sizeOf(typeName, declarations));
|
||||
}
|
||||
|
||||
Object*
|
||||
parseMember(Object* t, Object* p, Object* declarations);
|
||||
|
||||
Object*
|
||||
parseMember(Object* t, Object* p, Object* declarations, bool* isNew)
|
||||
{
|
||||
Object* member = parseMember(t, p, declarations);
|
||||
for (MemberIterator it(t); it.hasMore();) {
|
||||
Object* m = it.next();
|
||||
if (equal(memberName(m), memberName(member))) {
|
||||
if (not equal(memberTypeName(m), memberTypeName(member))) {
|
||||
abort();
|
||||
}
|
||||
*isNew = false;
|
||||
return m;
|
||||
}
|
||||
}
|
||||
*isNew = true;
|
||||
return member;
|
||||
}
|
||||
|
||||
Object*
|
||||
parseMember(Object* t, Object* p, Object* declarations)
|
||||
{
|
||||
@ -1094,13 +1120,24 @@ parseMember(Object* t, Object* p, Object* declarations)
|
||||
if (equal(spec, "array")) {
|
||||
return parseArray(t, cdr(p), declarations);
|
||||
} else if (equal(spec, "noassert")) {
|
||||
Object* member = parseMember(t, cdr(p), declarations);
|
||||
bool isNew;
|
||||
Object* member = parseMember(t, cdr(p), declarations, &isNew);
|
||||
memberNoAssert(member) = true;
|
||||
return member;
|
||||
return isNew ? member : 0;
|
||||
} else if (equal(spec, "nogc")) {
|
||||
Object* member = parseMember(t, cdr(p), declarations);
|
||||
bool isNew;
|
||||
Object* member = parseMember(t, cdr(p), declarations, &isNew);
|
||||
memberNoGC(member) = true;
|
||||
return member;
|
||||
return isNew ? member : 0;
|
||||
} else if (equal(spec, "require")) {
|
||||
bool isNew;
|
||||
Object* member = parseMember(t, cdr(p), declarations, &isNew);
|
||||
return isNew ? member : 0;
|
||||
} else if (equal(spec, "alias")) {
|
||||
bool isNew;
|
||||
Object* member = parseMember(t, cdr(cdr(p)), declarations, &isNew);
|
||||
memberName(member) = string(car(cdr(p)));
|
||||
return isNew ? member : 0;
|
||||
} else {
|
||||
return Scalar::make(t, declaration(spec, declarations), spec,
|
||||
string(car(cdr(p))),
|
||||
@ -1120,7 +1157,9 @@ parseSubdeclaration(Object* t, Object* p, Object* declarations)
|
||||
assert(typeSuper(t)->type == Object::Type);
|
||||
} else {
|
||||
Object* member = parseMember(t, p, declarations);
|
||||
addMember(t, member);
|
||||
if (member) {
|
||||
addMember(t, member);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1311,14 +1350,6 @@ parseJavaClass(Object* type, Stream* s, Object* declarations)
|
||||
Object* member = Scalar::make
|
||||
(type, 0, memberType, name, sizeOf(memberType, declarations));
|
||||
|
||||
if (equal(typeJavaName(type), "java/lang/ref/Reference")
|
||||
and (equal(name, "vmNext")
|
||||
or equal(name, "target")
|
||||
or equal(name, "queue")))
|
||||
{
|
||||
memberNoGC(member) = true;
|
||||
}
|
||||
|
||||
addMember(type, member);
|
||||
}
|
||||
}
|
||||
@ -1379,8 +1410,10 @@ parseType(Object::ObjectType type, Object* p, Object* declarations,
|
||||
parseSubdeclaration(t, car(p), declarations);
|
||||
} else {
|
||||
Object* member = parseMember(t, car(p), declarations);
|
||||
assert(member->type == Object::Scalar);
|
||||
addMember(t, member);
|
||||
if (member) {
|
||||
assert(member->type == Object::Scalar);
|
||||
addMember(t, member);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,18 @@
|
||||
(type class avian/VMClass
|
||||
(array void* vtable))
|
||||
|
||||
(type jclass java/lang/Class)
|
||||
(type jclass java/lang/Class
|
||||
(require object vmClass))
|
||||
|
||||
(type jaccessibleObject java/lang/reflect/AccessibleObject)
|
||||
|
||||
(type jfield java/lang/reflect/Field)
|
||||
|
||||
(type jmethod java/lang/reflect/Method)
|
||||
|
||||
(type jconstructor java/lang/reflect/Constructor)
|
||||
|
||||
(type constantPool sun/reflect/ConstantPool)
|
||||
|
||||
(type singleton
|
||||
(array uintptr_t body))
|
||||
@ -22,6 +33,10 @@
|
||||
|
||||
(type classAddendum avian/ClassAddendum)
|
||||
|
||||
(type methodAddendum avian/MethodAddendum)
|
||||
|
||||
(type fieldAddendum avian/FieldAddendum)
|
||||
|
||||
(type nativeMethodData
|
||||
(void* function)
|
||||
(uint16_t argumentTableSize)
|
||||
@ -30,6 +45,10 @@
|
||||
(type pointer
|
||||
(void* value))
|
||||
|
||||
(type native
|
||||
(void* function)
|
||||
(uint8_t fast))
|
||||
|
||||
(pod exceptionHandler
|
||||
(uint16_t start)
|
||||
(uint16_t end)
|
||||
@ -142,15 +161,23 @@
|
||||
|
||||
(type callbackReceiver avian/CallbackReceiver)
|
||||
|
||||
(type string java/lang/String)
|
||||
(type string java/lang/String
|
||||
(alias data object value)
|
||||
(alias length uint32_t count)
|
||||
(alias hashCode uint32_t hash))
|
||||
|
||||
(type thread java/lang/Thread)
|
||||
(type thread java/lang/Thread
|
||||
(require object sleepLock)
|
||||
(require uint8_t interrupted)
|
||||
(alias peer uint64_t eetop))
|
||||
|
||||
(type threadGroup java/lang/ThreadGroup)
|
||||
|
||||
(type stackTraceElement java/lang/StackTraceElement)
|
||||
|
||||
(type throwable java/lang/Throwable)
|
||||
(type throwable java/lang/Throwable
|
||||
(alias message object detailMessage)
|
||||
(alias trace object backtrace))
|
||||
|
||||
(type exception java/lang/Exception)
|
||||
|
||||
@ -184,6 +211,8 @@
|
||||
|
||||
(type virtualMachineError java/lang/VirtualMachineError)
|
||||
|
||||
(type outOfMemoryError java/lang/OutOfMemoryError)
|
||||
|
||||
(type stackOverflowError java/lang/StackOverflowError)
|
||||
|
||||
(type linkageError java/lang/LinkageError)
|
||||
@ -221,9 +250,17 @@
|
||||
|
||||
(type double java/lang/Double)
|
||||
|
||||
(type referenceQueue java/lang/ref/ReferenceQueue)
|
||||
(type referenceQueue java/lang/ref/ReferenceQueue
|
||||
(alias front object head))
|
||||
|
||||
(type jreference java/lang/ref/Reference)
|
||||
(type jreference java/lang/ref/Reference
|
||||
(alias target object referent)
|
||||
(alias queue object queue)
|
||||
(alias jNext object next)
|
||||
(alias vmNext object discovered)
|
||||
(nogc object target)
|
||||
(nogc object queue)
|
||||
(nogc object vmNext))
|
||||
|
||||
(type weakReference java/lang/ref/WeakReference)
|
||||
|
||||
|
@ -4,6 +4,7 @@ log=build/log.txt
|
||||
vg="nice valgrind --leak-check=full --num-callers=32 \
|
||||
--freelist-vol=100000000 --error-exitcode=1"
|
||||
|
||||
library_path=${1}; shift
|
||||
vm=${1}; shift
|
||||
mode=${1}; shift
|
||||
flags=${1}; shift
|
||||
@ -18,10 +19,11 @@ for test in ${tests}; do
|
||||
|
||||
case ${mode} in
|
||||
debug|debug-fast|fast|small )
|
||||
${vm} ${flags} ${test} >>${log} 2>&1;;
|
||||
LD_LIBRARY_PATH=${library_path} ${vm} ${flags} ${test} >>${log} 2>&1;;
|
||||
|
||||
stress* )
|
||||
${vg} ${vm} ${flags} ${test} >>${log} 2>&1;;
|
||||
LD_LIBRARY_PATH=${library_path} ${vg} ${vm} ${flags} ${test} \
|
||||
>>${log} 2>&1;;
|
||||
|
||||
* )
|
||||
echo "unknown mode: ${mode}" >&2
|
||||
|
Loading…
Reference in New Issue
Block a user