Merge remote-tracking branch 'rt/master'

This commit is contained in:
Luke Wahlmeier 2016-01-10 03:04:30 -07:00
commit 62a03898c3
34 changed files with 1309 additions and 650 deletions

View File

@ -8,7 +8,9 @@ os:
env:
matrix:
- BUILD_STEP=""
- BUILD_STEP="PUBLISH"
# disabled until/unless jfrog.org credentials are updated and someone
# decides they care about published artifacts:
# - BUILD_STEP="PUBLISH"
global:
- TERM=dumb
- secure: rh1utD4shKmYtokItuRYEF9WsfTnvZO5XqnTU4DHTS7quHHgLihtOO2/3+B+2W2hEd5Obr2or8zx+zmzWcNUyLokZ0j/FRLWSScNkLzTtm12pupLrncY+/g1NIdfbhn+OLRIzBz6zB6m6a2qWFEJ+bScUNGD/7wZVtzkujqlDEE=

View File

@ -45,7 +45,7 @@ Introduction
Avian is a lightweight virtual machine and class library designed to
provide a useful subset of Java's features, suitable for building
self-contained applications. More information is available at the
project [web site](http://oss.readytalk.com/avian).
project [web site](http://readytalk.github.io/avian).
If you have any trouble building, running, or embedding Avian, please
post a message to our [discussion group](http://groups.google.com/group/avian).
@ -168,8 +168,8 @@ Library" below for details.
These flags determine the name of the directory used for the build.
The name always starts with _${platform}-${arch}_, and each non-default
build option is appended to the name. For example, a debug build with
bootimage enabled on Linux/i386 would be built in
_build/linux-i386-debug-bootimage_. This allows you to build with
bootimage enabled on Linux/x86_64 would be built in
_build/linux-x86_64-debug-bootimage_. This allows you to build with
several different sets of options independently and even
simultaneously without doing a clean build each time.
@ -293,9 +293,10 @@ 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). Note that you'll still need to use
vm.pro in that case -- openjdk.pro just adds additional constraints
specific to the OpenJDK port. 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.
specific to the OpenJDK port. Also see
[app.mk](https://github.com/ReadyTalk/avian-swt-examples/blob/master/app.mk)
in the _avian-swt-examples_ project 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:
@ -575,7 +576,7 @@ For boot image builds:
Note you can use ProGuard without using a boot image and vice-versa,
as desired.
The following instructions assume we are building for Linux/i386.
The following instructions assume we are building for Linux/x86_64.
Please refer to the previous example for guidance on other platforms.
__1.__ Build Avian, create a new directory, and populate it with the
@ -584,13 +585,13 @@ VM object files.
$ make bootimage=true
$ mkdir hello
$ cd hello
$ ar x ../build/linux-i386-bootimage/libavian.a
$ ar x ../build/linux-x86_64-bootimage/libavian.a
__2.__ Create a stage1 directory and extract the contents of the
class library jar into it.
$ mkdir stage1
$ (cd stage1 && jar xf ../../build/linux-i386-bootimage/classpath.jar)
$ (cd stage1 && jar xf ../../build/linux-x86_64-bootimage/classpath.jar)
__3.__ Build the Java code and add it to stage1.
@ -630,10 +631,11 @@ using the OpenJDK library.)
__6.__ Build the boot and code images.
$ ../build/linux-i386-bootimage/bootimage-generator \
$ ../build/linux-x86_64-bootimage/bootimage-generator \
-cp stage2 \
-bootimage bootimage-bin.o \
-codeimage codeimage-bin.o
-codeimage codeimage-bin.o \
-hostvm ../build/linux-x86_64-interpret/libjvm.so
Note that you can override the default names for the start and end
symbols in the boot/code image by also passing:

View File

@ -423,6 +423,27 @@ public class Classes {
}
}
public static VMMethod findMethod(ClassLoader loader,
String class_,
String name,
String spec)
throws ClassNotFoundException
{
VMClass c = SystemClassLoader.vmClass(loader.loadClass(class_));
VMMethod[] methodTable = c.methodTable;
if (methodTable != null) {
link(c);
for (int i = 0; i < methodTable.length; ++i) {
VMMethod m = methodTable[i];
if (toString(m.name).equals(name) && toString(m.spec).equals(spec)) {
return m;
}
}
}
return null;
}
public static int findMethod(VMClass vmClass, String name,
Class[] parameterTypes)
{

View File

@ -20,6 +20,8 @@ import java.util.Enumeration;
import java.util.NoSuchElementException;
public class SystemClassLoader extends ClassLoader {
public static native ClassLoader appLoader();
private native VMClass findVMClass(String name)
throws ClassNotFoundException;
@ -81,6 +83,8 @@ public class SystemClassLoader extends ClassLoader {
if (source != null) {
// todo: load attributes from JAR manifest
definePackage(name, null, null, null, null, null, null, null);
} else {
definePackage(name, null, null, null, null, null, null, null);
}
}

View File

@ -10,17 +10,111 @@
package avian.http;
import java.net.URL;
import java.net.URLStreamHandler;
import java.net.URLConnection;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.util.HashMap;
import java.util.Map;
public class Handler extends URLStreamHandler {
protected URLConnection openConnection(URL url) {
throw new UnsupportedOperationException();
}
public class Handler extends URLStreamHandler
{
public URLConnection openConnection(URL url) throws IOException
{
return new HttpURLConnection(url);
}
class HttpURLConnection extends URLConnection
{
Socket socket;
private BufferedWriter writer;
private InputStream bin;
private Map<String,String> header = new HashMap<String, String>();
private int status;
protected HttpURLConnection(URL url)
{
super(url);
}
@Override
public void connect() throws IOException
{
if(socket == null)
{
URLConnection con = null;
String host = url.getHost();
int port =url.getPort();
if(port < 0) port = 80;
socket = new Socket(host, port);
OutputStream out = socket.getOutputStream();
writer = new BufferedWriter(new OutputStreamWriter(out));
writer.write("GET " + url.getPath() + " HTTP/1.1");
writer.write("\r\nHost: " + host);
writer.write("\r\n\r\n");
writer.flush();
bin = new BufferedInputStream(socket.getInputStream());
readHeader();
// System.out.println("Status: " + status);
// System.out.println("Headers: " + header);
}
}
private void readHeader() throws IOException
{
byte[] buf = new byte[8192];
int b = 0;
int index = 0;
while(b >= 0)
{
if(index >= 4 && buf[index-4] == '\r' && buf[index-3] == '\n' && buf[index-2] == '\r' && buf[index-1] == '\n')
{
break;
}
b = bin.read();
buf[index] = (byte) b;
index++;
if(index >= buf.length)
{
throw new IOException("Header exceeded maximum size of 8k.");
}
}
BufferedReader reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(buf, 0, index)));
String line = reader.readLine();
int x = line.indexOf(' ');
status = Integer.parseInt(line.substring(x + 1 , line.indexOf(' ', x+1)));
while(line != null)
{
int i = line.indexOf(':');
if(i > 0)
{
header.put(line.substring(0, i), line.substring(i + 1) .trim());
}
line = reader.readLine();
}
reader.close();
}
@Override
public InputStream getInputStream() throws IOException
{
connect();
return bin;
}
@Override
public OutputStream getOutputStream() throws IOException
{
throw new UnsupportedOperationException("Can' write to HTTP Connection");
}
}
}

View File

@ -7,9 +7,11 @@
There is NO WARRANTY for this software. See license.txt for
details. */
package java.io;
import java.io.IOException;
import java.io.InputStream;
public class BufferedInputStream extends InputStream {
private final InputStream in;
private final byte[] buffer;
@ -25,17 +27,16 @@ public class BufferedInputStream extends InputStream {
this(in, 4096);
}
private void fill() throws IOException {
private int fill() throws IOException {
position = 0;
limit = in.read(buffer);
return limit;
}
public int read() throws IOException {
if (position >= limit) {
fill();
if (limit == -1) {
return -1;
}
if (position >= limit && fill() == -1) {
return -1;
}
return buffer[position++] & 0xFF;
@ -43,7 +44,9 @@ public class BufferedInputStream extends InputStream {
public int read(byte[] b, int offset, int length) throws IOException {
int count = 0;
if (position >= limit && fill() == -1) {
return -1;
}
if (position < limit) {
int remaining = limit - position;
if (remaining > length) {
@ -57,8 +60,8 @@ public class BufferedInputStream extends InputStream {
offset += remaining;
length -= remaining;
}
while (length > 0) {
while (length > 0 && in.available() > 0)
{
int c = in.read(b, offset, length);
if (c == -1) {
if (count == 0) {
@ -69,13 +72,8 @@ public class BufferedInputStream extends InputStream {
offset += c;
count += c;
length -= c;
if (in.available() <= 0) {
break;
}
}
}
return count;
}
@ -87,3 +85,4 @@ public class BufferedInputStream extends InputStream {
in.close();
}
}

View File

@ -15,7 +15,10 @@ import java.util.Random;
public final class Math {
public static final double E = 2.718281828459045;
public static final double PI = 3.141592653589793;
private static final Random random = new Random();
private static class Static {
public static final Random random = new Random();
}
private Math() { }
@ -84,7 +87,7 @@ public final class Math {
}
public static double random() {
return random.nextDouble();
return Static.random.nextDouble();
}
public static native double floor(double v);

View File

@ -22,7 +22,9 @@ import java.util.Hashtable;
import java.util.Properties;
public abstract class System {
private static final long NanoTimeBaseInMillis = currentTimeMillis();
private static class NanoTime {
public static final long BaseInMillis = currentTimeMillis();
}
private static class Static {
public static Properties properties = makeProperties();
@ -94,7 +96,7 @@ public abstract class System {
public static native int identityHashCode(Object o);
public static long nanoTime() {
return (currentTimeMillis() - NanoTimeBaseInMillis) * 1000000;
return (currentTimeMillis() - NanoTime.BaseInMillis) * 1000000;
}
public static String mapLibraryName(String name) {

View File

@ -187,14 +187,28 @@ public class LambdaMetafactory {
return result;
}
public static CallSite metafactory(MethodHandles.Lookup caller,
String invokedName,
MethodType invokedType,
MethodType methodType,
MethodHandle methodImplementation,
MethodType instantiatedMethodType)
throws LambdaConversionException
public static byte[] makeLambda(String invokedName,
String invokedType,
String methodType,
String implementationClass,
String implementationName,
String implementationSpec,
int implementationKind)
{
return makeLambda(invokedName,
new MethodType(invokedType),
new MethodType(methodType),
new MethodHandle(implementationClass,
implementationName,
implementationSpec,
implementationKind));
}
private static byte[] makeLambda(String invokedName,
MethodType invokedType,
MethodType methodType,
MethodHandle methodImplementation)
{
String className;
{ int number;
@ -265,8 +279,19 @@ public class LambdaMetafactory {
throw error;
}
byte[] classData = out.toByteArray();
return out.toByteArray();
}
public static CallSite metafactory(MethodHandles.Lookup caller,
String invokedName,
MethodType invokedType,
MethodType methodType,
MethodHandle methodImplementation,
MethodType instantiatedMethodType)
throws LambdaConversionException
{
byte[] classData = makeLambda(invokedName, invokedType, methodType, methodImplementation);
try {
return new CallSite
(new MethodHandle

View File

@ -1,6 +1,7 @@
package java.lang.invoke;
import avian.Classes;
import avian.SystemClassLoader;
public class MethodHandle {
static final int REF_invokeStatic = 6;
@ -17,6 +18,20 @@ public class MethodHandle {
this.method = method;
}
MethodHandle(String class_,
String name,
String spec,
int kind)
{
this.kind = kind;
this.loader = SystemClassLoader.appLoader();
try {
this.method = Classes.findMethod(this.loader, class_, name, spec);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
public String toString() {
StringBuilder sb = new StringBuilder();
if (method.class_ != null) {

View File

@ -4,6 +4,7 @@ import static avian.Assembler.*;
import avian.Assembler;
import avian.Classes;
import avian.SystemClassLoader;
import avian.VMClass;
import java.util.List;
@ -25,6 +26,12 @@ public final class MethodType implements java.io.Serializable {
this.spec = spec;
}
MethodType(String spec) {
this.loader = SystemClassLoader.appLoader();
this.spec = new byte[spec.length() + 1];
spec.getBytes(0, spec.length(), this.spec, 0);
}
public String toMethodDescriptorString() {
return Classes.makeString(spec, 0, spec.length - 1);
}

View File

@ -86,18 +86,16 @@ public class Socket implements Closeable, AutoCloseable {
@Override
public int read(byte[] buffer) throws IOException {
if(buffer.length == 0) return 0; //spec says return 0 if buffer length is zero.
int fullSize = buffer.length;
int index = 0;
int size;
do {
size = recv(sock, buffer, index, Math.min(fullSize, Socket.BUFFER_SIZE));
fullSize -= size;
index += size;
} while (fullSize != 0 && size != 0);
return index;
size = recv(sock, buffer, 0, Math.min(fullSize, Socket.BUFFER_SIZE));
fullSize -= size;
//removed loop, because otherwise interactive protocols will not work.
if(size < 0) throw new IOException("Error while reading stream"); //as the manpage of recv says, a value below zero indicates an error.
if(size == 0) return -1; // if the stream is closed (size == 0), then return -1 to indicate end of stream.
return size;
}
}
private class SocketOutputStream extends OutputStream {

View File

@ -1,13 +1,18 @@
FROM debian:jessie
MAINTAINER Joshua Warner, joshuawarner32@gmail.com
RUN echo 'deb http://http.debian.net/debian jessie-backports main' >> /etc/apt/sources.list && \
echo 'deb-src http://http.debian.net/debian jessie-backports main' >> /etc/apt/sources.list && \
dpkg --add-architecture i386 && \
apt-get update && \
mkdir /var/src/
# Install base dependencies and build tools, general debugging tools
RUN apt-get update && \
apt-get install -y \
RUN apt-get install -y \
build-essential \
g++-4.8 \
g++-4.9 \
zlib1g-dev \
openjdk-7-jdk \
openjdk-8-jdk \
locales \
--no-install-recommends && \
apt-get clean all
@ -20,8 +25,59 @@ RUN dpkg-reconfigure locales && \
ENV LC_ALL C.UTF-8
# Set JAVA_HOME for avian's benefit
ENV JAVA_HOME /usr/lib/jvm/java-7-openjdk-amd64
ENV JAVA_HOME /usr/lib/jvm/java-8-openjdk-amd64
# Add i386 libraries
RUN apt-get install -y \
libc6-dev-i386 && \
apt-get download \
zlib1g-dev:i386 && \
dpkg -x *.deb / && \
rm *.deb && \
apt-get clean all
# Install cross-compile toolchain and emulator for testing
RUN apt-get install -y \
mingw-w64 \
wget \
unzip \
--no-install-recommends && \
apt-get clean all
# Download win32 and win64 adjacent to avian
RUN cd /var/src/ && \
wget https://github.com/ReadyTalk/win32/archive/master.zip -O win32.zip && \
unzip win32.zip && \
rm win32.zip && \
mv win32-* win32 && \
wget https://github.com/ReadyTalk/win64/archive/master.zip -O win64.zip && \
unzip win64.zip && \
rm win64.zip && \
mv win64-* win64
# Add openjdk-src stuff
RUN apt-get install -y \
libcups2-dev \
libgconf2-dev && \
mkdir /var/src/openjdk/ && \
cd /var/src/openjdk/ && \
apt-get source openjdk-8 && \
apt-get clean all && \
find /var/src/openjdk && \
rm /var/src/openjdk/*.gz /var/src/openjdk/*.dsc && \
cd /var/src/openjdk/ && \
tar -xf /var/src/openjdk/openjdk*/jdk.tar.xz && \
mv /var/src/openjdk/jdk-*/src /var/src/openjdk-src && \
rm -rf /var/src/openjdk && \
apt-get clean all
# Download/extract lzma source
RUN mkdir /var/src/lzma && \
cd /var/src/lzma && \
apt-get install -y p7zip && \
wget http://www.7-zip.org/a/lzma1507.7z -O lzma.7z && \
p7zip -d lzma.7z
# Avian build location
VOLUME /var/avian
WORKDIR /var/avian
VOLUME /var/src/avian
WORKDIR /var/src/avian

View File

@ -38,4 +38,4 @@ fi
DIR=$(cd $(dirname "$0") && cd .. && pwd)
docker run --rm -i -t -v "${DIR}":/var/avian ${THE_USER} "${CONTAINER}" "${@}"
docker run --rm -i -t -v "${DIR}":/var/src/avian ${THE_USER} "${CONTAINER}" "${@}"

View File

@ -1,12 +0,0 @@
FROM joshuawarner32/avian-build
MAINTAINER Joshua Warner, joshuawarner32@gmail.com
RUN dpkg --add-architecture i386 && \
apt-get update && \
apt-get install -y \
libc6-dev-i386 && \
apt-get download \
zlib1g-dev:i386 && \
dpkg -x *.deb / && \
rm *.deb && \
apt-get clean all

View File

@ -1,17 +0,0 @@
FROM joshuawarner32/avian-build-i386
MAINTAINER Joshua Warner, joshuawarner32@gmail.com
RUN echo 'deb-src http://http.debian.net/debian jessie main' >> /etc/apt/sources.list && \
apt-get update && \
apt-get install -y \
libcups2-dev \
libgconf2-dev && \
mkdir /var/openjdk/ && \
cd /var/openjdk/ && \
apt-get source openjdk-7 && \
apt-get clean all && \
rm /var/openjdk/*.gz /var/openjdk/*.dsc && \
cd /var/openjdk/ && \
tar -xzf /var/openjdk/openjdk*/jdk.tar.gz && \
mv /var/openjdk/jdk-*/src /var/openjdk-src && \
rm -rf /var/openjdk

View File

@ -1,23 +0,0 @@
FROM joshuawarner32/avian-build
MAINTAINER Joshua Warner, joshuawarner32@gmail.com
# Install cross-compile toolchain and emulator for testing
RUN apt-get update && \
apt-get install -y \
mingw-w64 \
wget \
unzip \
--no-install-recommends && \
apt-get clean all
# Download win32 and win64 adjacent to avian
RUN cd .. && \
wget https://github.com/ReadyTalk/win32/archive/master.zip -O win32.zip && \
unzip win32.zip && \
rm win32.zip && \
mv win32-* win32 && \
wget https://github.com/ReadyTalk/win64/archive/master.zip -O win64.zip && \
unzip win64.zip && \
rm win64.zip && \
mv win64-* win64

View File

@ -176,7 +176,7 @@ inline void NO_RETURN sysAbort(System* s)
// #endif // not NDEBUG
AVIAN_EXPORT System* makeSystem();
AVIAN_EXPORT System* makeSystem(bool reentrant = false);
} // namespace vm

118
makefile
View File

@ -45,6 +45,11 @@ ifneq ($(lzma),)
endif
ifeq ($(bootimage),true)
options := $(options)-bootimage
ifeq ($(bootimage-test),true)
# this option indicates that we should AOT-compile the test
# classes as well as the class library
options := $(options)-test
endif
endif
ifeq ($(tails),true)
options := $(options)-tails
@ -92,6 +97,12 @@ ifeq ($(platform),ios)
endif
endif
ifeq ($(bootimage-test),true)
ifneq ($(bootimage),true)
x := $(error "bootimage-test=true only works when bootimage=true")
endif
endif
aot-only = false
root := $(shell (cd .. && pwd))
build = build/$(platform)-$(arch)$(options)
@ -109,6 +120,12 @@ wp8 ?= $(root)/wp8
classpath = avian
bootimage-classpath = $(classpath-build)
ifeq ($(bootimage-test),true)
bootimage-classpath = $(classpath-build):$(test-build)
endif
test-executable = $(shell pwd)/$(executable)
boot-classpath = $(classpath-build)
embed-prefix = /avian-embedded
@ -746,13 +763,14 @@ ifeq ($(kernel),darwin)
rpath =
ifeq ($(platform),ios)
ifeq (,$(filter arm arm64,$(arch)))
ifeq ($(sim),true)
target = iPhoneSimulator
sdk = iphonesimulator$(ios-version)
ifeq ($(arch),i386)
arch-flag = -arch i386
else
arch-flag = -arch x86_64
arch = x86_64
endif
release = Release-iphonesimulator
else
@ -762,6 +780,7 @@ ifeq ($(kernel),darwin)
arch-flag = -arch armv7
else
arch-flag = -arch arm64
arch = arm64
endif
release = Release-iphoneos
endif
@ -770,7 +789,9 @@ ifeq ($(kernel),darwin)
sdk-dir = $(platform-dir)/Developer/SDKs
ios-version := $(shell \
if test -d $(sdk-dir)/$(target)8.3.sdk; then echo 8.3; \
if test -L $(sdk-dir)/$(target)9.1.sdk; then echo 9.1; \
elif test -L $(sdk-dir)/$(target)9.0.sdk; then echo 9.0; \
elif test -d $(sdk-dir)/$(target)8.3.sdk; then echo 8.3; \
elif test -d $(sdk-dir)/$(target)8.2.sdk; then echo 8.2; \
elif test -d $(sdk-dir)/$(target)8.1.sdk; then echo 8.1; \
elif test -d $(sdk-dir)/$(target)8.0.sdk; then echo 8.0; \
@ -811,39 +832,57 @@ ifeq ($(kernel),darwin)
cflags += $(flags)
asmflags += $(flags)
lflags += $(flags)
endif
ifeq ($(arch),i386)
ifeq ($(platform),ios)
classpath-extra-cflags += \
-arch i386 -miphoneos-version-min=$(ios-version)
cflags += -arch i386 -miphoneos-version-min=$(ios-version)
asmflags += -arch i386 -miphoneos-version-min=$(ios-version)
lflags += -arch i386 -miphoneos-version-min=$(ios-version)
ios-version-min=$(ios-version)
ifdef ios_deployment_target
ios-version-min=ios_deployment_target
endif
ifeq ($(sim),true)
ifeq ($(arch),x86_64)
classpath-extra-cflags += \
-arch x86_64 -miphoneos-version-min=$(ios-version-min)
cflags += -arch x86_64 -miphoneos-version-min=$(ios-version-min)
asmflags += -arch x86_64 -miphoneos-version-min=$(ios-version-min)
lflags += -arch x86_64 -miphoneos-version-min=$(ios-version-min)
else
classpath-extra-cflags += \
-arch i386 -miphoneos-version-min=$(ios-version-min)
cflags += -arch i386 -miphoneos-version-min=$(ios-version-min)
asmflags += -arch i386 -miphoneos-version-min=$(ios-version-min)
lflags += -arch i386 -miphoneos-version-min=$(ios-version-min)
endif
else
classpath-extra-cflags += \
-arch i386 -mmacosx-version-min=${OSX_SDK_VERSION}
cflags += -arch i386 -mmacosx-version-min=${OSX_SDK_VERSION}
asmflags += -arch i386 -mmacosx-version-min=${OSX_SDK_VERSION}
lflags += -arch i386 -mmacosx-version-min=${OSX_SDK_VERSION}
ifeq ($(arch),arm64)
classpath-extra-cflags += \
-arch arm64 -miphoneos-version-min=$(ios-version-min)
cflags += -arch arm64 -miphoneos-version-min=$(ios-version-min)
asmflags += -arch arm64 -miphoneos-version-min=$(ios-version-min)
lflags += -arch arm64 -miphoneos-version-min=$(ios-version-min)
else
classpath-extra-cflags += \
-arch armv7 -miphoneos-version-min=$(ios-version-min)
cflags += -arch armv7 -miphoneos-version-min=$(ios-version-min)
asmflags += -arch armv7 -miphoneos-version-min=$(ios-version-min)
lflags += -arch armv7 -miphoneos-version-min=$(ios-version-min)
endif
endif
else # not ios
ifeq ($(arch),i386)
classpath-extra-cflags += \
-arch i386 -mmacosx-version-min=${OSX_SDK_VERSION}
cflags += -arch i386 -mmacosx-version-min=${OSX_SDK_VERSION}
asmflags += -arch i386 -mmacosx-version-min=${OSX_SDK_VERSION}
lflags += -arch i386 -mmacosx-version-min=${OSX_SDK_VERSION}
endif
ifeq ($(arch),x86_64)
classpath-extra-cflags += -arch x86_64
cflags += -arch x86_64
asmflags += -arch x86_64
lflags += -arch x86_64
endif
endif
ifeq ($(arch),x86_64)
ifeq ($(platform),ios)
classpath-extra-cflags += \
-arch x86_64 -miphoneos-version-min=$(ios-version)
cflags += -arch x86_64 -miphoneos-version-min=$(ios-version)
asmflags += -arch x86_64 -miphoneos-version-min=$(ios-version)
lflags += -arch x86_64 -miphoneos-version-min=$(ios-version)
else
classpath-extra-cflags += -arch x86_64
cflags += -arch x86_64
asmflags += -arch x86_64
lflags += -arch x86_64
endif
endif
cflags += -I$(JAVA_HOME)/include/darwin
endif
@ -1333,6 +1372,12 @@ bootimage-generator-objects = \
$(call cpp-objects,$(bootimage-generator-sources),$(src),$(build))
bootimage-generator = $(build)/bootimage-generator
ifneq ($(mode),fast)
host-vm-options := -$(mode)
endif
host-vm = build/$(build-platform)-$(build-arch)-interpret$(host-vm-options)/libjvm.so
bootimage-object = $(build)/bootimage-bin.o
codeimage-object = $(build)/codeimage-bin.o
@ -1641,7 +1686,6 @@ debug: build
vg: build
$(library-path) $(vg) $(test-executable) $(test-args)
.PHONY: test
test: build-test run-test
@ -2060,11 +2104,12 @@ else
endif
$(bootimage-object) $(codeimage-object): $(bootimage-generator) \
$(classpath-jar-dep)
$(classpath-jar-dep) $(test-dep)
@echo "generating bootimage and codeimage binaries from $(classpath-build) using $(<)"
$(<) -cp $(classpath-build) -bootimage $(bootimage-object) -codeimage $(codeimage-object) \
$(<) -cp $(bootimage-classpath) -bootimage $(bootimage-object) -codeimage $(codeimage-object) \
-bootimage-symbols $(bootimage-symbols) \
-codeimage-symbols $(codeimage-symbols)
-codeimage-symbols $(codeimage-symbols) \
-hostvm $(host-vm)
executable-objects = $(vm-objects) $(classpath-objects) $(driver-object) \
$(vm-heapwalk-objects) $(boot-object) $(vm-classpath-objects) \
@ -2119,6 +2164,7 @@ $(unittest-executable): $(unittest-executable-objects)
$(bootimage-generator): $(bootimage-generator-objects) $(vm-objects)
echo building $(bootimage-generator) arch=$(build-arch) platform=$(bootimage-platform)
$(MAKE) process=interpret bootimage= bootimage-test= mode=$(mode)
$(MAKE) mode=$(mode) \
build=$(host-build-root) \
arch=$(build-arch) \

View File

@ -55,10 +55,13 @@ class BootImage {
} PACKED;
class GcField;
class GcClass;
class OffsetResolver {
public:
virtual unsigned fieldOffset(Thread*, GcField*) = 0;
virtual void addClass(Thread*, GcClass*, const uint8_t*, size_t) = 0;
};
#define NAME(x) Target##x

View File

@ -20,6 +20,7 @@
#define EMBED_PREFIX_PROPERTY "avian.embed.prefix"
#define CLASSPATH_PROPERTY "java.class.path"
#define JAVA_HOME_PROPERTY "java.home"
#define REENTRANT_PROPERTY "avian.reentrant"
#define BOOTCLASSPATH_PREPEND_OPTION "bootclasspath/p"
#define BOOTCLASSPATH_OPTION "bootclasspath"
#define BOOTCLASSPATH_APPEND_OPTION "bootclasspath/a"

View File

@ -198,6 +198,14 @@ const unsigned ConstructorFlag = 1 << 1;
#define JNI_VERSION_1_6 0x00010006
#endif
#ifndef JNI_TRUE
#define JNI_TRUE 1
#endif
#ifndef JNI_OK
#define JNI_OK 0
#endif
typedef Machine JavaVM;
typedef Thread JNIEnv;
@ -207,6 +215,19 @@ struct JNINativeMethod {
void* function;
};
struct JavaVMOption {
char* optionString;
void* extraInfo;
};
struct JavaVMInitArgs {
jint version;
jint nOptions;
JavaVMOption* options;
jboolean ignoreUnrecognized;
};
struct JavaVMVTable {
void* reserved0;
void* reserved1;
@ -3737,10 +3758,10 @@ void populateMultiArray(Thread* t,
GcMethod* getCaller(Thread* t, unsigned target, bool skipMethodInvoke = false);
object defineClass(Thread* t,
GcClassLoader* loader,
const uint8_t* buffer,
unsigned length);
GcClass* defineClass(Thread* t,
GcClassLoader* loader,
const uint8_t* buffer,
unsigned length);
inline GcMethod* methodClone(Thread* t, GcMethod* method)
{

View File

@ -170,7 +170,8 @@ class Processor {
GcTriple** calls,
avian::codegen::DelayedPromise** addresses,
GcMethod* method,
OffsetResolver* resolver) = 0;
OffsetResolver* resolver,
Machine* hostVM) = 0;
virtual void visitRoots(Thread* t, HeapWalker* w) = 0;

View File

@ -183,6 +183,12 @@ extern "C" AVIAN_EXPORT int64_t JNICALL
t->m->classpath->makeString(t, array, offset, length));
}
extern "C" AVIAN_EXPORT int64_t JNICALL
Avian_avian_SystemClassLoader_appLoader(Thread* t, object, uintptr_t*)
{
return reinterpret_cast<int64_t>(roots(t)->appLoader());
}
extern "C" AVIAN_EXPORT int64_t JNICALL
Avian_avian_SystemClassLoader_findLoadedVMClass(Thread* t,
object,

View File

@ -909,14 +909,16 @@ class BootContext {
GcTriple* calls,
avian::codegen::DelayedPromise* addresses,
Zone* zone,
OffsetResolver* resolver)
OffsetResolver* resolver,
JavaVM* hostVM)
: protector(t, this),
constants(constants),
calls(calls),
addresses(addresses),
addressSentinal(addresses),
zone(zone),
resolver(resolver)
resolver(resolver),
hostVM(hostVM)
{
}
@ -927,6 +929,7 @@ class BootContext {
avian::codegen::DelayedPromise* addressSentinal;
Zone* zone;
OffsetResolver* resolver;
JavaVM* hostVM;
};
class Context {
@ -3991,6 +3994,34 @@ void checkField(Thread* t, GcField* field, bool shouldBeStatic)
}
}
bool isLambda(Thread* t,
GcClassLoader* loader,
GcCharArray* bootstrapArray,
GcInvocation* invocation)
{
GcMethod* bootstrap = cast<GcMethod>(t,
resolve(t,
loader,
invocation->pool(),
bootstrapArray->body()[0],
findMethodInClass,
GcNoSuchMethodError::Type));
PROTECT(t, bootstrap);
return vm::strcmp(reinterpret_cast<const int8_t*>(
"java/lang/invoke/LambdaMetafactory"),
bootstrap->class_()->name()->body().begin()) == 0
and vm::strcmp(reinterpret_cast<const int8_t*>("metafactory"),
bootstrap->name()->body().begin()) == 0
and vm::strcmp(
reinterpret_cast<const int8_t*>(
"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/"
"String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/"
"MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/"
"invoke/MethodType;)Ljava/lang/invoke/CallSite;"),
bootstrap->spec()->body().begin()) == 0;
}
void compile(MyThread* t,
Frame* initialFrame,
unsigned initialIp,
@ -5054,36 +5085,168 @@ loop:
invocation->setClass(t, context->method->class_());
unsigned index = addDynamic(t, invocation);
BootContext* bc = context->bootContext;
if (bc) {
// When we're AOT-compiling an application, we can't handle
// invokedynamic in general, since it usually implies runtime
// code generation. However, Java 8 lambda expressions are a
// special case for which we can generate code ahead of time.
//
// The only tricky part about it is that the class synthesis
// code resides in LambdaMetaFactory, which means we need to
// call out to a separate Java VM to execute it (the VM we're
// currently executing in won't work because it only knows how
// to compile code for the target machine, which might not be
// the same as the host; plus we don't want to pollute the
// runtime heap image with stuff that's only needed at compile
// time).
GcMethod* template_ = invocation->template_();
unsigned returnCode = template_->returnCode();
unsigned rSize = resultSize(t, returnCode);
unsigned parameterFootprint = template_->parameterFootprint();
GcClass* c = context->method->class_();
PROTECT(t, c);
// TODO: can we allow tailCalls in general?
// e.g. what happens if the call site is later bound to a method that can't be tail called?
// NOTE: calling isTailCall right now would cause an segfault, since
// invocation->template_()->class_() will be null.
// bool tailCall
// = isTailCall(t, code, ip, context->method, invocation->template_());
bool tailCall = false;
GcCharArray* bootstrapArray = cast<GcCharArray>(
t,
cast<GcArray>(t, c->addendum()->bootstrapMethodTable())
->body()[invocation->bootstrap()]);
PROTECT(t, bootstrapArray);
// todo: do we need to tell the compiler to add a load barrier
// here for VolatileCallSite instances?
if (isLambda(t, c->loader(), bootstrapArray, invocation)) {
JNIEnv* e;
if (bc->hostVM->vtable->AttachCurrentThread(bc->hostVM, &e, 0) == 0) {
e->vtable->PushLocalFrame(e, 256);
ir::Value* result = c->stackCall(
c->memory(c->memory(c->threadRegister(), ir::Type::object(),
TARGET_THREAD_DYNAMICTABLE),
ir::Type::object(), index * TargetBytesPerWord),
tailCall ? Compiler::TailJump : 0, frame->trace(0, 0),
operandTypeForFieldCode(t, returnCode),
frame->peekMethodArguments(parameterFootprint));
jclass lmfClass
= e->vtable->FindClass(e, "java/lang/invoke/LambdaMetafactory");
jmethodID makeLambda = e->vtable->GetStaticMethodID(
e,
lmfClass,
"makeLambda",
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/"
"lang/String;Ljava/lang/String;Ljava/lang/String;I)[B");
frame->popFootprint(parameterFootprint);
GcReference* reference = cast<GcReference>(
t,
singletonObject(
t, invocation->pool(), bootstrapArray->body()[2]));
int kind = reference->kind();
if (rSize) {
frame->pushReturnValue(returnCode, result);
GcMethod* method
= cast<GcMethod>(t,
resolve(t,
c->loader(),
invocation->pool(),
bootstrapArray->body()[2],
findMethodInClass,
GcNoSuchMethodError::Type));
jarray lambda = e->vtable->CallStaticObjectMethod(
e,
lmfClass,
makeLambda,
e->vtable->NewStringUTF(
e,
reinterpret_cast<const char*>(
invocation->template_()->name()->body().begin())),
e->vtable->NewStringUTF(
e,
reinterpret_cast<const char*>(
invocation->template_()->spec()->body().begin())),
e->vtable->NewStringUTF(
e,
reinterpret_cast<const char*>(
cast<GcByteArray>(
t,
singletonObject(t,
invocation->pool(),
bootstrapArray->body()[1]))
->body()
.begin())),
e->vtable->NewStringUTF(
e,
reinterpret_cast<const char*>(
method->class_()->name()->body().begin())),
e->vtable->NewStringUTF(e,
reinterpret_cast<const char*>(
method->name()->body().begin())),
e->vtable->NewStringUTF(e,
reinterpret_cast<const char*>(
method->spec()->body().begin())),
kind);
uint8_t* bytes = reinterpret_cast<uint8_t*>(
e->vtable->GetPrimitiveArrayCritical(e, lambda, 0));
GcClass* lambdaClass
= defineClass(t,
roots(t)->appLoader(),
bytes,
e->vtable->GetArrayLength(e, lambda));
bc->resolver->addClass(
t, lambdaClass, bytes, e->vtable->GetArrayLength(e, lambda));
e->vtable->ReleasePrimitiveArrayCritical(e, lambda, bytes, 0);
e->vtable->PopLocalFrame(e, 0);
THREAD_RUNTIME_ARRAY(
t, char, spec, invocation->template_()->spec()->length());
memcpy(RUNTIME_ARRAY_BODY(spec),
invocation->template_()->spec()->body().begin(),
invocation->template_()->spec()->length());
GcMethod* target = resolveMethod(
t, lambdaClass, "make", RUNTIME_ARRAY_BODY(spec));
bool tailCall = isTailCall(t, code, ip, context->method, target);
compileDirectInvoke(t, frame, target, tailCall);
} else {
throwNew(
t, GcVirtualMachineError::Type, "unable to attach to host VM");
}
} else {
throwNew(t,
GcVirtualMachineError::Type,
"invokedynamic not supported for AOT-compiled code except "
"in the case of lambda expressions");
}
} else {
unsigned index = addDynamic(t, invocation);
GcMethod* template_ = invocation->template_();
unsigned returnCode = template_->returnCode();
unsigned rSize = resultSize(t, returnCode);
unsigned parameterFootprint = template_->parameterFootprint();
// TODO: can we allow tailCalls in general?
// e.g. what happens if the call site is later bound to a method that
// can't be tail called?
// NOTE: calling isTailCall right now would cause an segfault, since
// invocation->template_()->class_() will be null.
// bool tailCall
// = isTailCall(t, code, ip, context->method,
// invocation->template_());
bool tailCall = false;
// todo: do we need to tell the compiler to add a load barrier
// here for VolatileCallSite instances?
ir::Value* result
= c->stackCall(c->memory(c->memory(c->threadRegister(),
ir::Type::object(),
TARGET_THREAD_DYNAMICTABLE),
ir::Type::object(),
index * TargetBytesPerWord),
tailCall ? Compiler::TailJump : 0,
frame->trace(0, 0),
operandTypeForFieldCode(t, returnCode),
frame->peekMethodArguments(parameterFootprint));
frame->popFootprint(parameterFootprint);
if (rSize) {
frame->pushReturnValue(returnCode, result);
}
}
} break;
@ -9134,10 +9297,12 @@ class MyProcessor : public Processor {
GcTriple** calls,
avian::codegen::DelayedPromise** addresses,
GcMethod* method,
OffsetResolver* resolver)
OffsetResolver* resolver,
JavaVM* hostVM)
{
MyThread* t = static_cast<MyThread*>(vmt);
BootContext bootContext(t, *constants, *calls, *addresses, zone, resolver);
BootContext bootContext(
t, *constants, *calls, *addresses, zone, resolver, hostVM);
compile(t, &codeAllocator, &bootContext, method);

View File

@ -3512,7 +3512,8 @@ class MyProcessor : public Processor {
GcTriple**,
avian::codegen::DelayedPromise**,
GcMethod*,
OffsetResolver*)
OffsetResolver*,
JavaVM*)
{
abort(s);
}

View File

@ -3617,6 +3617,7 @@ extern "C" AVIAN_EXPORT jint JNICALL
const char* bootLibraries = 0;
const char* classpath = 0;
const char* javaHome = AVIAN_JAVA_HOME;
bool reentrant = false;
const char* embedPrefix = AVIAN_EMBED_PREFIX;
const char* bootClasspathPrepend = "";
const char* bootClasspath = 0;
@ -3667,6 +3668,9 @@ extern "C" AVIAN_EXPORT jint JNICALL
} else if (strncmp(p, JAVA_HOME_PROPERTY "=", sizeof(JAVA_HOME_PROPERTY))
== 0) {
javaHome = p + sizeof(JAVA_HOME_PROPERTY);
} else if (strncmp(p, REENTRANT_PROPERTY "=", sizeof(REENTRANT_PROPERTY))
== 0) {
reentrant = strcmp(p + sizeof(REENTRANT_PROPERTY), "true") == 0;
} else if (strncmp(p,
EMBED_PREFIX_PROPERTY "=",
sizeof(EMBED_PREFIX_PROPERTY)) == 0) {
@ -3689,7 +3693,7 @@ extern "C" AVIAN_EXPORT jint JNICALL
++propertyCount;
}
System* s = makeSystem();
System* s = makeSystem(reentrant);
Heap* h = makeHeap(s, heapLimit);
Classpath* c = makeClasspath(s, h, javaHome, embedPrefix);

View File

@ -5889,14 +5889,14 @@ GcMethod* getCaller(Thread* t, unsigned target, bool skipMethodInvoke)
return v.method;
}
object defineClass(Thread* t,
GcClassLoader* loader,
const uint8_t* buffer,
unsigned length)
GcClass* defineClass(Thread* t,
GcClassLoader* loader,
const uint8_t* buffer,
unsigned length)
{
PROTECT(t, loader);
object c = parseClass(t, loader, buffer, length);
GcClass* c = parseClass(t, loader, buffer, length);
// char name[byteArrayLength(t, className(t, c))];
// memcpy(name, &byteArrayBody(t, className(t, c), 0),
@ -5915,7 +5915,7 @@ object defineClass(Thread* t,
PROTECT(t, c);
saveLoadedClass(t, loader, cast<GcClass>(t, c));
saveLoadedClass(t, loader, c);
return c;
}

View File

@ -92,7 +92,7 @@ const int signals[] = {VisitSignal, InterruptSignal, PipeSignal};
const unsigned SignalCount = 3;
class MySystem;
MySystem* system;
MySystem* globalSystem;
void handleSignal(int signal, siginfo_t* info, void* context);
@ -624,16 +624,18 @@ class MySystem : public System {
System::Library* next_;
};
MySystem() : threadVisitor(0), visitTarget(0)
MySystem(bool reentrant) : reentrant(reentrant), threadVisitor(0), visitTarget(0)
{
expect(this, system == 0);
system = this;
if (not reentrant) {
expect(this, globalSystem == 0);
globalSystem = this;
expect(this, registerHandler(InterruptSignalIndex));
expect(this, registerHandler(VisitSignalIndex));
expect(this, registerHandler(PipeSignalIndex));
expect(this, make(&visitLock) == 0);
expect(this, registerHandler(InterruptSignalIndex));
expect(this, registerHandler(VisitSignalIndex));
expect(this, registerHandler(PipeSignalIndex));
expect(this, make(&visitLock) == 0);
}
}
// Returns true on success, false on failure
@ -708,6 +710,8 @@ class MySystem : public System {
System::Thread* sTarget,
ThreadVisitor* visitor)
{
expect(this, not reentrant);
assertT(this, st != sTarget);
Thread* target = static_cast<Thread*>(sTarget);
@ -767,7 +771,7 @@ class MySystem : public System {
threadVisitor = 0;
system->visitLock->notifyAll(t);
globalSystem->visitLock->notifyAll(t);
return result;
#endif // not __APPLE__
@ -938,18 +942,21 @@ class MySystem : public System {
virtual void dispose()
{
visitLock->dispose();
if (not reentrant) {
visitLock->dispose();
expect(this, unregisterHandler(InterruptSignalIndex));
expect(this, unregisterHandler(VisitSignalIndex));
expect(this, unregisterHandler(PipeSignalIndex));
system = 0;
expect(this, unregisterHandler(InterruptSignalIndex));
expect(this, unregisterHandler(VisitSignalIndex));
expect(this, unregisterHandler(PipeSignalIndex));
globalSystem = 0;
}
::free(this);
}
struct sigaction oldHandlers[SignalCount];
bool reentrant;
ThreadVisitor* threadVisitor;
Thread* visitTarget;
System::Monitor* visitLock;
@ -965,13 +972,13 @@ void handleSignal(int signal, siginfo_t*, void* context)
switch (signal) {
case VisitSignal: {
system->threadVisitor->visit(ip, stack, link);
globalSystem->threadVisitor->visit(ip, stack, link);
System::Thread* t = system->visitTarget;
system->visitTarget = 0;
System::Thread* t = globalSystem->visitTarget;
globalSystem->visitTarget = 0;
ACQUIRE_MONITOR(t, system->visitLock);
system->visitLock->notifyAll(t);
ACQUIRE_MONITOR(t, globalSystem->visitLock);
globalSystem->visitLock->notifyAll(t);
} break;
case InterruptSignal:
@ -987,9 +994,9 @@ void handleSignal(int signal, siginfo_t*, void* context)
namespace vm {
AVIAN_EXPORT System* makeSystem()
AVIAN_EXPORT System* makeSystem(bool reentrant)
{
return new (malloc(sizeof(MySystem))) MySystem();
return new (malloc(sizeof(MySystem))) MySystem(reentrant);
}
} // namespace vm

View File

@ -115,7 +115,7 @@ class MutexResource {
};
class MySystem;
MySystem* system;
MySystem* globalSystem;
DWORD WINAPI run(void* r)
{
@ -655,10 +655,12 @@ class MySystem : public System {
System::Library* next_;
};
MySystem()
MySystem(bool reentrant): reentrant(reentrant)
{
expect(this, system == 0);
system = this;
if (not reentrant) {
expect(this, globalSystem == 0);
globalSystem = this;
}
mutex = CreateMutex(0, false, 0);
assertT(this, mutex);
@ -1007,21 +1009,25 @@ class MySystem : public System {
virtual void dispose()
{
system = 0;
if (not reentrant) {
globalSystem = 0;
}
CloseHandle(mutex);
::free(this);
}
HANDLE mutex;
bool reentrant;
};
} // namespace
namespace vm {
AVIAN_EXPORT System* makeSystem()
AVIAN_EXPORT System* makeSystem(bool reentrant)
{
return new (malloc(sizeof(MySystem))) MySystem();
return new (malloc(sizeof(MySystem))) MySystem(reentrant);
}
} // namespace vm

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,80 @@
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.BufferedInputStream;
/**
* Checks that BufferedInputStream does not block if data is available in it's internal buffer.
*/
public class BufferedInputStreamTest
{
public static void main(String[] args) throws IOException
{
MyByteArrayStream in = new MyByteArrayStream(new byte[100]);
BufferedInputStream bin = new BufferedInputStream(in);
//read a single byte to fill the buffer
int b = bin.read();
byte[] buf = new byte[10];
//now try to read 10 bytes. this should a least return the content of the buffer. On OpenJDK this are
//4 bytes (the rest of the buffer returned by MyByteArrayStream in the first call).
//It should definately NOT block.
int count = bin.read(buf);
System.out.println("Read bytes: " + count);
}
/**
* Internal Stream used to show the BufferedInputStream behaviour.
*/
static class MyByteArrayStream extends ByteArrayInputStream
{
boolean stopReading = false;
/**
* @param buf
*/
public MyByteArrayStream(byte[] buf)
{
super(buf);
}
/* (non-Javadoc)
* @see java.io.ByteArrayInputStream#read(byte[], int, int)
*/
@Override
public synchronized int read(byte[] b, int off, int len)
{
if(stopReading == false)
{ //On the first call 5 bytes are returned.
stopReading = true;
return super.read(b, off, 5);
}
//on all following calls block. The spec says, that a least one byte is returned, if the
//stream is not at EOF.
while(available() == 0)
{
try
{
Thread.sleep(100);
}
catch (InterruptedException e)
{
}
}
return 0;
}
/* (non-Javadoc)
* @see java.io.ByteArrayInputStream#available()
*/
@Override
public synchronized int available()
{
if(stopReading)
{
return 0;
}
return super.available();
}
}
}

View File

@ -291,9 +291,18 @@ public class Misc {
test = true;
}
}
expect(count == 2);
expect(test);
expect(extraDir);
// This test is only relevant if multi-classpath-test.txt
// actually exists in somewhere under the classpath from which
// Misc.class was loaded. Since we run this test from an
// AOT-compiled boot image as well as straight from the
// filesystem, and the boot image does not contain
// multi-classpath-test.txt, we'll skip the test if it's not
// present.
if (count != 0) {
expect(count == 2);
expect(test);
expect(extraDir);
}
} catch (IOException e) {
throw new RuntimeException(e);
}

View File

@ -97,6 +97,7 @@ else
if has_flag openjdk-src || ! has_flag openjdk; then
run make ${flags} mode=debug bootimage=true ${make_target}
run make ${flags} bootimage=true ${make_target}
run make ${flags} bootimage=true bootimage-test=true ${make_target}
fi
if ! has_flag openjdk && ! has_flag android && ! has_flag arch; then