Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace opField with opMethod for lambdas. #301

Open
wants to merge 1 commit into
base: code-reflection
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,9 @@
final boolean isSerializable; // Should the returned instance be serializable
final Class<?>[] altInterfaces; // Additional interfaces to be implemented
final MethodType[] altMethods; // Signatures of additional methods to bridge
final MethodHandle quotableOpField; // A getter method handle that is used to retrieve the
// string representation of the quotable lambda's associated
// intermediate representation (can be null).
final MethodHandleInfo quotableOpFieldInfo; // Info about the quotable getter method handle (can be null).
final MethodHandle quotableOpGetter; // A getter method handle that is used to retrieve the
// the quotable lambda's associated intermediate representation (can be null).
final MethodHandleInfo quotableOpGetterInfo; // Info about the quotable getter method handle (can be null).

/**
* Meta-factory constructor.
Expand Down Expand Up @@ -187,7 +186,7 @@
this.isSerializable = isSerializable;
this.altInterfaces = altInterfaces;
this.altMethods = altMethods;
this.quotableOpField = reflectiveField;
this.quotableOpGetter = reflectiveField;

if (interfaceMethodName.isEmpty() ||
interfaceMethodName.indexOf('.') >= 0 ||
Expand Down Expand Up @@ -217,16 +216,15 @@

if (reflectiveField != null) {
try {
quotableOpFieldInfo = caller.revealDirect(reflectiveField); // may throw SecurityException
quotableOpGetterInfo = caller.revealDirect(reflectiveField); // may throw SecurityException
} catch (IllegalArgumentException e) {
throw new LambdaConversionException(implementation + " is not direct or cannot be cracked");
}
if (quotableOpFieldInfo.getReferenceKind() != REF_getField &&
quotableOpFieldInfo.getReferenceKind() != REF_getStatic) {
throw new LambdaConversionException(String.format("Unsupported MethodHandle kind: %s", quotableOpFieldInfo));
if (quotableOpGetterInfo.getReferenceKind() != REF_invokeStatic) {
throw new LambdaConversionException(String.format("Unsupported MethodHandle kind: %s", quotableOpGetterInfo));
}
} else {
quotableOpFieldInfo = null;
quotableOpGetterInfo = null;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ public void accept(ClassBuilder clb) {
}

// if quotable, generate the field that will hold the value of quoted
if (quotableOpField != null) {
if (quotableOpGetter != null) {
clb.withField(quotedInstanceFieldName, CodeReflectionSupport.CD_Quoted, ACC_PRIVATE + ACC_FINAL);
}

Expand Down Expand Up @@ -367,7 +367,7 @@ public void accept(ClassBuilder clb) {
else if (finalAccidentallySerializable)
generateSerializationHostileMethods(clb);

if (quotableOpField != null) {
if (quotableOpGetter != null) {
generateQuotableMethod(clb);
}
}
Expand All @@ -378,10 +378,10 @@ else if (finalAccidentallySerializable)
try {
// this class is linked at the indy callsite; so define a hidden nestmate
List<?> classdata;
if (useImplMethodHandle || quotableOpField != null) {
classdata = quotableOpField == null ?
if (useImplMethodHandle || quotableOpGetter != null) {
classdata = quotableOpGetter == null ?
List.of(implementation) :
List.of(implementation, quotableOpField, CodeReflectionSupport.HANDLE_MAKE_QUOTED);
List.of(implementation, quotableOpGetter, CodeReflectionSupport.HANDLE_MAKE_QUOTED);
} else {
classdata = null;
}
Expand Down Expand Up @@ -434,7 +434,7 @@ public void accept(CodeBuilder cob) {
cob.loadLocal(TypeKind.from(argType), cob.parameterSlot(i));
cob.putfield(pool.fieldRefEntry(lambdaClassEntry, pool.nameAndTypeEntry(argNames[i], argDescs[i])));
}
if (quotableOpField != null) {
if (quotableOpGetter != null) {
generateQuotedFieldInitializer(cob);
}
cob.return_();
Expand All @@ -451,8 +451,8 @@ private void generateQuotedFieldInitializer(CodeBuilder cob) {
.ldc(cp.constantDynamicEntry(cp.bsmEntry(bsmDataAt, List.of(cp.intEntry(2))), natMH))
// load op string from field
.ldc(cp.constantDynamicEntry(cp.bsmEntry(bsmDataAt, List.of(cp.intEntry(1))), natMH));
MethodType mtype = quotableOpFieldInfo.getMethodType();
if (quotableOpFieldInfo.getReferenceKind() != MethodHandleInfo.REF_getStatic) {
MethodType mtype = quotableOpGetterInfo.getMethodType();
if (quotableOpGetterInfo.getReferenceKind() != MethodHandleInfo.REF_invokeStatic) {
mtype = mtype.insertParameterTypes(0, implClass);
}
cob.invokevirtual(CD_MethodHandle, "invokeExact", mtype.describeConstable().get());
Expand Down Expand Up @@ -492,8 +492,10 @@ static class CodeReflectionSupport {
.loadClass("jdk.incubator.code.Quotable");
Class<?> quotedHelper = layer.findLoader("jdk.incubator.code")
.loadClass("jdk.incubator.code.internal.QuotedHelper");
Class<?> funcOp = layer.findLoader("jdk.incubator.code")
.loadClass("jdk.incubator.code.op.CoreOp$FuncOp");
MethodHandle makeQuoted = Lookup.IMPL_LOOKUP.findStatic(quotedHelper, "makeQuoted",
MethodType.methodType(QUOTED_CLASS, MethodHandles.Lookup.class, String.class, Object[].class));
MethodType.methodType(QUOTED_CLASS, MethodHandles.Lookup.class, funcOp, Object[].class));
HANDLE_MAKE_QUOTED = makeQuoted.bindTo(Lookup.IMPL_LOOKUP);
} catch (Throwable ex) {
throw new ExceptionInInitializerError(ex);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,8 @@ public static CallSite altMetafactory(MethodHandles.Lookup caller,
int flags = extractArg(args, argIndex++, Integer.class);
Class<?>[] altInterfaces = EMPTY_CLASS_ARRAY;
MethodType[] altMethods = EMPTY_MT_ARRAY;
MethodHandle quotableField = null;
// Getter that returns the op of a Quotable instance
MethodHandle quotableOpGetter = null;
if ((flags & FLAG_MARKERS) != 0) {
int altInterfaceCount = extractArg(args, argIndex++, Integer.class);
if (altInterfaceCount < 0) {
Expand All @@ -522,7 +523,7 @@ public static CallSite altMetafactory(MethodHandles.Lookup caller,
}
}
if ((flags & FLAG_QUOTABLE) != 0) {
quotableField = extractArg(args, argIndex++, MethodHandle.class);
quotableOpGetter = extractArg(args, argIndex++, MethodHandle.class);
altInterfaces = Arrays.copyOf(altInterfaces, altInterfaces.length + 1);
altInterfaces[altInterfaces.length-1] = InnerClassLambdaMetafactory.CodeReflectionSupport.QUOTABLE_CLASS;
}
Expand Down Expand Up @@ -551,7 +552,7 @@ public static CallSite altMetafactory(MethodHandles.Lookup caller,
isSerializable,
altInterfaces,
altMethods,
quotableField);
quotableOpGetter);
mf.validateMetafactoryArgs();
return mf.buildCallSite();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -879,8 +879,8 @@ private JCExpression makeMetafactoryIndyCall(JCFunctionalExpression tree,
}
}
if (isQuotable) {
VarSymbol reflectField = (VarSymbol)tree.codeModel;
staticArgs = staticArgs.append(reflectField.asMethodHandle(true));
MethodSymbol opMethodSym = (MethodSymbol)tree.codeModel;
staticArgs = staticArgs.append(opMethodSym.asHandle());
}
if (isSerializable) {
int prevPos = make.pos;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -494,7 +494,7 @@ private static Optional<FuncOp> createCodeModel(Method method) {
case '.', ';', '[', '/': sig[i] = '$';
}
}
String opMethodName = "method$op$" + new String(sig);
String opMethodName = "op$" + new String(sig);
Method opMethod;
try {
// @@@ Use method handle with full power mode
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import jdk.incubator.code.Value;
import jdk.incubator.code.op.CoreOp;
import jdk.incubator.code.op.CoreOp.*;
import jdk.incubator.code.parser.OpParser;
import jdk.incubator.code.type.ArrayType;
import jdk.incubator.code.type.FieldRef;
import jdk.incubator.code.type.FunctionType;
Expand Down Expand Up @@ -163,9 +164,15 @@ public static <O extends Op & Op.Invokable> byte[] generateClassData(MethodHandl
for (int i = 0; i < lambdaSink.size(); i++) {
LambdaOp lop = lambdaSink.get(i);
if (quotable.get(i)) {
clb.withField("lambda$" + i + "$op", CD_String, fb -> fb
.withFlags(ClassFile.ACC_STATIC)
.with(ConstantValueAttribute.of(quote(lop).toText())));
// return (FuncOp) OpParser.fromOpString(opText)
clb.withMethod("op$lambda$" + i, MethodTypeDesc.of(FuncOp.class.describeConstable().get()),
ClassFile.ACC_PUBLIC | ClassFile.ACC_STATIC | ClassFile.ACC_SYNTHETIC, mb -> mb.withCode(cb -> cb
.loadConstant(quote(lop).toText())
.invoke(Opcode.INVOKESTATIC, OpParser.class.describeConstable().get(),
"fromStringOfFuncOp",
MethodTypeDesc.of(Op.class.describeConstable().get(), CD_String), false)
.checkcast(FuncOp.class.describeConstable().get())
.areturn()));
}
generateMethod(lookup, className, "lambda$" + i, lop, clb, lambdaSink, quotable);
}
Expand Down Expand Up @@ -891,10 +898,10 @@ private void generate() {
mtd.insertParameterTypes(0, captureTypes)),
mtd,
LambdaMetafactory.FLAG_QUOTABLE,
MethodHandleDesc.ofField(DirectMethodHandleDesc.Kind.STATIC_GETTER,
className,
"lambda$" + lambdaIndex + "$op",
CD_String)));
MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.STATIC,
className,
"op$lambda$" + lambdaIndex,
MethodTypeDesc.of(FuncOp.class.describeConstable().get()))));
quotable.set(lambdaSink.size());
} else {
cob.invokedynamic(DynamicCallSiteDesc.of(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,7 @@ public static Quoted makeQuoted(MethodHandles.Lookup lookup, String opText, Obje
FuncOp op = (FuncOp)OpParser.fromStringOfFuncOp(opText);
return (Quoted)Interpreter.invoke(lookup, op, args);
}
public static Quoted makeQuoted(MethodHandles.Lookup lookup, FuncOp op, Object[] args) {
return (Quoted)Interpreter.invoke(lookup, op, args);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -253,24 +253,23 @@ public void visitLambda(JCLambda tree) {
// dump the method IR if requested
log.note(QuotedIrDump(funcOp.toText()));
}
// create a static final field holding the op' string text.
// The name of the field is foo$op, where 'foo' is the name of the corresponding method.
JCVariableDecl opField = opFieldDecl(lambdaName(), 0, funcOp);
classOps.add(opField);
// create a static method that returns the FuncOp representing the lambda
JCMethodDecl opMethod = opMethodDecl(lambdaName(), funcOp);
classOps.add(opMethod);

switch (kind) {
case QUOTED_STRUCTURAL -> {
// @@@ Consider replacing with invokedynamic to quoted bootstrap method
// Thereby we avoid certain dependencies and hide specific details
JCIdent opFieldId = make.Ident(opField.sym);
JCIdent opMethodId = make.Ident(opMethod.sym);
ListBuffer<JCExpression> interpreterArgs = new ListBuffer<>();
// Obtain MethodHandles.lookup()
// @@@ Could probably use MethodHandles.publicLookup()
JCMethodInvocation lookup = make.App(make.Ident(crSyms.methodHandlesLookup), com.sun.tools.javac.util.List.nil());
interpreterArgs.append(lookup);
// Deserialize the func operation
JCMethodInvocation parsedOp = make.App(make.Ident(crSyms.opParserFromString), com.sun.tools.javac.util.List.of(opFieldId));
interpreterArgs.append(parsedOp);
JCMethodInvocation op = make.App(opMethodId);
interpreterArgs.append(op);
// Append captured vars
ListBuffer<JCExpression> capturedArgs = quotedCapturedArgs(tree, bodyScanner);
interpreterArgs.appendList(capturedArgs.toList());
Expand All @@ -283,7 +282,7 @@ public void visitLambda(JCLambda tree) {
}
case QUOTABLE -> {
// leave the lambda in place, but also leave a trail for LambdaToMethod
tree.codeModel = opField.sym;
tree.codeModel = opMethod.sym;
super.visitLambda(tree);
}
}
Expand Down Expand Up @@ -315,11 +314,10 @@ public void visitReference(JCMemberReference tree) {
// dump the method IR if requested
log.note(QuotedIrDump(funcOp.toText()));
}
// create a static final field holding the op' string text.
// The name of the field is foo$op, where 'foo' is the name of the corresponding method.
JCVariableDecl opField = opFieldDecl(lambdaName(), 0, funcOp);
classOps.add(opField);
tree.codeModel = opField.sym;
// create a method that returns the FuncOp representing the lambda
JCMethodDecl opMethod = opMethodDecl(lambdaName(), funcOp);
classOps.add(opMethod);
tree.codeModel = opMethod.sym;
super.visitReference(tree);
if (recvDecl != null) {
result = copyReferenceWithReceiverVar(tree, recvDecl);
Expand Down Expand Up @@ -390,22 +388,10 @@ Name methodName(MethodRef method) {
return names.fromChars(sigCh, 0, sigCh.length);
}

private JCVariableDecl opFieldDecl(Name prefix, long flags, CoreOp.FuncOp op) {
VarSymbol opFieldSym = new VarSymbol(flags | Flags.STATIC | Flags.FINAL | Flags.SYNTHETIC,
prefix.append('$', names.fromString("op")),
syms.stringType,
currentClassSym);

currentClassSym.members().enter(opFieldSym);
JCLiteral opText = make.Literal(op.toText());
JCVariableDecl opFieldTree = make.VarDef(opFieldSym, opText);
return opFieldTree;
}

private JCMethodDecl opMethodDecl(Name methodName, CoreOp.FuncOp op) {
var mt = new MethodType(com.sun.tools.javac.util.List.nil(), crSyms.funcOpType,
com.sun.tools.javac.util.List.nil(), syms.methodClass);
var mn = names.fromString("method$op$").append(methodName);
var mn = names.fromString("op$").append(methodName);
var ms = new MethodSymbol(PUBLIC | STATIC | SYNTHETIC, mn, mt, currentClassSym);
currentClassSym.members().enter(ms);

Expand Down