From 678d7debda8aca1c73c2c8f37b85d2b3189ecfe5 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 5 Dec 2016 17:41:02 -0700 Subject: [PATCH] fix bootimage build We now detect both metafactory and altMetafactory lambdas when bootimage-compiling invokedynamic instructions, as well as make allowance for the same lambda being invoked by multiple invokedynamic instructions (as is the case for Serializable lambdas). --- classpath/avian/ClassAddendum.java | 2 + src/compile.cpp | 274 ++++++++++++++++------------- src/machine.cpp | 2 +- 3 files changed, 159 insertions(+), 119 deletions(-) diff --git a/classpath/avian/ClassAddendum.java b/classpath/avian/ClassAddendum.java index 156c4df4a1..ef558b59c4 100644 --- a/classpath/avian/ClassAddendum.java +++ b/classpath/avian/ClassAddendum.java @@ -27,4 +27,6 @@ public class ClassAddendum extends Addendum { public Pair enclosingMethod; public VMMethod[] bootstrapMethodTable; + + public VMMethod[] bootstrapLambdaTable; } diff --git a/src/compile.cpp b/src/compile.cpp index 97240fbb89..6a36649181 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -4040,15 +4040,26 @@ bool isLambda(Thread* t, return vm::strcmp(reinterpret_cast( "java/lang/invoke/LambdaMetafactory"), bootstrap->class_()->name()->body().begin()) == 0 - and vm::strcmp(reinterpret_cast("metafactory"), - bootstrap->name()->body().begin()) == 0 - and vm::strcmp( - reinterpret_cast( - "(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; + and ((vm::strcmp(reinterpret_cast("metafactory"), + bootstrap->name()->body().begin()) == 0 + and vm::strcmp( + reinterpret_cast( + "(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) + or (vm::strcmp(reinterpret_cast("altMetafactory"), + bootstrap->name()->body().begin()) == 0 + and vm::strcmp( + reinterpret_cast( + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/" + "lang/" + "String;Ljava/lang/invoke/MethodType;[Ljava/lang/" + "Object;)Ljava/lang/invoke/CallSite;"), + bootstrap->spec()->body().begin()) == 0)); } void compile(MyThread* t, @@ -5133,120 +5144,147 @@ loop: GcClass* c = context->method->class_(); PROTECT(t, c); - GcCharArray* bootstrapArray = cast( - t, - cast(t, c->addendum()->bootstrapMethodTable()) - ->body()[invocation->bootstrap()]); - PROTECT(t, bootstrapArray); + GcMethod* target + = c->addendum()->bootstrapLambdaTable() + ? cast( + t, + cast(t, c->addendum()->bootstrapLambdaTable()) + ->body()[invocation->bootstrap()]) + : nullptr; + PROTECT(t, target); - if (isLambda(t, c->loader(), bootstrapArray, invocation)) { - if (bc->hostVM == 0) { + if (target == nullptr) { + GcCharArray* bootstrapArray = cast( + t, + cast(t, c->addendum()->bootstrapMethodTable()) + ->body()[invocation->bootstrap()]); + PROTECT(t, bootstrapArray); + + if (isLambda(t, c->loader(), bootstrapArray, invocation)) { + if (bc->hostVM == 0) { + throwNew( + t, + GcVirtualMachineError::Type, + "lambda expression encountered, but host VM is not " + "available; use -hostvm option to bootimage-generator to " + "fix this"); + } + + JNIEnv* e; + if (bc->hostVM->vtable->AttachCurrentThread(bc->hostVM, &e, 0) + == 0) { + e->vtable->PushLocalFrame(e, 256); + + 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"); + + GcReference* reference = cast( + t, + singletonObject( + t, invocation->pool(), bootstrapArray->body()[2])); + int kind = reference->kind(); + + GcMethod* method + = cast(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( + invocation->template_()->name()->body().begin())), + e->vtable->NewStringUTF( + e, + reinterpret_cast( + invocation->template_()->spec()->body().begin())), + e->vtable->NewStringUTF( + e, + reinterpret_cast( + cast( + t, + singletonObject(t, + invocation->pool(), + bootstrapArray->body()[1])) + ->body() + .begin())), + e->vtable->NewStringUTF( + e, + reinterpret_cast( + method->class_()->name()->body().begin())), + e->vtable->NewStringUTF(e, + reinterpret_cast( + method->name()->body().begin())), + e->vtable->NewStringUTF(e, + reinterpret_cast( + method->spec()->body().begin())), + kind); + + uint8_t* bytes = reinterpret_cast( + 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()); + + target = resolveMethod( + t, lambdaClass, "make", RUNTIME_ARRAY_BODY(spec)); + + GcArray* table + = cast(t, c->addendum()->bootstrapLambdaTable()); + if (table == nullptr) { + table = makeArray( + t, + cast(t, c->addendum()->bootstrapMethodTable()) + ->length()); + c->addendum()->setBootstrapLambdaTable(t, table); + } + + table->setBodyElement(t, invocation->bootstrap(), target); + } else { + throwNew(t, + GcVirtualMachineError::Type, + "unable to attach to host VM"); + } + } else { throwNew(t, GcVirtualMachineError::Type, - "lambda expression encountered, but host VM is not " - "available; use -hostvm option to bootimage-generator to " - "fix this"); + "invokedynamic not supported for AOT-compiled code except " + "in the case of lambda expressions"); } - - JNIEnv* e; - if (bc->hostVM->vtable->AttachCurrentThread(bc->hostVM, &e, 0) == 0) { - e->vtable->PushLocalFrame(e, 256); - - 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"); - - GcReference* reference = cast( - t, - singletonObject( - t, invocation->pool(), bootstrapArray->body()[2])); - int kind = reference->kind(); - - GcMethod* method - = cast(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( - invocation->template_()->name()->body().begin())), - e->vtable->NewStringUTF( - e, - reinterpret_cast( - invocation->template_()->spec()->body().begin())), - e->vtable->NewStringUTF( - e, - reinterpret_cast( - cast( - t, - singletonObject(t, - invocation->pool(), - bootstrapArray->body()[1])) - ->body() - .begin())), - e->vtable->NewStringUTF( - e, - reinterpret_cast( - method->class_()->name()->body().begin())), - e->vtable->NewStringUTF(e, - reinterpret_cast( - method->name()->body().begin())), - e->vtable->NewStringUTF(e, - reinterpret_cast( - method->spec()->body().begin())), - kind); - - uint8_t* bytes = reinterpret_cast( - 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"); } + + bool tailCall = isTailCall(t, code, ip, context->method, target); + compileDirectInvoke(t, frame, target, tailCall); } else { unsigned index = addDynamic(t, invocation); diff --git a/src/machine.cpp b/src/machine.cpp index 5fe8f2136d..3bf4aa9dfb 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1220,7 +1220,7 @@ GcClassAddendum* getClassAddendum(Thread* t, GcClass* class_, GcSingleton* pool) if (addendum == 0) { PROTECT(t, class_); - addendum = makeClassAddendum(t, pool, 0, 0, 0, 0, -1, 0, 0, 0); + addendum = makeClassAddendum(t, pool, 0, 0, 0, 0, -1, 0, 0, 0, 0); setField(t, class_, ClassAddendum, addendum); } return addendum;