Merge pull request #511 from dicej/lambda-fixes

Lambda fixes
This commit is contained in:
Joel Dice 2016-12-06 09:50:16 -07:00 committed by GitHub
commit c5d7e5b8c5
13 changed files with 410 additions and 170 deletions

View File

@ -27,4 +27,6 @@ public class ClassAddendum extends Addendum {
public Pair enclosingMethod;
public VMMethod[] bootstrapMethodTable;
public VMMethod[] bootstrapLambdaTable;
}

View File

@ -1,3 +1,13 @@
/* Copyright (c) 2008-2016, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.lang.invoke;
public class CallSite {

View File

@ -1,3 +1,13 @@
/* Copyright (c) 2008-2016, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.lang.invoke;
public class LambdaConversionException extends java.lang.Exception {

View File

@ -1,3 +1,13 @@
/* Copyright (c) 2008-2016, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.lang.invoke;
import static avian.Stream.write1;
@ -25,17 +35,17 @@ import avian.SystemClassLoader;
public class LambdaMetafactory {
private static int nextNumber = 0;
private static Class resolveReturnInterface(MethodType type) {
int index = 1;
byte[] s = type.spec;
while (s[index] != ')') ++ index;
if (s[++ index] != 'L') throw new AssertionError();
++ index;
int end = index + 1;
while (s[end] != ';') ++ end;
@ -52,11 +62,11 @@ public class LambdaMetafactory {
while (array[i] != c) ++i;
return i;
}
private static String constructorSpec(MethodType type) {
return Classes.makeString(type.spec, 0, indexOf(')', type.spec) + 1) + "V";
}
private static byte[] makeFactoryCode(List<PoolEntry> pool,
String className,
String constructorSpec,
@ -89,7 +99,7 @@ public class LambdaMetafactory {
byte[] result = out.toByteArray();
set4(result, 4, result.length - 12);
return result;
return result;
}
private static byte[] makeConstructorCode(List<PoolEntry> pool,
@ -124,7 +134,7 @@ public class LambdaMetafactory {
byte[] result = out.toByteArray();
set4(result, 4, result.length - 12);
return result;
return result;
}
private static byte[] makeInvocationCode(List<PoolEntry> pool,
@ -167,7 +177,7 @@ public class LambdaMetafactory {
default: throw new AssertionError
("todo: implement per http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.4.3.5");
}
write2(out, ConstantPool.addMethodRef
(pool,
Classes.makeString(implementation.method.class_.name, 0,
@ -233,7 +243,7 @@ public class LambdaMetafactory {
}
String constructorSpec = constructorSpec(invokedType);
List<MethodData> methodTable = new ArrayList();
try {
@ -261,9 +271,9 @@ public class LambdaMetafactory {
} catch (IOException e) {
AssertionError error = new AssertionError();
error.initCause(e);
throw error;
throw error;
}
int nameIndex = ConstantPool.addClass(pool, className);
int superIndex = ConstantPool.addClass(pool, "java/lang/Object");
@ -276,12 +286,12 @@ public class LambdaMetafactory {
} catch (IOException e) {
AssertionError error = new AssertionError();
error.initCause(e);
throw error;
throw error;
}
return out.toByteArray();
}
public static CallSite metafactory(MethodHandles.Lookup caller,
String invokedName,
MethodType invokedType,
@ -291,7 +301,7 @@ public class LambdaMetafactory {
throws LambdaConversionException
{
byte[] classData = makeLambda(invokedName, invokedType, methodType, methodImplementation);
try {
return new CallSite
(new MethodHandle
@ -306,4 +316,14 @@ public class LambdaMetafactory {
throw error;
}
}
public static CallSite altMetafactory(MethodHandles.Lookup caller,
String invokedName,
MethodType invokedType,
Object... args)
throws LambdaConversionException
{
// todo: handle flags
return metafactory(caller, invokedName, invokedType, (MethodType) args[0], (MethodHandle) args[1], (MethodType) args[2]);
}
}

View File

@ -1,3 +1,13 @@
/* Copyright (c) 2008-2016, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.lang.invoke;
import avian.Classes;
@ -6,12 +16,12 @@ import avian.SystemClassLoader;
public class MethodHandle {
static final int REF_invokeStatic = 6;
static final int REF_invokeSpecial = 7;
final int kind;
private final ClassLoader loader;
final avian.VMMethod method;
private volatile MethodType type;
MethodHandle(int kind, ClassLoader loader, avian.VMMethod method) {
this.kind = kind;
this.loader = loader;
@ -44,7 +54,7 @@ public class MethodHandle {
sb.append(Classes.makeString(method.spec, 0,
method.spec.length - 1));
return sb.toString();
}
}
public MethodType type() {
if (type == null) {

View File

@ -1,3 +1,13 @@
/* Copyright (c) 2008-2016, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.lang.invoke;
public class MethodHandles {

View File

@ -1,3 +1,13 @@
/* Copyright (c) 2008-2016, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.lang.invoke;
import static avian.Assembler.*;
@ -14,7 +24,7 @@ public final class MethodType implements java.io.Serializable {
private static final char[] Primitives = new char[] {
'V', 'Z', 'B', 'C', 'S', 'I', 'F', 'J', 'D'
};
final ClassLoader loader;
final byte[] spec;
private volatile List<Parameter> parameters;
@ -31,11 +41,11 @@ public final class MethodType implements java.io.Serializable {
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);
}
private static String spec(Class c) {
if (c.isPrimitive()) {
VMClass vmc = Classes.toVMClass(c);
@ -56,7 +66,7 @@ public final class MethodType implements java.io.Serializable {
Class ... ptypes)
{
loader = rtype.getClassLoader();
StringBuilder sb = new StringBuilder();
sb.append('(');
parameters = new ArrayList(ptypes.length);
@ -66,7 +76,7 @@ public final class MethodType implements java.io.Serializable {
sb.append(spec);
Type type = type(spec);
parameters.add(new Parameter(i,
position,
spec,
@ -86,7 +96,7 @@ public final class MethodType implements java.io.Serializable {
this.spec = sb.toString().getBytes();
}
public static MethodType methodType(Class rtype,
Class ptype0,
Class ... ptypes)
@ -129,7 +139,7 @@ public final class MethodType implements java.io.Serializable {
return array;
}
public Iterable<Parameter> parameters() {
if (parameters == null) {
List<Parameter> list = new ArrayList();
@ -147,7 +157,7 @@ public final class MethodType implements java.io.Serializable {
case '[': {
++ i;
while (spec[i] == '[') ++ i;
switch (spec[i]) {
case 'L':
++ i;
@ -174,7 +184,7 @@ public final class MethodType implements java.io.Serializable {
String paramSpec = Classes.makeString(spec, start, (i - start) + 1);
Type type = type(paramSpec);
list.add(new Parameter
(index,
position,
@ -192,14 +202,14 @@ public final class MethodType implements java.io.Serializable {
String paramSpec = Classes.makeString(spec, i, spec.length - i - 1);
Type type = type(paramSpec);
result = new Result(paramSpec,
Classes.forCanonicalName(loader, paramSpec),
type.return_);
parameters = list;
}
return parameters;
}
@ -234,18 +244,18 @@ public final class MethodType implements java.io.Serializable {
case 'V':
return Type.VoidType;
default: throw new AssertionError();
}
default: throw new AssertionError();
}
}
private static enum Type {
ObjectType(aload, areturn, 1),
IntegerType(iload, ireturn, 1),
FloatType(fload, freturn, 1),
LongType(lload, lreturn, 1),
DoubleType(dload, dreturn, 1),
LongType(lload, lreturn, 2),
DoubleType(dload, dreturn, 2),
VoidType(-1, Assembler.return_, -1);
public final int load;
public final int return_;
public final int size;
@ -256,7 +266,7 @@ public final class MethodType implements java.io.Serializable {
this.size = size;
}
}
public static class Parameter {
private final int index;
private final int position;

View File

@ -0,0 +1,48 @@
/* Copyright (c) 2008-2016, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.lang.invoke;
public class SerializedLambda implements java.io.Serializable {
public int getImplMethodKind() {
// todo
return 0;
}
public String getImplClass() {
// todo
return null;
}
public String getImplMethodName() {
// todo
return null;
}
public String getImplMethodSignature() {
// todo
return null;
}
public String getFunctionalInterfaceClass() {
// todo
return null;
}
public String getFunctionalInterfaceMethodName() {
// todo
return null;
}
public String getFunctionalInterfaceMethodSignature() {
// todo
return null;
}
}

View File

@ -523,6 +523,9 @@ class MyClasspath : public Classpath {
GcJobject* blockerLock = makeJobject(t);
thread->setBlockerLock(t, blockerLock);
#if HAVE_ThreadName_Ljava_lang_String_
GcString* name = vm::makeString(t, "Thread-%p", thread);
#else
const unsigned BufferSize = 256;
char buffer[BufferSize];
unsigned length = vm::snprintf(buffer, BufferSize, "Thread-%p", thread);
@ -530,6 +533,7 @@ class MyClasspath : public Classpath {
for (unsigned i = 0; i < length; ++i) {
name->body()[i] = buffer[i];
}
#endif
thread->setName(t, name);
return thread;

View File

@ -4040,15 +4040,26 @@ bool isLambda(Thread* t,
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;
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)
or (vm::strcmp(reinterpret_cast<const int8_t*>("altMetafactory"),
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/"
"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<GcCharArray>(
t,
cast<GcArray>(t, c->addendum()->bootstrapMethodTable())
->body()[invocation->bootstrap()]);
PROTECT(t, bootstrapArray);
GcMethod* target
= c->addendum()->bootstrapLambdaTable()
? cast<GcMethod>(
t,
cast<GcArray>(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<GcCharArray>(
t,
cast<GcArray>(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<GcReference>(
t,
singletonObject(
t, invocation->pool(), bootstrapArray->body()[2]));
int kind = reference->kind();
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());
target = resolveMethod(
t, lambdaClass, "make", RUNTIME_ARRAY_BODY(spec));
GcArray* table
= cast<GcArray>(t, c->addendum()->bootstrapLambdaTable());
if (table == nullptr) {
table = makeArray(
t,
cast<GcArray>(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<GcReference>(
t,
singletonObject(
t, invocation->pool(), bootstrapArray->body()[2]));
int kind = reference->kind();
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");
}
bool tailCall = isTailCall(t, code, ip, context->method, target);
compileDirectInvoke(t, frame, target, tailCall);
} else {
unsigned index = addDynamic(t, invocation);

View File

@ -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;
@ -6055,8 +6055,6 @@ GcCallSite* resolveDynamic(Thread* t, GcInvocation* invocation)
GcNoSuchMethodError::Type));
PROTECT(t, bootstrap);
assertT(t, bootstrap->parameterCount() == 2 + bootstrapArray->length());
GcLookup* lookup
= makeLookup(t, c, ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC);
PROTECT(t, lookup);
@ -6078,14 +6076,47 @@ GcCallSite* resolveDynamic(Thread* t, GcInvocation* invocation)
array->setBodyElement(t, argument++, name);
array->setBodyElement(t, argument++, type);
MethodSpecIterator it(
t, reinterpret_cast<const char*>(bootstrap->spec()->body().begin()));
const char* spec;
GcArray* argArray = array;
PROTECT(t, argArray);
if (::strcmp(reinterpret_cast<char*>(bootstrap->spec()->body().begin()),
"(Ljava/lang/invoke/MethodHandles$Lookup;"
"Ljava/lang/String;"
"Ljava/lang/invoke/MethodType;"
"[Ljava/lang/Object;)"
"Ljava/lang/invoke/CallSite;") == 0) {
// LambdaMetaFactory.altMetafactory
array = makeArray(t, bootstrapArray->length() - 1);
spec = "(Ljava/lang/invoke/MethodHandles$Lookup;"
"Ljava/lang/String;"
"Ljava/lang/invoke/MethodType;"
"Ljava/lang/invoke/MethodType;"
"Ljava/lang/invoke/MethodHandle;"
"Ljava/lang/invoke/MethodType;"
"I"
"I"
"[Ljava/lang/Class;"
"I"
"[Ljava/lang/invoke/MethodType;"
")Ljava/lang/invoke/CallSite;";
} else if (bootstrap->parameterCount() == 2 + bootstrapArray->length()) {
spec = reinterpret_cast<char*>(bootstrap->spec()->body().begin());
} else {
abort(t);
}
MethodSpecIterator it(t, spec);
for (unsigned i = 0; i < argument; ++i)
it.next();
if (argArray != array) {
argument = 0;
}
unsigned i = 0;
while (it.hasNext()) {
while (i + 1 < bootstrapArray->length() && it.hasNext()) {
const char* p = it.next();
switch (*p) {
case 'L': {
@ -6162,8 +6193,12 @@ GcCallSite* resolveDynamic(Thread* t, GcInvocation* invocation)
? 0
: makeMethodHandle(t, REF_invokeSpecial, c->loader(), bootstrap, 0);
if (argArray != array) {
argArray->setBodyElement(t, 3, array);
}
return cast<GcCallSite>(
t, t->m->processor->invokeArray(t, bootstrap, handle, array));
t, t->m->processor->invokeArray(t, bootstrap, handle, argArray));
}
void noop()

View File

@ -19,6 +19,7 @@
#include <vector>
#include <set>
#include <sstream>
#include <algorithm>
#include "avian/constants.h"
#include "avian/finder.h"
@ -908,8 +909,6 @@ std::string cppFieldType(Module& module, Field* f)
void writeAccessor(Output* out, Class* cl, Field* f)
{
std::string typeName = f->typeName;
out->write("const unsigned ");
out->write(capitalize(cl->name));
out->write(capitalize(f->name));
@ -920,7 +919,22 @@ void writeAccessor(Output* out, Class* cl, Field* f)
out->write("#define HAVE_");
out->write(capitalize(cl->name));
out->write(capitalize(f->name));
out->write(" 1\n\n");
out->write(" 1\n");
if (! f->javaSpec.empty()) {
std::string s = f->javaSpec;
std::replace(s.begin(), s.end(), '/', '_');
std::replace(s.begin(), s.end(), '$', '_');
std::replace(s.begin(), s.end(), ';', '_');
std::replace(s.begin(), s.end(), '[', '_');
out->write("#define HAVE_");
out->write(capitalize(cl->name));
out->write(capitalize(f->name));
out->write("_");
out->write(s);
out->write(" 1\n\n");
}
}
void writeAccessors(Output* out, Module& module)

View File

@ -4,15 +4,33 @@ public class InvokeDynamic {
private InvokeDynamic(int foo) {
this.foo = foo;
}
private interface Operation {
int operate(int a, int b);
}
private interface Operation2 {
long operate(long a, int b);
}
private static class Pair<A, B> {
public final A first;
public final B second;
public Pair(A first, B second) {
this.first = first;
this.second = second;
}
}
private interface Supplier<T> extends java.io.Serializable {
T get();
}
private static void expect(boolean v) {
if (! v) throw new RuntimeException();
}
public static void main(String[] args) {
int c = 4;
Operation op = (a, b) -> a + b - c;
@ -24,8 +42,19 @@ public class InvokeDynamic {
}
private void test() {
int c = 2;
Operation op = (a, b) -> ((a + b) * c) - foo;
expect(op.operate(2, 3) == ((2 + 3) * 2) - foo);
{ int c = 2;
Operation op = (a, b) -> ((a + b) * c) - foo;
expect(op.operate(2, 3) == ((2 + 3) * 2) - foo);
}
{ int c = 2;
Operation2 op = (a, b) -> ((a + b) * c) - foo;
expect(op.operate(2, 3) == ((2 + 3) * 2) - foo);
}
{ Supplier<Pair<Long, Double>> s = () -> new Pair<Long, Double>(42L, 77.1D);
expect(s.get().first == 42L);
expect(s.get().second == 77.1D);
}
}
}