Merge branch 'oss-master'

This commit is contained in:
Joel Dice 2011-07-08 16:11:50 -06:00
commit 381165f26d
76 changed files with 6364 additions and 1506 deletions

View File

@ -12,5 +12,6 @@ package avian;
public class Addendum {
public Object pool;
public Object annotationTable;
public Object annotationTable;
public Object signature;
}

View File

@ -10,4 +10,8 @@
package avian;
public class ClassAddendum extends Addendum { }
public class ClassAddendum extends Addendum {
public Object[] interfaceTable;
public Object[] innerClassTable;
public Object[] methodTable;
}

View File

@ -26,8 +26,6 @@ public class Classes {
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);
@ -53,7 +51,7 @@ public class Classes {
return c;
} catch (ClassNotFoundException e) {
NoClassDefFoundError error = new NoClassDefFoundError
(new String(nameBytes, offset, length, false));
(new String(nameBytes, offset, length));
error.initCause(e);
throw error;
}
@ -96,7 +94,7 @@ public class Classes {
case 's': {
byte[] data = (byte[]) Singleton.getObject(pool, read2(in) - 1);
return new String(data, 0, data.length - 1, false);
return new String(data, 0, data.length - 1);
}
case 'e': {
@ -106,7 +104,7 @@ public class Classes {
return Enum.valueOf
(SystemClassLoader.getClass
(loadVMClass(loader, typeName, 1, typeName.length - 3)),
new String(name, 0, name.length - 1, false));
new String(name, 0, name.length - 1));
}
case 'c':{
@ -143,7 +141,7 @@ public class Classes {
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] = new String(name, 0, name.length - 1);
annotation[i + 1] = parseAnnotationValue(loader, pool, in);
}

View File

@ -12,4 +12,5 @@ package avian;
public class MethodAddendum extends Addendum {
public Object exceptionTable;
public Object annotationDefault;
}

View File

@ -10,14 +10,55 @@
package avian;
import java.net.URL;
import java.net.MalformedURLException;
import java.security.CodeSource;
import java.security.AllPermission;
import java.security.Permissions;
import java.security.ProtectionDomain;
import java.security.cert.Certificate;
public class OpenJDK {
public static ProtectionDomain getProtectionDomain() {
public static ProtectionDomain getProtectionDomain(VMClass c) {
CodeSource source = null;
if (c.source != null) {
try {
source = new CodeSource
(new URL(new String(c.source, 0, c.source.length - 1)),
(Certificate[]) null);
} catch (MalformedURLException ignored) { }
}
Permissions p = new Permissions();
p.add(new AllPermission());
return new ProtectionDomain(null, p);
return new ProtectionDomain(source, p);
}
private static byte[] replace(int a, int b, byte[] s, int offset,
int length)
{
byte[] array = new byte[length];
for (int i = 0; i < length; ++i) {
byte c = s[i];
array[i] = (byte) (c == a ? b : c);
}
return array;
}
public static Class getDeclaringClass(VMClass c) {
try {
String name = new String
(replace('/', '.', c.name, 0, c.name.length - 1), 0,
c.name.length - 1);
int index = name.lastIndexOf("$");
if (index == -1) {
return null;
} else {
return c.loader.loadClass(name.substring(0, index));
}
} catch (ClassNotFoundException e) {
return null;
}
}
}

View File

@ -12,6 +12,7 @@ package avian;
import java.net.URL;
import java.net.MalformedURLException;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.ArrayList;
@ -34,17 +35,59 @@ public class SystemClassLoader extends ClassLoader {
return c == null ? null : getClass(c);
}
private native boolean resourceExists(String name);
private native String resourceURLPrefix(String name);
protected URL findResource(String name) {
if (resourceExists(name)) {
String prefix = resourceURLPrefix(name);
if (prefix != null) {
try {
return new URL("resource:" + name);
return new URL(prefix + name);
} catch (MalformedURLException ignored) { }
}
return null;
}
// OpenJDK's java.lang.ClassLoader.getResource makes use of
// sun.misc.Launcher to load bootstrap resources, which is not
// appropriate for the Avian build, so we override it to ensure we
// get the behavior we want. This implementation is the same as
// that of Avian's java.lang.ClassLoader.getResource.
public URL getResource(String path) {
URL url = null;
ClassLoader parent = getParent();
if (parent != null) {
url = parent.getResource(path);
}
if (url == null) {
url = findResource(path);
}
return url;
}
// As above, we override this method to avoid inappropriate behavior
// in OpenJDK's java.lang.ClassLoader.getResources.
public Enumeration<URL> getResources(String name) throws IOException {
Collection<URL> urls = new ArrayList<URL>(5);
ClassLoader parent = getParent();
if (parent != null) {
for (Enumeration<URL> e = parent.getResources(name);
e.hasMoreElements();)
{
urls.add(e.nextElement());
}
}
URL url = findResource(name);
if (url != null) {
urls.add(url);
}
return Collections.enumeration(urls);
}
protected Enumeration<URL> findResources(String name) {
Collection<URL> urls = new ArrayList(1);
URL url = findResource(name);

View File

@ -25,7 +25,8 @@ public class VMClass {
public VMMethod[] virtualTable;
public VMField[] fieldTable;
public VMMethod[] methodTable;
public avian.ClassAddendum addendum;
public ClassAddendum addendum;
public Object staticTable;
public ClassLoader loader;
public byte[] source;
}

View File

@ -15,6 +15,7 @@ public class VMField {
public byte code;
public short flags;
public short offset;
public int nativeID;
public byte[] name;
public byte[] spec;
public FieldAddendum addendum;

View File

@ -0,0 +1,44 @@
/* Copyright (c) 2011, 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.file;
import java.net.URL;
import java.net.URLStreamHandler;
import java.net.URLConnection;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class Handler extends URLStreamHandler {
protected URLConnection openConnection(URL url) {
return new FileURLConnection(url);
}
private static class FileURLConnection extends URLConnection {
public FileURLConnection(URL url) {
super(url);
}
public int getContentLength() {
return (int) new File(url.getFile()).length();
}
public InputStream getInputStream() throws IOException {
return new FileInputStream(url.getFile());
}
public void connect() {
// ignore
}
}
}

View File

@ -0,0 +1,84 @@
/* Copyright (c) 2011, 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.jar;
import java.net.URL;
import java.net.MalformedURLException;
import java.net.URLStreamHandler;
import java.net.JarURLConnection;
import java.net.URLConnection;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.jar.JarFile;
import java.util.jar.JarEntry;
public class Handler extends URLStreamHandler {
protected URLConnection openConnection(URL url) {
return new MyJarURLConnection(url);
}
protected void parseURL(URL url, String s, int start, int end)
throws MalformedURLException
{
// skip "jar:"
s = s.toString().substring(4);
int index = s.indexOf("!/");
if (index < 0) {
throw new MalformedURLException();
}
URL file = new URL(s.substring(0, index));
if (! "file".equals(file.getProtocol())) {
throw new RuntimeException
("protocol " + file.getProtocol() + " not yet supported");
}
url.set("jar", "", -1, s, null);
}
private static class MyJarURLConnection extends JarURLConnection {
private final JarFile file;
private final JarEntry entry;
public MyJarURLConnection(URL url) {
super(url);
String s = url.getFile();
int index = s.indexOf("!/");
try {
this.file = new JarFile(new URL(s.substring(0, index)).getFile());
this.entry = this.file.getJarEntry(s.substring(index + 2));
} catch (MalformedURLException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public JarFile getJarFile() throws IOException {
return file;
}
public int getContentLength() {
return entry.getSize();
}
public InputStream getInputStream() throws IOException {
return file.getInputStream(entry);
}
public void connect() {
// ignore
}
}
}

View File

@ -17,6 +17,7 @@
#include "jni-util.h"
#include "errno.h"
#include "fcntl.h"
#include "ctype.h"
#ifdef PLATFORM_WINDOWS
@ -128,6 +129,61 @@ namespace {
#endif
}
class Locale { // represents an ISO two-char language/country pair
static const unsigned FIELDLEN = 2;
static const unsigned FIELDSIZE = FIELDLEN + 1;
static const char* DEFAULT_LANGUAGE;
static const char* DEFAULT_REGION;
char language[FIELDSIZE];
char region[FIELDSIZE];
bool isLanguage(const char* language) {
if (!language) return false;
unsigned len = strlen(language);
if (len != FIELDLEN) return false;
const char* p = language - 1;
while (islower(*++p)) ;
if (*p != '\0') return false;
return true;
}
bool isRegion(const char* region) {
if (!region) return false;
unsigned len = strlen(region);
if (len != FIELDLEN) return false;
const char* p = region - 1;
while (isupper(*++p)) ;
if (*p != '\0') return false;
return true;
}
public:
Locale(const char* language = "") {
Locale l(language, "");
*this = l;
}
Locale(const char* language, const char* region) {
language = isLanguage(language) ? language : DEFAULT_LANGUAGE;
region = isRegion(region) ? region : DEFAULT_REGION;
memcpy(this->language, language, FIELDSIZE);
memcpy(this->region, region, FIELDSIZE);
}
Locale& operator=(const Locale& l) {
memcpy(language, l.language, FIELDSIZE);
memcpy(region, l.region, FIELDSIZE);
return *this;
}
const char* getLanguage() { return reinterpret_cast<const char*>(language); }
const char* getRegion() { return reinterpret_cast<const char*>(region); }
};
const char* Locale::DEFAULT_LANGUAGE = "en";
const char* Locale::DEFAULT_REGION = "";
#ifdef PLATFORM_WINDOWS
extern "C" JNIEXPORT void JNICALL
Java_java_lang_Runtime_exec(JNIEnv* e, jclass,
@ -221,6 +277,82 @@ Java_java_lang_Runtime_waitFor(JNIEnv* e, jclass, jlong pid, jlong tid)
return exitCode;
}
Locale getLocale() {
const char* lang = "";
const char* reg = "";
unsigned langid = GetUserDefaultUILanguage();
unsigned prilang = langid & 0x3ff;
unsigned sublang = langid >> 10;
switch (prilang) {
case 0x004: {
lang = "zh";
switch (sublang) {
case 0x01: reg = "CN"; break;
case 0x02: reg = "TW"; break;
case 0x03: reg = "HK"; break;
case 0x04: reg = "SG"; break;
}
} break;
case 0x006: lang = "da"; reg = "DK"; break;
case 0x007: lang = "de"; reg = "DE"; break;
case 0x009: {
lang = "en";
switch (sublang) {
case 0x01: reg = "US"; break;
case 0x02: reg = "GB"; break;
case 0x03: reg = "AU"; break;
case 0x04: reg = "CA"; break;
case 0x05: reg = "NZ"; break;
case 0x06: reg = "IE"; break;
case 0x07: reg = "ZA"; break;
case 0x10: reg = "IN"; break;
}
} break;
case 0x00a: {
lang = "es";
switch (sublang) {
case 0x01: case 0x03: reg = "ES"; break;
case 0x02: reg = "MX"; break;
}
} break;
case 0x00c: {
lang = "fr";
switch (sublang) {
case 0x01: reg = "FR"; break;
case 0x02: reg = "BE"; break;
case 0x03: reg = "CA"; break;
}
} break;
case 0x010: lang = "it"; reg = "IT"; break;
case 0x011: lang = "ja"; reg = "JP"; break;
case 0x012: lang = "ko"; reg = "KR"; break;
case 0x013: {
lang = "nl";
switch (sublang) {
case 0x01: reg = "NL"; break;
case 0x02: reg = "BE"; break;
}
} break;
case 0x014: lang = "no"; reg = "NO"; break;
case 0x015: lang = "pl"; reg = "PL"; break;
case 0x016: {
lang = "pt";
switch (sublang) {
case 0x01: reg = "BR"; break;
case 0x02: reg = "PT"; break;
}
} break;
case 0x018: lang = "ro"; reg = "RO"; break;
case 0x019: lang = "ru"; reg = "RU"; break;
case 0x01d: lang = "sv"; reg = "SE"; break;
default: lang = "en";
}
Locale locale(lang, reg);
return locale;
}
#else
extern "C" JNIEXPORT void JNICALL
Java_java_lang_Runtime_exec(JNIEnv* e, jclass,
@ -331,6 +463,32 @@ Java_java_lang_Runtime_waitFor(JNIEnv*, jclass, jlong pid, jlong)
return exitCode;
}
Locale getLocale() {
Locale fallback;
const char* LANG = getenv("LANG");
if (!LANG || strcmp(LANG, "C") == 0) return fallback;
int len = strlen(LANG);
char buf[len + 1]; // + 1 for the '\0' char
memcpy(buf, LANG, len + 1);
char* tracer = buf;
const char* reg;
while (*tracer && *tracer != '_') ++tracer;
if (!*tracer) return fallback;
*tracer = '\0';
reg = ++tracer;
while (*tracer && *tracer != '.') ++tracer;
if (tracer == reg) return fallback;
*tracer = '\0';
Locale locale(buf, reg);
return locale;
}
#endif
extern "C" JNIEXPORT jstring JNICALL
@ -437,6 +595,13 @@ Java_java_lang_System_getProperty(JNIEnv* e, jclass, jstring name,
r = e->NewStringUTF(getenv("HOME"));
}
#endif
else if (strcmp(chars, "user.language") == 0) {
Locale locale = getLocale();
if (strlen(locale.getLanguage())) r = e->NewStringUTF(locale.getLanguage());
} else if (strcmp(chars, "user.region") == 0) {
Locale locale = getLocale();
if (strlen(locale.getRegion())) r = e->NewStringUTF(locale.getRegion());
}
e->ReleaseStringUTFChars(name, chars);
}

View File

@ -121,7 +121,7 @@ Java_java_util_zip_Deflater_deflate
(JNIEnv* e, jclass, jlong peer,
jbyteArray input, jint inputOffset, jint inputLength,
jbyteArray output, jint outputOffset, jint outputLength,
jintArray results)
jboolean finish, jintArray results)
{
z_stream* s = reinterpret_cast<z_stream*>(peer);
@ -145,7 +145,7 @@ Java_java_util_zip_Deflater_deflate
s->next_out = reinterpret_cast<Bytef*>(out);
s->avail_out = outputLength;
int r = deflate(s, Z_SYNC_FLUSH);
int r = deflate(s, finish ? Z_FINISH : Z_NO_FLUSH);
jint resultArray[3]
= { r, inputLength - s->avail_in, outputLength - s->avail_out };

View File

@ -98,6 +98,10 @@ public class ByteArrayOutputStream extends OutputStream {
return array;
}
public String toString(String encoding) throws UnsupportedEncodingException {
return new String(toByteArray(), encoding);
}
private static class Cell {
public byte[] array;
public int offset;

View File

@ -10,7 +10,7 @@
package java.io;
public class File {
public class File implements Serializable {
private static final String FileSeparator
= System.getProperty("file.separator");
@ -82,6 +82,10 @@ public class File {
}
}
public String toString() {
return getPath();
}
public String getPath() {
return path;
}

View File

@ -0,0 +1,40 @@
/* Copyright (c) 2011, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
public class FilterOutputStream extends OutputStream {
protected OutputStream out;
public FilterOutputStream(OutputStream out) {
this.out = out;
}
public void close() throws IOException {
out.close();
}
public void flush() throws IOException {
out.flush();
}
public void write(byte[] b) throws IOException {
out.write(b);
}
public void write(byte[] b, int off, int len) throws IOException {
out.write(b, off, len);
}
public void write(int b) throws IOException {
out.write(b);
}
}

View File

@ -10,6 +10,8 @@
package java.io;
import avian.VMClass;
import java.util.HashMap;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
@ -110,7 +112,7 @@ public class ObjectInputStream extends InputStream {
StringBuilder sb = new StringBuilder();
int c;
while ((c = r.read()) != -1 && ! Character.isWhitespace((char) c)) {
while ((c = r.read()) != -1 && ! Character.isWhitespace((char) c) && c != ')') {
sb.append((char) c);
}
if (c != -1) {
@ -149,7 +151,6 @@ public class ObjectInputStream extends InputStream {
throws IOException, ClassNotFoundException
{
skipSpace();
switch (r.read()) {
case 'a':
return deserializeArray(map);
@ -203,7 +204,7 @@ public class ObjectInputStream extends InputStream {
return o;
}
private static native Object makeInstance(Class c);
private static native Object makeInstance(VMClass c);
private Object deserializeObject(HashMap<Integer, Object> map)
throws IOException, ClassNotFoundException
@ -211,11 +212,11 @@ public class ObjectInputStream extends InputStream {
read('(');
int id = (int) readLongToken();
Class c = Class.forName(readStringToken());
Object o = makeInstance(c);
Object o = makeInstance(c.vmClass);
map.put(id, o);
for (Field f: c.getFields()) {
for (Field f: c.getAllFields()) {
int modifiers = f.getModifiers();
if ((modifiers & (Modifier.TRANSIENT | Modifier.STATIC)) == 0) {
try {

View File

@ -39,7 +39,7 @@ public class ObjectOutputStream extends OutputStream {
}
public void writeObject(Object o) throws IOException {
writeObject(o, new IdentityHashMap(), 0);
writeObject(o, new IdentityHashMap(), new int[] {0});
}
public void writeBoolean(boolean v) {
@ -87,7 +87,7 @@ public class ObjectOutputStream extends OutputStream {
}
private void writeObject(Object o, IdentityHashMap<Object, Integer> map,
int nextId)
int[] nextId)
throws IOException
{
if (o == null) {
@ -95,7 +95,7 @@ public class ObjectOutputStream extends OutputStream {
} else {
Integer id = map.get(o);
if (id == null) {
map.put(o, nextId);
map.put(o, nextId[0]);
Class c = o.getClass();
if (c.isArray()) {
@ -113,7 +113,7 @@ public class ObjectOutputStream extends OutputStream {
}
private void serializeArray(Object o, IdentityHashMap<Object, Integer> map,
int nextId)
int[] nextId)
throws IOException
{
Class c = o.getClass();
@ -121,7 +121,7 @@ public class ObjectOutputStream extends OutputStream {
int length = Array.getLength(o);
out.print("a(");
out.print(nextId++);
out.print(nextId[0]++);
out.print(" ");
out.print(c.getName());
out.print(" ");
@ -155,17 +155,17 @@ public class ObjectOutputStream extends OutputStream {
}
private void serializeObject(Object o, IdentityHashMap<Object, Integer> map,
int nextId)
int[] nextId)
throws IOException
{
Class c = o.getClass();
out.print("l(");
out.print(nextId++);
out.print(nextId[0]++);
out.print(" ");
out.print(c.getName());
for (Field f: c.getFields()) {
for (Field f: c.getAllFields()) {
int modifiers = f.getModifiers();
if ((modifiers & (Modifier.TRANSIENT | Modifier.STATIC)) == 0) {
out.print(" ");

View File

@ -29,6 +29,7 @@ import java.lang.annotation.Annotation;
import java.io.InputStream;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.security.ProtectionDomain;
@ -424,6 +425,25 @@ public final class Class <T> implements Type, AnnotatedElement {
return array;
}
private static void getAllFields(VMClass vmClass, ArrayList<Field> fields) {
if (vmClass.super_ != null) {
getAllFields(vmClass.super_, fields);
}
if (vmClass.fieldTable != null) {
Classes.link(vmClass);
for (int i = 0; i < vmClass.fieldTable.length; ++i) {
fields.add(new Field(vmClass.fieldTable[i]));
}
}
}
public Field[] getAllFields() {
ArrayList<Field> fields = new ArrayList<Field>();
getAllFields(vmClass, fields);
return fields.toArray(new Field[fields.size()]);
}
private int countMethods(boolean publicOnly) {
int count = 0;
if (vmClass.methodTable != null) {
@ -515,7 +535,7 @@ public final class Class <T> implements Type, AnnotatedElement {
}
public Class getSuperclass() {
return SystemClassLoader.getClass(vmClass.super_);
return (vmClass.super_ == null ? null : SystemClassLoader.getClass(vmClass.super_));
}
public boolean isArray() {

View File

@ -93,7 +93,7 @@ public abstract class ClassLoader {
avian.Classes.link(c.vmClass, this);
}
private ClassLoader getParent() {
public final ClassLoader getParent() {
return parent;
}

View File

@ -494,6 +494,42 @@ public final class String
public String replaceAll(String regex, String replacement) {
return Pattern.compile(regex).matcher(this).replaceAll(replacement);
}
public String replace(CharSequence target, CharSequence replace) {
if (target.length() == 0) {
return this.infuse(replace.toString());
}
String targetString = target.toString();
String replaceString = replace.toString();
int targetSize = target.length();
StringBuilder returnValue = new StringBuilder();
String unhandled = this;
int index = -1;
while ((index = unhandled.indexOf(targetString)) != -1) {
returnValue.append(unhandled.substring(0, index)).append(replaceString);
unhandled = unhandled.substring(index + targetSize,
unhandled.length());
}
returnValue.append(unhandled);
return returnValue.toString();
}
private String infuse(String infuseWith) {
StringBuilder retVal = new StringBuilder();
String me = this;
for (int i = 0; i < me.length(); i++) {
retVal.append(infuseWith).append(me.substring(i, i + 1));
}
retVal.append(infuseWith);
return retVal.toString();
}
public native String intern();

View File

@ -20,6 +20,8 @@ import java.io.FileDescriptor;
import java.util.Properties;
public abstract class System {
private static final long NanoTimeBaseInMillis = currentTimeMillis();
private static Property properties;
private static SecurityManager securityManager;
@ -94,6 +96,10 @@ public abstract class System {
public static native int identityHashCode(Object o);
public static long nanoTime() {
return (currentTimeMillis() - NanoTimeBaseInMillis) * 1000000;
}
public static String mapLibraryName(String name) {
if (name != null) {
return doMapLibraryName(name);

View File

@ -205,7 +205,7 @@ public class Field<T> extends AccessibleObject {
} else {
throw new IllegalArgumentException
("needed " + getType() + ", got "
+ Class.getName(Classes.vmClass(target)) +
+ value.getClass().getName() +
" when setting " + Class.getName(vmField.class_) + "." + getName());
}
break;

View File

@ -11,5 +11,5 @@
package java.lang.reflect;
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] arguments);
public Object invoke(Object proxy, Method method, Object[] arguments) throws Throwable;
}

View File

@ -0,0 +1,22 @@
/* Copyright (c) 2011, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.net;
import java.io.IOException;
import java.util.jar.JarFile;
public abstract class JarURLConnection extends URLConnection {
public JarURLConnection(URL url) {
super(url);
}
public abstract JarFile getJarFile() throws IOException;
}

View File

@ -73,13 +73,17 @@ public final class URL {
{
if ("resource".equals(protocol)) {
return new avian.resource.Handler();
} else if ("file".equals(protocol)) {
return new avian.file.Handler();
} else if ("jar".equals(protocol)) {
return new avian.jar.Handler();
} else {
throw new MalformedURLException("unknown protocol: " + protocol);
}
}
protected void set(String protocol, String host, int port, String file,
String ref)
public void set(String protocol, String host, int port, String file,
String ref)
{
this.protocol = protocol;
this.host = host;

View File

@ -13,7 +13,9 @@ package java.net;
import java.io.IOException;
public abstract class URLStreamHandler {
protected void parseURL(URL url, String s, int start, int end) {
protected void parseURL(URL url, String s, int start, int end)
throws MalformedURLException
{
String protocol = s.substring(0, start - 1);
s = s.substring(start, end);

View File

@ -10,4 +10,17 @@
package java.security;
public class CodeSource { }
import java.net.URL;
import java.security.cert.Certificate;
public class CodeSource {
private final URL url;
public CodeSource(URL url, Certificate[] certificates) {
this.url = url;
}
public URL getLocation() {
return url;
}
}

View File

@ -20,4 +20,8 @@ public class ProtectionDomain {
this.codeSource = codeSource;
this.permissions = permissions;
}
public CodeSource getCodeSource() {
return codeSource;
}
}

View File

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

View File

@ -10,7 +10,7 @@
package java.util;
public class ArrayList<T> extends AbstractList<T> {
public class ArrayList<T> extends AbstractList<T> implements java.io.Serializable {
private static final int MinimumCapacity = 16;
private Object[] array;

View File

@ -52,6 +52,23 @@ public class Collections {
return array;
}
public static final List EMPTY_LIST
= new UnmodifiableList<Object>(new ArrayList<Object>(0));
public static final <E> List<E> emptyList() {
return EMPTY_LIST;
}
public static final <K,V> Map<K,V> emptyMap() {
return (Map<K, V>) new UnmodifiableMap<Object, Object>(
new HashMap<Object, Object>(0));
}
public static final <T> Set<T> emptySet() {
return (Set<T>) new UnmodifiableSet<Object>(
new HashSet<Object>(0));
}
static String toString(Collection c) {
StringBuilder sb = new StringBuilder();
sb.append("[");
@ -293,8 +310,153 @@ public class Collections {
}
}
public static <T> List<T> unmodifiableList(List<T> list) {
return new UnmodifiableList<T>(list);
}
static class UnmodifiableList<T> implements List<T> {
private List<T> inner;
UnmodifiableList(List<T> l) {
this.inner = l;
}
public T get(int index) {
return inner.get(index);
}
public T set(int index, T value) {
throw new UnsupportedOperationException("not supported");
}
public T remove(int index) {
throw new UnsupportedOperationException("not supported");
}
public boolean remove(Object o) {
throw new UnsupportedOperationException("not supported");
}
public boolean add(T element) {
throw new UnsupportedOperationException("not supported");
}
public void add(int index, T element) {
throw new UnsupportedOperationException("not supported");
}
public Iterator<T> iterator() {
return inner.iterator();
}
public int indexOf(Object value) {
return inner.indexOf(value);
}
public int lastIndexOf(Object value) {
return inner.lastIndexOf(value);
}
public boolean isEmpty() {
return inner.isEmpty();
}
public ListIterator<T> listIterator(int index) {
return inner.listIterator(index);
}
public ListIterator<T> listIterator() {
return inner.listIterator();
}
public int size() {
return inner.size();
}
public boolean contains(Object element) {
return inner.contains(element);
}
public boolean addAll(Collection<? extends T> collection) {
throw new UnsupportedOperationException("not supported");
}
public Object[] toArray() {
return inner.toArray();
}
public <S> S[] toArray(S[] array) {
return inner.toArray(array);
}
public void clear() {
throw new UnsupportedOperationException("not supported");
}
}
public static <K,V> Map<K,V> unmodifiableMap(Map<K,V> m) {
return new UnmodifiableMap<K, V>(m);
}
static class UnmodifiableMap<K, V> implements Map<K, V> {
private Map<K, V> inner;
UnmodifiableMap(Map<K, V> m) {
this.inner = m;
}
public void clear() {
throw new UnsupportedOperationException("not supported");
}
public boolean containsKey(Object key) {
return inner.containsKey(key);
}
public boolean containsValue(Object value) {
return inner.containsValue(value);
}
public Set<Map.Entry<K, V>> entrySet() {
return unmodifiableSet(inner.entrySet());
}
public V get(Object key) {
return inner.get(key);
}
public boolean isEmpty() {
return inner.isEmpty();
}
public Set<K> keySet() {
return unmodifiableSet(inner.keySet());
}
public V put(K key, V value) {
throw new UnsupportedOperationException("not supported");
}
public void putAll(Map<? extends K, ? extends V> t) {
throw new UnsupportedOperationException("not supported");
}
public V remove(Object key) {
throw new UnsupportedOperationException("not supported");
}
public int size() {
return inner.size();
}
public Collection<V> values() {
return unmodifiableSet((Set<V>)inner.values());
}
}
static class UnmodifiableSet<T> implements Set<T> {
Set<T> inner;
private Set<T> inner;
UnmodifiableSet(Set<T> inner) {
this.inner = inner;
@ -396,7 +558,5 @@ public class Collections {
public int compare(T o1, T o2) {
return - cmp.compare(o1, o2);
}
}
}

View File

@ -11,12 +11,18 @@
package java.util;
public class Locale {
public static final Locale ENGLISH = new Locale("en", "us");
private static final Locale DEFAULT;
public static final Locale ENGLISH = new Locale("en", "");
private final String language;
private final String country;
private final String variant;
static {
DEFAULT = new Locale(System.getProperty("user.language"),
System.getProperty("user.region"));
}
public Locale(String language, String country, String variant) {
this.language = language;
this.country = country;
@ -24,11 +30,11 @@ public class Locale {
}
public Locale(String language, String country) {
this(language, country, null);
this(language, country, "");
}
public Locale(String language) {
this(language, null);
this(language, "");
}
public String getLanguage() {
@ -44,6 +50,15 @@ public class Locale {
}
public static Locale getDefault() {
return ENGLISH;
return DEFAULT;
}
public final String toString() {
boolean hasLanguage = language != "";
boolean hasCountry = country != "";
boolean hasVariant = variant != "";
if (!hasLanguage && !hasCountry) return "";
return language + (hasCountry || hasVariant ? '_' + country : "") + (hasVariant ? '_' + variant : "");
}
}

View File

@ -85,7 +85,18 @@ public class Properties extends Hashtable {
}
abstract int readCharacter() throws IOException;
char readUtf16() throws IOException {
char c = 0;
for (int i = 0; i < 4; ++i) {
int digit = Character.digit((char)readCharacter(), 16);
if (digit == -1) throw new IOException("Invalid Unicode escape encountered.");
c <<= 4;
c |= digit;
}
return c;
}
void parse(Map map)
throws IOException
{
@ -148,6 +159,13 @@ public class Properties extends Hashtable {
}
break;
case 'u':
if (escaped) {
append(readUtf16());
} else {
append(c);
} break;
default:
append(c);
break;

View File

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

View File

@ -10,7 +10,7 @@
package java.util;
public class Vector<T> extends AbstractList<T> {
public class Vector<T> extends AbstractList<T> implements java.io.Serializable {
private final ArrayList<T> list;
public Vector(int capacity) {
@ -81,6 +81,10 @@ public class Vector<T> extends AbstractList<T> {
remove(index);
}
public synchronized void removeAllElements() {
list.clear();
}
public synchronized boolean remove(Object element) {
return list.remove(element);
}

View File

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

View File

@ -0,0 +1,81 @@
/* Copyright (c) 2011, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.util.jar;
import java.io.File;
import java.io.IOException;
import java.util.Enumeration;
import java.util.zip.ZipFile;
import java.util.zip.ZipEntry;
public class JarFile extends ZipFile {
public JarFile(String name) throws IOException {
super(name);
}
public JarFile(File file) throws IOException {
super(file);
}
public Enumeration<JarEntry> entries() {
return (Enumeration<JarEntry>) makeEnumeration(JarEntryFactory.Instance);
}
public JarEntry getJarEntry(String name) {
return (JarEntry) getEntry(JarEntryFactory.Instance, name);
}
private static class MyJarEntry extends JarEntry implements MyEntry {
public final Window window;
public final int pointer;
public MyJarEntry(Window window, int pointer) {
this.window = window;
this.pointer = pointer;
}
public String getName() {
try {
return entryName(window, pointer);
} catch (IOException e) {
return null;
}
}
public int getCompressedSize() {
try {
return compressedSize(window, pointer);
} catch (IOException e) {
return 0;
}
}
public int getSize() {
try {
return uncompressedSize(window, pointer);
} catch (IOException e) {
return 0;
}
}
public int pointer() {
return pointer;
}
}
private static class JarEntryFactory implements EntryFactory {
public static final JarEntryFactory Instance = new JarEntryFactory();
public ZipEntry makeEntry(Window window, int pointer) {
return new MyJarEntry(window, pointer);
}
}
}

View File

@ -0,0 +1,69 @@
/* Copyright (c) 2011, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.util.zip;
public class CRC32 {
private static final int Polynomial = 0x04C11DB7;
private static final int Width = 32;
private static final int Top = 1 << (Width - 1);
private static final int InitialRemainder = 0xFFFFFFFF;
private static final long ResultXor = 0xFFFFFFFFL;
private static final int[] table = new int[256];
static {
for (int dividend = 0; dividend < 256; ++ dividend) {
int remainder = dividend << (Width - 8);
for (int bit = 8; bit > 0; --bit) {
remainder = ((remainder & Top) != 0)
? (remainder << 1) ^ Polynomial
: (remainder << 1);
}
table[dividend] = remainder;
}
}
private int remainder = InitialRemainder;
public void reset() {
remainder = InitialRemainder;
}
public void update(int b) {
remainder = table[reflect(b, 8) ^ (remainder >>> (Width - 8))]
^ (remainder << 8);
}
public void update(byte[] array, int offset, int length) {
for (int i = 0; i < length; ++i) {
update(array[offset + i] & 0xFF);
}
}
public void update(byte[] array) {
update(array, 0, array.length);
}
public long getValue() {
return (reflect(remainder, Width) ^ ResultXor) & 0xFFFFFFFFL;
}
private static int reflect(int x, int n) {
int reflection = 0;
for (int i = 0; i < n; ++i) {
if ((x & 1) != 0) {
reflection |= (1 << ((n - 1) - i));
}
x = (x >>> 1);
}
return reflection;
}
}

View File

@ -27,14 +27,19 @@ public class Deflater {
private boolean needDictionary;
private boolean finished;
private final boolean nowrap;
private boolean finish;
public Deflater(boolean nowrap) {
public Deflater(int level, boolean nowrap) {
this.nowrap = nowrap;
peer = make(nowrap, DEFAULT_LEVEL);
peer = make(nowrap, level);
}
public Deflater(int level) {
this(level, false);
}
public Deflater() {
this(false);
this(DEFAULT_LEVEL);
}
private void check() {
@ -85,16 +90,15 @@ public class Deflater {
peer = make(nowrap, DEFAULT_LEVEL);
input = null;
offset = length = 0;
finish = false;
needDictionary = finished = false;
}
public int deflate(byte[] output) throws DataFormatException {
public int deflate(byte[] output) {
return deflate(output, 0, output.length);
}
public int deflate(byte[] output, int offset, int length)
throws DataFormatException
{
public int deflate(byte[] output, int offset, int length) {
final int zlibResult = 0;
final int inputCount = 1;
final int outputCount = 2;
@ -110,10 +114,10 @@ public class Deflater {
int[] results = new int[3];
deflate(peer,
input, this.offset, this.length,
output, offset, length, results);
output, offset, length, finish, results);
if (results[zlibResult] < 0) {
throw new DataFormatException();
throw new AssertionError();
}
switch (results[zlibResult]) {
@ -132,10 +136,15 @@ public class Deflater {
return results[outputCount];
}
public void finish() {
finish = true;
}
private static native void deflate
(long peer,
byte[] input, int inputOffset, int inputLength,
byte[] output, int outputOffset, int outputLength,
boolean finish,
int[] results);
public void end() {

View File

@ -52,23 +52,25 @@ public class DeflaterOutputStream extends OutputStream {
} else if (length == 0) {
return;
}
for (int i = 0; i < length; i+= buffer.length) {
deflater.setInput(b, offset + i, Math.min(buffer.length, length - i));
while (deflater.getRemaining() > 0) {
try {
int len = deflater.deflate(buffer, 0, buffer.length);
if (len > 0) {
out.write(buffer, 0, len);
}
} catch (DataFormatException e) {
e.printStackTrace();
}
}
deflater.setInput(b, offset, length);
while (deflater.getRemaining() > 0) {
deflate();
}
}
private void deflate() throws IOException {
int len = deflater.deflate(buffer, 0, buffer.length);
if (len > 0) {
out.write(buffer, 0, len);
}
}
public void close() throws IOException {
deflater.finish();
while (! deflater.finished()) {
deflate();
}
out.close();
deflater.dispose();
}

View File

@ -13,4 +13,5 @@ package java.util.zip;
public abstract class ZipEntry {
public abstract String getName();
public abstract int getCompressedSize();
public abstract int getSize();
}

View File

@ -63,17 +63,27 @@ public class ZipFile {
return index.size();
}
protected Enumeration<? extends ZipEntry> makeEnumeration
(EntryFactory factory)
{
return new MyEnumeration(factory, window, index.values().iterator());
}
public Enumeration<? extends ZipEntry> entries() {
return new MyEnumeration(window, index.values().iterator());
return makeEnumeration(ZipEntryFactory.Instance);
}
protected ZipEntry getEntry(EntryFactory factory, String name) {
Integer pointer = index.get(name);
return (pointer == null ? null : factory.makeEntry(window, pointer));
}
public ZipEntry getEntry(String name) {
Integer pointer = index.get(name);
return (pointer == null ? null : new MyZipEntry(window, pointer));
return getEntry(ZipEntryFactory.Instance, name);
}
public InputStream getInputStream(ZipEntry entry) throws IOException {
int pointer = ((MyZipEntry) entry).pointer;
int pointer = ((MyEntry) entry).pointer();
int method = compressionMethod(window, pointer);
int size = compressedSize(window, pointer);
InputStream in = new MyInputStream(file, fileData(window, pointer), size);
@ -126,7 +136,7 @@ public class ZipFile {
return get2(w, p + 28);
}
private static String entryName(Window w, int p) throws IOException {
protected static String entryName(Window w, int p) throws IOException {
int length = entryNameLength(w, p);
return new String(w.data, w.seek(p + 46, length), length);
}
@ -135,10 +145,14 @@ public class ZipFile {
return get2(w, p + 10);
}
private static int compressedSize(Window w, int p) throws IOException {
protected static int compressedSize(Window w, int p) throws IOException {
return get4(w, p + 20);
}
protected static int uncompressedSize(Window w, int p) throws IOException {
return get4(w, p + 24);
}
private static int fileNameLength(Window w, int p) throws IOException {
return get2(w, p + 28);
}
@ -186,7 +200,7 @@ public class ZipFile {
file.close();
}
private static class Window {
protected static class Window {
private final RandomAccessFile file;
public final byte[] data;
public int start;
@ -231,7 +245,11 @@ public class ZipFile {
}
}
private static class MyZipEntry extends ZipEntry {
protected interface MyEntry {
public int pointer();
}
private static class MyZipEntry extends ZipEntry implements MyEntry {
public final Window window;
public final int pointer;
@ -255,13 +273,41 @@ public class ZipFile {
return 0;
}
}
public int getSize() {
try {
return uncompressedSize(window, pointer);
} catch (IOException e) {
return 0;
}
}
public int pointer() {
return pointer;
}
}
protected interface EntryFactory {
public ZipEntry makeEntry(Window window, int pointer);
}
private static class ZipEntryFactory implements EntryFactory {
public static final ZipEntryFactory Instance = new ZipEntryFactory();
public ZipEntry makeEntry(Window window, int pointer) {
return new MyZipEntry(window, pointer);
}
}
private static class MyEnumeration implements Enumeration<ZipEntry> {
private final EntryFactory factory;
private final Window window;
private final Iterator<Integer> iterator;
public MyEnumeration(Window window, Iterator<Integer> iterator) {
public MyEnumeration(EntryFactory factory, Window window,
Iterator<Integer> iterator)
{
this.factory = factory;
this.window = window;
this.iterator = iterator;
}
@ -271,7 +317,7 @@ public class ZipFile {
}
public ZipEntry nextElement() {
return new MyZipEntry(window, iterator.next());
return factory.makeEntry(window, iterator.next());
}
}

View File

@ -0,0 +1,13 @@
/* Copyright (c) 2011, 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 sun.misc;
public class Cleaner { }

View File

@ -90,7 +90,19 @@ ifneq ($(openjdk),)
openjdk-jar-dep = $(build)/openjdk-jar.dep
classpath-jar-dep = $(openjdk-jar-dep)
javahome = $(embed-prefix)/javahomeJar
javahome-files = lib/zi lib/currency.data
javahome-files = lib/zi lib/currency.data lib/security/java.security \
lib/security/java.policy lib/security/cacerts
local-policy = lib/security/local_policy.jar
ifeq ($(shell test -e $(openjdk)/$(local-policy) && echo found),found)
javahome-files += $(local-policy)
endif
export-policy = lib/security/US_export_policy.jar
ifeq ($(shell test -e $(openjdk)/$(export-policy) && echo found),found)
javahome-files += $(export-policy)
endif
ifeq ($(platform),windows)
javahome-files += lib/tzmappings
endif
@ -304,7 +316,7 @@ ifeq ($(platform),windows)
exe-suffix = .exe
lflags = -L$(lib) $(common-lflags) -lws2_32 -mwindows -mconsole
cflags = -I$(inc) $(common-cflags)
cflags = -I$(inc) $(common-cflags) -DWINVER=0x0500
ifeq (,$(filter mingw32 cygwin,$(build-platform)))
openjdk-extra-cflags += -I$(src)/openjdk/caseSensitive
@ -359,9 +371,22 @@ ifeq ($(mode),stress-major)
endif
ifeq ($(mode),fast)
optimization-cflags = -O3 -g3 -DNDEBUG
use-lto = true
endif
ifeq ($(mode),small)
optimization-cflags = -Os -g3 -DNDEBUG
use-lto = true
endif
ifeq ($(use-lto),true)
# only try to use LTO when GCC 4.6.0 or greater is available
gcc-major := $(shell $(cc) -dumpversion | cut -f1 -d.)
gcc-minor := $(shell $(cc) -dumpversion | cut -f2 -d.)
ifeq ($(shell expr 4 \< $(gcc-major) \
\| \( 4 \<= $(gcc-major) \& 6 \<= $(gcc-minor) \)),1)
optimization-cflags += -flto
lflags += $(optimization-cflags)
endif
endif
cflags += $(optimization-cflags)
@ -544,12 +569,14 @@ ifneq ($(classpath),avian)
$(classpath-src)/avian/Callback.java \
$(classpath-src)/avian/CallbackReceiver.java \
$(classpath-src)/avian/ClassAddendum.java \
$(classpath-src)/avian/Classes.java \
$(classpath-src)/avian/ConstantPool.java \
$(classpath-src)/avian/Continuations.java \
$(classpath-src)/avian/FieldAddendum.java \
$(classpath-src)/avian/IncompatibleContinuationException.java \
$(classpath-src)/avian/Machine.java \
$(classpath-src)/avian/MethodAddendum.java \
$(classpath-src)/avian/Singleton.java \
$(classpath-src)/avian/Stream.java \
$(classpath-src)/avian/SystemClassLoader.java \
$(classpath-src)/avian/VMClass.java \
@ -590,6 +617,11 @@ ifeq ($(continuations),true)
extra.DynamicWind
endif
ifeq ($(tails),true)
tail-tests = \
extra.Tails
endif
class-name = $(patsubst $(1)/%.class,%,$(2))
class-names = $(foreach x,$(2),$(call class-name,$(1),$(x)))
@ -622,7 +654,7 @@ test: build
$(library-path) /bin/sh $(test)/test.sh 2>/dev/null \
$(test-executable) $(mode) "$(test-flags)" \
$(call class-names,$(test-build),$(test-classes)) \
$(continuation-tests)
$(continuation-tests) $(tail-tests)
.PHONY: tarball
tarball:
@ -873,7 +905,7 @@ $(generator): $(generator-objects)
@echo "linking $(@)"
$(build-ld) $(^) $(build-lflags) -o $(@)
$(openjdk-objects): $(build)/openjdk/%.o: $(openjdk-src)/%.c \
$(openjdk-objects): $(build)/openjdk/%-openjdk.o: $(openjdk-src)/%.c \
$(openjdk-headers-dep)
@echo "compiling $(@)"
@mkdir -p $(dir $(@))
@ -882,7 +914,7 @@ $(openjdk-objects): $(build)/openjdk/%.o: $(openjdk-src)/%.c \
$(optimization-cflags) -w -c $(build)/openjdk/$(notdir $(<)) \
$(call output,$(@))
$(openjdk-local-objects): $(build)/openjdk/%.o: $(src)/openjdk/%.c \
$(openjdk-local-objects): $(build)/openjdk/%-openjdk.o: $(src)/openjdk/%.c \
$(openjdk-headers-dep)
@echo "compiling $(@)"
@mkdir -p $(dir $(@))
@ -912,5 +944,6 @@ $(openjdk-jar-dep):
$(jar) xf "$$($(native-path) "$(openjdk)/jre/lib/rt.jar")" && \
$(jar) xf "$$($(native-path) "$(openjdk)/jre/lib/jsse.jar")" && \
$(jar) xf "$$($(native-path) "$(openjdk)/jre/lib/jce.jar")" && \
$(jar) xf "$$($(native-path) "$(openjdk)/jre/lib/ext/sunjce_provider.jar")" && \
$(jar) xf "$$($(native-path) "$(openjdk)/jre/lib/resources.jar")")
@touch $(@)

View File

@ -298,7 +298,7 @@ endif
openjdk-local-sources = \
$(src)/openjdk/my_net_util.c
c-objects = $(foreach x,$(1),$(patsubst $(2)/%.c,$(3)/%.o,$(x)))
c-objects = $(foreach x,$(1),$(patsubst $(2)/%.c,$(3)/%-openjdk.o,$(x)))
openjdk-objects = \
$(call c-objects,$(openjdk-sources),$(openjdk-src),$(build)/openjdk)

View File

@ -104,7 +104,8 @@
}
-keepclassmembers class java.io.FileDescriptor {
private int fd;
private int fd;
private long handle;
}
-keep class java.net.InetAddress {
@ -132,7 +133,8 @@
}
-keepclassmembers class java.io.FileOutputStream {
private java.io.FileDescriptor fd;
private java.io.FileDescriptor fd;
private boolean append;
}
# changed in native code via sun.misc.Unsafe (todo: handle other
@ -174,6 +176,10 @@
public UnixFileSystem();
}
-keep class java.io.WinNTFileSystem {
public WinNTFileSystem();
}
-keep class java.io.File {
private java.lang.String path;
}

View File

@ -51,7 +51,7 @@ Supported Platforms
Avian can currently target the following platforms:
Linux (i386, x86_64 and ARM)
Linux (i386, x86_64, ARM, and 32-bit PowerPC)
Windows (i386 and x86_64)
Mac OS X (i386, x86_64 and 32-bit PowerPC)
@ -260,7 +260,58 @@ an LZMA-enabled version:
You can reduce the size futher for embedded builds by using ProGuard
and the supplied openjdk.pro configuration file (see "Embedding with
ProGuard and a Boot Image" below).
ProGuard and a Boot Image" below). Also see app.mk in
git://oss.readytalk.com/avian-swt-examples.git for an example of using
Avian, OpenJDK, ProGuard, and UPX in concert.
Here are some examples of how to install OpenJDK and build Avian with
it on various OSes:
Debian-based Linux:
# conventional build:
apt-get install openjdk-6-jdk
make openjdk=/usr/lib/jvm/java-6-openjdk test
# stand-alone build:
apt-get install openjdk-6-jdk
apt-get source openjdk-6-jdk
apt-get build-dep openjdk-6-jdk
(cd openjdk-6-6b18-1.8.3 && ./debian/rules patch)
make openjdk=/usr/lib/jvm/java-6-openjdk \
openjdk-src=$(pwd)/openjdk-6-6b18-1.8.3/build/openjdk/jdk/src \
test
Mac OS X:
# Prerequisite: install MacPorts (http://www.macports.org/)
sudo port selfupdate
# conventional build:
sudo port install openjdk6
make openjdk=/opt/local/share/java/openjdk6 test
# stand-alone build:
sudo port fetch openjdk6
sudo port patch openjdk6
make openjdk=/opt/local/share/java/openjdk6 \
openjdk-src=/opt/local/var/macports/build/_opt_local_var_macports_sources_rsync.macports.org_release_ports_java_openjdk6/work/jdk/src \
test
Windows (Cygwin):
# conventional build:
# Prerequisite: download and install the latest Windows OpenJDK
# build from http://www.openscg.com/se/openjdk/
make openjdk=/cygdrive/c/OpenSCG/openjdk-6.21 test
# stand-alone build:
# Prerequisite: install OpenSCG build as above, plus the
# corresponding source bundle from
# http://download.java.net/openjdk/jdk6/promoted/, e.g.:
wget http://download.java.net/openjdk/jdk6/promoted/b21/openjdk-6-src-b21-20_jan_2011.tar.gz
mkdir openjdk
(cd openjdk && tar xzf openjdk-6-src-b21-20_jan_2011.tar.gz)
make openjdk=/cygdrive/c/OpenSCG/openjdk-6.21 \
openjdk-src=$(pwd)/openjdk/jdk/src \
test
Installing

View File

@ -664,13 +664,19 @@ appendPoolEvent(Context* c, MyBlock* b, unsigned offset, PoolOffset* head,
b->poolEventTail = e;
}
bool
needJump(MyBlock* b)
{
return b->next or b->size != (b->size & PoolOffsetMask);
}
unsigned
padding(MyBlock* b, unsigned offset)
{
unsigned total = 0;
for (PoolEvent* e = b->poolEventHead; e; e = e->next) {
if (e->offset <= offset) {
if (b->next) {
if (needJump(b)) {
total += BytesPerWord;
}
for (PoolOffset* o = e->poolOffsetHead; o; o = o->next) {
@ -2363,7 +2369,7 @@ class MyAssembler: public Assembler {
unsigned entry = dstOffset + poolSize;
if (b->next) {
if (needJump(b)) {
entry += BytesPerWord;
}
@ -2381,7 +2387,7 @@ class MyAssembler: public Assembler {
poolSize += BytesPerWord;
}
if (b->next) {
if (needJump(b)) {
write4(dst + dstOffset, ::b((poolSize + BytesPerWord - 8) >> 2));
}

View File

@ -42,11 +42,37 @@ search(Thread* t, object loader, object name,
object
resolveSystemClassThrow(Thread* t, object loader, object spec)
{
return resolveSystemClass(t, loader, spec, true);
return resolveSystemClass
(t, loader, spec, true, Machine::ClassNotFoundExceptionType);
}
} // namespace
extern "C" JNIEXPORT void JNICALL
Avian_avian_Classes_acquireClassLock
(Thread* t, object, uintptr_t*)
{
acquire(t, t->m->classLock);
}
extern "C" JNIEXPORT void JNICALL
Avian_avian_Classes_releaseClassLock
(Thread* t, object, uintptr_t*)
{
release(t, t->m->classLock);
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_avian_Classes_resolveVMClass
(Thread* t, object, uintptr_t* arguments)
{
object loader = reinterpret_cast<object>(arguments[0]);
object spec = reinterpret_cast<object>(arguments[1]);
return reinterpret_cast<int64_t>
(resolveClass(t, loader, spec, true, Machine::ClassNotFoundExceptionType));
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_avian_SystemClassLoader_findLoadedVMClass
(Thread* t, object, uintptr_t* arguments)
@ -68,7 +94,7 @@ Avian_avian_SystemClassLoader_findVMClass
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_avian_SystemClassLoader_resourceExists
Avian_avian_SystemClassLoader_resourceURLPrefix
(Thread* t, object, uintptr_t* arguments)
{
object loader = reinterpret_cast<object>(arguments[0]);
@ -78,13 +104,10 @@ Avian_avian_SystemClassLoader_resourceExists
THREAD_RUNTIME_ARRAY(t, char, n, stringLength(t, name) + 1);
stringChars(t, name, RUNTIME_ARRAY_BODY(n));
unsigned length;
bool r = static_cast<Finder*>(systemClassLoaderFinder(t, loader))->stat
(RUNTIME_ARRAY_BODY(n), &length) == System::TypeFile;
const char* name = static_cast<Finder*>
(systemClassLoaderFinder(t, loader))->urlPrefix(RUNTIME_ARRAY_BODY(n));
// fprintf(stderr, "resource %s exists? %d\n", n, r);
return r;
return name ? reinterpret_cast<uintptr_t>(makeString(t, "%s", name)) : 0;
} else {
throwNew(t, Machine::NullPointerExceptionType);
}

View File

@ -10,6 +10,7 @@
#include "machine.h"
#include "classpath-common.h"
#include "process.h"
using namespace vm;
@ -63,6 +64,12 @@ class MyClasspath : public Classpath {
t->m->processor->invoke(t, method, 0, t->javaThread);
}
virtual void
resolveNative(Thread* t, object method)
{
vm::resolveNative(t, method);
}
virtual void
boot(Thread*)
{
@ -589,30 +596,6 @@ Avian_java_lang_Thread_yield
t->m->system->yield();
}
extern "C" JNIEXPORT void JNICALL
Avian_avian_Classes_acquireClassLock
(Thread* t, object, uintptr_t*)
{
acquire(t, t->m->classLock);
}
extern "C" JNIEXPORT void JNICALL
Avian_avian_Classes_releaseClassLock
(Thread* t, object, uintptr_t*)
{
release(t, t->m->classLock);
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_avian_Classes_resolveVMClass
(Thread* t, object, uintptr_t* arguments)
{
object loader = reinterpret_cast<object>(arguments[0]);
object spec = reinterpret_cast<object>(arguments[1]);
return reinterpret_cast<int64_t>(resolveClass(t, loader, spec));
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_avian_Classes_primitiveClass
(Thread* t, object, uintptr_t* arguments)

File diff suppressed because it is too large Load Diff

View File

@ -61,11 +61,7 @@ typedef uint64_t uintptr_t;
namespace vm {
inline intptr_t&
alias(void* p, unsigned offset)
{
return *reinterpret_cast<intptr_t*>(static_cast<uint8_t*>(p) + offset);
}
typedef intptr_t intptr_alias_t;
} // namespace vm
@ -99,11 +95,6 @@ alias(void* p, unsigned offset)
namespace vm {
typedef intptr_t __attribute__((__may_alias__)) intptr_alias_t;
inline intptr_alias_t&
alias(void* p, unsigned offset)
{
return *reinterpret_cast<intptr_alias_t*>(static_cast<uint8_t*>(p) + offset);
}
} // namespace vm
@ -178,6 +169,12 @@ inline void* operator new(size_t, void* p) throw() { return p; }
namespace vm {
inline intptr_alias_t&
alias(void* p, unsigned offset)
{
return *reinterpret_cast<intptr_alias_t*>(static_cast<uint8_t*>(p) + offset);
}
#ifdef _MSC_VER
template <class T>
@ -537,6 +534,16 @@ replace(char a, char b, char* dst, const char* src)
dst[i] = 0;
}
inline bool
equal(const void* a, unsigned al, const void* b, unsigned bl)
{
if (al == bl) {
return memcmp(a, b, al) == 0;
} else {
return false;
}
}
class Machine;
class Thread;

File diff suppressed because it is too large Load Diff

View File

@ -218,7 +218,8 @@ class LogicalInstruction {
class Resource {
public:
Resource(bool reserved = false):
value(0), site(0), freezeCount(0), referenceCount(0), reserved(reserved)
value(0), site(0), previousAcquired(0), nextAcquired(0), freezeCount(0),
referenceCount(0), reserved(reserved)
{ }
virtual void freeze(Context*, Value*) = 0;
@ -229,6 +230,8 @@ class Resource {
Value* value;
Site* site;
Resource* previousAcquired;
Resource* nextAcquired;
uint8_t freezeCount;
uint8_t referenceCount;
bool reserved;
@ -326,7 +329,7 @@ class Value: public Compiler::Operand {
Site* target;
Value* buddy;
Value* nextWord;
int8_t home;
int16_t home;
ValueType type;
uint8_t wordIndex;
};
@ -379,6 +382,7 @@ class Context {
(static_cast<RegisterResource*>
(zone->allocate(sizeof(RegisterResource) * registerLimit))),
frameResources(0),
acquiredResources(0),
firstConstant(0),
lastConstant(0),
machineCode(0),
@ -426,6 +430,7 @@ class Context {
uint8_t floatRegisterLimit;
RegisterResource* registerResources;
FrameResource* frameResources;
Resource* acquiredResources;
ConstantPoolNode* firstConstant;
ConstantPoolNode* lastConstant;
uint8_t* machineCode;
@ -527,7 +532,8 @@ class IpPromise: public Promise {
}
virtual bool resolved() {
return c->machineCode != 0;
return c->machineCode != 0
and c->logicalCode[logicalIp]->machineOffset->resolved();
}
Context* c;
@ -2585,6 +2591,12 @@ acquire(Context* c, Resource* resource, Value* value, Site* site)
steal(c, resource, value);
}
if (c->acquiredResources) {
c->acquiredResources->previousAcquired = resource;
resource->nextAcquired = c->acquiredResources;
}
c->acquiredResources = resource;
resource->value = value;
resource->site = site;
}
@ -2604,6 +2616,21 @@ release(Context* c, Resource* resource, Value* value UNUSED, Site* site UNUSED)
assert(c, buddies(resource->value, value));
assert(c, site == resource->site);
Resource* next = resource->nextAcquired;
if (next) {
next->previousAcquired = resource->previousAcquired;
resource->nextAcquired = 0;
}
Resource* previous = resource->previousAcquired;
if (previous) {
previous->nextAcquired = next;
resource->previousAcquired = 0;
} else {
assert(c, c->acquiredResources == resource);
c->acquiredResources = next;
}
resource->value = 0;
resource->site = 0;
@ -5526,6 +5553,10 @@ resetFrame(Context* c, Event* e)
FrameIterator::Element el = it.next(c);
clearSites(c, el.value);
}
while (c->acquiredResources) {
clearSites(c, c->acquiredResources->value);
}
}
void

View File

@ -32,6 +32,17 @@ append(Allocator* allocator, const char* a, const char* b, const char* c)
return p;
}
const char*
append(Allocator* allocator, const char* a, const char* b)
{
unsigned al = strlen(a);
unsigned bl = strlen(b);
char* p = static_cast<char*>(allocator->allocate((al + bl) + 1));
memcpy(p, a, al);
memcpy(p + al, b, bl + 1);
return p;
}
const char*
copy(Allocator* allocator, const char* a)
{
@ -41,16 +52,6 @@ copy(Allocator* allocator, const char* a)
return p;
}
bool
equal(const void* a, unsigned al, const void* b, unsigned bl)
{
if (al == bl) {
return memcmp(a, b, al) == 0;
} else {
return false;
}
}
class Element {
public:
class Iterator {
@ -65,6 +66,8 @@ class Element {
virtual System::Region* find(const char* name) = 0;
virtual System::FileType stat(const char* name, unsigned* length,
bool tryDirectory) = 0;
virtual const char* urlPrefix() = 0;
virtual const char* sourceUrl() = 0;
virtual void dispose() = 0;
Element* next;
@ -133,7 +136,9 @@ class DirectoryElement: public Element {
};
DirectoryElement(System* s, Allocator* allocator, const char* name):
s(s), allocator(allocator), name(name)
s(s), allocator(allocator), name(name),
urlPrefix_(append(allocator, "file:", name, "/")),
sourceUrl_(append(allocator, "file:", name))
{ }
virtual Element::Iterator* iterator() {
@ -167,14 +172,26 @@ class DirectoryElement: public Element {
return type;
}
virtual const char* urlPrefix() {
return urlPrefix_;
}
virtual const char* sourceUrl() {
return sourceUrl_;
}
virtual void dispose() {
allocator->free(name, strlen(name) + 1);
allocator->free(urlPrefix_, strlen(urlPrefix_) + 1);
allocator->free(sourceUrl_, strlen(sourceUrl_) + 1);
allocator->free(this, sizeof(*this));
}
System* s;
Allocator* allocator;
const char* name;
const char* urlPrefix_;
const char* sourceUrl_;
};
class PointerRegion: public System::Region {
@ -233,9 +250,6 @@ class DataRegion: public System::Region {
class JarIndex {
public:
static const unsigned LocalHeaderSize = 30;
static const unsigned HeaderSize = 46;
enum CompressionMethod {
Stored = 0,
Deflated = 8
@ -262,78 +276,6 @@ class JarIndex {
memset(table, 0, sizeof(Node*) * capacity);
}
static uint16_t get2(const uint8_t* p) {
return
(static_cast<uint16_t>(p[1]) << 8) |
(static_cast<uint16_t>(p[0]) );
}
static uint32_t get4(const uint8_t* p) {
return
(static_cast<uint32_t>(p[3]) << 24) |
(static_cast<uint32_t>(p[2]) << 16) |
(static_cast<uint32_t>(p[1]) << 8) |
(static_cast<uint32_t>(p[0]) );
}
static uint32_t signature(const uint8_t* p) {
return get4(p);
}
static uint16_t compressionMethod(const uint8_t* centralHeader) {
return get2(centralHeader + 10);
}
static uint32_t compressedSize(const uint8_t* centralHeader) {
return get4(centralHeader + 20);
}
static uint32_t uncompressedSize(const uint8_t* centralHeader) {
return get4(centralHeader + 24);
}
static uint16_t fileNameLength(const uint8_t* centralHeader) {
return get2(centralHeader + 28);
}
static uint16_t extraFieldLength(const uint8_t* centralHeader) {
return get2(centralHeader + 30);
}
static uint16_t commentFieldLength(const uint8_t* centralHeader) {
return get2(centralHeader + 32);
}
static uint32_t localHeaderOffset(const uint8_t* centralHeader) {
return get4(centralHeader + 42);
}
static uint16_t localFileNameLength(const uint8_t* localHeader) {
return get2(localHeader + 26);
}
static uint16_t localExtraFieldLength(const uint8_t* localHeader) {
return get2(localHeader + 28);
}
static uint32_t centralDirectoryOffset(const uint8_t* centralHeader) {
return get4(centralHeader + 16);
}
static const uint8_t* fileName(const uint8_t* centralHeader) {
return centralHeader + 46;
}
static const uint8_t* fileData(const uint8_t* localHeader) {
return localHeader + LocalHeaderSize + localFileNameLength(localHeader) +
localExtraFieldLength(localHeader);
}
static const uint8_t* endOfEntry(const uint8_t* p) {
return p + HeaderSize + fileNameLength(p) + extraFieldLength(p) +
commentFieldLength(p);
}
static JarIndex* make(System* s, Allocator* allocator, unsigned capacity) {
return new
(allocator->allocate(sizeof(JarIndex) + (sizeof(Node*) * capacity)))
@ -347,14 +289,14 @@ class JarIndex {
const uint8_t* start = region->start();
const uint8_t* end = start + region->length();
const uint8_t* p = end - 22;
const uint8_t* p = end - CentralDirectorySearchStart;
// Find end of central directory record
while (p > start) {
if (signature(p) == 0x06054b50) {
if (signature(p) == CentralDirectorySignature) {
p = region->start() + centralDirectoryOffset(p);
while (p < end) {
if (signature(p) == 0x02014b50) {
if (signature(p) == EntrySignature) {
index = index->add(hash(fileName(p), fileNameLength(p)), p);
p = endOfEntry(p);
@ -495,8 +437,8 @@ class JarElement: public Element {
virtual const char* next(unsigned* size) {
if (position < index->position) {
JarIndex::Node* n = index->nodes + (position++);
*size = JarIndex::fileNameLength(n->entry);
return reinterpret_cast<const char*>(JarIndex::fileName(n->entry));
*size = fileNameLength(n->entry);
return reinterpret_cast<const char*>(fileName(n->entry));
} else {
return 0;
}
@ -513,7 +455,10 @@ class JarElement: public Element {
};
JarElement(System* s, Allocator* allocator, const char* name):
s(s), allocator(allocator), name(name), region(0), index(0)
s(s), allocator(allocator), name(name),
urlPrefix_(name ? append(allocator, "jar:file:", name, "!/") : 0),
sourceUrl_(name ? append(allocator, "file:", name) : 0),
region(0), index(0)
{ }
JarElement(System* s, Allocator* allocator, const uint8_t* jarData,
@ -521,6 +466,8 @@ class JarElement: public Element {
s(s),
allocator(allocator),
name(0),
urlPrefix_(name ? append(allocator, "jar:file:", name, "!/") : 0),
sourceUrl_(name ? append(allocator, "file:", name) : 0),
region(new (allocator->allocate(sizeof(PointerRegion)))
PointerRegion(s, allocator, jarData, jarLength)),
index(JarIndex::open(s, allocator, region))
@ -570,12 +517,22 @@ class JarElement: public Element {
: System::TypeDoesNotExist);
}
virtual const char* urlPrefix() {
return urlPrefix_;
}
virtual const char* sourceUrl() {
return sourceUrl_;
}
virtual void dispose() {
dispose(sizeof(*this));
}
virtual void dispose(unsigned size) {
allocator->free(name, strlen(name) + 1);
allocator->free(urlPrefix_, strlen(urlPrefix_) + 1);
allocator->free(sourceUrl_, strlen(sourceUrl_) + 1);
if (index) {
index->dispose();
}
@ -588,6 +545,8 @@ class JarElement: public Element {
System* s;
Allocator* allocator;
const char* name;
const char* urlPrefix_;
const char* sourceUrl_;
System::Region* region;
JarIndex* index;
};
@ -620,6 +579,14 @@ class BuiltinElement: public JarElement {
}
}
virtual const char* urlPrefix() {
return "resource:";
}
virtual const char* sourceUrl() {
return 0;
}
virtual void dispose() {
library->disposeAll();
if (libraryName) {
@ -662,6 +629,33 @@ void
add(System* s, Element** first, Element** last, Allocator* allocator,
const char* name, unsigned nameLength, const char* bootLibrary);
void
addTokens(System* s, Element** first, Element** last, Allocator* allocator,
const char* jarName, unsigned jarNameBase, const char* tokens,
unsigned tokensLength, const char* bootLibrary)
{
for (Tokenizer t(tokens, tokensLength, ' '); t.hasMore();) {
Tokenizer::Token token(t.next());
RUNTIME_ARRAY(char, n, jarNameBase + token.length + 1);
memcpy(RUNTIME_ARRAY_BODY(n), jarName, jarNameBase);
memcpy(RUNTIME_ARRAY_BODY(n) + jarNameBase, token.s, token.length);
RUNTIME_ARRAY_BODY(n)[jarNameBase + token.length] = 0;
add(s, first, last, allocator, RUNTIME_ARRAY_BODY(n),
jarNameBase + token.length, bootLibrary);
}
}
bool
continuationLine(const uint8_t* base, unsigned total, unsigned* start,
unsigned* length)
{
return readLine(base, total, start, length)
and *length > 0
and base[*start] == ' ';
}
void
addJar(System* s, Element** first, Element** last, Allocator* allocator,
const char* name, const char* bootLibrary)
@ -673,6 +667,8 @@ addJar(System* s, Element** first, Element** last, Allocator* allocator,
JarElement* e = new (allocator->allocate(sizeof(JarElement)))
JarElement(s, allocator, name);
unsigned nameBase = baseName(name, s->fileSeparator());
add(first, last, e);
System::Region* region = e->find("META-INF/MANIFEST.MF");
@ -680,29 +676,60 @@ addJar(System* s, Element** first, Element** last, Allocator* allocator,
unsigned start = 0;
unsigned length;
while (readLine(region->start(), region->length(), &start, &length)) {
unsigned multilineTotal = 0;
const unsigned PrefixLength = 12;
if (strncmp("Class-Path: ", reinterpret_cast<const char*>
(region->start() + start), PrefixLength) == 0)
if (length > PrefixLength
and strncmp("Class-Path: ", reinterpret_cast<const char*>
(region->start() + start), PrefixLength) == 0)
{
for (Tokenizer t(reinterpret_cast<const char*>
(region->start() + start + PrefixLength),
length - PrefixLength, ' ');
t.hasMore();)
{
Tokenizer::Token token(t.next());
{ unsigned nextStart = start + length;
unsigned nextLength;
while (continuationLine
(region->start(), region->length(), &nextStart, &nextLength))
{
multilineTotal += nextLength;
nextStart += nextLength;
}
}
unsigned base = baseName(name, s->fileSeparator());
const char* line = reinterpret_cast<const char*>
(region->start() + start + PrefixLength);
RUNTIME_ARRAY(char, n, base + token.length + 1);
memcpy(RUNTIME_ARRAY_BODY(n), name, base);
memcpy(RUNTIME_ARRAY_BODY(n) + base, token.s, token.length);
RUNTIME_ARRAY_BODY(n)[base + token.length] = 0;
add(s, first, last, allocator, RUNTIME_ARRAY_BODY(n),
base + token.length, bootLibrary);
unsigned lineLength = length - PrefixLength;
if (multilineTotal) {
RUNTIME_ARRAY
(char, n, (length - PrefixLength) + multilineTotal + 1);
memcpy(RUNTIME_ARRAY_BODY(n), line, lineLength);
unsigned offset = lineLength;
{ unsigned nextStart = start + length;
unsigned nextLength;
while (continuationLine
(region->start(), region->length(), &nextStart,
&nextLength))
{
unsigned continuationLength = nextLength - 1;
memcpy(RUNTIME_ARRAY_BODY(n) + offset,
region->start() + nextStart + 1, continuationLength);
offset += continuationLength;
nextStart += nextLength;
}
}
addTokens(s, first, last, allocator, name, nameBase,
RUNTIME_ARRAY_BODY(n), offset, bootLibrary);
} else {
addTokens(s, first, last, allocator, name, nameBase, line,
lineLength, bootLibrary);
}
}
start += length;
start += length + multilineTotal;
}
region->dispose();
@ -854,6 +881,30 @@ class MyFinder: public Finder {
return System::TypeDoesNotExist;
}
virtual const char* urlPrefix(const char* name) {
for (Element* e = path_; e; e = e->next) {
unsigned length;
System::FileType type = e->stat(name, &length, true);
if (type != System::TypeDoesNotExist) {
return e->urlPrefix();
}
}
return 0;
}
virtual const char* sourceUrl(const char* name) {
for (Element* e = path_; e; e = e->next) {
unsigned length;
System::FileType type = e->stat(name, &length, true);
if (type != System::TypeDoesNotExist) {
return e->sourceUrl();
}
}
return 0;
}
virtual const char* path() {
return pathString;
}

View File

@ -17,6 +17,94 @@
namespace vm {
const unsigned LocalHeaderSize = 30;
const unsigned HeaderSize = 46;
const unsigned CentralDirectorySignature = 0x06054b50;
const unsigned EntrySignature = 0x02014b50;
const unsigned CentralDirectorySearchStart = 22;
inline uint16_t get2(const uint8_t* p) {
return
(static_cast<uint16_t>(p[1]) << 8) |
(static_cast<uint16_t>(p[0]) );
}
inline uint32_t get4(const uint8_t* p) {
return
(static_cast<uint32_t>(p[3]) << 24) |
(static_cast<uint32_t>(p[2]) << 16) |
(static_cast<uint32_t>(p[1]) << 8) |
(static_cast<uint32_t>(p[0]) );
}
inline uint32_t signature(const uint8_t* p) {
return get4(p);
}
inline uint16_t compressionMethod(const uint8_t* centralHeader) {
return get2(centralHeader + 10);
}
inline uint32_t fileTime(const uint8_t* centralHeader) {
return get4(centralHeader + 12);
}
inline uint32_t fileCRC(const uint8_t* centralHeader) {
return get4(centralHeader + 16);
}
inline uint32_t compressedSize(const uint8_t* centralHeader) {
return get4(centralHeader + 20);
}
inline uint32_t uncompressedSize(const uint8_t* centralHeader) {
return get4(centralHeader + 24);
}
inline uint16_t fileNameLength(const uint8_t* centralHeader) {
return get2(centralHeader + 28);
}
inline uint16_t extraFieldLength(const uint8_t* centralHeader) {
return get2(centralHeader + 30);
}
inline uint16_t commentFieldLength(const uint8_t* centralHeader) {
return get2(centralHeader + 32);
}
inline uint32_t localHeaderOffset(const uint8_t* centralHeader) {
return get4(centralHeader + 42);
}
inline uint16_t localFileNameLength(const uint8_t* localHeader) {
return get2(localHeader + 26);
}
inline uint16_t localExtraFieldLength(const uint8_t* localHeader) {
return get2(localHeader + 28);
}
inline uint32_t centralDirectoryOffset(const uint8_t* centralHeader) {
return get4(centralHeader + 16);
}
inline const uint8_t* fileName(const uint8_t* centralHeader) {
return centralHeader + 46;
}
inline const uint8_t* fileData(const uint8_t* localHeader) {
return localHeader + LocalHeaderSize + localFileNameLength(localHeader) +
localExtraFieldLength(localHeader);
}
inline const uint8_t* endOfEntry(const uint8_t* p) {
return p + HeaderSize + fileNameLength(p) + extraFieldLength(p) +
commentFieldLength(p);
}
inline bool
readLine(const uint8_t* base, unsigned total, unsigned* start,
unsigned* length)
@ -79,6 +167,8 @@ class Finder {
virtual System::FileType stat(const char* name,
unsigned* length,
bool tryDirectory = false) = 0;
virtual const char* urlPrefix(const char* name) = 0;
virtual const char* sourceUrl(const char* name) = 0;
virtual const char* path() = 0;
virtual void dispose() = 0;
};

View File

@ -1434,7 +1434,7 @@ visitDirtyFixies(Context* c, Fixie** p)
while (*p) {
Fixie* f = *p;
bool wasDirty = false;
bool wasDirty UNUSED = false;
bool clean = true;
uintptr_t* mask = f->mask();
@ -1527,7 +1527,7 @@ void
collect(Context* c, Segment::Map* map, unsigned start, unsigned end,
bool* dirty, bool expectDirty UNUSED)
{
bool wasDirty = false;
bool wasDirty UNUSED = false;
for (Segment::Map::Iterator it(map, start, end); it.hasMore();) {
wasDirty = true;
if (map->child) {

View File

@ -26,8 +26,6 @@ const unsigned FrameMethodOffset = 2;
const unsigned FrameIpOffset = 3;
const unsigned FrameFootprint = 4;
class ClassInitList;
class Thread: public vm::Thread {
public:
Thread(Machine* m, object javaThread, vm::Thread* parent):
@ -35,39 +33,16 @@ class Thread: public vm::Thread {
ip(0),
sp(0),
frame(-1),
code(0),
classInitList(0)
code(0)
{ }
unsigned ip;
unsigned sp;
int frame;
object code;
ClassInitList* classInitList;
uintptr_t stack[StackSizeInWords];
};
class ClassInitList {
public:
ClassInitList(Thread* t, object class_, ClassInitList* next):
t(t), class_(class_), next(next)
{ }
static void push(Thread* t, object class_) {
t->classInitList = new (t->m->heap->allocate(sizeof(ClassInitList)))
ClassInitList(t, class_, t->classInitList);
}
void pop() {
t->classInitList = next;
t->m->heap->free(this, sizeof(ClassInitList));
}
Thread* t;
object class_;
ClassInitList* next;
};
inline void
pushObject(Thread* t, object o)
{
@ -322,15 +297,29 @@ setLocalLong(Thread* t, unsigned index, uint64_t value)
void
pushFrame(Thread* t, object method)
{
if (t->frame >= 0) {
pokeInt(t, t->frame + FrameIpOffset, t->ip);
}
t->ip = 0;
PROTECT(t, method);
unsigned parameterFootprint = methodParameterFootprint(t, method);
unsigned base = t->sp - parameterFootprint;
unsigned locals = parameterFootprint;
if (methodFlags(t, method) & ACC_SYNCHRONIZED) {
// Try to acquire the monitor before doing anything else.
// Otherwise, if we were to push the frame first, we risk trying
// to release a monitor we never successfully acquired when we try
// to pop the frame back off.
if (methodFlags(t, method) & ACC_STATIC) {
acquire(t, methodClass(t, method));
} else {
acquire(t, peekObject(t, base));
}
}
if (t->frame >= 0) {
pokeInt(t, t->frame + FrameIpOffset, t->ip);
}
t->ip = 0;
if ((methodFlags(t, method) & ACC_NATIVE) == 0) {
t->code = methodCode(t, method);
@ -349,14 +338,6 @@ pushFrame(Thread* t, object method)
pokeInt(t, frame + FrameBaseOffset, base);
pokeObject(t, frame + FrameMethodOffset, method);
pokeInt(t, t->frame + FrameIpOffset, 0);
if (methodFlags(t, method) & ACC_SYNCHRONIZED) {
if (methodFlags(t, method) & ACC_STATIC) {
acquire(t, methodClass(t, method));
} else {
acquire(t, peekObject(t, base));
}
}
}
void
@ -371,15 +352,6 @@ popFrame(Thread* t)
release(t, peekObject(t, frameBase(t, t->frame)));
}
}
if (UNLIKELY(methodVmFlags(t, method) & ClassInitFlag)
and t->classInitList
and t->classInitList->class_ == methodClass(t, method))
{
t->classInitList->pop();
postInitClass(t, methodClass(t, method));
}
t->sp = frameBase(t, t->frame);
t->frame = frameNext(t, t->frame);
@ -685,32 +657,6 @@ invokeNative(Thread* t, object method)
}
}
bool
classInit2(Thread* t, object class_, unsigned ipOffset)
{
PROTECT(t, class_);
if (preInitClass(t, class_)) {
ClassInitList::push(t, class_);
t->code = classInitializer(t, class_);
t->ip -= ipOffset;
return true;
} else {
return false;
}
}
inline bool
classInit(Thread* t, object class_, unsigned ipOffset)
{
if (UNLIKELY(classVmFlags(t, class_) & NeedInitFlag)) {
return classInit2(t, class_, ipOffset);
} else {
return false;
}
}
inline void
store(Thread* t, unsigned index)
{
@ -816,9 +762,7 @@ interpret3(Thread* t, const int base)
goto throw_;
}
if (UNLIKELY(classInit(t, methodClass(t, frameMethod(t, frame)), 0))) {
goto invoke;
}
initClass(t, methodClass(t, frameMethod(t, frame)));
loop:
instruction = codeBody(t, code, ip++);
@ -1460,27 +1404,11 @@ interpret3(Thread* t, const int base)
assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0);
if (UNLIKELY((fieldFlags(t, field) & ACC_VOLATILE)
and BytesPerWord == 4
and (fieldCode(t, field) == DoubleField
or fieldCode(t, field) == LongField)))
{
PROTECT(t, field);
acquire(t, field);
}
PROTECT(t, field);
ACQUIRE_FIELD_FOR_READ(t, field);
pushField(t, popObject(t), field);
if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) {
if (BytesPerWord == 4
and (fieldCode(t, field) == DoubleField
or fieldCode(t, field) == LongField))
{
release(t, field);
} else {
loadMemoryBarrier();
}
}
} else {
exception = makeThrowable(t, Machine::NullPointerExceptionType);
goto throw_;
@ -1496,28 +1424,11 @@ interpret3(Thread* t, const int base)
PROTECT(t, field);
if (UNLIKELY(classInit(t, fieldClass(t, field), 3))) goto invoke;
initClass(t, fieldClass(t, field));
if (UNLIKELY((fieldFlags(t, field) & ACC_VOLATILE)
and BytesPerWord == 4
and (fieldCode(t, field) == DoubleField
or fieldCode(t, field) == LongField)))
{
acquire(t, field);
}
ACQUIRE_FIELD_FOR_READ(t, field);
pushField(t, classStaticTable(t, fieldClass(t, field)), field);
if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) {
if (BytesPerWord == 4
and (fieldCode(t, field) == DoubleField
or fieldCode(t, field) == LongField))
{
release(t, field);
} else {
loadMemoryBarrier();
}
}
} goto loop;
case goto_: {
@ -1891,7 +1802,10 @@ interpret3(Thread* t, const int base)
object class_ = methodClass(t, frameMethod(t, frame));
if (isSpecialMethod(t, method, class_)) {
class_ = classSuper(t, class_);
if (UNLIKELY(classInit(t, class_, 3))) goto invoke;
PROTECT(t, method);
PROTECT(t, class_);
initClass(t, class_);
code = findVirtualMethod(t, method, class_);
} else {
@ -1911,7 +1825,7 @@ interpret3(Thread* t, const int base)
object method = resolveMethod(t, frameMethod(t, frame), index - 1);
PROTECT(t, method);
if (UNLIKELY(classInit(t, methodClass(t, method), 3))) goto invoke;
initClass(t, methodClass(t, method));
code = method;
} goto invoke;
@ -1924,7 +1838,10 @@ interpret3(Thread* t, const int base)
unsigned parameterFootprint = methodParameterFootprint(t, method);
if (LIKELY(peekObject(t, sp - parameterFootprint))) {
object class_ = objectClass(t, peekObject(t, sp - parameterFootprint));
if (UNLIKELY(classInit(t, class_, 3))) goto invoke;
PROTECT(t, method);
PROTECT(t, class_);
initClass(t, class_);
code = findVirtualMethod(t, method, class_);
goto invoke;
@ -2385,7 +2302,7 @@ interpret3(Thread* t, const int base)
object class_ = resolveClassInPool(t, frameMethod(t, frame), index - 1);
PROTECT(t, class_);
if (UNLIKELY(classInit(t, class_, 3))) goto invoke;
initClass(t, class_);
pushObject(t, make(t, class_));
} goto loop;
@ -2460,80 +2377,61 @@ interpret3(Thread* t, const int base)
assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0);
PROTECT(t, field);
if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) {
if (BytesPerWord == 4
and (fieldCode(t, field) == DoubleField
or fieldCode(t, field) == LongField))
{
acquire(t, field);
} else {
storeStoreMemoryBarrier();
}
}
{ ACQUIRE_FIELD_FOR_WRITE(t, field);
switch (fieldCode(t, field)) {
case ByteField:
case BooleanField:
case CharField:
case ShortField:
case FloatField:
case IntField: {
int32_t value = popInt(t);
object o = popObject(t);
if (LIKELY(o)) {
switch (fieldCode(t, field)) {
case ByteField:
case BooleanField:
cast<int8_t>(o, fieldOffset(t, field)) = value;
break;
switch (fieldCode(t, field)) {
case ByteField:
case BooleanField:
case CharField:
case ShortField:
case FloatField:
case IntField: {
int32_t value = popInt(t);
object o = popObject(t);
if (LIKELY(o)) {
switch (fieldCode(t, field)) {
case ByteField:
case BooleanField:
cast<int8_t>(o, fieldOffset(t, field)) = value;
break;
case CharField:
case ShortField:
cast<int16_t>(o, fieldOffset(t, field)) = value;
break;
case CharField:
case ShortField:
cast<int16_t>(o, fieldOffset(t, field)) = value;
break;
case FloatField:
case IntField:
cast<int32_t>(o, fieldOffset(t, field)) = value;
break;
case FloatField:
case IntField:
cast<int32_t>(o, fieldOffset(t, field)) = value;
break;
}
} else {
exception = makeThrowable(t, Machine::NullPointerExceptionType);
}
} else {
exception = makeThrowable(t, Machine::NullPointerExceptionType);
}
} break;
} break;
case DoubleField:
case LongField: {
int64_t value = popLong(t);
object o = popObject(t);
if (LIKELY(o)) {
cast<int64_t>(o, fieldOffset(t, field)) = value;
} else {
exception = makeThrowable(t, Machine::NullPointerExceptionType);
}
} break;
case DoubleField:
case LongField: {
int64_t value = popLong(t);
object o = popObject(t);
if (LIKELY(o)) {
cast<int64_t>(o, fieldOffset(t, field)) = value;
} else {
exception = makeThrowable(t, Machine::NullPointerExceptionType);
}
} break;
case ObjectField: {
object value = popObject(t);
object o = popObject(t);
if (LIKELY(o)) {
set(t, o, fieldOffset(t, field), value);
} else {
exception = makeThrowable(t, Machine::NullPointerExceptionType);
}
} break;
case ObjectField: {
object value = popObject(t);
object o = popObject(t);
if (LIKELY(o)) {
set(t, o, fieldOffset(t, field), value);
} else {
exception = makeThrowable(t, Machine::NullPointerExceptionType);
}
} break;
default: abort(t);
}
if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) {
if (BytesPerWord == 4
and (fieldCode(t, field) == DoubleField
or fieldCode(t, field) == LongField))
{
release(t, field);
} else {
storeLoadMemoryBarrier();
default: abort(t);
}
}
@ -2551,18 +2449,9 @@ interpret3(Thread* t, const int base)
PROTECT(t, field);
if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) {
if (BytesPerWord == 4
and (fieldCode(t, field) == DoubleField
or fieldCode(t, field) == LongField))
{
acquire(t, field);
} else {
storeStoreMemoryBarrier();
}
}
ACQUIRE_FIELD_FOR_WRITE(t, field);
if (UNLIKELY(classInit(t, fieldClass(t, field), 3))) goto invoke;
initClass(t, fieldClass(t, field));
object table = classStaticTable(t, fieldClass(t, field));
@ -2603,17 +2492,6 @@ interpret3(Thread* t, const int base)
default: abort(t);
}
if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) {
if (BytesPerWord == 4
and (fieldCode(t, field) == DoubleField
or fieldCode(t, field) == LongField))
{
release(t, field);
} else {
storeLoadMemoryBarrier();
}
}
} goto loop;
case ret: {
@ -3048,7 +2926,7 @@ class MyProcessor: public Processor {
return vm::makeClass
(t, flags, vmFlags, fixedSize, arrayElementSize, arrayDimensions, 0,
objectMask, name, sourceFile, super, interfaceTable, virtualTable,
fieldTable, methodTable, addendum, staticTable, loader, 0);
fieldTable, methodTable, addendum, staticTable, loader, 0, 0);
}
virtual void
@ -3057,26 +2935,6 @@ class MyProcessor: public Processor {
// ignore
}
virtual bool
isInitializing(vm::Thread* vmt, object c)
{
Thread* t = static_cast<Thread*>(vmt);
for (ClassInitList* list = t->classInitList; list; list = list->next) {
if (list->class_ == c) {
return true;
}
}
for (Thread::ClassInitStack* s = t->classInitStack; s; s = s->next) {
if (s->class_ == c) {
return true;
}
}
return false;
}
virtual void
visitObjects(vm::Thread* vmt, Heap::Visitor* v)
{
@ -3089,10 +2947,6 @@ class MyProcessor: public Processor {
v->visit(reinterpret_cast<object*>(t->stack + (i * 2) + 1));
}
}
for (ClassInitList* list = t->classInitList; list; list = list->next) {
v->visit(reinterpret_cast<object*>(&(list->class_)));
}
}
virtual void

File diff suppressed because it is too large Load Diff

View File

@ -364,8 +364,18 @@ finalizerTargetUnreachable(Thread* t, Heap::Visitor* v, object* p)
object finalizer = *p;
*p = finalizerNext(t, finalizer);
finalizerNext(t, finalizer) = t->m->finalizeQueue;
t->m->finalizeQueue = finalizer;
void (*function)(Thread*, object);
memcpy(&function, &finalizerFinalize(t, finalizer), BytesPerWord);
if (function) {
finalizerNext(t, finalizer) = t->m->finalizeQueue;
t->m->finalizeQueue = finalizer;
} else {
set(t, finalizer, FinalizerQueueTarget, finalizerTarget(t, finalizer));
set(t, finalizer, FinalizerQueueNext, root(t, Machine::ObjectsToFinalize));
setRoot(t, Machine::ObjectsToFinalize, finalizer);
}
}
void
@ -379,26 +389,34 @@ referenceTargetUnreachable(Thread* t, Heap::Visitor* v, object* p)
v->visit(p);
jreferenceTarget(t, *p) = 0;
if (jreferenceQueue(t, *p)
and t->m->heap->status(jreferenceQueue(t, *p)) != Heap::Unreachable)
{
// queue is reachable - add the reference
if (objectClass(t, *p) == type(t, Machine::CleanerType)) {
object reference = *p;
*p = jreferenceVmNext(t, reference);
v->visit(&jreferenceQueue(t, *p));
set(t, reference, CleanerQueueNext, root(t, Machine::ObjectsToClean));
setRoot(t, Machine::ObjectsToClean, reference);
} else {
if (jreferenceQueue(t, *p)
and t->m->heap->status(jreferenceQueue(t, *p)) != Heap::Unreachable)
{
// queue is reachable - add the reference
object q = jreferenceQueue(t, *p);
v->visit(&jreferenceQueue(t, *p));
if (referenceQueueFront(t, q)) {
set(t, *p, JreferenceJNext, referenceQueueFront(t, q));
} else {
set(t, *p, JreferenceJNext, *p);
object q = jreferenceQueue(t, *p);
if (referenceQueueFront(t, q)) {
set(t, *p, JreferenceJNext, referenceQueueFront(t, q));
} else {
set(t, *p, JreferenceJNext, *p);
}
set(t, q, ReferenceQueueFront, *p);
jreferenceQueue(t, *p) = 0;
}
set(t, q, ReferenceQueueFront, *p);
jreferenceQueue(t, *p) = 0;
*p = jreferenceVmNext(t, *p);
}
*p = jreferenceVmNext(t, *p);
}
void
@ -602,8 +620,8 @@ postCollect(Thread* t)
uint64_t
invoke(Thread* t, uintptr_t* arguments)
{
object m = reinterpret_cast<object>(arguments[0]);
object o = reinterpret_cast<object>(arguments[1]);
object m = *reinterpret_cast<object*>(arguments[0]);
object o = *reinterpret_cast<object*>(arguments[1]);
t->m->processor->invoke(t, m, o);
@ -611,19 +629,22 @@ invoke(Thread* t, uintptr_t* arguments)
}
void
finalizeObject(Thread* t, object o)
finalizeObject(Thread* t, object o, const char* name)
{
for (object c = objectClass(t, o); c; c = classSuper(t, c)) {
for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, c)); ++i) {
object m = arrayBody(t, classMethodTable(t, c), i);
if (vm::strcmp(reinterpret_cast<const int8_t*>("finalize"),
if (vm::strcmp(reinterpret_cast<const int8_t*>(name),
&byteArrayBody(t, methodName(t, m), 0)) == 0
and vm::strcmp(reinterpret_cast<const int8_t*>("()V"),
&byteArrayBody(t, methodSpec(t, m), 0)) == 0)
{
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(m),
reinterpret_cast<uintptr_t>(o) };
PROTECT(t, m);
PROTECT(t, o);
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(&m),
reinterpret_cast<uintptr_t>(&o) };
run(t, invoke, arguments);
@ -736,7 +757,6 @@ parseUtf8(Thread* t, Stream& s, unsigned length)
value = v;
}
byteArrayBody(t, value, vi) = 0;
return value;
}
@ -949,8 +969,20 @@ addInterfaces(Thread* t, object class_, object map)
}
}
object
getClassAddendum(Thread* t, object class_, object pool)
{
object addendum = classAddendum(t, class_);
if (addendum == 0) {
addendum = makeClassAddendum(t, pool, 0, 0, 0, 0, 0);
set(t, class_, ClassAddendum, addendum);
}
return addendum;
}
void
parseInterfaceTable(Thread* t, Stream& s, object class_, object pool)
parseInterfaceTable(Thread* t, Stream& s, object class_, object pool,
Machine::Type throwType)
{
PROTECT(t, class_);
PROTECT(t, pool);
@ -963,14 +995,27 @@ parseInterfaceTable(Thread* t, Stream& s, object class_, object pool)
}
unsigned count = s.read2();
object table = 0;
PROTECT(t, table);
if (count) {
table = makeArray(t, count);
object addendum = getClassAddendum(t, class_, pool);
set(t, addendum, ClassAddendumInterfaceTable, table);
}
for (unsigned i = 0; i < count; ++i) {
object name = referenceName(t, singletonObject(t, pool, s.read2() - 1));
PROTECT(t, name);
object interface = resolveClass(t, classLoader(t, class_), name);
object interface = resolveClass
(t, classLoader(t, class_), name, true, throwType);
PROTECT(t, interface);
set(t, table, ArrayBody + (i * BytesPerWord), interface);
hashMapInsertMaybe(t, map, name, interface, byteArrayHash, byteArrayEqual);
addInterfaces(t, interface, map);
@ -1043,6 +1088,8 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
unsigned value = 0;
addendum = 0;
unsigned code = fieldCode
(t, byteArrayBody(t, singletonObject(t, pool, spec - 1), 0));
@ -1055,14 +1102,28 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
&byteArrayBody(t, name, 0)) == 0)
{
value = s.read2();
} else if (vm::strcmp(reinterpret_cast<const int8_t*>("Signature"),
&byteArrayBody(t, name, 0)) == 0)
{
if (addendum == 0) {
addendum = makeFieldAddendum(t, pool, 0, 0);
}
set(t, addendum, AddendumSignature,
singletonObject(t, pool, s.read2() - 1));
} else if (vm::strcmp(reinterpret_cast<const int8_t*>
("RuntimeVisibleAnnotations"),
&byteArrayBody(t, name, 0)) == 0)
{
if (addendum == 0) {
addendum = makeFieldAddendum(t, pool, 0, 0);
}
object body = makeByteArray(t, length);
s.read(reinterpret_cast<uint8_t*>(&byteArrayBody(t, body, 0)),
length);
addendum = makeFieldAddendum(t, pool, body);
set(t, addendum, AddendumAnnotationTable, body);
} else {
s.skip(length);
}
@ -1074,6 +1135,7 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
code,
flags,
0, // offset
0, // native ID
singletonObject(t, pool, name - 1),
singletonObject(t, pool, spec - 1),
addendum,
@ -1269,20 +1331,6 @@ parseCode(Thread* t, Stream& s, object pool)
return code;
}
void
scanMethodSpec(Thread* t, const char* s, unsigned* parameterCount,
unsigned* returnCode)
{
unsigned count = 0;
MethodSpecIterator it(t, s);
for (; it.hasNext(); it.next()) {
++ count;
}
*parameterCount = count;
*returnCode = fieldCode(t, *it.returnSpec());
}
object
addInterfaceMethods(Thread* t, object class_, object virtualMap,
unsigned* virtualCount, bool makeList)
@ -1396,6 +1444,7 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
unsigned name = s.read2();
unsigned spec = s.read2();
addendum = 0;
code = 0;
unsigned attributeCount = s.read2();
@ -1411,7 +1460,7 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
&byteArrayBody(t, name, 0)) == 0)
{
if (addendum == 0) {
addendum = makeMethodAddendum(t, pool, 0, 0);
addendum = makeMethodAddendum(t, pool, 0, 0, 0, 0);
}
unsigned exceptionCount = s.read2();
object body = makeShortArray(t, exceptionCount);
@ -1419,16 +1468,40 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
shortArrayBody(t, body, i) = s.read2();
}
set(t, addendum, MethodAddendumExceptionTable, body);
} else if (vm::strcmp(reinterpret_cast<const int8_t*>
("AnnotationDefault"),
&byteArrayBody(t, name, 0)) == 0)
{
if (addendum == 0) {
addendum = makeMethodAddendum(t, pool, 0, 0, 0, 0);
}
object body = makeByteArray(t, length);
s.read(reinterpret_cast<uint8_t*>(&byteArrayBody(t, body, 0)),
length);
set(t, addendum, MethodAddendumAnnotationDefault, body);
} else if (vm::strcmp(reinterpret_cast<const int8_t*>("Signature"),
&byteArrayBody(t, name, 0)) == 0)
{
if (addendum == 0) {
addendum = makeMethodAddendum(t, pool, 0, 0, 0, 0);
}
set(t, addendum, AddendumSignature,
singletonObject(t, pool, s.read2() - 1));
} else if (vm::strcmp(reinterpret_cast<const int8_t*>
("RuntimeVisibleAnnotations"),
&byteArrayBody(t, name, 0)) == 0)
{
if (addendum == 0) {
addendum = makeMethodAddendum(t, pool, 0, 0);
addendum = makeMethodAddendum(t, pool, 0, 0, 0, 0);
}
object body = makeByteArray(t, length);
s.read(reinterpret_cast<uint8_t*>(&byteArrayBody(t, body, 0)),
length);
set(t, addendum, AddendumAnnotationTable, body);
} else {
s.skip(length);
@ -1581,6 +1654,10 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
if (abstractVirtuals) {
PROTECT(t, vtable);
object addendum = getClassAddendum(t, class_, pool);
set(t, addendum, ClassAddendumMethodTable,
classMethodTable(t, class_));
unsigned oldLength = arrayLength(t, classMethodTable(t, class_));
object newMethodTable = makeArray
(t, oldLength + listSize(t, abstractVirtuals));
@ -1641,6 +1718,9 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
void
parseAttributeTable(Thread* t, Stream& s, object class_, object pool)
{
PROTECT(t, class_);
PROTECT(t, pool);
unsigned attributeCount = s.read2();
for (unsigned j = 0; j < attributeCount; ++j) {
object name = singletonObject(t, pool, s.read2() - 1);
@ -1650,16 +1730,46 @@ parseAttributeTable(Thread* t, Stream& s, object class_, object pool)
&byteArrayBody(t, name, 0)) == 0)
{
set(t, class_, ClassSourceFile, singletonObject(t, pool, s.read2() - 1));
} else if (vm::strcmp(reinterpret_cast<const int8_t*>("Signature"),
&byteArrayBody(t, name, 0)) == 0)
{
object addendum = getClassAddendum(t, class_, pool);
set(t, addendum, AddendumSignature,
singletonObject(t, pool, s.read2() - 1));
} else if (vm::strcmp(reinterpret_cast<const int8_t*>("InnerClasses"),
&byteArrayBody(t, name, 0)) == 0)
{
unsigned innerClassCount = s.read2();
object table = makeArray(t, innerClassCount);
PROTECT(t, table);
for (unsigned i = 0; i < innerClassCount; ++i) {
int16_t inner = s.read2();
int16_t outer = s.read2();
int16_t name = s.read2();
int16_t flags = s.read2();
object reference = makeInnerClassReference
(t, inner ? singletonObject(t, pool, inner - 1) : 0,
outer ? singletonObject(t, pool, outer - 1) : 0,
name ? singletonObject(t, pool, name - 1) : 0,
flags);
set(t, table, ArrayBody + (i * BytesPerWord), reference);
}
object addendum = getClassAddendum(t, class_, pool);
set(t, addendum, ClassAddendumInnerClassTable, table);
} else if (vm::strcmp(reinterpret_cast<const int8_t*>
("RuntimeVisibleAnnotations"),
&byteArrayBody(t, name, 0)) == 0)
{
object body = makeByteArray(t, length);
PROTECT(t, body);
s.read(reinterpret_cast<uint8_t*>(&byteArrayBody(t, body, 0)), length);
object addendum = makeClassAddendum(t, pool, body);
set(t, class_, ClassAddendum, addendum);
object addendum = getClassAddendum(t, class_, pool);
set(t, addendum, AddendumAnnotationTable, body);
} else {
s.skip(length);
}
@ -1722,6 +1832,7 @@ updateBootstrapClass(Thread* t, object bootstrapClass, object class_)
set(t, bootstrapClass, ClassFieldTable, classFieldTable(t, class_));
set(t, bootstrapClass, ClassMethodTable, classMethodTable(t, class_));
set(t, bootstrapClass, ClassStaticTable, classStaticTable(t, class_));
set(t, bootstrapClass, ClassAddendum, classAddendum(t, class_));
updateClassTables(t, bootstrapClass, class_);
}
@ -1773,8 +1884,26 @@ makeArrayClass(Thread* t, object loader, unsigned dimensions, object spec,
return c;
}
void
saveLoadedClass(Thread* t, object loader, object c)
{
PROTECT(t, loader);
PROTECT(t, c);
ACQUIRE(t, t->m->classLock);
if (classLoaderMap(t, loader) == 0) {
object map = makeHashMap(t, 0, 0);
set(t, loader, ClassLoaderMap, map);
}
hashMapInsert
(t, classLoaderMap(t, loader), className(t, c), c, byteArrayHash);
}
object
makeArrayClass(Thread* t, object loader, object spec, bool throw_)
makeArrayClass(Thread* t, object loader, object spec, bool throw_,
Machine::Type throwType)
{
PROTECT(t, loader);
PROTECT(t, spec);
@ -1816,20 +1945,32 @@ makeArrayClass(Thread* t, object loader, object spec, bool throw_)
byteArrayEqual);
if (elementClass == 0) {
elementClass = resolveClass(t, loader, elementSpec, throw_);
elementClass = resolveClass(t, loader, elementSpec, throw_, throwType);
if (elementClass == 0) return 0;
}
PROTECT(t, elementClass);
object class_ = findLoadedClass(t, classLoader(t, elementClass), spec);
ACQUIRE(t, t->m->classLock);
return class_ ? class_ : makeArrayClass
object class_ = findLoadedClass(t, classLoader(t, elementClass), spec);
if (class_) {
return class_;
}
class_ = makeArrayClass
(t, classLoader(t, elementClass), dimensions, spec, elementClass);
PROTECT(t, class_);
saveLoadedClass(t, classLoader(t, elementClass), class_);
return class_;
}
object
resolveArrayClass(Thread* t, object loader, object spec, bool throw_)
resolveArrayClass(Thread* t, object loader, object spec, bool throw_,
Machine::Type throwType)
{
object c = hashMapFind
(t, root(t, Machine::BootstrapClassMap), spec, byteArrayHash,
@ -1849,7 +1990,7 @@ resolveArrayClass(Thread* t, object loader, object spec, bool throw_)
if (c) {
return c;
} else {
return makeArrayClass(t, loader, spec, throw_);
return makeArrayClass(t, loader, spec, throw_, throwType);
}
}
}
@ -2166,8 +2307,13 @@ class HeapClient: public Heap::Client {
void
doCollect(Thread* t, Heap::CollectionType type)
{
expect(t, not t->m->collecting);
t->m->collecting = true;
THREAD_RESOURCE0(t, t->m->collecting = false);
#ifdef VM_STRESS
bool stress = (t->flags |= Thread::StressFlag);
bool stress = (t->flags & Thread::StressFlag) != 0;
if (not stress) atomicOr(&(t->flags), Thread::StressFlag);
#endif
@ -2198,20 +2344,17 @@ doCollect(Thread* t, Heap::CollectionType type)
if (not stress) atomicAnd(&(t->flags), ~Thread::StressFlag);
#endif
object f = t->m->finalizeQueue;
object finalizeQueue = t->m->finalizeQueue;
t->m->finalizeQueue = 0;
for (; f; f = finalizerNext(t, f)) {
for (; finalizeQueue; finalizeQueue = finalizerNext(t, finalizeQueue)) {
void (*function)(Thread*, object);
memcpy(&function, &finalizerFinalize(t, f), BytesPerWord);
if (function) {
function(t, finalizerTarget(t, f));
} else {
setRoot(t, Machine::ObjectsToFinalize, makePair
(t, finalizerTarget(t, f), root(t, Machine::ObjectsToFinalize)));
}
memcpy(&function, &finalizerFinalize(t, finalizeQueue), BytesPerWord);
function(t, finalizerTarget(t, finalizeQueue));
}
if (root(t, Machine::ObjectsToFinalize) and m->finalizeThread == 0) {
if ((root(t, Machine::ObjectsToFinalize) or root(t, Machine::ObjectsToClean))
and m->finalizeThread == 0)
{
m->finalizeThread = m->processor->makeThread
(m, root(t, Machine::FinalizerThread), m->rootThread);
@ -2224,6 +2367,28 @@ doCollect(Thread* t, Heap::CollectionType type)
}
}
uint64_t
invokeLoadClass(Thread* t, uintptr_t* arguments)
{
object method = reinterpret_cast<object>(arguments[0]);
object loader = reinterpret_cast<object>(arguments[1]);
object specString = reinterpret_cast<object>(arguments[2]);
return reinterpret_cast<uintptr_t>
(t->m->processor->invoke(t, method, loader, specString));
}
bool
isInitializing(Thread* t, object c)
{
for (Thread::ClassInitStack* s = t->classInitStack; s; s = s->next) {
if (s->class_ == c) {
return true;
}
}
return false;
}
} // namespace
namespace vm {
@ -2257,6 +2422,7 @@ Machine::Machine(System* system, Heap* heap, Finder* bootFinder,
referenceLock(0),
shutdownLock(0),
libraries(0),
errorLog(0),
types(0),
roots(0),
finalizers(0),
@ -2265,6 +2431,7 @@ Machine::Machine(System* system, Heap* heap, Finder* bootFinder,
weakReferences(0),
tenuredWeakReferences(0),
unsafe(false),
collecting(false),
triedBuiltinOnLoad(false),
dumpedHeapOnOOM(false),
heapPoolIndex(0)
@ -2388,6 +2555,7 @@ Thread::init()
setRoot(this, Machine::ClassRuntimeDataTable, makeVector(this, 0, 0));
setRoot(this, Machine::MethodRuntimeDataTable, makeVector(this, 0, 0));
setRoot(this, Machine::JNIMethodTable, makeVector(this, 0, 0));
setRoot(this, Machine::JNIFieldTable, makeVector(this, 0, 0));
m->localThread->set(this);
@ -3009,13 +3177,12 @@ isAssignableFrom(Thread* t, object a, object b)
}
}
for (; b; b = classSuper(t, b)) {
object itable = classInterfaceTable(t, b);
if (itable) {
for (unsigned i = 0; i < arrayLength(t, itable); i += 2) {
if (arrayBody(t, itable, i) == a) {
return true;
}
object itable = classInterfaceTable(t, b);
if (itable) {
unsigned stride = (classFlags(t, b) & ACC_INTERFACE) ? 1 : 2;
for (unsigned i = 0; i < arrayLength(t, itable); i += stride) {
if (arrayBody(t, itable, i) == a) {
return true;
}
}
}
@ -3057,7 +3224,7 @@ classInitializer(Thread* t, object class_)
return o;
}
}
abort(t);
return 0;
}
unsigned
@ -3141,7 +3308,8 @@ primitiveSize(Thread* t, unsigned code)
}
object
parseClass(Thread* t, object loader, const uint8_t* data, unsigned size)
parseClass(Thread* t, object loader, const uint8_t* data, unsigned size,
Machine::Type throwType)
{
PROTECT(t, loader);
@ -3189,22 +3357,25 @@ parseClass(Thread* t, object loader, const uint8_t* data, unsigned size)
0, // addendum
0, // static table
loader,
0, // source
0);// vtable length
PROTECT(t, class_);
unsigned super = s.read2();
if (super) {
object sc = resolveClass
(t, loader, referenceName(t, singletonObject(t, pool, super - 1)));
(t, loader, referenceName(t, singletonObject(t, pool, super - 1)),
true, throwType);
set(t, class_, ClassSuper, sc);
classVmFlags(t, class_)
|= (classVmFlags(t, sc)
& (ReferenceFlag | WeakReferenceFlag | HasFinalizerFlag));
& (ReferenceFlag | WeakReferenceFlag | HasFinalizerFlag
| NeedInitFlag));
}
parseInterfaceTable(t, s, class_, pool);
parseInterfaceTable(t, s, class_, pool, throwType);
parseFieldTable(t, s, class_, pool);
@ -3245,7 +3416,8 @@ parseClass(Thread* t, object loader, const uint8_t* data, unsigned size)
}
object
resolveSystemClass(Thread* t, object loader, object spec, bool throw_)
resolveSystemClass(Thread* t, object loader, object spec, bool throw_,
Machine::Type throwType)
{
PROTECT(t, loader);
PROTECT(t, spec);
@ -3256,6 +3428,8 @@ resolveSystemClass(Thread* t, object loader, object spec, bool throw_)
(t, classLoaderMap(t, loader), spec, byteArrayHash, byteArrayEqual);
if (class_ == 0) {
PROTECT(t, class_);
if (classLoaderParent(t, loader)) {
class_ = resolveSystemClass
(t, classLoaderParent(t, loader), spec, false);
@ -3265,7 +3439,7 @@ resolveSystemClass(Thread* t, object loader, object spec, bool throw_)
}
if (byteArrayBody(t, spec, 0) == '[') {
class_ = resolveArrayClass(t, loader, spec, throw_);
class_ = resolveArrayClass(t, loader, spec, throw_, throwType);
} else {
THREAD_RUNTIME_ARRAY(t, char, file, byteArrayLength(t, spec) + 6);
memcpy(RUNTIME_ARRAY_BODY(file),
@ -3287,7 +3461,8 @@ resolveSystemClass(Thread* t, object loader, object spec, bool throw_)
{ THREAD_RESOURCE(t, System::Region*, region, region->dispose());
// parse class file
class_ = parseClass(t, loader, region->start(), region->length());
class_ = parseClass
(t, loader, region->start(), region->length(), throwType);
}
if (Verbose) {
@ -3296,6 +3471,20 @@ resolveSystemClass(Thread* t, object loader, object spec, bool throw_)
class_);
}
{ const char* source = static_cast<Finder*>
(systemClassLoaderFinder(t, loader))->sourceUrl
(RUNTIME_ARRAY_BODY(file));
if (source) {
unsigned length = strlen(source);
object array = makeByteArray(t, length + 1);
memcpy(&byteArrayBody(t, array, 0), source, length);
array = internByteArray(t, array);
set(t, class_, ClassSource, array);
}
}
object bootstrapClass = hashMapFind
(t, root(t, Machine::BootstrapClassMap), spec, byteArrayHash,
byteArrayEqual);
@ -3310,12 +3499,9 @@ resolveSystemClass(Thread* t, object loader, object spec, bool throw_)
}
if (class_) {
PROTECT(t, class_);
hashMapInsert(t, classLoaderMap(t, loader), spec, class_, byteArrayHash);
} else if (throw_) {
throwNew(t, Machine::ClassNotFoundExceptionType, "%s",
&byteArrayBody(t, spec, 0));
throwNew(t, throwType, "%s", &byteArrayBody(t, spec, 0));
}
}
@ -3335,13 +3521,12 @@ findLoadedClass(Thread* t, object loader, object spec)
}
object
resolveClass(Thread* t, object loader, object spec, bool throw_)
resolveClass(Thread* t, object loader, object spec, bool throw_,
Machine::Type throwType)
{
if (objectClass(t, loader) == type(t, Machine::SystemClassLoaderType)) {
return resolveSystemClass(t, loader, spec, throw_);
return resolveSystemClass(t, loader, spec, throw_, throwType);
} else {
expect(t, throw_);
PROTECT(t, loader);
PROTECT(t, spec);
@ -3351,7 +3536,7 @@ resolveClass(Thread* t, object loader, object spec, bool throw_)
}
if (byteArrayBody(t, spec, 0) == '[') {
c = resolveArrayClass(t, loader, spec, throw_);
c = resolveArrayClass(t, loader, spec, throw_, throwType);
} else {
if (root(t, Machine::LoadClassMethod) == 0) {
object m = resolveMethod
@ -3381,31 +3566,39 @@ resolveClass(Thread* t, object loader, object spec, bool throw_)
(&byteArrayBody(t, spec, 0)));
object specString = makeString(t, "%s", RUNTIME_ARRAY_BODY(s));
PROTECT(t, specString);
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(method),
reinterpret_cast<uintptr_t>(loader),
reinterpret_cast<uintptr_t>(specString) };
object jc = reinterpret_cast<object>
(runRaw(t, invokeLoadClass, arguments));
object jc = t->m->processor->invoke(t, method, loader, specString);
if (LIKELY(jc)) {
c = jclassVmClass(t, jc);
} else if (t->exception) {
if (throw_) {
object e = type(t, throwType) == objectClass(t, t->exception)
? t->exception
: makeThrowable(t, throwType, specString, 0, t->exception);
t->exception = 0;
vm::throw_(t, e);
} else {
t->exception = 0;
}
}
}
if (LIKELY(c)) {
PROTECT(t, c);
ACQUIRE(t, t->m->classLock);
if (classLoaderMap(t, loader) == 0) {
object map = makeHashMap(t, 0, 0);
set(t, loader, ClassLoaderMap, map);
}
hashMapInsert
(t, classLoaderMap(t, loader), spec, c, byteArrayHash);
return c;
} else {
throwNew(t, Machine::ClassNotFoundExceptionType, "%s",
&byteArrayBody(t, spec, 0));
saveLoadedClass(t, loader, c);
} else if (throw_) {
throwNew(t, throwType, "%s", &byteArrayBody(t, spec, 0));
}
return c;
}
}
@ -3484,7 +3677,11 @@ classNeedsInit(Thread* t, object c)
bool
preInitClass(Thread* t, object c)
{
if (classVmFlags(t, c) & NeedInitFlag) {
int flags = classVmFlags(t, c);
loadMemoryBarrier();
if (flags & NeedInitFlag) {
PROTECT(t, c);
ACQUIRE(t, t->m->classLock);
@ -3493,7 +3690,7 @@ preInitClass(Thread* t, object c)
// If the class is currently being initialized and this the thread
// which is initializing it, we should not try to initialize it
// recursively.
if (t->m->processor->isInitializing(t, c)) {
if (isInitializing(t, c)) {
return false;
}
@ -3540,12 +3737,21 @@ initClass(Thread* t, object c)
{
PROTECT(t, c);
object super = classSuper(t, c);
if (super) {
initClass(t, super);
}
if (preInitClass(t, c)) {
OBJECT_RESOURCE(t, c, postInitClass(t, c));
Thread::ClassInitStack stack(t, c);
object initializer = classInitializer(t, c);
t->m->processor->invoke(t, classInitializer(t, c), 0);
if (initializer) {
Thread::ClassInitStack stack(t, c);
t->m->processor->invoke(t, initializer, 0);
}
}
}
@ -3697,7 +3903,7 @@ addFinalizer(Thread* t, object target, void (*finalize)(Thread*, object))
void* function;
memcpy(&function, &finalize, BytesPerWord);
object f = makeFinalizer(t, 0, function, 0);
object f = makeFinalizer(t, 0, function, 0, 0, 0);
finalizerTarget(t, f) = target;
finalizerNext(t, f) = t->m->finalizers;
t->m->finalizers = f;
@ -3887,42 +4093,44 @@ printTrace(Thread* t, object exception)
for (object e = exception; e; e = throwableCause(t, e)) {
if (e != exception) {
fprintf(stderr, "caused by: ");
fprintf(errorLog(t), "caused by: ");
}
fprintf(stderr, "%s", &byteArrayBody
fprintf(errorLog(t), "%s", &byteArrayBody
(t, className(t, objectClass(t, e)), 0));
if (throwableMessage(t, e)) {
object m = throwableMessage(t, e);
THREAD_RUNTIME_ARRAY(t, char, message, stringLength(t, m) + 1);
stringChars(t, m, RUNTIME_ARRAY_BODY(message));
fprintf(stderr, ": %s\n", RUNTIME_ARRAY_BODY(message));
fprintf(errorLog(t), ": %s\n", RUNTIME_ARRAY_BODY(message));
} else {
fprintf(stderr, "\n");
fprintf(errorLog(t), "\n");
}
object trace = throwableTrace(t, e);
for (unsigned i = 0; i < objectArrayLength(t, trace); ++i) {
object e = objectArrayBody(t, trace, i);
const int8_t* class_ = &byteArrayBody
(t, className(t, methodClass(t, traceElementMethod(t, e))), 0);
const int8_t* method = &byteArrayBody
(t, methodName(t, traceElementMethod(t, e)), 0);
int line = t->m->processor->lineNumber
(t, traceElementMethod(t, e), traceElementIp(t, e));
if (trace) {
for (unsigned i = 0; i < objectArrayLength(t, trace); ++i) {
object e = objectArrayBody(t, trace, i);
const int8_t* class_ = &byteArrayBody
(t, className(t, methodClass(t, traceElementMethod(t, e))), 0);
const int8_t* method = &byteArrayBody
(t, methodName(t, traceElementMethod(t, e)), 0);
int line = t->m->processor->lineNumber
(t, traceElementMethod(t, e), traceElementIp(t, e));
fprintf(stderr, " at %s.%s ", class_, method);
fprintf(errorLog(t), " at %s.%s ", class_, method);
switch (line) {
case NativeLine:
fprintf(stderr, "(native)\n");
break;
case UnknownLine:
fprintf(stderr, "(unknown line)\n");
break;
default:
fprintf(stderr, "(line %d)\n", line);
switch (line) {
case NativeLine:
fprintf(errorLog(t), "(native)\n");
break;
case UnknownLine:
fprintf(errorLog(t), "(unknown line)\n");
break;
default:
fprintf(errorLog(t), "(line %d)\n", line);
}
}
}
@ -3931,7 +4139,7 @@ printTrace(Thread* t, object exception)
}
}
fflush(stderr);
fflush(errorLog(t));
}
object
@ -3989,14 +4197,18 @@ makeTrace(Thread* t, Thread* target)
void
runFinalizeThread(Thread* t)
{
object list = 0;
PROTECT(t, list);
object finalizeList = 0;
PROTECT(t, finalizeList);
object cleanList = 0;
PROTECT(t, cleanList);
while (true) {
{ ACQUIRE(t, t->m->stateLock);
while (t->m->finalizeThread
and root(t, Machine::ObjectsToFinalize) == 0)
and root(t, Machine::ObjectsToFinalize) == 0
and root(t, Machine::ObjectsToClean) == 0)
{
ENTER(t, Thread::IdleState);
t->m->stateLock->wait(t->systemThread, 0);
@ -4005,13 +4217,20 @@ runFinalizeThread(Thread* t)
if (t->m->finalizeThread == 0) {
return;
} else {
list = root(t, Machine::ObjectsToFinalize);
finalizeList = root(t, Machine::ObjectsToFinalize);
setRoot(t, Machine::ObjectsToFinalize, 0);
cleanList = root(t, Machine::ObjectsToClean);
setRoot(t, Machine::ObjectsToClean, 0);
}
}
for (; list; list = pairSecond(t, list)) {
finalizeObject(t, pairFirst(t, list));
for (; finalizeList; finalizeList = finalizerQueueNext(t, finalizeList)) {
finalizeObject(t, finalizerQueueTarget(t, finalizeList), "finalize");
}
for (; cleanList; cleanList = cleanerQueueNext(t, cleanList)) {
finalizeObject(t, cleanList, "clean");
}
}
}
@ -4072,23 +4291,60 @@ defineClass(Thread* t, object loader, const uint8_t* buffer, unsigned length)
PROTECT(t, loader);
object c = parseClass(t, loader, buffer, length);
// char name[byteArrayLength(t, className(t, c))];
// memcpy(name, &byteArrayBody(t, className(t, c), 0),
// byteArrayLength(t, className(t, c)));
// replace('/', '-', name);
if (c) {
PROTECT(t, c);
ACQUIRE(t, t->m->classLock);
// const unsigned BufferSize = 1024;
// char path[BufferSize];
// snprintf(path, BufferSize, "/tmp/avian-define-class/%s.class", name);
if (classLoaderMap(t, loader) == 0) {
object map = makeHashMap(t, 0, 0);
set(t, loader, ClassLoaderMap, map);
}
// FILE* file = fopen(path, "wb");
// if (file) {
// fwrite(buffer, length, 1, file);
// fclose(file);
// }
hashMapInsert
(t, classLoaderMap(t, loader), className(t, c), c, byteArrayHash);
}
PROTECT(t, c);
saveLoadedClass(t, loader, c);
return c;
}
void
populateMultiArray(Thread* t, object array, int32_t* counts,
unsigned index, unsigned dimensions)
{
if (index + 1 == dimensions or counts[index] == 0) {
return;
}
PROTECT(t, array);
object spec = className(t, objectClass(t, array));
PROTECT(t, spec);
object elementSpec = makeByteArray(t, byteArrayLength(t, spec) - 1);
memcpy(&byteArrayBody(t, elementSpec, 0),
&byteArrayBody(t, spec, 1),
byteArrayLength(t, spec) - 1);
object class_ = resolveClass
(t, classLoader(t, objectClass(t, array)), elementSpec);
PROTECT(t, class_);
for (int32_t i = 0; i < counts[index]; ++i) {
object a = makeArray(t, counts[index + 1]);
setObjectClass(t, a, class_);
set(t, array, ArrayBody + (i * BytesPerWord), a);
populateMultiArray(t, a, counts, index + 1, dimensions);
}
}
void
noop()
{ }

View File

@ -33,6 +33,12 @@
#define ACQUIRE_OBJECT(t, x) \
ObjectMonitorResource MAKE_NAME(monitorResource_) (t, x)
#define ACQUIRE_FIELD_FOR_READ(t, field) \
FieldReadResource MAKE_NAME(monitorResource_) (t, field)
#define ACQUIRE_FIELD_FOR_WRITE(t, field) \
FieldWriteResource MAKE_NAME(monitorResource_) (t, field)
#define ACQUIRE_RAW(t, x) RawMonitorResource MAKE_NAME(monitorResource_) (t, x)
#define ENTER(t, state) StateResource MAKE_NAME(stateResource_) (t, state)
@ -132,8 +138,8 @@ enum StackTag {
ObjectTag
};
const int NativeLine = -1;
const int UnknownLine = -2;
const int NativeLine = -2;
const int UnknownLine = -1;
// class vmFlags:
const unsigned ReferenceFlag = 1 << 0;
@ -1250,9 +1256,11 @@ class Machine {
ClassRuntimeDataTable,
MethodRuntimeDataTable,
JNIMethodTable,
JNIFieldTable,
ShutdownHooks,
FinalizerThread,
ObjectsToFinalize,
ObjectsToClean,
NullPointerException,
ArithmeticException,
ArrayIndexOutOfBoundsException,
@ -1298,6 +1306,7 @@ class Machine {
System::Monitor* referenceLock;
System::Monitor* shutdownLock;
System::Library* libraries;
FILE* errorLog;
object types;
object roots;
object finalizers;
@ -1306,6 +1315,7 @@ class Machine {
object weakReferences;
object tenuredWeakReferences;
bool unsafe;
bool collecting;
bool triedBuiltinOnLoad;
bool dumpedHeapOnOOM;
JavaVMVTable javaVMVTable;
@ -1557,6 +1567,9 @@ class Classpath {
virtual void
runThread(Thread* t) = 0;
virtual void
resolveNative(Thread* t, object method) = 0;
virtual void
boot(Thread* t) = 0;
@ -2250,7 +2263,11 @@ markHashTaken(Thread* t, object o)
inline uint32_t
takeHash(Thread*, object o)
{
return reinterpret_cast<uintptr_t>(o) / BytesPerWord;
// some broken code implicitly relies on System.identityHashCode
// always returning a non-negative number (e.g. old versions of
// com/sun/xml/bind/v2/util/CollisionCheckStack.hash), hence the "&
// 0x7FFFFFFF":
return (reinterpret_cast<uintptr_t>(o) / BytesPerWord) & 0x7FFFFFFF;
}
inline uint32_t
@ -2429,6 +2446,20 @@ fieldSize(Thread* t, object field)
return fieldSize(t, fieldCode(t, field));
}
inline void
scanMethodSpec(Thread* t, const char* s, unsigned* parameterCount,
unsigned* returnCode)
{
unsigned count = 0;
MethodSpecIterator it(t, s);
for (; it.hasNext(); it.next()) {
++ count;
}
*parameterCount = count;
*returnCode = fieldCode(t, *it.returnSpec());
}
object
findLoadedClass(Thread* t, object loader, object spec);
@ -2444,21 +2475,26 @@ object
parseUtf8(Thread* t, const char* data, unsigned length);
object
parseClass(Thread* t, object loader, const uint8_t* data, unsigned length);
parseClass(Thread* t, object loader, const uint8_t* data, unsigned length,
Machine::Type throwType = Machine::NoClassDefFoundErrorType);
object
resolveClass(Thread* t, object loader, object name, bool throw_ = true);
resolveClass(Thread* t, object loader, object name, bool throw_ = true,
Machine::Type throwType = Machine::NoClassDefFoundErrorType);
inline object
resolveClass(Thread* t, object loader, const char* name, bool throw_ = true)
resolveClass(Thread* t, object loader, const char* name, bool throw_ = true,
Machine::Type throwType = Machine::NoClassDefFoundErrorType)
{
PROTECT(t, loader);
object n = makeByteArray(t, "%s", name);
return resolveClass(t, loader, n, throw_);
return resolveClass(t, loader, n, throw_, throwType);
}
object
resolveSystemClass(Thread* t, object loader, object name, bool throw_ = true);
resolveSystemClass
(Thread* t, object loader, object name, bool throw_ = true,
Machine::Type throwType = Machine::NoClassDefFoundErrorType);
inline object
resolveSystemClass(Thread* t, object loader, const char* name)
@ -2597,6 +2633,7 @@ inline void NO_RETURN
throw_(Thread* t, object e)
{
assert(t, t->exception == 0);
assert(t, e);
expect(t, not t->checkpoint->noThrow);
@ -2637,11 +2674,11 @@ findInHierarchyOrNull(Thread* t, object class_, object name, object spec,
inline object
findInHierarchy(Thread* t, object class_, object name, object spec,
object (*find)(Thread*, object, object, object),
Machine::Type errorType)
Machine::Type errorType, bool throw_ = true)
{
object o = findInHierarchyOrNull(t, class_, name, spec, find);
if (o == 0) {
if (throw_ and o == 0) {
throwNew(t, errorType, "%s %s not found in %s",
&byteArrayBody(t, name, 0),
&byteArrayBody(t, spec, 0),
@ -2765,11 +2802,13 @@ atomicCompareAndSwapObject(Thread* t, object target, unsigned offset,
// Queue Algorithm: http://www.cs.rochester.edu/u/michael/PODC96.html
inline void
monitorAtomicAppendAcquire(Thread* t, object monitor)
monitorAtomicAppendAcquire(Thread* t, object monitor, object node)
{
PROTECT(t, monitor);
if (node == 0) {
PROTECT(t, monitor);
object node = makeMonitorNode(t, t, 0);
node = makeMonitorNode(t, t, 0);
}
while (true) {
object tail = monitorAcquireTail(t, monitor);
@ -2849,14 +2888,15 @@ monitorTryAcquire(Thread* t, object monitor)
}
inline void
monitorAcquire(Thread* t, object monitor)
monitorAcquire(Thread* t, object monitor, object node = 0)
{
if (not monitorTryAcquire(t, monitor)) {
PROTECT(t, monitor);
PROTECT(t, node);
ACQUIRE(t, t->lock);
monitorAtomicAppendAcquire(t, monitor);
monitorAtomicAppendAcquire(t, monitor, node);
// note that we don't try to acquire the lock until we're first in
// line, both because it's fair and because we don't support
@ -2980,6 +3020,11 @@ monitorWait(Thread* t, object monitor, int64_t time)
PROTECT(t, monitor);
// pre-allocate monitor node so we don't get an OutOfMemoryError
// when we try to re-acquire the monitor below
object monitorNode = makeMonitorNode(t, t, 0);
PROTECT(t, monitorNode);
{ ACQUIRE(t, t->lock);
monitorAppendWait(t, monitor);
@ -2994,7 +3039,7 @@ monitorWait(Thread* t, object monitor, int64_t time)
interrupted = t->lock->wait(t->systemThread, time);
}
monitorAcquire(t, monitor);
monitorAcquire(t, monitor, monitorNode);
monitorDepth(t, monitor) = depth;
@ -3330,93 +3375,208 @@ poolSize(Thread* t, object pool)
inline object
resolveClassInObject(Thread* t, object loader, object container,
unsigned classOffset)
unsigned classOffset, bool throw_ = true)
{
object o = cast<object>(container, classOffset);
loadMemoryBarrier();
if (objectClass(t, o) == type(t, Machine::ByteArrayType)) {
PROTECT(t, container);
o = resolveClass(t, loader, o);
o = resolveClass(t, loader, o, throw_);
set(t, container, classOffset, o);
if (o) {
storeStoreMemoryBarrier();
set(t, container, classOffset, o);
}
}
return o;
}
inline object
resolveClassInPool(Thread* t, object loader, object method, unsigned index)
resolveClassInPool(Thread* t, object loader, object method, unsigned index,
bool throw_ = true)
{
object o = singletonObject(t, codePool(t, methodCode(t, method)), index);
loadMemoryBarrier();
if (objectClass(t, o) == type(t, Machine::ReferenceType)) {
PROTECT(t, method);
o = resolveClass(t, loader, referenceName(t, o));
o = resolveClass(t, loader, referenceName(t, o), throw_);
set(t, codePool(t, methodCode(t, method)),
SingletonBody + (index * BytesPerWord), o);
if (o) {
storeStoreMemoryBarrier();
set(t, codePool(t, methodCode(t, method)),
SingletonBody + (index * BytesPerWord), o);
}
}
return o;
}
inline object
resolveClassInPool(Thread* t, object method, unsigned index)
resolveClassInPool(Thread* t, object method, unsigned index,
bool throw_ = true)
{
return resolveClassInPool(t, classLoader(t, methodClass(t, method)),
method, index);
method, index, throw_);
}
inline object
resolve(Thread* t, object loader, object method, unsigned index,
object (*find)(vm::Thread*, object, object, object),
Machine::Type errorType)
Machine::Type errorType, bool throw_ = true)
{
object o = singletonObject(t, codePool(t, methodCode(t, method)), index);
if (objectClass(t, o) == type(t, Machine::ReferenceType))
{
loadMemoryBarrier();
if (objectClass(t, o) == type(t, Machine::ReferenceType)) {
PROTECT(t, method);
object reference = o;
PROTECT(t, reference);
object class_ = resolveClassInObject(t, loader, o, ReferenceClass);
object class_ = resolveClassInObject(t, loader, o, ReferenceClass, throw_);
o = findInHierarchy
(t, class_, referenceName(t, reference), referenceSpec(t, reference),
find, errorType);
if (class_) {
o = findInHierarchy
(t, class_, referenceName(t, reference), referenceSpec(t, reference),
find, errorType, throw_);
set(t, codePool(t, methodCode(t, method)),
SingletonBody + (index * BytesPerWord), o);
if (o) {
storeStoreMemoryBarrier();
set(t, codePool(t, methodCode(t, method)),
SingletonBody + (index * BytesPerWord), o);
}
} else {
o = 0;
}
}
return o;
}
inline object
resolveField(Thread* t, object loader, object method, unsigned index)
resolveField(Thread* t, object loader, object method, unsigned index,
bool throw_ = true)
{
return resolve(t, loader, method, index, findFieldInClass,
Machine::NoSuchFieldErrorType);
Machine::NoSuchFieldErrorType, throw_);
}
inline object
resolveField(Thread* t, object method, unsigned index)
resolveField(Thread* t, object method, unsigned index, bool throw_ = true)
{
return resolveField
(t, classLoader(t, methodClass(t, method)), method, index);
(t, classLoader(t, methodClass(t, method)), method, index, throw_);
}
inline void
acquireFieldForRead(Thread* t, object field)
{
if (UNLIKELY((fieldFlags(t, field) & ACC_VOLATILE)
and BytesPerWord == 4
and (fieldCode(t, field) == DoubleField
or fieldCode(t, field) == LongField)))
{
acquire(t, field);
}
}
inline void
releaseFieldForRead(Thread* t, object field)
{
if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) {
if (BytesPerWord == 4
and (fieldCode(t, field) == DoubleField
or fieldCode(t, field) == LongField))
{
release(t, field);
} else {
loadMemoryBarrier();
}
}
}
class FieldReadResource {
public:
FieldReadResource(Thread* t, object o): o(o), protector(t, &(this->o)) {
acquireFieldForRead(protector.t, o);
}
~FieldReadResource() {
releaseFieldForRead(protector.t, o);
}
private:
object o;
Thread::SingleProtector protector;
};
inline void
acquireFieldForWrite(Thread* t, object field)
{
if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) {
if (BytesPerWord == 4
and (fieldCode(t, field) == DoubleField
or fieldCode(t, field) == LongField))
{
acquire(t, field);
} else {
storeStoreMemoryBarrier();
}
}
}
inline void
releaseFieldForWrite(Thread* t, object field)
{
if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) {
if (BytesPerWord == 4
and (fieldCode(t, field) == DoubleField
or fieldCode(t, field) == LongField))
{
release(t, field);
} else {
storeLoadMemoryBarrier();
}
}
}
class FieldWriteResource {
public:
FieldWriteResource(Thread* t, object o): o(o), protector(t, &(this->o)) {
acquireFieldForWrite(protector.t, o);
}
~FieldWriteResource() {
releaseFieldForWrite(protector.t, o);
}
private:
object o;
Thread::SingleProtector protector;
};
inline object
resolveMethod(Thread* t, object loader, object method, unsigned index)
resolveMethod(Thread* t, object loader, object method, unsigned index,
bool throw_ = true)
{
return resolve(t, loader, method, index, findMethodInClass,
Machine::NoSuchMethodErrorType);
Machine::NoSuchMethodErrorType, throw_);
}
inline object
resolveMethod(Thread* t, object method, unsigned index)
resolveMethod(Thread* t, object method, unsigned index, bool throw_ = true)
{
return resolveMethod
(t, classLoader(t, methodClass(t, method)), method, index);
(t, classLoader(t, methodClass(t, method)), method, index, throw_);
}
object
@ -3459,7 +3619,11 @@ getClassRuntimeData(Thread* t, object c)
inline object
getMethodRuntimeData(Thread* t, object method)
{
if (methodRuntimeDataIndex(t, method) == 0) {
int index = methodRuntimeDataIndex(t, method);
loadMemoryBarrier();
if (index == 0) {
PROTECT(t, method);
ACQUIRE(t, t->m->classLock);
@ -3470,6 +3634,8 @@ getMethodRuntimeData(Thread* t, object method)
setRoot(t, Machine::MethodRuntimeDataTable, vectorAppend
(t, root(t, Machine::MethodRuntimeDataTable), runtimeData));
storeStoreMemoryBarrier();
methodRuntimeDataIndex(t, method) = vectorSize
(t, root(t, Machine::MethodRuntimeDataTable));
}
@ -3485,12 +3651,17 @@ getJClass(Thread* t, object c)
PROTECT(t, c);
object jclass = classRuntimeDataJclass(t, getClassRuntimeData(t, c));
loadMemoryBarrier();
if (jclass == 0) {
ACQUIRE(t, t->m->classLock);
jclass = classRuntimeDataJclass(t, getClassRuntimeData(t, c));
if (jclass == 0) {
jclass = t->m->classpath->makeJclass(t, c);
storeStoreMemoryBarrier();
set(t, getClassRuntimeData(t, c), ClassRuntimeDataJclass, jclass);
}
@ -3548,6 +3719,10 @@ unregisterNatives(Thread* t, object c)
}
}
void
populateMultiArray(Thread* t, object array, int32_t* counts,
unsigned index, unsigned dimensions);
object
getCaller(Thread* t, unsigned target);
@ -3576,6 +3751,21 @@ methodClone(Thread* t, object method)
methodCode(t, method));
}
inline FILE*
errorLog(Thread* t)
{
if (t->m->errorLog == 0) {
const char* path = findProperty(t, "avian.error.log");
if (path) {
t->m->errorLog = vm::fopen(path, "wb");
} else {
t->m->errorLog = stderr;
}
}
return t->m->errorLog;
}
} // namespace vm
void

View File

@ -865,7 +865,7 @@ class MySystem: public System {
};
void
handleSignal(int signal, siginfo_t* info, void* context)
handleSignal(int signal, siginfo_t*, void* context)
{
ucontext_t* c = static_cast<ucontext_t*>(context);
@ -943,22 +943,14 @@ handleSignal(int signal, siginfo_t* info, void* context)
default: abort();
}
if (system->oldHandlers[index].sa_flags & SA_SIGINFO
and system->oldHandlers[index].sa_sigaction)
{
system->oldHandlers[index].sa_sigaction(signal, info, context);
} else if (system->oldHandlers[index].sa_handler) {
system->oldHandlers[index].sa_handler(signal);
} else {
switch (signal) {
case VisitSignal:
case InterruptSignal:
case PipeSignal:
break;
switch (signal) {
case VisitSignal:
case InterruptSignal:
case PipeSignal:
break;
default:
abort();
}
default:
abort();
}
}

View File

@ -196,7 +196,7 @@ class MyBlock: public Assembler::Block {
MyBlock(Context* context, unsigned offset):
context(context), next(0), jumpOffsetHead(0), jumpOffsetTail(0),
lastJumpOffsetTail(0), jumpEventHead(0), jumpEventTail(0),
lastEventOffset(0), offset(offset), start(~0), size(0)
lastEventOffset(0), offset(offset), start(~0), size(0), resolved(false)
{ }
virtual unsigned resolve(unsigned start, Assembler::Block* next) {
@ -205,6 +205,8 @@ class MyBlock: public Assembler::Block {
::resolve(this);
this->resolved = true;
return start + size + padding(this, size);
}
@ -219,6 +221,7 @@ class MyBlock: public Assembler::Block {
unsigned offset;
unsigned start;
unsigned size;
bool resolved;
};
class Task;
@ -326,13 +329,14 @@ class Offset: public Promise {
{ }
virtual bool resolved() {
return block->start != static_cast<unsigned>(~0);
return block->resolved;
}
virtual int64_t value() {
assert(c, resolved());
return block->start + (offset - block->offset);
unsigned o = offset - block->offset;
return block->start + padding(block, o) + o;
}
Context* c;
@ -495,38 +499,24 @@ appendJumpEvent(Context* c, MyBlock* b, unsigned offset, JumpOffset* head,
b->jumpEventTail = e;
}
bool
needJump(MyBlock* b)
{
return b->next or (not bounded(2, 16, b->size));
}
unsigned
padding(MyBlock* b, unsigned offset)
{
unsigned total = 0;
for (JumpEvent** e = &(b->jumpEventHead); *e;) {
if ((*e)->offset <= offset) {
for (JumpOffset** o = &((*e)->jumpOffsetHead); *o;) {
if ((*o)->task->promise->resolved()
and (*o)->task->instructionOffset->resolved())
{
int32_t v = reinterpret_cast<uint8_t*>((*o)->task->promise->value())
- (b->context->result + (*o)->task->instructionOffset->value());
if (bounded(2, 16, v)) {
// this conditional jump needs no indirection -- a direct
// jump will suffice
*o = (*o)->next;
continue;
}
}
for (JumpEvent* e = b->jumpEventHead; e; e = e->next) {
if (e->offset <= offset) {
for (JumpOffset* o = e->jumpOffsetHead; o; o = o->next) {
total += BytesPerWord;
o = &((*o)->next);
}
if ((*e)->jumpOffsetHead == 0) {
*e = (*e)->next;
} else {
if (b->next) {
total += BytesPerWord;
}
e = &((*e)->next);
if (needJump(b)) {
total += BytesPerWord;
}
} else {
break;
@ -541,6 +531,32 @@ resolve(MyBlock* b)
{
Context* c = b->context;
for (JumpEvent** e = &(b->jumpEventHead); *e;) {
for (JumpOffset** o = &((*e)->jumpOffsetHead); *o;) {
if ((*o)->task->promise->resolved()
and (*o)->task->instructionOffset->resolved())
{
int32_t v = reinterpret_cast<uint8_t*>((*o)->task->promise->value())
- (c->result + (*o)->task->instructionOffset->value());
if (bounded(2, 16, v)) {
// this conditional jump needs no indirection -- a direct
// jump will suffice
*o = (*o)->next;
continue;
}
}
o = &((*o)->next);
}
if ((*e)->jumpOffsetHead == 0) {
*e = (*e)->next;
} else {
e = &((*e)->next);
}
}
if (b->jumpOffsetHead) {
if (c->jumpOffsetTail) {
c->jumpOffsetTail->next = b->jumpOffsetHead;
@ -2423,16 +2439,16 @@ class MyAssembler: public Assembler {
return arch_;
}
virtual void checkStackOverflow(uintptr_t /*handler*/,
unsigned /*stackLimitOffsetFromThread*/)
virtual void checkStackOverflow(uintptr_t handler,
unsigned stackLimitOffsetFromThread)
{
/*Register stack(StackRegister);
Register stack(StackRegister);
Memory stackLimit(ThreadRegister, stackLimitOffsetFromThread);
Constant handlerConstant
(new (c.zone->allocate(sizeof(ResolvedPromise)))
ResolvedPromise(handler));
branchRM(&c, JumpIfGreaterOrEqual, BytesPerWord, &stack, &stackLimit,
&handlerConstant);*/
&handlerConstant);
}
virtual void saveFrame(unsigned stackOffset, unsigned) {
@ -2680,7 +2696,7 @@ class MyAssembler: public Assembler {
uint8_t* address = dst + dstOffset + jumpTableSize;
if (b->next) {
if (needJump(b)) {
address += BytesPerWord;
}
@ -2691,7 +2707,7 @@ class MyAssembler: public Assembler {
assert(&c, jumpTableSize);
if (b->next) {
if (needJump(b)) {
write4(dst + dstOffset, ::b(jumpTableSize + BytesPerWord));
}

View File

@ -56,37 +56,6 @@ isSpecialMethod(Thread* t, object method, object class_)
and isSuperclass(t, methodClass(t, method), class_);
}
inline void
populateMultiArray(Thread* t, object array, int32_t* counts,
unsigned index, unsigned dimensions)
{
if (index + 1 == dimensions or counts[index] == 0) {
return;
}
PROTECT(t, array);
object spec = className(t, objectClass(t, array));
PROTECT(t, spec);
object elementSpec = makeByteArray(t, byteArrayLength(t, spec) - 1);
memcpy(&byteArrayBody(t, elementSpec, 0),
&byteArrayBody(t, spec, 1),
byteArrayLength(t, spec) - 1);
object class_ = resolveClass
(t, classLoader(t, objectClass(t, array)), elementSpec);
PROTECT(t, class_);
for (int32_t i = 0; i < counts[index]; ++i) {
object a = makeArray(t, counts[index + 1]);
setObjectClass(t, a, class_);
set(t, array, ArrayBody + (i * BytesPerWord), a);
populateMultiArray(t, a, counts, index + 1, dimensions);
}
}
void
resolveNative(Thread* t, object method);

View File

@ -81,9 +81,6 @@ class Processor {
virtual void
initVtable(Thread* t, object c) = 0;
virtual bool
isInitializing(Thread* t, object c) = 0;
virtual void
visitObjects(Thread* t, Heap::Visitor* v) = 0;

View File

@ -1,5 +1,9 @@
THUNK(tryInitClass)
THUNK(findInterfaceMethodFromInstance)
THUNK(findInterfaceMethodFromInstanceAndReference)
THUNK(findSpecialMethodFromReference)
THUNK(findStaticMethodFromReference)
THUNK(findVirtualMethodFromReference)
THUNK(compareDoublesG)
THUNK(compareDoublesL)
THUNK(compareFloatsG)
@ -36,17 +40,32 @@ THUNK(intToFloat)
THUNK(longToDouble)
THUNK(longToFloat)
THUNK(makeBlankObjectArray)
THUNK(makeBlankObjectArrayFromReference)
THUNK(makeBlankArray)
THUNK(lookUpAddress)
THUNK(setMaybeNull)
THUNK(acquireMonitorForObject)
THUNK(acquireMonitorForObjectOnEntrance)
THUNK(releaseMonitorForObject)
THUNK(makeMultidimensionalArray)
THUNK(makeMultidimensionalArrayFromReference)
THUNK(throw_)
THUNK(checkCast)
THUNK(checkCastFromReference)
THUNK(getStaticFieldValueFromReference)
THUNK(getFieldValueFromReference)
THUNK(setStaticFieldValueFromReference)
THUNK(setFieldValueFromReference)
THUNK(setStaticLongFieldValueFromReference)
THUNK(setLongFieldValueFromReference)
THUNK(setStaticObjectFieldValueFromReference)
THUNK(setObjectFieldValueFromReference)
THUNK(instanceOf64)
THUNK(instanceOfFromReference)
THUNK(makeNewGeneral64)
THUNK(makeNew64)
THUNK(makeNewFromReference)
THUNK(set)
THUNK(getJClass64)
THUNK(getJClassFromReference)
THUNK(gcIfNecessary)

View File

@ -2177,8 +2177,22 @@ writeNameInitialization(Output* out, Object* type)
{
out->write("nameClass(t, Machine::");
out->write(capitalize(typeName(type)));
out->write("Type, \"vm::");
out->write(typeName(type));
out->write("Type, \"");
if (equal(typeName(type), "jbyte")
or equal(typeName(type), "jboolean")
or equal(typeName(type), "jshort")
or equal(typeName(type), "jchar")
or equal(typeName(type), "jint")
or equal(typeName(type), "jlong")
or equal(typeName(type), "jfloat")
or equal(typeName(type), "jdouble")
or equal(typeName(type), "jvoid"))
{
out->write(typeName(type) + 1);
} else {
out->write("vm::");
out->write(typeName(type));
}
out->write("\");\n");
}

View File

@ -104,7 +104,9 @@
(type finalizer
(nogc object target)
(void* finalize)
(nogc object next))
(nogc object next)
(object queueTarget)
(object queueNext))
(type hashMap
(uint32_t size)
@ -159,6 +161,12 @@
(void* value)
(object next))
(type innerClassReference
(object inner)
(object outer)
(object name)
(int16_t flags))
(type continuationContext
(object next)
(object before)
@ -294,6 +302,9 @@
(type phantomReference java/lang/ref/PhantomReference)
(type cleaner sun/misc/Cleaner
(object queueNext))
(type byteArray [B
(extends jobject)
(array int8_t body))

View File

@ -33,6 +33,7 @@ class Vector {
void dispose() {
if (data and minimumCapacity >= 0) {
allocator->free(data, capacity);
data = 0;
}
}

View File

@ -969,7 +969,7 @@ sseMoveRR(Context* c, unsigned aSize, Assembler::Register* a,
modrm(c, 0xc0, a, b);
} else {
opcode(c, 0xf2);
maybeRex(c, 4, a, b);
maybeRex(c, 4, b, a);
opcode(c, 0x0f, 0x10);
modrm(c, 0xc0, a, b);
}
@ -2865,7 +2865,7 @@ class MyArchitecture: public Assembler::Architecture {
virtual void updateCall(UnaryOperation op, void* returnAddress,
void* newTarget)
{
bool assertAlignment;
bool assertAlignment UNUSED;
switch (op) {
case AlignedCall:
op = Call;

View File

@ -45,23 +45,27 @@ class Zone: public Allocator {
next = seg->next;
allocator->free(seg, sizeof(Segment) + seg->size);
}
segment = 0;
}
bool ensure(unsigned space) {
if (segment == 0 or position + space > segment->size) {
unsigned size = max
(space, max
(minimumFootprint, segment == 0 ? 0 : segment->size * 2))
+ sizeof(Segment);
static unsigned padToPage(unsigned size) {
return (size + (LikelyPageSizeInBytes - 1))
& ~(LikelyPageSizeInBytes - 1);
}
// pad to page size
size = (size + (LikelyPageSizeInBytes - 1))
& ~(LikelyPageSizeInBytes - 1);
bool tryEnsure(unsigned space) {
if (segment == 0 or position + space > segment->size) {
unsigned size = padToPage
(max
(space, max
(minimumFootprint, segment == 0 ? 0 : segment->size * 2))
+ sizeof(Segment));
void* p = allocator->tryAllocate(size);
if (p == 0) {
size = space + sizeof(Segment);
void* p = allocator->tryAllocate(size);
size = padToPage(space + sizeof(Segment));
p = allocator->tryAllocate(size);
if (p == 0) {
return false;
}
@ -73,9 +77,19 @@ class Zone: public Allocator {
return true;
}
void ensure(unsigned space) {
if (segment == 0 or position + space > segment->size) {
unsigned size = padToPage(space + sizeof(Segment));
segment = new (allocator->allocate(size))
Segment(segment, size - sizeof(Segment));
position = 0;
}
}
virtual void* tryAllocate(unsigned size) {
size = pad(size);
if (ensure(size)) {
if (tryEnsure(size)) {
void* r = segment->data + position;
position += size;
return r;
@ -86,8 +100,14 @@ class Zone: public Allocator {
virtual void* allocate(unsigned size) {
void* p = tryAllocate(size);
expect(s, p);
return p;
if (p) {
return p;
} else {
ensure(size);
void* r = segment->data + position;
position += size;
return r;
}
}
virtual void free(const void*, unsigned) {

View File

@ -49,7 +49,7 @@ public class DefineClass {
}
public static void main(String[] args) throws Exception {
//testStatic();
testStatic();
testDerived();
}
@ -59,7 +59,7 @@ public class DefineClass {
}
public Class defineClass(String name, byte[] bytes) {
return super.defineClass(name, bytes, 0, bytes.length);
return defineClass(name, bytes, 0, bytes.length);
}
}

View File

@ -33,7 +33,91 @@ public class Floats {
return f.field * a;
}
private static void subdivide(double src[], int srcoff,
double left[], int leftoff,
double right[], int rightoff)
{
double x1 = src[srcoff + 0];
double y1 = src[srcoff + 1];
double ctrlx1 = src[srcoff + 2];
double ctrly1 = src[srcoff + 3];
double ctrlx2 = src[srcoff + 4];
double ctrly2 = src[srcoff + 5];
double x2 = src[srcoff + 6];
double y2 = src[srcoff + 7];
if (left != null) {
left[leftoff + 0] = x1;
left[leftoff + 1] = y1;
}
if (right != null) {
right[rightoff + 6] = x2;
right[rightoff + 7] = y2;
}
x1 = (x1 + ctrlx1) / 2.0;
y1 = (y1 + ctrly1) / 2.0;
x2 = (x2 + ctrlx2) / 2.0;
y2 = (y2 + ctrly2) / 2.0;
double centerx = (ctrlx1 + ctrlx2) / 2.0;
double centery = (ctrly1 + ctrly2) / 2.0;
ctrlx1 = (x1 + centerx) / 2.0;
ctrly1 = (y1 + centery) / 2.0;
ctrlx2 = (x2 + centerx) / 2.0;
ctrly2 = (y2 + centery) / 2.0;
centerx = (ctrlx1 + ctrlx2) / 2.0;
centery = (ctrly1 + ctrly2) / 2.0;
if (left != null) {
left[leftoff + 2] = x1;
left[leftoff + 3] = y1;
left[leftoff + 4] = ctrlx1;
left[leftoff + 5] = ctrly1;
left[leftoff + 6] = centerx;
left[leftoff + 7] = centery;
}
if (right != null) {
right[rightoff + 0] = centerx;
right[rightoff + 1] = centery;
right[rightoff + 2] = ctrlx2;
right[rightoff + 3] = ctrly2;
right[rightoff + 4] = x2;
right[rightoff + 5] = y2;
}
}
public static void main(String[] args) {
{ double input[] = new double[8];
double left[] = new double[8];
double right[] = new double[8];
input[0] = 732.0;
input[1] = 952.0;
input[2] = 761.0;
input[3] = 942.0;
input[4] = 786.0;
input[5] = 944.0;
input[6] = 813.0;
input[7] = 939.0;
subdivide(input, 0, left, 0, right, 0);
expect(left[0] == 732.0);
expect(left[1] == 952.0);
expect(left[2] == 746.5);
expect(left[3] == 947.0);
expect(left[4] == 760.0);
expect(left[5] == 945.0);
expect(left[6] == 773.25);
expect(left[7] == 943.625);
expect(right[0] == 773.25);
expect(right[1] == 943.625);
expect(right[2] == 786.5);
expect(right[3] == 942.25);
expect(right[4] == 799.5);
expect(right[5] == 941.5);
expect(right[6] == 813.0);
expect(right[7] == 939.0);
}
expect(multiply(0.5d, 0.5d) == 0.25d);
expect(multiply(0.5f, 0.5f) == 0.25f);

184
test/LazyLoading.java Normal file
View File

@ -0,0 +1,184 @@
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class LazyLoading {
private static boolean loadLazy;
private static void expect(boolean v) {
if (! v) throw new RuntimeException();
}
private static File findClass(String name, File directory) {
for (File file: directory.listFiles()) {
if (file.isFile()) {
if (file.getName().equals(name + ".class")) {
return file;
}
} else if (file.isDirectory()) {
File result = findClass(name, file);
if (result != null) {
return result;
}
}
}
return null;
}
private static byte[] read(File file) throws IOException {
byte[] bytes = new byte[(int) file.length()];
FileInputStream in = new FileInputStream(file);
try {
if (in.read(bytes) != (int) file.length()) {
throw new RuntimeException();
}
return bytes;
} finally {
in.close();
}
}
public static void main(String[] args) throws Exception {
Class c = new MyClassLoader(LazyLoading.class.getClassLoader()).loadClass
("LazyLoading$Test");
c.getMethod("test").invoke(null);
}
private static class MyClassLoader extends ClassLoader {
public MyClassLoader(ClassLoader parent) {
super(parent);
}
protected Class findClass(String name) throws ClassNotFoundException {
try {
return defineClass
(name, read
(LazyLoading.findClass
(name, new File(System.getProperty("user.dir")))));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public Class loadClass(String name) throws ClassNotFoundException {
if ("LazyLoading$Test".equals(name)) {
return findClass(name);
} else if ("LazyLoading$Lazy".equals(name)
|| "LazyLoading$Interface".equals(name))
{
if (loadLazy) {
return findClass(name);
} else {
throw new ClassNotFoundException();
}
} else {
return super.loadClass(name);
}
}
private Class defineClass(String name, byte[] bytes) {
return defineClass(name, bytes, 0, bytes.length);
}
}
public static class Test {
public static void test() {
doTest();
loadLazy = true;
doTest();
}
private static void doTest() {
if (loadLazy) {
// anewarray
Lazy[] array = new Lazy[1];
// new and invokespecial
Object lazy = new Lazy();
// checkcast
array[0] = (Lazy) lazy;
// instanceof
expect(lazy instanceof Lazy);
// invokeinterface
Interface i = array[0];
expect(i.interfaceMethod() == 42);
// invokestatic
expect(Lazy.staticMethod() == 43);
// invokevirtual
expect(array[0].virtualMethod() == 44);
// ldc
expect(Lazy.class == lazy.getClass());
// multianewarray
Lazy[][] multiarray = new Lazy[5][6];
multiarray[2][3] = array[0];
expect(multiarray[2][3] == array[0]);
// getfield
expect(array[0].intField == 45);
// getstatic
expect(Lazy.intStaticField == 46);
// putfield int
array[0].intField = 47;
expect(array[0].intField == 47);
// putfield long
array[0].longField = 48;
expect(array[0].longField == 48);
// putfield object
Object x = new Object();
array[0].objectField = x;
expect(array[0].objectField == x);
// putstatic int
array[0].intStaticField = 49;
expect(array[0].intStaticField == 49);
// putstatic long
array[0].longStaticField = 50;
expect(array[0].longStaticField == 50);
// putstatic object
Object y = new Object();
array[0].objectStaticField = y;
expect(array[0].objectStaticField == y);
}
}
}
private interface Interface {
public int interfaceMethod();
}
private static class Lazy implements Interface {
public static int intStaticField = 46;
public static long longStaticField;
public static Object objectStaticField;
public int intField = 45;
public long longField;
public Object objectField;
public int interfaceMethod() {
return 42;
}
public static int staticMethod() {
return 43;
}
public int virtualMethod() {
return 44;
}
}
}

View File

@ -1,4 +1,10 @@
public class Longs {
public class Longs {
private static volatile long volatileLong = getConstant();
private static long getConstant() {
return 0x123456789ABCDEFL;
}
private static void expect(boolean v) {
if (! v) throw new RuntimeException();
}
@ -60,6 +66,8 @@ public class Longs {
}
public static void main(String[] args) throws Exception {
expect(volatileLong == getConstant());
{ long a = 0x1FFFFFFFFL;
long b = -1;
expect(a != b);

49
test/extra/Tails.java Normal file
View File

@ -0,0 +1,49 @@
package extra;
public class Tails {
private static final int Limit = 1000000;
private static void expect(boolean v) {
if (! v) throw new RuntimeException();
}
private static int staticMethod(Interface i, int n) {
if (n < Limit) {
return i.interfaceMethod(n + 1);
} else {
return leafMethod(n);
}
}
private static int leafMethod(int n) {
expect(new Throwable().getStackTrace().length == 2);
return n;
}
public static void main(String[] args) {
expect(staticMethod(new Foo(), 0) == Limit);
}
private interface Interface {
public int interfaceMethod(int n);
}
private static class Foo implements Interface {
public int interfaceMethod(int n) {
if (n < Limit) {
return virtualMethod(n + 1, 1, 2, 3, 4, 5);
} else {
return leafMethod(n);
}
}
public int virtualMethod(int n, int a, int b, int c, int d, int e) {
if (n < Limit) {
return staticMethod(this, n + 1);
} else {
return leafMethod(n);
}
}
}
}