Merge pull request #454 from dicej/aot-lambda

support AOT-compilation of Java 8 lambda expressions
This commit is contained in:
Joshua Warner 2015-09-28 07:44:51 -06:00
commit d906db633c
22 changed files with 944 additions and 513 deletions

View File

@ -168,8 +168,8 @@ Library" below for details.
These flags determine the name of the directory used for the build. These flags determine the name of the directory used for the build.
The name always starts with _${platform}-${arch}_, and each non-default The name always starts with _${platform}-${arch}_, and each non-default
build option is appended to the name. For example, a debug build with build option is appended to the name. For example, a debug build with
bootimage enabled on Linux/i386 would be built in bootimage enabled on Linux/x86_64 would be built in
_build/linux-i386-debug-bootimage_. This allows you to build with _build/linux-x86_64-debug-bootimage_. This allows you to build with
several different sets of options independently and even several different sets of options independently and even
simultaneously without doing a clean build each time. simultaneously without doing a clean build each time.
@ -575,7 +575,7 @@ For boot image builds:
Note you can use ProGuard without using a boot image and vice-versa, Note you can use ProGuard without using a boot image and vice-versa,
as desired. 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. Please refer to the previous example for guidance on other platforms.
__1.__ Build Avian, create a new directory, and populate it with the __1.__ Build Avian, create a new directory, and populate it with the
@ -584,13 +584,13 @@ VM object files.
$ make bootimage=true $ make bootimage=true
$ mkdir hello $ mkdir hello
$ cd 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 __2.__ Create a stage1 directory and extract the contents of the
class library jar into it. class library jar into it.
$ mkdir stage1 $ 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. __3.__ Build the Java code and add it to stage1.
@ -630,10 +630,11 @@ using the OpenJDK library.)
__6.__ Build the boot and code images. __6.__ Build the boot and code images.
$ ../build/linux-i386-bootimage/bootimage-generator \ $ ../build/linux-x86_64-bootimage/bootimage-generator \
-cp stage2 \ -cp stage2 \
-bootimage bootimage-bin.o \ -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 Note that you can override the default names for the start and end
symbols in the boot/code image by also passing: 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, public static int findMethod(VMClass vmClass, String name,
Class[] parameterTypes) Class[] parameterTypes)
{ {

View File

@ -20,6 +20,8 @@ import java.util.Enumeration;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
public class SystemClassLoader extends ClassLoader { public class SystemClassLoader extends ClassLoader {
public static native ClassLoader appLoader();
private native VMClass findVMClass(String name) private native VMClass findVMClass(String name)
throws ClassNotFoundException; throws ClassNotFoundException;

View File

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

View File

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

View File

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

View File

@ -1,6 +1,7 @@
package java.lang.invoke; package java.lang.invoke;
import avian.Classes; import avian.Classes;
import avian.SystemClassLoader;
public class MethodHandle { public class MethodHandle {
static final int REF_invokeStatic = 6; static final int REF_invokeStatic = 6;
@ -17,6 +18,20 @@ public class MethodHandle {
this.method = method; 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() { public String toString() {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
if (method.class_ != null) { if (method.class_ != null) {

View File

@ -4,6 +4,7 @@ import static avian.Assembler.*;
import avian.Assembler; import avian.Assembler;
import avian.Classes; import avian.Classes;
import avian.SystemClassLoader;
import avian.VMClass; import avian.VMClass;
import java.util.List; import java.util.List;
@ -25,6 +26,12 @@ public final class MethodType implements java.io.Serializable {
this.spec = spec; 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() { public String toMethodDescriptorString() {
return Classes.makeString(spec, 0, spec.length - 1); return Classes.makeString(spec, 0, spec.length - 1);
} }

View File

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

View File

@ -1333,6 +1333,12 @@ bootimage-generator-objects = \
$(call cpp-objects,$(bootimage-generator-sources),$(src),$(build)) $(call cpp-objects,$(bootimage-generator-sources),$(src),$(build))
bootimage-generator = $(build)/bootimage-generator 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 bootimage-object = $(build)/bootimage-bin.o
codeimage-object = $(build)/codeimage-bin.o codeimage-object = $(build)/codeimage-bin.o
@ -2064,7 +2070,8 @@ $(bootimage-object) $(codeimage-object): $(bootimage-generator) \
@echo "generating bootimage and codeimage binaries from $(classpath-build) using $(<)" @echo "generating bootimage and codeimage binaries from $(classpath-build) using $(<)"
$(<) -cp $(classpath-build) -bootimage $(bootimage-object) -codeimage $(codeimage-object) \ $(<) -cp $(classpath-build) -bootimage $(bootimage-object) -codeimage $(codeimage-object) \
-bootimage-symbols $(bootimage-symbols) \ -bootimage-symbols $(bootimage-symbols) \
-codeimage-symbols $(codeimage-symbols) -codeimage-symbols $(codeimage-symbols) \
-hostvm $(host-vm)
executable-objects = $(vm-objects) $(classpath-objects) $(driver-object) \ executable-objects = $(vm-objects) $(classpath-objects) $(driver-object) \
$(vm-heapwalk-objects) $(boot-object) $(vm-classpath-objects) \ $(vm-heapwalk-objects) $(boot-object) $(vm-classpath-objects) \
@ -2119,6 +2126,7 @@ $(unittest-executable): $(unittest-executable-objects)
$(bootimage-generator): $(bootimage-generator-objects) $(vm-objects) $(bootimage-generator): $(bootimage-generator-objects) $(vm-objects)
echo building $(bootimage-generator) arch=$(build-arch) platform=$(bootimage-platform) echo building $(bootimage-generator) arch=$(build-arch) platform=$(bootimage-platform)
$(MAKE) process=interpret bootimage= mode=$(mode)
$(MAKE) mode=$(mode) \ $(MAKE) mode=$(mode) \
build=$(host-build-root) \ build=$(host-build-root) \
arch=$(build-arch) \ arch=$(build-arch) \

View File

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

View File

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

View File

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

View File

@ -170,7 +170,8 @@ class Processor {
GcTriple** calls, GcTriple** calls,
avian::codegen::DelayedPromise** addresses, avian::codegen::DelayedPromise** addresses,
GcMethod* method, GcMethod* method,
OffsetResolver* resolver) = 0; OffsetResolver* resolver,
Machine* hostVM) = 0;
virtual void visitRoots(Thread* t, HeapWalker* w) = 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)); 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 extern "C" AVIAN_EXPORT int64_t JNICALL
Avian_avian_SystemClassLoader_findLoadedVMClass(Thread* t, Avian_avian_SystemClassLoader_findLoadedVMClass(Thread* t,
object, object,

View File

@ -909,14 +909,16 @@ class BootContext {
GcTriple* calls, GcTriple* calls,
avian::codegen::DelayedPromise* addresses, avian::codegen::DelayedPromise* addresses,
Zone* zone, Zone* zone,
OffsetResolver* resolver) OffsetResolver* resolver,
JavaVM* hostVM)
: protector(t, this), : protector(t, this),
constants(constants), constants(constants),
calls(calls), calls(calls),
addresses(addresses), addresses(addresses),
addressSentinal(addresses), addressSentinal(addresses),
zone(zone), zone(zone),
resolver(resolver) resolver(resolver),
hostVM(hostVM)
{ {
} }
@ -927,6 +929,7 @@ class BootContext {
avian::codegen::DelayedPromise* addressSentinal; avian::codegen::DelayedPromise* addressSentinal;
Zone* zone; Zone* zone;
OffsetResolver* resolver; OffsetResolver* resolver;
JavaVM* hostVM;
}; };
class Context { 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, void compile(MyThread* t,
Frame* initialFrame, Frame* initialFrame,
unsigned initialIp, unsigned initialIp,
@ -5054,36 +5085,168 @@ loop:
invocation->setClass(t, context->method->class_()); 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_(); GcClass* c = context->method->class_();
unsigned returnCode = template_->returnCode(); PROTECT(t, c);
unsigned rSize = resultSize(t, returnCode);
unsigned parameterFootprint = template_->parameterFootprint();
// TODO: can we allow tailCalls in general? GcCharArray* bootstrapArray = cast<GcCharArray>(
// e.g. what happens if the call site is later bound to a method that can't be tail called? t,
// NOTE: calling isTailCall right now would cause an segfault, since cast<GcArray>(t, c->addendum()->bootstrapMethodTable())
// invocation->template_()->class_() will be null. ->body()[invocation->bootstrap()]);
// bool tailCall PROTECT(t, bootstrapArray);
// = isTailCall(t, code, ip, context->method, invocation->template_());
bool tailCall = false;
// todo: do we need to tell the compiler to add a load barrier if (isLambda(t, c->loader(), bootstrapArray, invocation)) {
// here for VolatileCallSite instances? JNIEnv* e;
if (bc->hostVM->vtable->AttachCurrentThread(bc->hostVM, &e, 0) == 0) {
e->vtable->PushLocalFrame(e, 256);
ir::Value* result = c->stackCall( jclass lmfClass
c->memory(c->memory(c->threadRegister(), ir::Type::object(), = e->vtable->FindClass(e, "java/lang/invoke/LambdaMetafactory");
TARGET_THREAD_DYNAMICTABLE), jmethodID makeLambda = e->vtable->GetStaticMethodID(
ir::Type::object(), index * TargetBytesPerWord), e,
tailCall ? Compiler::TailJump : 0, frame->trace(0, 0), lmfClass,
operandTypeForFieldCode(t, returnCode), "makeLambda",
frame->peekMethodArguments(parameterFootprint)); "(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) { GcMethod* method
frame->pushReturnValue(returnCode, result); = 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; } break;
@ -9134,10 +9297,12 @@ class MyProcessor : public Processor {
GcTriple** calls, GcTriple** calls,
avian::codegen::DelayedPromise** addresses, avian::codegen::DelayedPromise** addresses,
GcMethod* method, GcMethod* method,
OffsetResolver* resolver) OffsetResolver* resolver,
JavaVM* hostVM)
{ {
MyThread* t = static_cast<MyThread*>(vmt); 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); compile(t, &codeAllocator, &bootContext, method);

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff