mirror of
https://github.com/corda/corda.git
synced 2025-01-04 04:04:27 +00:00
Merge pull request #454 from dicej/aot-lambda
support AOT-compilation of Java 8 lambda expressions
This commit is contained in:
commit
d906db633c
15
README.md
15
README.md
@ -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.
|
||||
|
||||
@ -575,7 +575,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 +584,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 +630,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:
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
10
makefile
10
makefile
@ -1333,6 +1333,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
|
||||
|
||||
@ -2064,7 +2070,8 @@ $(bootimage-object) $(codeimage-object): $(bootimage-generator) \
|
||||
@echo "generating bootimage and codeimage binaries from $(classpath-build) using $(<)"
|
||||
$(<) -cp $(classpath-build) -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 +2126,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= mode=$(mode)
|
||||
$(MAKE) mode=$(mode) \
|
||||
build=$(host-build-root) \
|
||||
arch=$(build-arch) \
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
|
221
src/compile.cpp
221
src/compile.cpp
@ -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);
|
||||
|
||||
|
@ -3512,7 +3512,8 @@ class MyProcessor : public Processor {
|
||||
GcTriple**,
|
||||
avian::codegen::DelayedPromise**,
|
||||
GcMethod*,
|
||||
OffsetResolver*)
|
||||
OffsetResolver*,
|
||||
JavaVM*)
|
||||
{
|
||||
abort(s);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user