mirror of
https://github.com/corda/corda.git
synced 2025-01-08 14:03:06 +00:00
Merge branch 'oss-master'
This commit is contained in:
commit
381165f26d
@ -12,5 +12,6 @@ package avian;
|
||||
|
||||
public class Addendum {
|
||||
public Object pool;
|
||||
public Object annotationTable;
|
||||
public Object annotationTable;
|
||||
public Object signature;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -12,4 +12,5 @@ package avian;
|
||||
|
||||
public class MethodAddendum extends Addendum {
|
||||
public Object exceptionTable;
|
||||
public Object annotationDefault;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
44
classpath/avian/file/Handler.java
Normal file
44
classpath/avian/file/Handler.java
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
84
classpath/avian/jar/Handler.java
Normal file
84
classpath/avian/jar/Handler.java
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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 };
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
40
classpath/java/io/FilterOutputStream.java
Normal file
40
classpath/java/io/FilterOutputStream.java
Normal 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);
|
||||
}
|
||||
|
||||
}
|
@ -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 {
|
||||
|
@ -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(" ");
|
||||
|
@ -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() {
|
||||
|
@ -93,7 +93,7 @@ public abstract class ClassLoader {
|
||||
avian.Classes.link(c.vmClass, this);
|
||||
}
|
||||
|
||||
private ClassLoader getParent() {
|
||||
public final ClassLoader getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
22
classpath/java/net/JarURLConnection.java
Normal file
22
classpath/java/net/JarURLConnection.java
Normal 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;
|
||||
}
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -20,4 +20,8 @@ public class ProtectionDomain {
|
||||
this.codeSource = codeSource;
|
||||
this.permissions = permissions;
|
||||
}
|
||||
|
||||
public CodeSource getCodeSource() {
|
||||
return codeSource;
|
||||
}
|
||||
}
|
||||
|
13
classpath/java/security/cert/Certificate.java
Normal file
13
classpath/java/security/cert/Certificate.java
Normal 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 { }
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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 : "");
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
14
classpath/java/util/RandomAccess.java
Normal file
14
classpath/java/util/RandomAccess.java
Normal 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 {
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
15
classpath/java/util/jar/JarEntry.java
Normal file
15
classpath/java/util/jar/JarEntry.java
Normal 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 { }
|
81
classpath/java/util/jar/JarFile.java
Normal file
81
classpath/java/util/jar/JarFile.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
69
classpath/java/util/zip/CRC32.java
Normal file
69
classpath/java/util/zip/CRC32.java
Normal 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;
|
||||
}
|
||||
}
|
@ -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() {
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -13,4 +13,5 @@ package java.util.zip;
|
||||
public abstract class ZipEntry {
|
||||
public abstract String getName();
|
||||
public abstract int getCompressedSize();
|
||||
public abstract int getSize();
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
13
classpath/sun/misc/Cleaner.java
Normal file
13
classpath/sun/misc/Cleaner.java
Normal 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 { }
|
43
makefile
43
makefile
@ -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 $(@)
|
||||
|
@ -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)
|
||||
|
10
openjdk.pro
10
openjdk.pro
@ -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;
|
||||
}
|
||||
|
55
readme.txt
55
readme.txt
@ -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
|
||||
|
12
src/arm.cpp
12
src/arm.cpp
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
27
src/common.h
27
src/common.h
@ -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;
|
||||
|
||||
|
1726
src/compile.cpp
1726
src/compile.cpp
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
269
src/finder.cpp
269
src/finder.cpp
@ -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;
|
||||
}
|
||||
|
90
src/finder.h
90
src/finder.h
@ -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;
|
||||
};
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
949
src/jnienv.cpp
949
src/jnienv.cpp
File diff suppressed because it is too large
Load Diff
546
src/machine.cpp
546
src/machine.cpp
@ -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()
|
||||
{ }
|
||||
|
276
src/machine.h
276
src/machine.h
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
@ -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))
|
||||
|
@ -33,6 +33,7 @@ class Vector {
|
||||
void dispose() {
|
||||
if (data and minimumCapacity >= 0) {
|
||||
allocator->free(data, capacity);
|
||||
data = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
48
src/zone.h
48
src/zone.h
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
184
test/LazyLoading.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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
49
test/extra/Tails.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user