mirror of
https://github.com/corda/corda.git
synced 2025-01-01 02:36:44 +00:00
Merge branch 'master' into powerpc
Conflicts: makefile src/assembler.h src/compile.cpp src/compiler.cpp src/compiler.h src/finder.cpp
This commit is contained in:
parent
2304a656cf
commit
c80eb51c17
@ -14,12 +14,14 @@
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni-util.h"
|
||||
|
||||
#ifdef WIN32
|
||||
# include <windows.h>
|
||||
# include <io.h>
|
||||
|
||||
# define OPEN _open
|
||||
@ -34,6 +36,7 @@
|
||||
# define OPEN_MASK O_BINARY
|
||||
#else
|
||||
# include <unistd.h>
|
||||
# include "sys/mman.h"
|
||||
|
||||
# define OPEN open
|
||||
# define CLOSE close
|
||||
@ -47,6 +50,8 @@
|
||||
# define OPEN_MASK 0
|
||||
#endif
|
||||
|
||||
inline void* operator new(size_t, void* p) throw() { return p; }
|
||||
|
||||
namespace {
|
||||
|
||||
inline bool
|
||||
@ -95,9 +100,118 @@ doWrite(JNIEnv* e, jint fd, const jbyte* data, jint length)
|
||||
int r = WRITE(fd, data, length);
|
||||
if (r != length) {
|
||||
throwNew(e, "java/io/IOException", strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
class Mapping {
|
||||
public:
|
||||
Mapping(uint8_t* start, size_t length, HANDLE mapping, HANDLE file):
|
||||
start(start),
|
||||
length(length),
|
||||
mapping(mapping),
|
||||
file(file)
|
||||
{ }
|
||||
|
||||
uint8_t* start;
|
||||
size_t length;
|
||||
HANDLE mapping;
|
||||
HANDLE file;
|
||||
};
|
||||
|
||||
inline Mapping*
|
||||
map(JNIEnv* e, const char* path)
|
||||
{
|
||||
Mapping* result = 0;
|
||||
HANDLE file = CreateFile(path, FILE_READ_DATA, FILE_SHARE_READ, 0,
|
||||
OPEN_EXISTING, 0, 0);
|
||||
if (file != INVALID_HANDLE_VALUE) {
|
||||
unsigned size = GetFileSize(file, 0);
|
||||
if (size != INVALID_FILE_SIZE) {
|
||||
HANDLE mapping = CreateFileMapping(file, 0, PAGE_READONLY, 0, size, 0);
|
||||
if (mapping) {
|
||||
void* data = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
|
||||
if (data) {
|
||||
void* p = allocate(e, sizeof(Mapping));
|
||||
if (not e->ExceptionOccurred()) {
|
||||
result = new (p)
|
||||
Mapping(static_cast<uint8_t*>(data), size, file, mapping);
|
||||
}
|
||||
}
|
||||
|
||||
if (result == 0) {
|
||||
CloseHandle(mapping);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result == 0) {
|
||||
CloseHandle(file);
|
||||
}
|
||||
}
|
||||
if (result == 0 and not e->ExceptionOccurred()) {
|
||||
throwNew(e, "java/io/IOException", "%d", GetLastError());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void
|
||||
unmap(JNIEnv*, Mapping* mapping)
|
||||
{
|
||||
UnmapViewOfFile(mapping->start);
|
||||
CloseHandle(mapping->mapping);
|
||||
CloseHandle(mapping->file);
|
||||
free(mapping);
|
||||
}
|
||||
|
||||
#else // not WIN32
|
||||
|
||||
class Mapping {
|
||||
public:
|
||||
Mapping(uint8_t* start, size_t length):
|
||||
start(start),
|
||||
length(length)
|
||||
{ }
|
||||
|
||||
uint8_t* start;
|
||||
size_t length;
|
||||
};
|
||||
|
||||
inline Mapping*
|
||||
map(JNIEnv* e, const char* path)
|
||||
{
|
||||
Mapping* result = 0;
|
||||
int fd = open(path, O_RDONLY);
|
||||
if (fd != -1) {
|
||||
struct stat s;
|
||||
int r = fstat(fd, &s);
|
||||
if (r != -1) {
|
||||
void* data = mmap(0, s.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
if (data) {
|
||||
void* p = allocate(e, sizeof(Mapping));
|
||||
if (not e->ExceptionOccurred()) {
|
||||
result = new (p) Mapping(static_cast<uint8_t*>(data), s.st_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
if (result == 0 and not e->ExceptionOccurred()) {
|
||||
throwNew(e, "java/io/IOException", strerror(errno));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void
|
||||
unmap(JNIEnv*, Mapping* mapping)
|
||||
{
|
||||
munmap(mapping->start, mapping->length);
|
||||
free(mapping);
|
||||
}
|
||||
|
||||
#endif // not WIN32
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" JNIEXPORT jstring JNICALL
|
||||
@ -333,3 +447,42 @@ Java_java_io_FileOutputStream_close(JNIEnv* e, jclass, jint fd)
|
||||
{
|
||||
doClose(e, fd);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_java_io_RandomAccessFile_open(JNIEnv* e, jclass, jstring path,
|
||||
jlongArray result)
|
||||
{
|
||||
const char* chars = e->GetStringUTFChars(path, 0);
|
||||
if (chars) {
|
||||
Mapping* mapping = map(e, chars);
|
||||
|
||||
jlong peer = reinterpret_cast<jlong>(mapping);
|
||||
e->SetLongArrayRegion(result, 0, 1, &peer);
|
||||
|
||||
jlong length = (mapping ? mapping->length : 0);
|
||||
e->SetLongArrayRegion(result, 1, 1, &length);
|
||||
|
||||
e->ReleaseStringUTFChars(path, chars);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_java_io_RandomAccessFile_copy(JNIEnv* e, jclass, jlong peer,
|
||||
jlong position, jbyteArray buffer,
|
||||
int offset, int length)
|
||||
{
|
||||
uint8_t* dst = reinterpret_cast<uint8_t*>
|
||||
(e->GetPrimitiveArrayCritical(buffer, 0));
|
||||
|
||||
memcpy(dst + offset,
|
||||
reinterpret_cast<Mapping*>(peer)->start + position,
|
||||
length);
|
||||
|
||||
e->ReleasePrimitiveArrayCritical(buffer, dst, 0);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_java_io_RandomAccessFile_close(JNIEnv* e, jclass, jlong peer)
|
||||
{
|
||||
unmap(e, reinterpret_cast<Mapping*>(peer));
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "jni.h"
|
||||
|
@ -24,6 +24,13 @@ public class ByteArrayOutputStream extends OutputStream {
|
||||
this(0);
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
chain = null;
|
||||
length = 0;
|
||||
buffer = null;
|
||||
position = 0;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return length;
|
||||
}
|
||||
|
72
classpath/java/io/RandomAccessFile.java
Normal file
72
classpath/java/io/RandomAccessFile.java
Normal file
@ -0,0 +1,72 @@
|
||||
/* Copyright (c) 2008, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
package java.io;
|
||||
|
||||
public class RandomAccessFile {
|
||||
private long peer;
|
||||
private long length;
|
||||
private long position = 0;
|
||||
|
||||
public RandomAccessFile(String name, String mode)
|
||||
throws FileNotFoundException
|
||||
{
|
||||
if (! mode.equals("r")) throw new IllegalArgumentException();
|
||||
|
||||
long[] result = new long[2];
|
||||
open(name, result);
|
||||
peer = result[0];
|
||||
length = result[1];
|
||||
}
|
||||
|
||||
private static native void open(String name, long[] result)
|
||||
throws FileNotFoundException;
|
||||
|
||||
public long length() throws IOException {
|
||||
return length;
|
||||
}
|
||||
|
||||
public long getFilePointer() throws IOException {
|
||||
return position;
|
||||
}
|
||||
|
||||
public void seek(long position) throws IOException {
|
||||
if (position < 0 || position > length) throw new IOException();
|
||||
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public void readFully(byte[] buffer, int offset, int length)
|
||||
throws IOException
|
||||
{
|
||||
if (peer == 0) throw new IOException();
|
||||
|
||||
if (length == 0) return;
|
||||
|
||||
if (position + length > this.length) throw new EOFException();
|
||||
|
||||
if (offset < 0 || offset + length > buffer.length)
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
|
||||
copy(peer, position, buffer, offset, length);
|
||||
}
|
||||
|
||||
private static native void copy(long peer, long position, byte[] buffer,
|
||||
int offset, int length);
|
||||
|
||||
public void close() throws IOException {
|
||||
if (peer != 0) {
|
||||
close(peer);
|
||||
peer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static native void close(long peer);
|
||||
}
|
@ -219,6 +219,25 @@ public final class Class <T> {
|
||||
}
|
||||
}
|
||||
|
||||
public Constructor getDeclaredConstructor(Class ... parameterTypes)
|
||||
throws NoSuchMethodException
|
||||
{
|
||||
Constructor c = null;
|
||||
Constructor[] constructors = getDeclaredConstructors();
|
||||
|
||||
for (int i = 0; i < constructors.length; ++i) {
|
||||
if (match(parameterTypes, constructors[i].getParameterTypes())) {
|
||||
c = constructors[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (c == null) {
|
||||
throw new NoSuchMethodException();
|
||||
} else {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
private int countConstructors(boolean publicOnly) {
|
||||
int count = 0;
|
||||
if (methodTable != null) {
|
||||
|
@ -30,6 +30,10 @@ public final class Integer extends Number implements Comparable<Integer> {
|
||||
return new Integer(value);
|
||||
}
|
||||
|
||||
public static Integer valueOf(String value) {
|
||||
return valueOf(parseInt(value));
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof Integer && ((Integer) o).value == value;
|
||||
}
|
||||
|
@ -75,6 +75,8 @@ public class Runtime {
|
||||
|
||||
public native long totalMemory();
|
||||
|
||||
public static native void dumpHeap(String outputFile);
|
||||
|
||||
private static class MyProcess extends Process {
|
||||
private long pid;
|
||||
private final int in;
|
||||
|
@ -74,7 +74,15 @@ public class StringBuffer implements CharSequence {
|
||||
sb.append(b, 0, b.length);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public synchronized int indexOf(String s) {
|
||||
return sb.indexOf(s);
|
||||
}
|
||||
|
||||
public synchronized int indexOf(String s, int fromIndex) {
|
||||
return sb.indexOf(s, fromIndex);
|
||||
}
|
||||
|
||||
public synchronized StringBuffer insert(int i, String s) {
|
||||
sb.insert(i, s);
|
||||
return this;
|
||||
@ -85,6 +93,11 @@ public class StringBuffer implements CharSequence {
|
||||
return this;
|
||||
}
|
||||
|
||||
public synchronized StringBuffer insert(int i, int v) {
|
||||
sb.insert(i, v);
|
||||
return this;
|
||||
}
|
||||
|
||||
public synchronized StringBuffer delete(int start, int end) {
|
||||
sb.delete(start, end);
|
||||
return this;
|
||||
@ -112,6 +125,10 @@ public class StringBuffer implements CharSequence {
|
||||
sb.setLength(v);
|
||||
}
|
||||
|
||||
public synchronized void setCharAt(int index, char ch) {
|
||||
sb.setCharAt(index, ch);
|
||||
}
|
||||
|
||||
public synchronized void getChars(int srcOffset, int srcLength, char[] dst,
|
||||
int dstOffset)
|
||||
{
|
||||
|
@ -154,6 +154,10 @@ public class StringBuilder implements CharSequence {
|
||||
return insert(i, new String(new char[] { c }, 0, 1, false));
|
||||
}
|
||||
|
||||
public StringBuilder insert(int i, int v) {
|
||||
return insert(i, String.valueOf(v));
|
||||
}
|
||||
|
||||
public StringBuilder delete(int start, int end) {
|
||||
if (start >= end) {
|
||||
return this;
|
||||
@ -322,4 +326,10 @@ public class StringBuilder implements CharSequence {
|
||||
public CharSequence subSequence(int start, int end) {
|
||||
return substring(start, end);
|
||||
}
|
||||
|
||||
public void setCharAt(int index, char ch) {
|
||||
if(index < 0 || index >= length) throw new IndexOutOfBoundsException();
|
||||
deleteCharAt(index);
|
||||
insert(index, ch);
|
||||
}
|
||||
}
|
||||
|
@ -111,8 +111,8 @@ public class Method<T> extends AccessibleObject implements Member {
|
||||
}
|
||||
}
|
||||
|
||||
public static native Object invoke(Method method, Object instance,
|
||||
Object ... arguments)
|
||||
private static native Object invoke(Method method, Object instance,
|
||||
Object ... arguments)
|
||||
throws InvocationTargetException, IllegalAccessException;
|
||||
|
||||
public Class getReturnType() {
|
||||
|
@ -45,6 +45,12 @@ public abstract class Calendar {
|
||||
fields[field] = value;
|
||||
}
|
||||
|
||||
public void set(int year, int month, int date) {
|
||||
set(YEAR, year);
|
||||
set(MONTH, month);
|
||||
set(DAY_OF_MONTH, date);
|
||||
}
|
||||
|
||||
public void setTime(Date date) {
|
||||
time = date.getTime();
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
package java.util;
|
||||
|
||||
public class Locale {
|
||||
public static final Locale ENGLISH = new Locale("en");
|
||||
public static final Locale ENGLISH = new Locale("en", "us");
|
||||
|
||||
private final String language;
|
||||
private final String country;
|
||||
|
@ -23,4 +23,8 @@ public class PropertyResourceBundle extends ResourceBundle {
|
||||
public Object handleGetObject(String key) {
|
||||
return map.get(key);
|
||||
}
|
||||
|
||||
public Enumeration<String> getKeys() {
|
||||
return map.keys();
|
||||
}
|
||||
}
|
||||
|
@ -58,6 +58,21 @@ public class Random {
|
||||
return next(32);
|
||||
}
|
||||
|
||||
public void nextBytes(byte[] bytes) {
|
||||
final int length = bytes.length;
|
||||
for (int i = 0; i < length;) {
|
||||
int r = nextInt();
|
||||
for (int j = Math.min(length - i, 4); j > 0; --j) {
|
||||
bytes[i++] = (byte) r;
|
||||
r >>= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public long nextLong() {
|
||||
return ((long) next(32) << 32) + next(32);
|
||||
}
|
||||
|
||||
public double nextDouble() {
|
||||
return (((long) next(26) << 27) + next(27)) / (double) (1L << 53);
|
||||
}
|
||||
|
@ -118,4 +118,6 @@ public abstract class ResourceBundle {
|
||||
}
|
||||
|
||||
protected abstract Object handleGetObject(String key);
|
||||
|
||||
public abstract Enumeration<String> getKeys();
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ package java.util;
|
||||
|
||||
public class Stack<T> extends Vector<T> {
|
||||
public boolean empty() {
|
||||
return size() != 0;
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
public T peek() {
|
||||
|
@ -61,8 +61,8 @@ public class Vector<T> implements List<T> {
|
||||
return list.set(index, value);
|
||||
}
|
||||
|
||||
public T setElementAt(T value, int index) {
|
||||
return set(index, value);
|
||||
public void setElementAt(T value, int index) {
|
||||
set(index, value);
|
||||
}
|
||||
|
||||
public T elementAt(int index) {
|
||||
|
16
classpath/java/util/zip/ZipEntry.java
Normal file
16
classpath/java/util/zip/ZipEntry.java
Normal file
@ -0,0 +1,16 @@
|
||||
/* Copyright (c) 2008, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
package java.util.zip;
|
||||
|
||||
public abstract class ZipEntry {
|
||||
public abstract String getName();
|
||||
public abstract int getCompressedSize();
|
||||
}
|
313
classpath/java/util/zip/ZipFile.java
Normal file
313
classpath/java/util/zip/ZipFile.java
Normal file
@ -0,0 +1,313 @@
|
||||
/* Copyright (c) 2008, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
package java.util.zip;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class ZipFile {
|
||||
private final RandomAccessFile file;
|
||||
private final Window window;
|
||||
private final Map<String,Integer> index = new HashMap();
|
||||
|
||||
public ZipFile(String name) throws IOException {
|
||||
file = new RandomAccessFile(name, "r");
|
||||
window = new Window(file, 4096);
|
||||
|
||||
int fileLength = (int) file.length();
|
||||
int pointer = fileLength - 22;
|
||||
byte[] magic = new byte[] { 0x50, 0x4B, 0x05, 0x06 };
|
||||
while (pointer > 0) {
|
||||
if (equal(window.data, window.seek(pointer, magic.length),
|
||||
magic, 0, magic.length))
|
||||
{
|
||||
pointer = directoryOffset(window, pointer);
|
||||
|
||||
magic = new byte[] { 0x50, 0x4B, 0x01, 0x02 };
|
||||
while (pointer < fileLength) {
|
||||
if (equal(window.data, window.seek(pointer, magic.length),
|
||||
magic, 0, magic.length))
|
||||
{
|
||||
index.put(entryName(window, pointer), pointer);
|
||||
pointer = entryEnd(window, pointer);
|
||||
} else {
|
||||
pointer = fileLength;
|
||||
}
|
||||
}
|
||||
pointer = 0;
|
||||
} else {
|
||||
-- pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ZipFile(File file) throws IOException {
|
||||
this(file.getAbsolutePath());
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return index.size();
|
||||
}
|
||||
|
||||
public Enumeration<ZipEntry> entries() {
|
||||
return new MyEnumeration(window, index.values().iterator());
|
||||
}
|
||||
|
||||
public ZipEntry getEntry(String name) {
|
||||
Integer pointer = index.get(name);
|
||||
return (pointer == null ? null : new MyZipEntry(window, pointer));
|
||||
}
|
||||
|
||||
public InputStream getInputStream(ZipEntry entry) throws IOException {
|
||||
int pointer = ((MyZipEntry) entry).pointer;
|
||||
int method = compressionMethod(window, pointer);
|
||||
int size = compressedSize(window, pointer);
|
||||
InputStream in = new MyInputStream(file, fileData(window, pointer), size);
|
||||
|
||||
final int Stored = 0;
|
||||
final int Deflated = 8;
|
||||
|
||||
switch (method) {
|
||||
case Stored:
|
||||
return in;
|
||||
|
||||
case Deflated:
|
||||
return new InflaterInputStream(in, new Inflater(true));
|
||||
|
||||
default:
|
||||
throw new IOException();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean equal(byte[] a, int aOffset, byte[] b, int bOffset,
|
||||
int size)
|
||||
{
|
||||
for (int i = 0; i < size; ++i) {
|
||||
if (a[aOffset + i] != b[bOffset + i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static int get2(Window w, int p) throws IOException {
|
||||
int offset = w.seek(p, 2);
|
||||
return
|
||||
((w.data[offset + 1] & 0xFF) << 8) |
|
||||
((w.data[offset ] & 0xFF) );
|
||||
}
|
||||
|
||||
private static int get4(Window w, int p) throws IOException {
|
||||
int offset = w.seek(p, 4);
|
||||
return
|
||||
((w.data[offset + 3] & 0xFF) << 24) |
|
||||
((w.data[offset + 2] & 0xFF) << 16) |
|
||||
((w.data[offset + 1] & 0xFF) << 8) |
|
||||
((w.data[offset ] & 0xFF) );
|
||||
}
|
||||
|
||||
private static int directoryOffset(Window w, int p) throws IOException {
|
||||
return get4(w, p + 16);
|
||||
}
|
||||
|
||||
private static int entryNameLength(Window w, int p) throws IOException {
|
||||
return get2(w, p + 28);
|
||||
}
|
||||
|
||||
private 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);
|
||||
}
|
||||
|
||||
private static int compressionMethod(Window w, int p) throws IOException {
|
||||
return get2(w, p + 10);
|
||||
}
|
||||
|
||||
private static int compressedSize(Window w, int p) throws IOException {
|
||||
return get4(w, p + 20);
|
||||
}
|
||||
|
||||
private static int fileNameLength(Window w, int p) throws IOException {
|
||||
return get2(w, p + 28);
|
||||
}
|
||||
|
||||
private static int extraFieldLength(Window w, int p) throws IOException {
|
||||
return get2(w, p + 30);
|
||||
}
|
||||
|
||||
private static int commentFieldLength(Window w, int p) throws IOException {
|
||||
return get2(w, p + 32);
|
||||
}
|
||||
|
||||
private static int entryEnd(Window w, int p) throws IOException {
|
||||
final int HeaderSize = 46;
|
||||
return p + HeaderSize
|
||||
+ fileNameLength(w, p)
|
||||
+ extraFieldLength(w, p)
|
||||
+ commentFieldLength(w, p);
|
||||
}
|
||||
|
||||
private static int fileData(Window w, int p) throws IOException {
|
||||
int localHeader = localHeader(w, p);
|
||||
final int LocalHeaderSize = 30;
|
||||
return localHeader
|
||||
+ LocalHeaderSize
|
||||
+ localFileNameLength(w, localHeader)
|
||||
+ localExtraFieldLength(w, localHeader);
|
||||
}
|
||||
|
||||
private static int localHeader(Window w, int p) throws IOException {
|
||||
return get4(w, p + 42);
|
||||
}
|
||||
|
||||
private static int localFileNameLength(Window w, int p) throws IOException {
|
||||
return get2(w, p + 26);
|
||||
}
|
||||
|
||||
private static int localExtraFieldLength(Window w, int p)
|
||||
throws IOException
|
||||
{
|
||||
return get2(w, p + 28);
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
file.close();
|
||||
}
|
||||
|
||||
private static class Window {
|
||||
private final RandomAccessFile file;
|
||||
public final byte[] data;
|
||||
public int start;
|
||||
public int length;
|
||||
|
||||
public Window(RandomAccessFile file, int size) {
|
||||
this.file = file;
|
||||
data = new byte[size];
|
||||
}
|
||||
|
||||
public int seek(int start, int length) throws IOException {
|
||||
int fileLength = (int) file.length();
|
||||
|
||||
if (length > data.length) {
|
||||
throw new IllegalArgumentException
|
||||
("length " + length + " greater than buffer length " + data.length);
|
||||
}
|
||||
|
||||
if (start < 0) {
|
||||
throw new IllegalArgumentException("negative start " + start);
|
||||
}
|
||||
|
||||
if (start + length > fileLength) {
|
||||
throw new IllegalArgumentException
|
||||
("end " + (start + length) + " greater than file length " +
|
||||
fileLength);
|
||||
}
|
||||
|
||||
if (start < this.start || start + length > this.start + this.length) {
|
||||
this.length = Math.min(data.length, fileLength);
|
||||
this.start = start - ((this.length - length) / 2);
|
||||
if (this.start < 0) {
|
||||
this.start = 0;
|
||||
} else if (this.start + this.length > fileLength) {
|
||||
this.start = fileLength - this.length;
|
||||
}
|
||||
file.seek(this.start);
|
||||
file.readFully(data, 0, this.length);
|
||||
}
|
||||
|
||||
return start - this.start;
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyZipEntry extends ZipEntry {
|
||||
public final Window window;
|
||||
public final int pointer;
|
||||
|
||||
public MyZipEntry(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyEnumeration implements Enumeration<ZipEntry> {
|
||||
private final Window window;
|
||||
private final Iterator<Integer> iterator;
|
||||
|
||||
public MyEnumeration(Window window, Iterator<Integer> iterator) {
|
||||
this.window = window;
|
||||
this.iterator = iterator;
|
||||
}
|
||||
|
||||
public boolean hasMoreElements() {
|
||||
return iterator.hasNext();
|
||||
}
|
||||
|
||||
public ZipEntry nextElement() {
|
||||
return new MyZipEntry(window, iterator.next());
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyInputStream extends InputStream {
|
||||
private RandomAccessFile file;
|
||||
private int offset;
|
||||
private int length;
|
||||
|
||||
public MyInputStream(RandomAccessFile file, int start, int length) {
|
||||
this.file = file;
|
||||
this.offset = start;
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
public int read() throws IOException {
|
||||
byte[] b = new byte[1];
|
||||
int c = read(b);
|
||||
return (c == -1 ? -1 : b[0] & 0xFF);
|
||||
}
|
||||
|
||||
public int read(byte[] b, int offset, int length) throws IOException {
|
||||
if (this.length == 0) return -1;
|
||||
|
||||
if (length > this.length) length = this.length;
|
||||
|
||||
file.seek(this.offset);
|
||||
file.readFully(b, offset, length);
|
||||
|
||||
this.offset += length;
|
||||
this.length -= length;
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
file = null;
|
||||
}
|
||||
}
|
||||
}
|
@ -11,6 +11,9 @@
|
||||
#ifndef JNI_UTIL
|
||||
#define JNI_UTIL
|
||||
|
||||
#include "stdio.h"
|
||||
#include "stdlib.h"
|
||||
|
||||
#undef JNIEXPORT
|
||||
#ifdef __MINGW32__
|
||||
# define JNIEXPORT __declspec(dllexport)
|
||||
@ -23,15 +26,37 @@
|
||||
namespace {
|
||||
|
||||
inline void
|
||||
throwNew(JNIEnv* e, const char* class_, const char* message)
|
||||
throwNew(JNIEnv* e, const char* class_, const char* message, ...)
|
||||
{
|
||||
jclass c = e->FindClass(class_);
|
||||
if (c) {
|
||||
e->ThrowNew(c, message);
|
||||
if (message) {
|
||||
static const unsigned BufferSize = 256;
|
||||
char buffer[BufferSize];
|
||||
|
||||
va_list list;
|
||||
va_start(list, message);
|
||||
vsnprintf(buffer, BufferSize - 1, message, list);
|
||||
va_end(list);
|
||||
|
||||
e->ThrowNew(c, buffer);
|
||||
} else {
|
||||
e->ThrowNew(c, 0);
|
||||
}
|
||||
e->DeleteLocalRef(c);
|
||||
}
|
||||
}
|
||||
|
||||
inline void*
|
||||
allocate(JNIEnv* e, unsigned size)
|
||||
{
|
||||
void* p = malloc(size);
|
||||
if (p == 0) {
|
||||
throwNew(e, "java/lang/OutOfMemoryError", 0);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif//JNI_UTIL
|
||||
|
104
makefile
104
makefile
@ -3,21 +3,18 @@ MAKEFLAGS = -s
|
||||
name = avian
|
||||
version = 0.1.1
|
||||
|
||||
build-arch = $(shell uname -m)
|
||||
build-arch = $(shell uname -m | sed 's/^i.86$$/i386/')
|
||||
ifeq ($(build-arch),Power)
|
||||
build-arch = powerpc
|
||||
endif
|
||||
ifeq ($(build-arch),i586)
|
||||
build-arch = i386
|
||||
endif
|
||||
ifeq ($(build-arch),i686)
|
||||
build-arch = i386
|
||||
endif
|
||||
|
||||
build-platform = $(shell uname -s | tr [:upper:] [:lower:])
|
||||
build-platform = \
|
||||
$(shell uname -s | tr [:upper:] [:lower:] \
|
||||
| sed 's/^mingw32.*$$/mingw32/' \
|
||||
| sed 's/^cygwin.*$$/cygwin/')
|
||||
|
||||
arch = $(build-arch)
|
||||
platform = $(build-platform)
|
||||
platform = $(subst cygwin,windows,$(subst mingw32,windows,$(build-platform)))
|
||||
|
||||
ifeq ($(platform),windows)
|
||||
arch = i386
|
||||
@ -44,31 +41,38 @@ cxx = $(build-cxx)
|
||||
cc = $(build-cc)
|
||||
ar = ar
|
||||
ranlib = ranlib
|
||||
dlltool = dlltool
|
||||
objcopy = objcopy
|
||||
vg = nice valgrind --num-callers=32 --db-attach=yes --freelist-vol=100000000
|
||||
vg += --leak-check=full --suppressions=valgrind.supp
|
||||
db = gdb --args
|
||||
javac = javac
|
||||
jar = jar
|
||||
javac = "$(JAVA_HOME)/bin/javac"
|
||||
jar = "$(JAVA_HOME)/bin/jar"
|
||||
strip = :
|
||||
strip-all = --strip-all
|
||||
|
||||
rdynamic = -rdynamic
|
||||
|
||||
warnings = -Wall -Wextra -Werror -Wunused-parameter -Winit-self
|
||||
# note that we supress the non-virtual-dtor warning because we never
|
||||
# use the delete operator, which means we don't need virtual
|
||||
# destructors:
|
||||
warnings = -Wall -Wextra -Werror -Wunused-parameter -Winit-self \
|
||||
-Wno-non-virtual-dtor
|
||||
|
||||
common-cflags = $(warnings) -fno-rtti -fno-exceptions \
|
||||
-I$(JAVA_HOME)/include -idirafter $(src) -I$(native-build) \
|
||||
"-I$(JAVA_HOME)/include" -idirafter $(src) -I$(native-build) \
|
||||
-D__STDC_LIMIT_MACROS -D_JNI_IMPLEMENTATION_ -DAVIAN_VERSION=\"$(version)\" \
|
||||
-DBOOT_CLASSPATH=\"[classpathJar]\"
|
||||
|
||||
build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \
|
||||
-I$(JAVA_HOME)/include/linux -I$(src) -pthread
|
||||
"-I$(JAVA_HOME)/include/linux" -I$(src) -pthread
|
||||
|
||||
cflags = $(build-cflags)
|
||||
|
||||
common-lflags = -lm -lz
|
||||
|
||||
build-lflags =
|
||||
|
||||
lflags = $(common-lflags) -lpthread -ldl
|
||||
|
||||
system = posix
|
||||
@ -83,6 +87,8 @@ so-suffix = .so
|
||||
|
||||
shared = -shared
|
||||
|
||||
native-path = echo
|
||||
|
||||
ifeq ($(arch),i386)
|
||||
object-arch = i386
|
||||
object-format = elf32-i386
|
||||
@ -96,8 +102,7 @@ ifeq ($(arch),powerpc)
|
||||
endif
|
||||
|
||||
ifeq ($(platform),darwin)
|
||||
build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \
|
||||
-I$(JAVA_HOME)/include/linux -I$(src)
|
||||
build-cflags = $(common-cflags) -fPIC -fvisibility=hidden -I$(src)
|
||||
lflags = $(common-lflags) -ldl -framework CoreFoundation
|
||||
rdynamic =
|
||||
strip-all = -S -x
|
||||
@ -107,25 +112,37 @@ ifeq ($(platform),darwin)
|
||||
endif
|
||||
|
||||
ifeq ($(platform),windows)
|
||||
inc = $(root)/win32/include
|
||||
lib = $(root)/win32/lib
|
||||
inc = "$(root)/win32/include"
|
||||
lib = "$(root)/win32/lib"
|
||||
|
||||
system = windows
|
||||
object-format = pe-i386
|
||||
|
||||
so-prefix =
|
||||
so-suffix = .dll
|
||||
exe-suffix = .exe
|
||||
|
||||
cxx = i586-mingw32msvc-g++
|
||||
cc = i586-mingw32msvc-gcc
|
||||
dlltool = i586-mingw32msvc-dlltool
|
||||
ar = i586-mingw32msvc-ar
|
||||
ranlib = i586-mingw32msvc-ranlib
|
||||
objcopy = i586-mingw32msvc-objcopy
|
||||
|
||||
rdynamic = -Wl,--export-dynamic
|
||||
lflags = -L$(lib) $(common-lflags) -lws2_32 -mwindows -mconsole
|
||||
cflags = $(common-cflags) -I$(inc)
|
||||
|
||||
ifeq (,$(filter mingw32 cygwin,$(build-platform)))
|
||||
cxx = i586-mingw32msvc-g++
|
||||
cc = i586-mingw32msvc-gcc
|
||||
dlltool = i586-mingw32msvc-dlltool
|
||||
ar = i586-mingw32msvc-ar
|
||||
ranlib = i586-mingw32msvc-ranlib
|
||||
objcopy = i586-mingw32msvc-objcopy
|
||||
else
|
||||
build-cflags = $(common-cflags) \
|
||||
"-I$(JAVA_HOME)/include/win32" -I$(src) -mthreads
|
||||
ifeq ($(build-platform),cygwin)
|
||||
build-lflags += -mno-cygwin
|
||||
build-cflags += -mno-cygwin
|
||||
lflags += -mno-cygwin
|
||||
cflags += -mno-cygwin
|
||||
native-path = cygpath -m
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(mode),debug)
|
||||
@ -144,6 +161,10 @@ ifeq ($(mode),fast)
|
||||
cflags += -O3 -g3 -DNDEBUG
|
||||
strip = strip
|
||||
endif
|
||||
ifeq ($(mode),small)
|
||||
cflags += -Os -g3 -DNDEBUG
|
||||
strip = strip
|
||||
endif
|
||||
|
||||
cpp-objects = $(foreach x,$(1),$(patsubst $(2)/%.cpp,$(3)/%.o,$(x)))
|
||||
asm-objects = $(foreach x,$(1),$(patsubst $(2)/%.S,$(3)/%-asm.o,$(x)))
|
||||
@ -190,6 +211,11 @@ vm-sources = \
|
||||
$(src)/process.cpp \
|
||||
$(src)/$(asm).cpp
|
||||
|
||||
ifeq ($(heapdump),true)
|
||||
vm-sources += $(src)/heapdump.cpp
|
||||
cflags += -DAVIAN_HEAPDUMP
|
||||
endif
|
||||
|
||||
vm-asm-sources = $(src)/$(asm).S
|
||||
|
||||
ifeq ($(process),compile)
|
||||
@ -220,9 +246,9 @@ generator-objects = \
|
||||
generator = $(native-build)/generator
|
||||
|
||||
static-library = $(native-build)/lib$(name).a
|
||||
executable = $(native-build)/$(name)
|
||||
executable = $(native-build)/$(name)${exe-suffix}
|
||||
dynamic-library = $(native-build)/$(so-prefix)$(name)$(so-suffix)
|
||||
executable-dynamic = $(native-build)/$(name)-dynamic
|
||||
executable-dynamic = $(native-build)/$(name)-dynamic${exe-suffix}
|
||||
|
||||
classpath-sources = $(shell find $(classpath) -name '*.java')
|
||||
classpath-classes = \
|
||||
@ -261,7 +287,7 @@ vg: build
|
||||
|
||||
.PHONY: test
|
||||
test: build
|
||||
/bin/bash $(test)/test.sh 2>/dev/null \
|
||||
/bin/sh $(test)/test.sh 2>/dev/null \
|
||||
$(executable) $(mode) "$(flags)" \
|
||||
$(call class-names,$(test-build),$(test-classes))
|
||||
|
||||
@ -299,7 +325,7 @@ $(classpath-dep): $(classpath-sources)
|
||||
@echo "compiling classpath classes"
|
||||
@mkdir -p $(dir $(@))
|
||||
$(javac) -d $(dir $(@)) -bootclasspath $(classpath-build) \
|
||||
$(shell make -s --no-print-directory $(classpath-classes))
|
||||
$(shell $(MAKE) -s --no-print-directory $(classpath-classes))
|
||||
@touch $(@)
|
||||
|
||||
$(test-build)/%.class: $(test)/%.java
|
||||
@ -309,7 +335,7 @@ $(test-dep): $(test-sources)
|
||||
@echo "compiling test classes"
|
||||
@mkdir -p $(dir $(@))
|
||||
$(javac) -d $(dir $(@)) -bootclasspath $(classpath-build) \
|
||||
$(shell make -s --no-print-directory $(test-classes))
|
||||
$(shell $(MAKE) -s --no-print-directory $(test-classes))
|
||||
@touch $(@)
|
||||
|
||||
define compile-object
|
||||
@ -318,11 +344,17 @@ define compile-object
|
||||
$(cxx) $(cflags) -c $(<) -o $(@)
|
||||
endef
|
||||
|
||||
define compile-asm-object
|
||||
@echo "compiling $(@)"
|
||||
@mkdir -p $(dir $(@))
|
||||
$(cc) -I$(src) -c $(<) -o $(@)
|
||||
endef
|
||||
|
||||
$(vm-cpp-objects): $(native-build)/%.o: $(src)/%.cpp $(vm-depends)
|
||||
$(compile-object)
|
||||
|
||||
$(vm-asm-objects): $(native-build)/%-asm.o: $(src)/%.S
|
||||
$(compile-object)
|
||||
$(compile-asm-object)
|
||||
|
||||
$(driver-object): $(driver-source)
|
||||
$(compile-object)
|
||||
@ -339,7 +371,7 @@ $(boot-object): $(boot-source)
|
||||
$(build)/classpath.jar: $(classpath-dep)
|
||||
(wd=$$(pwd); \
|
||||
cd $(classpath-build); \
|
||||
$(jar) c0f $${wd}/$(@) $$(find . -name '*.class'))
|
||||
$(jar) c0f "$$($(native-path) "$${wd}/$(@)")" $$(find . -name '*.class'))
|
||||
|
||||
$(binaryToMacho): $(src)/binaryToMacho.cpp
|
||||
$(cxx) $(^) -o $(@)
|
||||
@ -353,7 +385,7 @@ else
|
||||
(wd=$$(pwd); \
|
||||
cd $(build); \
|
||||
$(objcopy) -I binary classpath.jar \
|
||||
-O $(object-format) -B $(object-arch) $${wd}/$(@))
|
||||
-O $(object-format) -B $(object-arch) "$${wd}/$(@)")
|
||||
endif
|
||||
|
||||
$(generator-objects): $(native-build)/%.o: $(src)/%.cpp
|
||||
@ -377,7 +409,7 @@ $(executable): \
|
||||
@echo "linking $(@)"
|
||||
ifeq ($(platform),windows)
|
||||
$(dlltool) -z $(@).def $(^)
|
||||
$(dlltool) -k -d $(@).def -e $(@).exp
|
||||
$(dlltool) -d $(@).def -e $(@).exp
|
||||
$(cc) $(@).exp $(^) $(lflags) -o $(@)
|
||||
else
|
||||
$(cc) $(^) $(rdynamic) $(lflags) -o $(@)
|
||||
@ -398,5 +430,5 @@ $(executable-dynamic): $(driver-dynamic-object) $(dynamic-library)
|
||||
|
||||
$(generator): $(generator-objects)
|
||||
@echo "linking $(@)"
|
||||
$(build-cc) $(^) -o $(@)
|
||||
$(build-cc) $(^) $(build-lflags) -o $(@)
|
||||
|
||||
|
78
readme.txt
78
readme.txt
@ -10,6 +10,21 @@ on Mac OS X:
|
||||
$ export JAVA_HOME=/Library/Java/Home
|
||||
$ make
|
||||
$ build/darwin-i386-compile-fast/avian -cp build/test Hello
|
||||
|
||||
on Windows (MSYS):
|
||||
|
||||
$ export JAVA_HOME="C:/Program Files/Java/jdk1.6.0_07"
|
||||
$ make
|
||||
$ build/windows-i386-compile-fast/avian -cp build/test Hello
|
||||
|
||||
on Windows (Cygwin):
|
||||
|
||||
$ export JAVA_HOME="/cygdrive/c/Program Files/Java/jdk1.6.0_07"
|
||||
$ make
|
||||
$ build/windows-i386-compile-fast/avian -cp build/test Hello
|
||||
|
||||
Adjust JAVA_HOME according to your system, but be sure to use forward
|
||||
slashes in the path.
|
||||
|
||||
|
||||
Introduction
|
||||
@ -40,10 +55,6 @@ Avian can currently target the following platforms:
|
||||
Win32 (i386)
|
||||
Mac OS X (i386)
|
||||
|
||||
The Win32 port may be built on Linux using a MinGW cross compiler and
|
||||
build environment. Builds on MSYS or Cygwin are not yet supported,
|
||||
but patches to enable them are welcome.
|
||||
|
||||
|
||||
Building
|
||||
--------
|
||||
@ -60,20 +71,11 @@ Build requirements include:
|
||||
Earlier versions of some of these packages may also work but have not
|
||||
been tested.
|
||||
|
||||
If you are cross-compiling for Windows, you may find it useful to use
|
||||
our win32 repository: (run this from the directory containing the
|
||||
avian directory)
|
||||
|
||||
$ git clone git://oss.readytalk.com/win32.git
|
||||
|
||||
This gives you the Windows JNI headers, zlib headers and library, and
|
||||
a few other useful libraries like OpenSSL and libjpeg.
|
||||
|
||||
The build is directed by a single makefile and may be influenced via
|
||||
certain flags described below.
|
||||
|
||||
$ make platform={linux,windows,darwin} arch={i386,x86_64} \
|
||||
process={compile,interpret} mode={debug,debug-fast,fast}
|
||||
process={compile,interpret} mode={debug,debug-fast,fast,small}
|
||||
|
||||
* platform - the target platform
|
||||
default: output of $(uname -s | tr [:upper:] [:lower:])
|
||||
@ -89,6 +91,33 @@ certain flags described below.
|
||||
* process - choice between pure interpreter or JIT compiler
|
||||
default: compile
|
||||
|
||||
If you are compiling for Windows, you may either cross-compile using
|
||||
MinGW or build natively on Windows under MSYS or Cygwin.
|
||||
|
||||
Installing MSYS:
|
||||
|
||||
1. Download and install the current MinGW and MSYS packages from
|
||||
mingw.org, selecting the C and C++ compilers when prompted. Use the
|
||||
post-install script to create the filesystem link to the compiler.
|
||||
|
||||
2. Download GNU Make 3.81 from the MSYS download page
|
||||
(make-3.81-MSYS-1.0.11-2.tar.bz2) and extract the tar file into
|
||||
e.g. c:/msys/1.0.
|
||||
|
||||
Installing Cygwin:
|
||||
|
||||
1. Download and run setup.exe from cygwin.com, installing the base
|
||||
system and these packages: make, gcc-mingw-g++, and (optionally)
|
||||
git.
|
||||
|
||||
You may also find our win32 repository useful: (run this from the
|
||||
directory containing the avian directory)
|
||||
|
||||
$ git clone git://oss.readytalk.com/win32.git
|
||||
|
||||
This gives you the Windows JNI headers, zlib headers and library, and
|
||||
a few other useful libraries like OpenSSL and libjpeg.
|
||||
|
||||
|
||||
Installing
|
||||
----------
|
||||
@ -102,6 +131,9 @@ Embedding
|
||||
The following series of commands illustrates how to produce a
|
||||
stand-alone executable out of a Java application using Avian.
|
||||
|
||||
Note: if you are building on Cygwin, add -mno-cygwin to each of the
|
||||
compile and link commands below.
|
||||
|
||||
Step 1: Build Avian, create a new directory, and populate it with the
|
||||
VM object files and bootstrap classpath jar.
|
||||
|
||||
@ -223,7 +255,17 @@ main(int ac, const char** av)
|
||||
return exitCode;
|
||||
}
|
||||
EOF
|
||||
$ g++ -I$JAVA_HOME/include -c main.cpp -o main.o
|
||||
|
||||
on Linux:
|
||||
$ g++ -I$JAVA_HOME/include -I$JAVA_HOME/include/linux \
|
||||
-D_JNI_IMPLEMENTATION_ -c main.cpp -o main.o
|
||||
|
||||
on Mac OS X:
|
||||
$ g++ -I$JAVA_HOME/include -D_JNI_IMPLEMENTATION_ -c main.cpp -o main.o
|
||||
|
||||
on Windows:
|
||||
$ g++ -I$JAVA_HOME/include -I$JAVA_HOME/include/win32 \
|
||||
-D_JNI_IMPLEMENTATION_ -c main.cpp -o main.o
|
||||
|
||||
|
||||
Step 5: Link the objects produced above to produce the final
|
||||
@ -237,3 +279,9 @@ on Mac OS X:
|
||||
$ g++ -rdynamic *.o -ldl -lpthread -lz -o hello -framework CoreFoundation
|
||||
$ strip -S -x hello
|
||||
|
||||
on Windows:
|
||||
$ dlltool -z hello.def *.o
|
||||
$ dlltool -d hello.def -e hello.exp
|
||||
$ g++ hello.exp *.o -L../../win32/lib -lmingwthrd -lm -lz -lws2_32 \
|
||||
-mwindows -mconsole -o hello.exe
|
||||
$ strip --strip-all hello.exe
|
||||
|
@ -17,7 +17,6 @@ namespace vm {
|
||||
|
||||
class Allocator {
|
||||
public:
|
||||
virtual ~Allocator() { }
|
||||
virtual void* tryAllocate(unsigned size) = 0;
|
||||
virtual void* allocate(unsigned size) = 0;
|
||||
virtual void free(const void* p, unsigned size) = 0;
|
||||
|
@ -78,8 +78,6 @@ const int NoRegister = -1;
|
||||
|
||||
class Promise {
|
||||
public:
|
||||
virtual ~Promise() { }
|
||||
|
||||
virtual int64_t value() = 0;
|
||||
virtual bool resolved() = 0;
|
||||
};
|
||||
@ -101,8 +99,6 @@ class ResolvedPromise: public Promise {
|
||||
|
||||
class TraceHandler {
|
||||
public:
|
||||
virtual ~TraceHandler() { }
|
||||
|
||||
virtual void handleTrace(Promise* address, unsigned padIndex,
|
||||
unsigned padding) = 0;
|
||||
};
|
||||
@ -147,8 +143,6 @@ class Assembler {
|
||||
|
||||
class Client {
|
||||
public:
|
||||
virtual ~Client() { }
|
||||
|
||||
virtual int acquireTemporary
|
||||
(uint32_t mask = ~static_cast<uint32_t>(0)) = 0;
|
||||
virtual void releaseTemporary(int r) = 0;
|
||||
@ -159,15 +153,11 @@ class Assembler {
|
||||
|
||||
class Block {
|
||||
public:
|
||||
virtual ~Block() { }
|
||||
|
||||
virtual unsigned resolve(unsigned start, Block* next) = 0;
|
||||
};
|
||||
|
||||
class Architecture {
|
||||
public:
|
||||
virtual ~Architecture() { }
|
||||
|
||||
virtual unsigned registerCount() = 0;
|
||||
|
||||
virtual int stack() = 0;
|
||||
@ -214,8 +204,6 @@ class Assembler {
|
||||
virtual void release() = 0;
|
||||
};
|
||||
|
||||
virtual ~Assembler() { }
|
||||
|
||||
virtual void setClient(Client* client) = 0;
|
||||
|
||||
virtual Architecture* arch() = 0;
|
||||
|
@ -11,10 +11,9 @@
|
||||
#include "stdint.h"
|
||||
#include "stdlib.h"
|
||||
|
||||
// since we don't link against libstdc++, we must implement some dummy
|
||||
// functions:
|
||||
// since we aren't linking against libstdc++, we must implement this
|
||||
// ourselves:
|
||||
extern "C" void __cxa_pure_virtual(void) { abort(); }
|
||||
void operator delete(void*) { abort(); }
|
||||
|
||||
#ifdef __MINGW32__
|
||||
# define EXPORT __declspec(dllexport)
|
||||
|
@ -456,6 +456,13 @@ Java_java_lang_System_getVMProperty(Thread* t, jclass, jstring name,
|
||||
r = makeLocalReference(t, makeString(t, "%s", t->m->finder->path()));
|
||||
} else if (strcmp(n, "avian.version") == 0) {
|
||||
r = makeLocalReference(t, makeString(t, AVIAN_VERSION));
|
||||
} else if (strcmp(n, "file.encoding") == 0) {
|
||||
r = makeLocalReference(t, makeString(t, "ASCII"));
|
||||
} else {
|
||||
const char* v = findProperty(t, n);
|
||||
if (v) {
|
||||
r = makeLocalReference(t, makeString(t, v));
|
||||
}
|
||||
}
|
||||
|
||||
if (r) {
|
||||
@ -536,8 +543,9 @@ Java_java_lang_Runtime_load(Thread* t, jclass, jstring name, jboolean mapName)
|
||||
char n[length + 1];
|
||||
stringChars(t, *name, n);
|
||||
|
||||
if (mapName and t->m->builtins) {
|
||||
const char* s = t->m->builtins;
|
||||
const char* builtins = findProperty(t, "avian.builtins");
|
||||
if (mapName and builtins) {
|
||||
const char* s = builtins;
|
||||
while (*s) {
|
||||
if (strncmp(s, n, length) == 0
|
||||
and (s[length] == ',' or s[length] == 0))
|
||||
@ -578,6 +586,30 @@ Java_java_lang_Runtime_gc(Thread* t, jobject)
|
||||
collect(t, Heap::MajorCollection);
|
||||
}
|
||||
|
||||
#ifdef AVIAN_HEAPDUMP
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_java_lang_Runtime_dumpHeap(Thread* t, jclass, jstring outputFile)
|
||||
{
|
||||
ENTER(t, Thread::ActiveState);
|
||||
|
||||
unsigned length = stringLength(t, *outputFile);
|
||||
char n[length + 1];
|
||||
stringChars(t, *outputFile, n);
|
||||
FILE* out = fopen(n, "wb");
|
||||
if (out) {
|
||||
{ ENTER(t, Thread::ExclusiveState);
|
||||
dumpHeap(t, out);
|
||||
}
|
||||
fclose(out);
|
||||
} else {
|
||||
object message = makeString(t, "file not found: %s", n);
|
||||
t->exception = makeRuntimeException(t, message);
|
||||
}
|
||||
}
|
||||
|
||||
#endif//AVIAN_HEAPDUMP
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_java_lang_Runtime_exit(Thread* t, jobject, jint code)
|
||||
{
|
||||
|
@ -27,7 +27,7 @@ vmCall();
|
||||
|
||||
namespace {
|
||||
|
||||
const bool Verbose = true;
|
||||
const bool DebugCompile = true;
|
||||
const bool DebugNatives = false;
|
||||
const bool DebugCallTable = false;
|
||||
const bool DebugMethodTree = false;
|
||||
@ -2387,7 +2387,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
||||
} break;
|
||||
|
||||
case goto_: {
|
||||
uint32_t newIp = (ip - 3) + codeReadInt16(t, code, ip);
|
||||
uint32_t offset = codeReadInt16(t, code, ip);
|
||||
uint32_t newIp = (ip - 3) + offset;
|
||||
assert(t, newIp < codeLength(t, code));
|
||||
|
||||
c->jmp(frame->machineIp(newIp));
|
||||
@ -2395,7 +2396,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
||||
} break;
|
||||
|
||||
case goto_w: {
|
||||
uint32_t newIp = (ip - 5) + codeReadInt32(t, code, ip);
|
||||
uint32_t offset = codeReadInt32(t, code, ip);
|
||||
uint32_t newIp = (ip - 5) + offset;
|
||||
assert(t, newIp < codeLength(t, code));
|
||||
|
||||
c->jmp(frame->machineIp(newIp));
|
||||
@ -2480,7 +2482,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
||||
|
||||
case if_acmpeq:
|
||||
case if_acmpne: {
|
||||
uint32_t newIp = (ip - 3) + codeReadInt16(t, code, ip);
|
||||
uint32_t offset = codeReadInt16(t, code, ip);
|
||||
uint32_t newIp = (ip - 3) + offset;
|
||||
assert(t, newIp < codeLength(t, code));
|
||||
|
||||
Compiler::Operand* a = frame->popObject();
|
||||
@ -2504,7 +2507,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
||||
case if_icmpge:
|
||||
case if_icmplt:
|
||||
case if_icmple: {
|
||||
uint32_t newIp = (ip - 3) + codeReadInt16(t, code, ip);
|
||||
uint32_t offset = codeReadInt16(t, code, ip);
|
||||
uint32_t newIp = (ip - 3) + offset;
|
||||
assert(t, newIp < codeLength(t, code));
|
||||
|
||||
Compiler::Operand* a = frame->popInt();
|
||||
@ -2543,7 +2547,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
||||
case ifge:
|
||||
case iflt:
|
||||
case ifle: {
|
||||
uint32_t newIp = (ip - 3) + codeReadInt16(t, code, ip);
|
||||
uint32_t offset = codeReadInt16(t, code, ip);
|
||||
uint32_t newIp = (ip - 3) + offset;
|
||||
assert(t, newIp < codeLength(t, code));
|
||||
|
||||
Compiler::Operand* a = frame->popInt();
|
||||
@ -2577,7 +2582,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
||||
|
||||
case ifnull:
|
||||
case ifnonnull: {
|
||||
uint32_t newIp = (ip - 3) + codeReadInt16(t, code, ip);
|
||||
uint32_t offset = codeReadInt16(t, code, ip);
|
||||
uint32_t newIp = (ip - 3) + offset;
|
||||
assert(t, newIp < codeLength(t, code));
|
||||
|
||||
Compiler::Operand* a = frame->popObject();
|
||||
@ -2824,14 +2830,18 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
||||
uint32_t newIp;
|
||||
|
||||
if (instruction == jsr) {
|
||||
newIp = (ip - 3) + codeReadInt16(t, code, ip);
|
||||
uint32_t offset = codeReadInt16(t, code, ip);
|
||||
newIp = (ip - 3) + offset;
|
||||
} else {
|
||||
newIp = (ip - 5) + codeReadInt32(t, code, ip);
|
||||
uint32_t offset = codeReadInt32(t, code, ip);
|
||||
newIp = (ip - 5) + offset;
|
||||
}
|
||||
|
||||
assert(t, newIp < codeLength(t, code));
|
||||
|
||||
// todo: flush stack to memory here
|
||||
abort(t);
|
||||
|
||||
Compiler::State* state = c->saveState();
|
||||
|
||||
frame->pushAddress(frame->machineIp(ip));
|
||||
@ -3447,12 +3457,26 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
||||
}
|
||||
|
||||
void
|
||||
logCompile(const void* code, unsigned size, const char* class_,
|
||||
logCompile(MyThread* t, const void* code, unsigned size, const char* class_,
|
||||
const char* name, const char* spec)
|
||||
{
|
||||
fprintf(stderr, "%s.%s%s: %p %p\n",
|
||||
class_, name, spec, code,
|
||||
static_cast<const uint8_t*>(code) + size);
|
||||
static FILE* log = 0;
|
||||
static bool open = false;
|
||||
if (not open) {
|
||||
open = true;
|
||||
const char* path = findProperty(t, "avian.jit.log");
|
||||
if (name) {
|
||||
log = fopen(path, "wb");
|
||||
} else if (DebugCompile) {
|
||||
log = stderr;
|
||||
}
|
||||
}
|
||||
|
||||
if (log) {
|
||||
fprintf(log, "%p %p %s.%s%s\n",
|
||||
code, static_cast<const uint8_t*>(code) + size,
|
||||
class_, name, spec);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -3717,9 +3741,7 @@ finish(MyThread* t, Assembler* a, const char* name)
|
||||
|
||||
a->writeTo(start);
|
||||
|
||||
if (Verbose) {
|
||||
logCompile(start, a->length(), 0, name, 0);
|
||||
}
|
||||
logCompile(t, start, a->length(), 0, name, 0);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -3861,16 +3883,14 @@ finish(MyThread* t, Context* context)
|
||||
set(t, result, SingletonBody + offset, p->value);
|
||||
}
|
||||
|
||||
if (Verbose) {
|
||||
logCompile
|
||||
(start, codeSize,
|
||||
reinterpret_cast<const char*>
|
||||
(&byteArrayBody(t, className(t, methodClass(t, context->method)), 0)),
|
||||
reinterpret_cast<const char*>
|
||||
(&byteArrayBody(t, methodName(t, context->method), 0)),
|
||||
reinterpret_cast<const char*>
|
||||
(&byteArrayBody(t, methodSpec(t, context->method), 0)));
|
||||
}
|
||||
logCompile
|
||||
(t, start, codeSize,
|
||||
reinterpret_cast<const char*>
|
||||
(&byteArrayBody(t, className(t, methodClass(t, context->method)), 0)),
|
||||
reinterpret_cast<const char*>
|
||||
(&byteArrayBody(t, methodName(t, context->method), 0)),
|
||||
reinterpret_cast<const char*>
|
||||
(&byteArrayBody(t, methodSpec(t, context->method), 0)));
|
||||
|
||||
// for debugging:
|
||||
if (false and
|
||||
@ -5092,10 +5112,7 @@ compileThunks(MyThread* t, MyProcessor* p)
|
||||
uint8_t* start = reinterpret_cast<uint8_t*>
|
||||
(&singletonValue(t, p->thunkTable, 0));
|
||||
|
||||
if (Verbose) {
|
||||
logCompile(start, p->thunkSize * ThunkCount, 0, "thunkTable", 0);
|
||||
fprintf(stderr, "thunk size: %d\n", p->thunkSize);
|
||||
}
|
||||
logCompile(t, start, p->thunkSize * ThunkCount, 0, "thunkTable", 0);
|
||||
|
||||
tableContext.promise.resolved_ = true;
|
||||
|
||||
|
@ -86,8 +86,6 @@ class Site {
|
||||
public:
|
||||
Site(): next(0) { }
|
||||
|
||||
virtual ~Site() { }
|
||||
|
||||
virtual Site* readTarget(Context*, Read*) { return this; }
|
||||
|
||||
virtual void toString(Context*, char*, unsigned) = 0;
|
||||
@ -219,8 +217,6 @@ class Read {
|
||||
value(0), event(0), eventNext(0), size(size)
|
||||
{ }
|
||||
|
||||
virtual ~Read() { }
|
||||
|
||||
virtual Site* pickSite(Context* c, Value* v, bool includeBuddies) = 0;
|
||||
|
||||
virtual Site* allocateSite(Context* c) = 0;
|
||||
@ -257,8 +253,6 @@ class Value: public Compiler::Operand {
|
||||
local(false)
|
||||
{ }
|
||||
|
||||
virtual ~Value() { }
|
||||
|
||||
virtual void addPredecessor(Context*, Event*) { }
|
||||
|
||||
Read* reads;
|
||||
@ -559,8 +553,6 @@ class Event {
|
||||
readCount(0)
|
||||
{ }
|
||||
|
||||
virtual ~Event() { }
|
||||
|
||||
virtual const char* name() = 0;
|
||||
|
||||
virtual void compile(Context* c) = 0;
|
||||
|
@ -21,8 +21,6 @@ class Compiler {
|
||||
public:
|
||||
class Client {
|
||||
public:
|
||||
virtual ~Client() { }
|
||||
|
||||
virtual intptr_t getThunk(UnaryOperation op, unsigned size) = 0;
|
||||
virtual intptr_t getThunk(TernaryOperation op, unsigned size) = 0;
|
||||
};
|
||||
@ -34,8 +32,6 @@ class Compiler {
|
||||
class StackElement { };
|
||||
class State { };
|
||||
|
||||
virtual ~Compiler() { }
|
||||
|
||||
virtual State* saveState() = 0;
|
||||
virtual void restoreState(State* state) = 0;
|
||||
|
||||
|
@ -52,7 +52,7 @@ equal(const void* a, unsigned al, const void* b, unsigned bl)
|
||||
class Element {
|
||||
public:
|
||||
Element(): next(0) { }
|
||||
virtual ~Element() { }
|
||||
|
||||
virtual System::Region* find(const char* name) = 0;
|
||||
virtual bool exists(const char* name) = 0;
|
||||
virtual void dispose() = 0;
|
||||
@ -372,7 +372,7 @@ class JarIndex {
|
||||
class JarElement: public Element {
|
||||
public:
|
||||
JarElement(System* s, const char* name):
|
||||
s(s), name(name), index(0)
|
||||
s(s), name(name), region(0), index(0)
|
||||
{ }
|
||||
|
||||
virtual void init() {
|
||||
|
@ -19,7 +19,6 @@ namespace vm {
|
||||
|
||||
class Finder {
|
||||
public:
|
||||
virtual ~Finder() { }
|
||||
virtual System::Region* find(const char* name) = 0;
|
||||
virtual bool exists(const char* name) = 0;
|
||||
virtual const char* path() = 0;
|
||||
|
@ -32,19 +32,16 @@ class Heap: public Allocator {
|
||||
|
||||
class Visitor {
|
||||
public:
|
||||
virtual ~Visitor() { }
|
||||
virtual void visit(void*) = 0;
|
||||
};
|
||||
|
||||
class Walker {
|
||||
public:
|
||||
virtual ~Walker() { }
|
||||
virtual bool visit(unsigned) = 0;
|
||||
};
|
||||
|
||||
class Client {
|
||||
public:
|
||||
virtual ~Client() { }
|
||||
virtual void collect(void* context, CollectionType type) = 0;
|
||||
virtual void visitRoots(Visitor*) = 0;
|
||||
virtual bool isFixed(void*) = 0;
|
||||
@ -54,7 +51,6 @@ class Heap: public Allocator {
|
||||
virtual void walk(void*, Walker*) = 0;
|
||||
};
|
||||
|
||||
virtual ~Heap() { }
|
||||
virtual void setClient(Client* client) = 0;
|
||||
virtual void collect(CollectionType type, unsigned footprint) = 0;
|
||||
virtual void* allocateFixed(Allocator* allocator, unsigned sizeInWords,
|
||||
|
329
src/heapdump.cpp
Normal file
329
src/heapdump.cpp
Normal file
@ -0,0 +1,329 @@
|
||||
/* Copyright (c) 2008, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
#include "machine.h"
|
||||
|
||||
using namespace vm;
|
||||
|
||||
namespace {
|
||||
|
||||
const uintptr_t PointerShift = log(BytesPerWord);
|
||||
|
||||
class Set {
|
||||
public:
|
||||
class Entry {
|
||||
public:
|
||||
object value;
|
||||
uint32_t number;
|
||||
int next;
|
||||
};
|
||||
|
||||
static unsigned footprint(unsigned capacity) {
|
||||
return sizeof(Set)
|
||||
+ pad(sizeof(int) * capacity)
|
||||
+ pad(sizeof(Set::Entry) * capacity);
|
||||
}
|
||||
|
||||
Set(unsigned capacity):
|
||||
size(0),
|
||||
capacity(capacity),
|
||||
index(reinterpret_cast<int*>
|
||||
(reinterpret_cast<uint8_t*>(this)
|
||||
+ sizeof(Set))),
|
||||
entries(reinterpret_cast<Entry*>
|
||||
(reinterpret_cast<uint8_t*>(index)
|
||||
+ pad(sizeof(int) * capacity)))
|
||||
{ }
|
||||
|
||||
unsigned size;
|
||||
unsigned capacity;
|
||||
int* index;
|
||||
Entry* entries;
|
||||
};
|
||||
|
||||
class Stack {
|
||||
public:
|
||||
class Entry {
|
||||
public:
|
||||
object value;
|
||||
int offset;
|
||||
};
|
||||
|
||||
static const unsigned Capacity = 4096;
|
||||
|
||||
Stack(Stack* next): next(next), entryCount(0) { }
|
||||
|
||||
Stack* next;
|
||||
unsigned entryCount;
|
||||
Entry entries[Capacity];
|
||||
};
|
||||
|
||||
class Context {
|
||||
public:
|
||||
Context(Thread* thread, FILE* out):
|
||||
thread(thread), out(out), objects(0), stack(0), nextNumber(1)
|
||||
{ }
|
||||
|
||||
~Context() {
|
||||
if (objects) {
|
||||
thread->m->heap->free(objects, Set::footprint(objects->capacity));
|
||||
}
|
||||
while (stack) {
|
||||
Stack* dead = stack;
|
||||
stack = dead->next;
|
||||
thread->m->heap->free(stack, sizeof(Stack));
|
||||
}
|
||||
}
|
||||
|
||||
Thread* thread;
|
||||
FILE* out;
|
||||
Set* objects;
|
||||
Stack* stack;
|
||||
uint32_t nextNumber;
|
||||
};
|
||||
|
||||
void
|
||||
push(Context* c, object p, int offset)
|
||||
{
|
||||
if (c->stack == 0 or c->stack->entryCount == Stack::Capacity) {
|
||||
c->stack = new (c->thread->m->heap->allocate(sizeof(Stack)))
|
||||
Stack(c->stack);
|
||||
}
|
||||
Stack::Entry* e = c->stack->entries + (c->stack->entryCount++);
|
||||
e->value = p;
|
||||
e->offset = offset;
|
||||
}
|
||||
|
||||
bool
|
||||
pop(Context* c, object* p, int* offset)
|
||||
{
|
||||
if (c->stack) {
|
||||
if (c->stack->entryCount == 0) {
|
||||
if (c->stack->next) {
|
||||
Stack* dead = c->stack;
|
||||
c->stack = dead->next;
|
||||
c->thread->m->heap->free(dead, sizeof(Stack));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Stack::Entry* e = c->stack->entries + (--c->stack->entryCount);
|
||||
*p = e->value;
|
||||
*offset = e->offset;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned
|
||||
hash(object p, unsigned capacity)
|
||||
{
|
||||
return (reinterpret_cast<uintptr_t>(p) >> PointerShift)
|
||||
& (capacity - 1);
|
||||
}
|
||||
|
||||
Set::Entry*
|
||||
find(Context* c, object p)
|
||||
{
|
||||
if (c->objects == 0) return false;
|
||||
|
||||
for (int i = c->objects->index[hash(p, c->objects->capacity)]; i >= 0;) {
|
||||
Set::Entry* e = c->objects->entries + i;
|
||||
if (e->value == p) {
|
||||
return e;
|
||||
}
|
||||
i = e->next;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Set::Entry*
|
||||
add(Context* c UNUSED, Set* set, object p, uint32_t number)
|
||||
{
|
||||
assert(c->thread, set->size < set->capacity);
|
||||
|
||||
unsigned index = hash(p, set->capacity);
|
||||
|
||||
int offset = set->size++;
|
||||
Set::Entry* e = set->entries + offset;
|
||||
e->value = p;
|
||||
e->number = number;
|
||||
e->next = set->index[index];
|
||||
set->index[index] = offset;
|
||||
return e;
|
||||
}
|
||||
|
||||
Set::Entry*
|
||||
add(Context* c, object p)
|
||||
{
|
||||
if (c->objects == 0 or c->objects->size == c->objects->capacity) {
|
||||
unsigned capacity;
|
||||
if (c->objects) {
|
||||
capacity = c->objects->capacity * 2;
|
||||
} else {
|
||||
capacity = 4096; // must be power of two
|
||||
}
|
||||
|
||||
Set* set = new (c->thread->m->heap->allocate(Set::footprint(capacity)))
|
||||
Set(capacity);
|
||||
|
||||
memset(set->index, 0xFF, sizeof(int) * capacity);
|
||||
|
||||
if (c->objects) {
|
||||
for (unsigned i = 0; i < c->objects->capacity; ++i) {
|
||||
for (int j = c->objects->index[i]; j >= 0;) {
|
||||
Set::Entry* e = c->objects->entries + j;
|
||||
add(c, set, e->value, e->number);
|
||||
j = e->next;
|
||||
}
|
||||
}
|
||||
|
||||
c->thread->m->heap->free
|
||||
(c->objects, Set::footprint(c->objects->capacity));
|
||||
}
|
||||
|
||||
c->objects = set;
|
||||
}
|
||||
|
||||
return add(c, c->objects, p, 0);
|
||||
}
|
||||
|
||||
enum {
|
||||
Root,
|
||||
Size,
|
||||
ClassName,
|
||||
Push,
|
||||
Pop
|
||||
};
|
||||
|
||||
inline object
|
||||
get(object o, unsigned offsetInWords)
|
||||
{
|
||||
return static_cast<object>
|
||||
(mask(cast<void*>(o, offsetInWords * BytesPerWord)));
|
||||
}
|
||||
|
||||
void
|
||||
write1(Context* c, uint8_t v)
|
||||
{
|
||||
fwrite(&v, 1, 1, c->out);
|
||||
}
|
||||
|
||||
void
|
||||
write4(Context* c, uint32_t v)
|
||||
{
|
||||
uint8_t b[] = { v >> 24, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF };
|
||||
fwrite(b, 4, 1, c->out);
|
||||
}
|
||||
|
||||
void
|
||||
writeString(Context* c, int8_t* p, unsigned size)
|
||||
{
|
||||
write4(c, size);
|
||||
fwrite(p, size, 1, c->out);
|
||||
}
|
||||
|
||||
unsigned
|
||||
objectSize(Thread* t, object o)
|
||||
{
|
||||
unsigned n = baseSize(t, o, objectClass(t, o));
|
||||
if (objectExtended(t, o)) {
|
||||
++ n;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
void
|
||||
visit(Context* c, object p)
|
||||
{
|
||||
Thread* t = c->thread;
|
||||
int nextChildOffset;
|
||||
|
||||
write1(c, Root);
|
||||
|
||||
visit: {
|
||||
Set::Entry* e = find(c, p);
|
||||
if (e) {
|
||||
write4(c, e->number);
|
||||
} else {
|
||||
e = add(c, p);
|
||||
e->number = c->nextNumber++;
|
||||
|
||||
write4(c, e->number);
|
||||
|
||||
write1(c, Size);
|
||||
write4(c, objectSize(t, p));
|
||||
|
||||
if (objectClass(t, p) == arrayBody(t, t->m->types, Machine::ClassType)) {
|
||||
object name = className(t, p);
|
||||
if (name) {
|
||||
write1(c, ClassName);
|
||||
writeString(c, &byteArrayBody(t, name, 0),
|
||||
byteArrayLength(t, name) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
nextChildOffset = walkNext(t, p, -1);
|
||||
if (nextChildOffset != -1) {
|
||||
goto children;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
goto pop;
|
||||
|
||||
children: {
|
||||
write1(c, Push);
|
||||
push(c, p, nextChildOffset);
|
||||
p = get(p, nextChildOffset);
|
||||
goto visit;
|
||||
}
|
||||
|
||||
pop: {
|
||||
if (pop(c, &p, &nextChildOffset)) {
|
||||
write1(c, Pop);
|
||||
nextChildOffset = walkNext(t, p, nextChildOffset);
|
||||
if (nextChildOffset >= 0) {
|
||||
goto children;
|
||||
} else {
|
||||
goto pop;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace vm {
|
||||
|
||||
void
|
||||
dumpHeap(Thread* t, FILE* out)
|
||||
{
|
||||
Context context(t, out);
|
||||
|
||||
class Visitor : public Heap::Visitor {
|
||||
public:
|
||||
Visitor(Context* c): c(c) { }
|
||||
|
||||
virtual void visit(void* p) {
|
||||
::visit(c, static_cast<object>(mask(*static_cast<void**>(p))));
|
||||
}
|
||||
|
||||
Context* c;
|
||||
} v(&context);
|
||||
|
||||
add(&context, 0)->number = 0;
|
||||
|
||||
visitRoots(t->m, &v);
|
||||
}
|
||||
|
||||
} // namespace vm
|
@ -2046,12 +2046,13 @@ populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable)
|
||||
|
||||
} // namespace vm
|
||||
|
||||
#define BUILTINS_PROPERTY "avian.builtins"
|
||||
#define BOOTSTRAP_PROPERTY "avian.bootstrap"
|
||||
#define CRASHDIR_PROPERTY "avian.crash.dir"
|
||||
#define CLASSPATH_PROPERTY "java.class.path"
|
||||
#define BOOTCLASSPATH_PREPEND_OPTION "bootclasspath/p"
|
||||
#define BOOTCLASSPATH_OPTION "bootclasspath"
|
||||
#define BOOTCLASSPATH_APPEND_OPTION "bootclasspath/a"
|
||||
#define BOOTCLASSPATH_APPEND_OPTION "bootclasspath/a"
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
JNI_GetDefaultJavaVMInitArgs(void*)
|
||||
@ -2065,12 +2066,14 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args)
|
||||
JavaVMInitArgs* a = static_cast<JavaVMInitArgs*>(args);
|
||||
|
||||
unsigned heapLimit = 0;
|
||||
const char* builtins = 0;
|
||||
const char* bootLibrary = 0;
|
||||
const char* classpath = 0;
|
||||
const char* bootClasspathPrepend = "";
|
||||
const char* bootClasspath = "";
|
||||
const char* bootClasspathAppend = "";
|
||||
const char* crashDumpDirectory = 0;
|
||||
|
||||
unsigned propertyCount = 0;
|
||||
|
||||
for (int i = 0; i < a->nOptions; ++i) {
|
||||
if (strncmp(a->options[i].optionString, "-X", 2) == 0) {
|
||||
@ -2092,21 +2095,21 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args)
|
||||
}
|
||||
} else if (strncmp(a->options[i].optionString, "-D", 2) == 0) {
|
||||
const char* p = a->options[i].optionString + 2;
|
||||
if (strncmp(p, BUILTINS_PROPERTY "=",
|
||||
sizeof(BUILTINS_PROPERTY)) == 0)
|
||||
{
|
||||
builtins = p + sizeof(BUILTINS_PROPERTY);
|
||||
} else if (strncmp(p, BOOTSTRAP_PROPERTY "=",
|
||||
sizeof(BOOTSTRAP_PROPERTY)) == 0)
|
||||
if (strncmp(p, BOOTSTRAP_PROPERTY "=",
|
||||
sizeof(BOOTSTRAP_PROPERTY)) == 0)
|
||||
{
|
||||
bootLibrary = p + sizeof(BOOTSTRAP_PROPERTY);
|
||||
} else if (strncmp(p, CRASHDIR_PROPERTY "=",
|
||||
sizeof(CRASHDIR_PROPERTY)) == 0)
|
||||
{
|
||||
crashDumpDirectory = p + sizeof(CRASHDIR_PROPERTY);
|
||||
} else if (strncmp(p, CLASSPATH_PROPERTY "=",
|
||||
sizeof(CLASSPATH_PROPERTY)) == 0)
|
||||
{
|
||||
classpath = p + sizeof(CLASSPATH_PROPERTY);
|
||||
}
|
||||
|
||||
// todo: add properties to VM
|
||||
++ propertyCount;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2128,13 +2131,22 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args)
|
||||
append(&classpathPointer, bootClasspathAppend, bcpal, PATH_SEPARATOR);
|
||||
append(&classpathPointer, classpath, cpl, 0);
|
||||
|
||||
System* s = makeSystem();
|
||||
System* s = makeSystem(crashDumpDirectory);
|
||||
Heap* h = makeHeap(s, heapLimit);
|
||||
Finder* f = makeFinder(s, classpathBuffer, bootLibrary);
|
||||
Processor* p = makeProcessor(s, h);
|
||||
|
||||
const char** properties = static_cast<const char**>
|
||||
(h->allocate(sizeof(const char*) * propertyCount));
|
||||
const char** propertyPointer = properties;
|
||||
for (int i = 0; i < a->nOptions; ++i) {
|
||||
if (strncmp(a->options[i].optionString, "-D", 2) == 0) {
|
||||
*(propertyPointer++) = a->options[i].optionString + 2;
|
||||
}
|
||||
}
|
||||
|
||||
*m = new (h->allocate(sizeof(Machine)))
|
||||
Machine(s, h, f, p, bootLibrary, builtins);
|
||||
Machine(s, h, f, p, properties, propertyCount);
|
||||
|
||||
*t = p->makeThread(*m, 0, 0);
|
||||
|
||||
|
110
src/machine.cpp
110
src/machine.cpp
@ -198,13 +198,13 @@ visitRoots(Thread* t, Heap::Visitor* v)
|
||||
|
||||
void
|
||||
walk(Thread*, Heap::Walker* w, uint32_t* mask, unsigned fixedSize,
|
||||
unsigned arrayElementSize, unsigned arrayLength)
|
||||
unsigned arrayElementSize, unsigned arrayLength, unsigned start)
|
||||
{
|
||||
unsigned fixedSizeInWords = ceiling(fixedSize, BytesPerWord);
|
||||
unsigned arrayElementSizeInWords
|
||||
= ceiling(arrayElementSize, BytesPerWord);
|
||||
|
||||
for (unsigned i = 0; i < fixedSizeInWords; ++i) {
|
||||
for (unsigned i = start; i < fixedSizeInWords; ++i) {
|
||||
if (mask[i / 32] & (static_cast<uint32_t>(1) << (i % 32))) {
|
||||
if (not w->visit(i)) {
|
||||
return;
|
||||
@ -222,8 +222,19 @@ walk(Thread*, Heap::Walker* w, uint32_t* mask, unsigned fixedSize,
|
||||
}
|
||||
|
||||
if (arrayObjectElements) {
|
||||
for (unsigned i = 0; i < arrayLength; ++i) {
|
||||
for (unsigned j = 0; j < arrayElementSizeInWords; ++j) {
|
||||
unsigned arrayStart;
|
||||
unsigned elementStart;
|
||||
if (start > fixedSizeInWords) {
|
||||
unsigned s = start - fixedSizeInWords;
|
||||
arrayStart = s / arrayElementSizeInWords;
|
||||
elementStart = s % arrayElementSizeInWords;
|
||||
} else {
|
||||
arrayStart = 0;
|
||||
elementStart = 0;
|
||||
}
|
||||
|
||||
for (unsigned i = arrayStart; i < arrayLength; ++i) {
|
||||
for (unsigned j = elementStart; j < arrayElementSizeInWords; ++j) {
|
||||
unsigned k = fixedSizeInWords + j;
|
||||
if (mask[k / 32] & (static_cast<uint32_t>(1) << (k % 32))) {
|
||||
if (not w->visit
|
||||
@ -238,7 +249,7 @@ walk(Thread*, Heap::Walker* w, uint32_t* mask, unsigned fixedSize,
|
||||
}
|
||||
|
||||
void
|
||||
walk(Thread* t, Heap::Walker* w, object o)
|
||||
walk(Thread* t, Heap::Walker* w, object o, unsigned start)
|
||||
{
|
||||
object class_ = static_cast<object>(t->m->heap->follow(objectClass(t, o)));
|
||||
object objectMask = static_cast<object>
|
||||
@ -255,16 +266,16 @@ walk(Thread* t, Heap::Walker* w, object o)
|
||||
memcpy(mask, &intArrayBody(t, objectMask, 0),
|
||||
intArrayLength(t, objectMask) * 4);
|
||||
|
||||
walk(t, w, mask, fixedSize, arrayElementSize, arrayLength);
|
||||
walk(t, w, mask, fixedSize, arrayElementSize, arrayLength, start);
|
||||
} else if (classVmFlags(t, class_) & SingletonFlag) {
|
||||
unsigned length = singletonLength(t, o);
|
||||
if (length) {
|
||||
walk(t, w, singletonMask(t, o),
|
||||
(singletonCount(t, o) + 2) * BytesPerWord, 0, 0);
|
||||
} else {
|
||||
(singletonCount(t, o) + 2) * BytesPerWord, 0, 0, start);
|
||||
} else if (start == 0) {
|
||||
w->visit(0);
|
||||
}
|
||||
} else {
|
||||
} else if (start == 0) {
|
||||
w->visit(0);
|
||||
}
|
||||
}
|
||||
@ -1534,20 +1545,7 @@ class HeapClient: public Heap::Client {
|
||||
HeapClient(Machine* m): m(m) { }
|
||||
|
||||
virtual void visitRoots(Heap::Visitor* v) {
|
||||
v->visit(&(m->loader));
|
||||
v->visit(&(m->bootstrapClassMap));
|
||||
v->visit(&(m->monitorMap));
|
||||
v->visit(&(m->stringMap));
|
||||
v->visit(&(m->types));
|
||||
v->visit(&(m->jniMethodTable));
|
||||
|
||||
for (Reference* r = m->jniReferences; r; r = r->next) {
|
||||
v->visit(&(r->target));
|
||||
}
|
||||
|
||||
for (Thread* t = m->rootThread; t; t = t->peer) {
|
||||
::visitRoots(t, v);
|
||||
}
|
||||
::visitRoots(m, v);
|
||||
|
||||
postVisit(m->rootThread, v);
|
||||
}
|
||||
@ -1616,7 +1614,7 @@ class HeapClient: public Heap::Client {
|
||||
|
||||
virtual void walk(void* p, Heap::Walker* w) {
|
||||
object o = static_cast<object>(m->heap->follow(mask(p)));
|
||||
::walk(m->rootThread, w, o);
|
||||
::walk(m->rootThread, w, o, 0);
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
@ -1632,8 +1630,8 @@ class HeapClient: public Heap::Client {
|
||||
namespace vm {
|
||||
|
||||
Machine::Machine(System* system, Heap* heap, Finder* finder,
|
||||
Processor* processor, const char* bootLibrary,
|
||||
const char* builtins):
|
||||
Processor* processor, const char** properties,
|
||||
unsigned propertyCount):
|
||||
vtable(&javaVMVTable),
|
||||
system(system),
|
||||
heapClient(new (heap->allocate(sizeof(HeapClient)))
|
||||
@ -1644,7 +1642,8 @@ Machine::Machine(System* system, Heap* heap, Finder* finder,
|
||||
rootThread(0),
|
||||
exclusive(0),
|
||||
jniReferences(0),
|
||||
builtins(builtins),
|
||||
properties(properties),
|
||||
propertyCount(propertyCount),
|
||||
activeCount(0),
|
||||
liveCount(0),
|
||||
fixedFootprint(0),
|
||||
@ -1677,7 +1676,8 @@ Machine::Machine(System* system, Heap* heap, Finder* finder,
|
||||
not system->success(system->make(&heapLock)) or
|
||||
not system->success(system->make(&classLock)) or
|
||||
not system->success(system->make(&referenceLock)) or
|
||||
not system->success(system->load(&libraries, bootLibrary, false)))
|
||||
not system->success
|
||||
(system->load(&libraries, findProperty(this, "avian.bootstrap"), false)))
|
||||
{
|
||||
system->abort();
|
||||
}
|
||||
@ -1706,6 +1706,8 @@ Machine::dispose()
|
||||
heap->free(heapPool[i], Thread::HeapSizeInBytes);
|
||||
}
|
||||
|
||||
heap->free(properties, sizeof(const char*) * propertyCount);
|
||||
|
||||
static_cast<HeapClient*>(heapClient)->dispose();
|
||||
|
||||
heap->free(this, sizeof(*this));
|
||||
@ -2595,12 +2597,14 @@ findInHierarchy(Thread* t, object class_, object name, object spec,
|
||||
PROTECT(t, class_);
|
||||
|
||||
object o = 0;
|
||||
if (classFlags(t, class_) & ACC_INTERFACE) {
|
||||
if (classVirtualTable(t, class_)) {
|
||||
o = findInTable
|
||||
(t, classVirtualTable(t, class_), name, spec, methodName, methodSpec);
|
||||
}
|
||||
} else {
|
||||
if ((classFlags(t, class_) & ACC_INTERFACE)
|
||||
and classVirtualTable(t, class_))
|
||||
{
|
||||
o = findInTable
|
||||
(t, classVirtualTable(t, class_), name, spec, methodName, methodSpec);
|
||||
}
|
||||
|
||||
if (o == 0) {
|
||||
for (; o == 0 and class_; class_ = classSuper(t, class_)) {
|
||||
o = find(t, class_, name, spec);
|
||||
}
|
||||
@ -2765,6 +2769,44 @@ collect(Thread* t, Heap::CollectionType type)
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
walkNext(Thread* t, object o, int previous)
|
||||
{
|
||||
class Walker: public Heap::Walker {
|
||||
public:
|
||||
Walker(): value(-1) { }
|
||||
|
||||
bool visit(unsigned offset) {
|
||||
value = offset;
|
||||
return false;
|
||||
}
|
||||
|
||||
int value;
|
||||
} walker;
|
||||
|
||||
walk(t, &walker, o, previous + 1);
|
||||
return walker.value;
|
||||
}
|
||||
|
||||
void
|
||||
visitRoots(Machine* m, Heap::Visitor* v)
|
||||
{
|
||||
v->visit(&(m->loader));
|
||||
v->visit(&(m->bootstrapClassMap));
|
||||
v->visit(&(m->monitorMap));
|
||||
v->visit(&(m->stringMap));
|
||||
v->visit(&(m->types));
|
||||
v->visit(&(m->jniMethodTable));
|
||||
|
||||
for (Reference* r = m->jniReferences; r; r = r->next) {
|
||||
v->visit(&(r->target));
|
||||
}
|
||||
|
||||
for (Thread* t = m->rootThread; t; t = t->peer) {
|
||||
::visitRoots(t, v);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
printTrace(Thread* t, object exception)
|
||||
{
|
||||
|
@ -1138,7 +1138,7 @@ class Machine {
|
||||
};
|
||||
|
||||
Machine(System* system, Heap* heap, Finder* finder, Processor* processor,
|
||||
const char* bootLibrary, const char* builtins);
|
||||
const char** properties, unsigned propertyCount);
|
||||
|
||||
~Machine() {
|
||||
dispose();
|
||||
@ -1159,7 +1159,8 @@ class Machine {
|
||||
Thread* rootThread;
|
||||
Thread* exclusive;
|
||||
Reference* jniReferences;
|
||||
const char* builtins;
|
||||
const char** properties;
|
||||
unsigned propertyCount;
|
||||
unsigned activeCount;
|
||||
unsigned liveCount;
|
||||
unsigned fixedFootprint;
|
||||
@ -1227,7 +1228,7 @@ class Thread {
|
||||
t->protector = this;
|
||||
}
|
||||
|
||||
virtual ~Protector() {
|
||||
~Protector() {
|
||||
t->protector = next;
|
||||
}
|
||||
|
||||
@ -1526,6 +1527,29 @@ setObjectClass(Thread*, object o, object value)
|
||||
| (reinterpret_cast<uintptr_t>(cast<object>(o, 0)) & (~PointerMask)));
|
||||
}
|
||||
|
||||
inline const char*
|
||||
findProperty(Machine* m, const char* name)
|
||||
{
|
||||
for (unsigned i = 0; i < m->propertyCount; ++i) {
|
||||
const char* p = m->properties[i];
|
||||
const char* n = name;
|
||||
while (*p and *p != '=' and *n and *p == *n) {
|
||||
++ p;
|
||||
++ n;
|
||||
}
|
||||
if (*p == '=' and *n == 0) {
|
||||
return p + 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline const char*
|
||||
findProperty(Thread* t, const char* name)
|
||||
{
|
||||
return findProperty(t->m, name);
|
||||
}
|
||||
|
||||
object&
|
||||
arrayBodyUnsafe(Thread*, object, unsigned);
|
||||
|
||||
@ -2200,6 +2224,12 @@ intern(Thread* t, object s);
|
||||
void
|
||||
exit(Thread* t);
|
||||
|
||||
int
|
||||
walkNext(Thread* t, object o, int previous);
|
||||
|
||||
void
|
||||
visitRoots(Machine* m, Heap::Visitor* v);
|
||||
|
||||
inline jobject
|
||||
makeLocalReference(Thread* t, object o)
|
||||
{
|
||||
@ -2293,6 +2323,9 @@ makeSingleton(Thread* t, unsigned count)
|
||||
return o;
|
||||
}
|
||||
|
||||
void
|
||||
dumpHeap(Thread* t, FILE* out);
|
||||
|
||||
} // namespace vm
|
||||
|
||||
void
|
||||
|
@ -257,9 +257,10 @@ class MySystem: public System {
|
||||
Thread* t = static_cast<Thread*>(context);
|
||||
|
||||
if (owner_ == t) {
|
||||
bool interrupted;
|
||||
bool notified;
|
||||
unsigned depth;
|
||||
// Initialized here to make gcc 4.2 a happy compiler
|
||||
bool interrupted = false;
|
||||
bool notified = false;
|
||||
unsigned depth = 0;
|
||||
|
||||
{ ACQUIRE(t->mutex);
|
||||
|
||||
@ -820,7 +821,7 @@ handleSignal(int signal, siginfo_t* info, void* context)
|
||||
namespace vm {
|
||||
|
||||
System*
|
||||
makeSystem()
|
||||
makeSystem(const char*)
|
||||
{
|
||||
return new (malloc(sizeof(MySystem))) MySystem();
|
||||
}
|
||||
|
@ -301,8 +301,6 @@ class Task {
|
||||
public:
|
||||
Task(Task* next): next(next) { }
|
||||
|
||||
virtual ~Task() { }
|
||||
|
||||
virtual void run(Context* c) = 0;
|
||||
|
||||
Task* next;
|
||||
|
@ -167,8 +167,7 @@ resolveNativeMethod2(Thread* t, object method)
|
||||
}
|
||||
|
||||
#ifdef __MINGW32__
|
||||
// on windows, we also try the _%s@%d variant, since the SWT
|
||||
// libraries use it.
|
||||
// on windows, we also try the _%s@%d and %s@%d variants
|
||||
unsigned footprint = methodParameterFootprint(t, method) + 1;
|
||||
if (methodFlags(t, method) & ACC_STATIC) {
|
||||
++ footprint;
|
||||
@ -186,6 +185,12 @@ resolveNativeMethod2(Thread* t, object method)
|
||||
if (p) {
|
||||
return p;
|
||||
}
|
||||
|
||||
// one more try without the leading underscore
|
||||
p = ::resolveNativeMethod(t, undecorated + 1, decorated + 1);
|
||||
if (p) {
|
||||
return p;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
@ -23,15 +23,11 @@ class Processor {
|
||||
|
||||
class StackVisitor {
|
||||
public:
|
||||
virtual ~StackVisitor() { }
|
||||
|
||||
virtual bool visit(StackWalker* walker) = 0;
|
||||
};
|
||||
|
||||
class StackWalker {
|
||||
public:
|
||||
virtual ~StackWalker() { }
|
||||
|
||||
virtual void walk(StackVisitor* v) = 0;
|
||||
|
||||
virtual object method() = 0;
|
||||
@ -41,8 +37,6 @@ class Processor {
|
||||
virtual unsigned count() = 0;
|
||||
};
|
||||
|
||||
virtual ~Processor() { }
|
||||
|
||||
virtual Thread*
|
||||
makeThread(Machine* m, object javaThread, Thread* parent) = 0;
|
||||
|
||||
|
@ -19,7 +19,6 @@ class Stream {
|
||||
public:
|
||||
class Client {
|
||||
public:
|
||||
virtual ~Client() { }
|
||||
virtual void NO_RETURN handleError() = 0;
|
||||
};
|
||||
|
||||
|
14
src/system.h
14
src/system.h
@ -28,7 +28,6 @@ class System {
|
||||
|
||||
class Thread {
|
||||
public:
|
||||
virtual ~Thread() { }
|
||||
virtual void interrupt() = 0;
|
||||
virtual void join() = 0;
|
||||
virtual void dispose() = 0;
|
||||
@ -36,13 +35,11 @@ class System {
|
||||
|
||||
class ThreadVisitor {
|
||||
public:
|
||||
virtual ~ThreadVisitor() { }
|
||||
virtual void visit(void* ip, void* base, void* stack) = 0;
|
||||
};
|
||||
|
||||
class Runnable {
|
||||
public:
|
||||
virtual ~Runnable() { }
|
||||
virtual void attach(Thread*) = 0;
|
||||
virtual void run() = 0;
|
||||
virtual bool interrupted() = 0;
|
||||
@ -51,7 +48,6 @@ class System {
|
||||
|
||||
class Mutex {
|
||||
public:
|
||||
virtual ~Mutex() { }
|
||||
virtual void acquire() = 0;
|
||||
virtual void release() = 0;
|
||||
virtual void dispose() = 0;
|
||||
@ -59,7 +55,6 @@ class System {
|
||||
|
||||
class Monitor {
|
||||
public:
|
||||
virtual ~Monitor() { }
|
||||
virtual bool tryAcquire(Thread* context) = 0;
|
||||
virtual void acquire(Thread* context) = 0;
|
||||
virtual void release(Thread* context) = 0;
|
||||
@ -72,7 +67,6 @@ class System {
|
||||
|
||||
class Local {
|
||||
public:
|
||||
virtual ~Local() { }
|
||||
virtual void* get() = 0;
|
||||
virtual void set(void* p) = 0;
|
||||
virtual void dispose() = 0;
|
||||
@ -80,7 +74,6 @@ class System {
|
||||
|
||||
class Region {
|
||||
public:
|
||||
virtual ~Region() { }
|
||||
virtual const uint8_t* start() = 0;
|
||||
virtual size_t length() = 0;
|
||||
virtual void dispose() = 0;
|
||||
@ -88,7 +81,6 @@ class System {
|
||||
|
||||
class Library {
|
||||
public:
|
||||
virtual ~Library() { }
|
||||
virtual void* resolve(const char* function) = 0;
|
||||
virtual const char* name() = 0;
|
||||
virtual bool mapName() = 0;
|
||||
@ -99,8 +91,6 @@ class System {
|
||||
|
||||
class SignalHandler {
|
||||
public:
|
||||
virtual ~SignalHandler() { }
|
||||
|
||||
virtual bool handleSignal(void** ip, void** base, void** stack,
|
||||
void** thread) = 0;
|
||||
};
|
||||
@ -120,8 +110,6 @@ class System {
|
||||
System::Monitor* m;
|
||||
};
|
||||
|
||||
virtual ~System() { }
|
||||
|
||||
virtual bool success(Status) = 0;
|
||||
virtual void* tryAllocate(unsigned sizeInBytes) = 0;
|
||||
virtual void free(const void* p) = 0;
|
||||
@ -193,7 +181,7 @@ assert(System* s, bool v)
|
||||
#endif // not NDEBUG
|
||||
|
||||
System*
|
||||
makeSystem();
|
||||
makeSystem(const char* crashDumpDirectory);
|
||||
|
||||
} // namespace vm
|
||||
|
||||
|
@ -371,7 +371,6 @@ class Scalar : public Object {
|
||||
unsigned elementSize;
|
||||
bool noassert;
|
||||
bool nogc;
|
||||
bool hide;
|
||||
|
||||
static Scalar* make(Object* owner, Object* typeObject, const char* typeName,
|
||||
const char* name, unsigned size)
|
||||
@ -385,7 +384,6 @@ class Scalar : public Object {
|
||||
o->elementSize = size;
|
||||
o->noassert = false;
|
||||
o->nogc = false;
|
||||
o->hide = false;
|
||||
return o;
|
||||
}
|
||||
};
|
||||
@ -527,19 +525,6 @@ memberGC(Object* o)
|
||||
return not memberNoGC(o) and equal(memberTypeName(o), "object");
|
||||
}
|
||||
|
||||
bool&
|
||||
memberHide(Object* o)
|
||||
{
|
||||
switch (o->type) {
|
||||
case Object::Scalar:
|
||||
case Object::Array:
|
||||
return static_cast<Scalar*>(o)->hide;
|
||||
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
}
|
||||
|
||||
class Method : public Object {
|
||||
public:
|
||||
Object* owner;
|
||||
@ -588,7 +573,6 @@ class Type : public Object {
|
||||
Object* super;
|
||||
List members;
|
||||
List methods;
|
||||
bool hideConstructor;
|
||||
bool overridesMethods;
|
||||
|
||||
static Type* make(Object::ObjectType type, const char* name,
|
||||
@ -601,7 +585,6 @@ class Type : public Object {
|
||||
o->super = 0;
|
||||
o->members.first = o->members.last = 0;
|
||||
o->methods.first = o->methods.last = 0;
|
||||
o->hideConstructor = false;
|
||||
o->overridesMethods = false;
|
||||
return o;
|
||||
}
|
||||
@ -718,18 +701,6 @@ typeSuper(Object* o)
|
||||
}
|
||||
}
|
||||
|
||||
bool&
|
||||
typeHideConstructor(Object* o)
|
||||
{
|
||||
switch (o->type) {
|
||||
case Object::Type:
|
||||
return static_cast<Type*>(o)->hideConstructor;
|
||||
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
}
|
||||
|
||||
class Number : public Object {
|
||||
public:
|
||||
unsigned value;
|
||||
@ -1141,15 +1112,7 @@ void
|
||||
parseSubdeclaration(Object* t, Object* p, Object* declarations)
|
||||
{
|
||||
const char* front = string(car(p));
|
||||
if (equal(front, "hide")) {
|
||||
if (equal(string(car(cdr(p))), "constructor")) {
|
||||
typeHideConstructor(t) = true;
|
||||
} else {
|
||||
Object* member = parseMember(t, cdr(p), declarations);
|
||||
memberHide(member) = true;
|
||||
addMember(t, member);
|
||||
}
|
||||
} else if (equal(front, "extends")) {
|
||||
if (equal(front, "extends")) {
|
||||
assert(t->type == Object::Type);
|
||||
assert(typeSuper(t) == 0);
|
||||
typeSuper(t) = declaration(string(car(cdr(p))), declarations);
|
||||
@ -1169,8 +1132,7 @@ memberEqual(Object* a, Object* b)
|
||||
case Object::Scalar:
|
||||
return equal(memberTypeName(a), memberTypeName(b))
|
||||
and memberNoAssert(a) == memberNoAssert(b)
|
||||
and memberNoGC(a) == memberNoGC(b)
|
||||
and memberHide(a) == memberHide(b);
|
||||
and memberNoGC(a) == memberNoGC(b);
|
||||
|
||||
// todo: compare array fields
|
||||
|
||||
@ -1468,8 +1430,7 @@ parse(Input* in, const char* javaClassDirectory)
|
||||
}
|
||||
|
||||
void
|
||||
writeAccessorName(Output* out, Object* member, bool respectHide = false,
|
||||
bool unsafe = false)
|
||||
writeAccessorName(Output* out, Object* member, bool unsafe = false)
|
||||
{
|
||||
const char* owner = typeName(memberOwner(member));
|
||||
out->write(owner);
|
||||
@ -1477,9 +1438,6 @@ writeAccessorName(Output* out, Object* member, bool respectHide = false,
|
||||
if (unsafe) {
|
||||
out->write("Unsafe");
|
||||
}
|
||||
if (respectHide and memberHide(member)) {
|
||||
out->write("0");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -1557,7 +1515,7 @@ writeAccessor(Output* out, Object* member, Object* offset, bool unsafe = false)
|
||||
}
|
||||
|
||||
out->write("\n");
|
||||
writeAccessorName(out, member, true, unsafe);
|
||||
writeAccessorName(out, member, unsafe);
|
||||
if (memberOwner(member)->type == Object::Pod) {
|
||||
out->write("(");
|
||||
out->write(capitalize(::typeName(memberOwner(member))));
|
||||
@ -1876,7 +1834,7 @@ writeConstructorInitializations(Output* out, Object* t)
|
||||
switch (m->type) {
|
||||
case Object::Scalar: {
|
||||
out->write(" ");
|
||||
writeAccessorName(out, m, true);
|
||||
writeAccessorName(out, m);
|
||||
out->write("(t, o) = ");
|
||||
out->write(obfuscate(memberName(m)));
|
||||
out->write(";\n");
|
||||
@ -1887,7 +1845,7 @@ writeConstructorInitializations(Output* out, Object* t)
|
||||
if (memberTypeObject(m) == 0) {
|
||||
out->write("&");
|
||||
}
|
||||
writeAccessorName(out, m, true);
|
||||
writeAccessorName(out, m);
|
||||
out->write("(t, o, 0), 0, length * ");
|
||||
out->write(arrayElementSize(m));
|
||||
out->write(");\n");
|
||||
@ -1914,7 +1872,6 @@ writeInitializerDeclarations(Output* out, Object* declarations)
|
||||
case Object::Type: {
|
||||
out->write("void init");
|
||||
out->write(capitalize(typeName(o)));
|
||||
if (typeHideConstructor(o)) out->write("0");
|
||||
out->write("(Thread* t, object o");
|
||||
|
||||
writeConstructorParameters(out, o);
|
||||
@ -1936,7 +1893,6 @@ writeConstructorDeclarations(Output* out, Object* declarations)
|
||||
case Object::Type: {
|
||||
out->write("object make");
|
||||
out->write(capitalize(typeName(o)));
|
||||
if (typeHideConstructor(o)) out->write("0");
|
||||
out->write("(Thread* t");
|
||||
|
||||
writeConstructorParameters(out, o);
|
||||
@ -1958,7 +1914,6 @@ writeInitializers(Output* out, Object* declarations)
|
||||
case Object::Type: {
|
||||
out->write("void\ninit");
|
||||
out->write(capitalize(typeName(o)));
|
||||
if (typeHideConstructor(o)) out->write("0");
|
||||
out->write("(Thread* t, object o");
|
||||
|
||||
writeConstructorParameters(out, o);
|
||||
@ -1989,7 +1944,6 @@ writeConstructors(Output* out, Object* declarations)
|
||||
case Object::Type: {
|
||||
out->write("object make");
|
||||
out->write(capitalize(typeName(o)));
|
||||
if (typeHideConstructor(o)) out->write("0");
|
||||
out->write("(Thread* t");
|
||||
|
||||
writeConstructorParameters(out, o);
|
||||
@ -2027,7 +1981,6 @@ writeConstructors(Output* out, Object* declarations)
|
||||
|
||||
out->write(" init");
|
||||
out->write(capitalize(typeName(o)));
|
||||
if (typeHideConstructor(o)) out->write("0");
|
||||
out->write("(t, o");
|
||||
writeConstructorArguments(out, o);
|
||||
out->write(");\n");
|
||||
|
128
src/windows.cpp
128
src/windows.cpp
@ -10,6 +10,7 @@
|
||||
|
||||
#include "sys/stat.h"
|
||||
#include "windows.h"
|
||||
#include "sys/timeb.h"
|
||||
|
||||
#undef max
|
||||
#undef min
|
||||
@ -40,25 +41,11 @@ class MutexResource {
|
||||
HANDLE m;
|
||||
};
|
||||
|
||||
System::SignalHandler* segFaultHandler = 0;
|
||||
LPTOP_LEVEL_EXCEPTION_FILTER oldSegFaultHandler = 0;
|
||||
class MySystem;
|
||||
MySystem* system;
|
||||
|
||||
LONG CALLBACK
|
||||
handleException(LPEXCEPTION_POINTERS e)
|
||||
{
|
||||
if (e->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) {
|
||||
bool jump = segFaultHandler->handleSignal
|
||||
(reinterpret_cast<void**>(&(e->ContextRecord->Eip)),
|
||||
reinterpret_cast<void**>(&(e->ContextRecord->Ebp)),
|
||||
reinterpret_cast<void**>(&(e->ContextRecord->Esp)),
|
||||
reinterpret_cast<void**>(&(e->ContextRecord->Ebx)));
|
||||
|
||||
if (jump) {
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
}
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
handleException(LPEXCEPTION_POINTERS e);
|
||||
|
||||
DWORD WINAPI
|
||||
run(void* r)
|
||||
@ -495,7 +482,14 @@ class MySystem: public System {
|
||||
System::Library* next_;
|
||||
};
|
||||
|
||||
MySystem() {
|
||||
MySystem(const char* crashDumpDirectory):
|
||||
segFaultHandler(0),
|
||||
oldSegFaultHandler(0),
|
||||
crashDumpDirectory(crashDumpDirectory)
|
||||
{
|
||||
expect(this, system == 0);
|
||||
system = this;
|
||||
|
||||
mutex = CreateMutex(0, false, 0);
|
||||
assert(this, mutex);
|
||||
}
|
||||
@ -721,26 +715,116 @@ class MySystem: public System {
|
||||
}
|
||||
|
||||
virtual void abort() {
|
||||
asm("int3");
|
||||
::abort();
|
||||
// trigger an EXCEPTION_ACCESS_VIOLATION, which we will catch and
|
||||
// generate a debug dump for
|
||||
*static_cast<int*>(0) = 0;
|
||||
}
|
||||
|
||||
virtual void dispose() {
|
||||
system = 0;
|
||||
CloseHandle(mutex);
|
||||
::free(this);
|
||||
}
|
||||
|
||||
HANDLE mutex;
|
||||
System::SignalHandler* segFaultHandler;
|
||||
LPTOP_LEVEL_EXCEPTION_FILTER oldSegFaultHandler;
|
||||
const char* crashDumpDirectory;
|
||||
};
|
||||
|
||||
struct MINIDUMP_EXCEPTION_INFORMATION {
|
||||
DWORD thread;
|
||||
LPEXCEPTION_POINTERS exception;
|
||||
BOOL exceptionInCurrentAddressSpace;
|
||||
};
|
||||
|
||||
struct MINIDUMP_USER_STREAM_INFORMATION;
|
||||
struct MINIDUMP_CALLBACK_INFORMATION;
|
||||
|
||||
enum MINIDUMP_TYPE {
|
||||
MiniDumpNormal = 0
|
||||
};
|
||||
|
||||
typedef BOOL (*MiniDumpWriteDumpType)
|
||||
(HANDLE processHandle,
|
||||
DWORD processId,
|
||||
HANDLE file,
|
||||
MINIDUMP_TYPE type,
|
||||
const MINIDUMP_EXCEPTION_INFORMATION* exception,
|
||||
const MINIDUMP_USER_STREAM_INFORMATION* userStream,
|
||||
const MINIDUMP_CALLBACK_INFORMATION* callback);
|
||||
|
||||
void
|
||||
dump(LPEXCEPTION_POINTERS e, const char* directory)
|
||||
{
|
||||
HINSTANCE dbghelp = LoadLibrary("dbghelp.dll");
|
||||
|
||||
if (dbghelp) {
|
||||
MiniDumpWriteDumpType MiniDumpWriteDump = reinterpret_cast
|
||||
<MiniDumpWriteDumpType>(GetProcAddress(dbghelp, "MiniDumpWriteDump"));
|
||||
|
||||
if (MiniDumpWriteDump) {
|
||||
char name[MAX_PATH];
|
||||
_timeb tb;
|
||||
_ftime(&tb);
|
||||
snprintf(name, MAX_PATH, "%s\\crash-%lld.mdmp", directory,
|
||||
(static_cast<int64_t>(tb.time) * 1000)
|
||||
+ static_cast<int64_t>(tb.millitm));
|
||||
|
||||
HANDLE file = CreateFile
|
||||
(name, FILE_WRITE_DATA, 0, 0, CREATE_ALWAYS, 0, 0);
|
||||
|
||||
if (file != INVALID_HANDLE_VALUE) {
|
||||
MINIDUMP_EXCEPTION_INFORMATION exception
|
||||
= { GetCurrentThreadId(), e, true };
|
||||
|
||||
MiniDumpWriteDump
|
||||
(GetCurrentProcess(),
|
||||
GetCurrentProcessId(),
|
||||
file,
|
||||
MiniDumpNormal,
|
||||
&exception,
|
||||
0,
|
||||
0);
|
||||
|
||||
CloseHandle(file);
|
||||
}
|
||||
}
|
||||
|
||||
FreeLibrary(dbghelp);
|
||||
}
|
||||
}
|
||||
|
||||
LONG CALLBACK
|
||||
handleException(LPEXCEPTION_POINTERS e)
|
||||
{
|
||||
if (e->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) {
|
||||
bool jump = system->segFaultHandler->handleSignal
|
||||
(reinterpret_cast<void**>(&(e->ContextRecord->Eip)),
|
||||
reinterpret_cast<void**>(&(e->ContextRecord->Ebp)),
|
||||
reinterpret_cast<void**>(&(e->ContextRecord->Esp)),
|
||||
reinterpret_cast<void**>(&(e->ContextRecord->Ebx)));
|
||||
|
||||
if (jump) {
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
}
|
||||
|
||||
if (system->crashDumpDirectory) {
|
||||
dump(e, system->crashDumpDirectory);
|
||||
}
|
||||
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace vm {
|
||||
|
||||
System*
|
||||
makeSystem()
|
||||
makeSystem(const char* crashDumpDirectory)
|
||||
{
|
||||
return new (malloc(sizeof(MySystem))) MySystem();
|
||||
return new (malloc(sizeof(MySystem))) MySystem(crashDumpDirectory);
|
||||
}
|
||||
|
||||
} // namespace vm
|
||||
|
@ -216,8 +216,6 @@ class Task {
|
||||
public:
|
||||
Task(Task* next): next(next) { }
|
||||
|
||||
virtual ~Task() { }
|
||||
|
||||
virtual void run(Context* c) = 0;
|
||||
|
||||
Task* next;
|
||||
|
26
test/Zip.java
Normal file
26
test/Zip.java
Normal file
@ -0,0 +1,26 @@
|
||||
import java.io.InputStream;
|
||||
import java.util.Enumeration;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipEntry;
|
||||
|
||||
public class Zip {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
ZipFile file = new ZipFile("build/classpath.jar");
|
||||
|
||||
byte[] buffer = new byte[4096];
|
||||
for (Enumeration<ZipEntry> e = file.entries(); e.hasMoreElements();) {
|
||||
ZipEntry entry = e.nextElement();
|
||||
InputStream in = file.getInputStream(entry);
|
||||
try {
|
||||
int size = 0;
|
||||
int c; while ((c = in.read(buffer)) != -1) size += c;
|
||||
System.out.println
|
||||
(entry.getName() + " " + entry.getCompressedSize() + " " + size);
|
||||
} finally {
|
||||
in.read();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -17,7 +17,7 @@ for test in ${tests}; do
|
||||
printf "%16s" "${test}: "
|
||||
|
||||
case ${mode} in
|
||||
debug|debug-fast|fast )
|
||||
debug|debug-fast|fast|small )
|
||||
${vm} ${flags} ${test} >>${log} 2>&1;;
|
||||
|
||||
stress* )
|
||||
|
Loading…
Reference in New Issue
Block a user