Skip to content

Commit d276cba

Browse files
author
Mourad Abbay
committed
Add isQuotable attribute to LambdaOp
Reviewed-by: psandoz
1 parent bde6eb4 commit d276cba

File tree

8 files changed

+100
-44
lines changed

8 files changed

+100
-44
lines changed

src/jdk.incubator.code/share/classes/jdk/incubator/code/bytecode/BytecodeGenerator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -884,7 +884,7 @@ private void generate() {
884884
ClassDesc[] captureTypes = op.capturedValues().stream()
885885
.map(Value::type).map(BytecodeGenerator::toClassDesc).toArray(ClassDesc[]::new);
886886
int lambdaIndex = lambdaSink.size();
887-
if (Quotable.class.isAssignableFrom(intfClass)) {
887+
if (op.isQuotable()) {
888888
cob.invokedynamic(DynamicCallSiteDesc.of(
889889
DMHD_LAMBDA_ALT_METAFACTORY,
890890
funcIntfMethodName(intfClass),

src/jdk.incubator.code/share/classes/jdk/incubator/code/bytecode/BytecodeLift.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
import java.lang.constant.DynamicConstantDesc;
5252
import java.lang.constant.MethodTypeDesc;
5353
import java.lang.invoke.CallSite;
54+
import java.lang.invoke.LambdaMetafactory;
5455
import java.lang.invoke.MethodHandle;
5556
import java.lang.reflect.AccessFlag;
5657
import jdk.incubator.code.Block;
@@ -474,6 +475,17 @@ yield op(JavaOp.invoke(JavaOp.InvokeOp.InvokeKind.SUPER, false,
474475
JavaOp.LambdaOp.Builder lambda = JavaOp.lambda(currentBlock.parentBody(),
475476
lambdaFunc,
476477
JavaType.type(inst.typeSymbol().returnType()));
478+
// if FLAG_QUOTABLE is set, the lambda is quotable
479+
if (bsm.methodName().equals("altMetafactory")) {
480+
assert inst.bootstrapArgs().size() > 3;
481+
assert inst.bootstrapArgs().get(3) instanceof Integer;
482+
483+
if (inst.bootstrapArgs().get(3) instanceof Integer flags
484+
&& (flags & LambdaMetafactory.FLAG_QUOTABLE) != 0) {
485+
lambda = lambda.quotable();
486+
}
487+
}
488+
477489
if (dmhd.methodName().startsWith("lambda$") && dmhd.owner().equals(classModel.thisClass().asSymbol())) {
478490
// inline lambda impl method
479491
MethodModel implMethod = classModel.methods().stream().filter(m -> m.methodName().equalsString(dmhd.methodName())).findFirst().orElseThrow();

src/jdk.incubator.code/share/classes/jdk/incubator/code/dialect/java/JavaOp.java

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -158,47 +158,70 @@ public static class Builder {
158158
final Body.Builder ancestorBody;
159159
final FunctionType funcType;
160160
final TypeElement functionalInterface;
161+
final boolean isQuotable;
161162

162163
Builder(Body.Builder ancestorBody, FunctionType funcType, TypeElement functionalInterface) {
163164
this.ancestorBody = ancestorBody;
164165
this.funcType = funcType;
165166
this.functionalInterface = functionalInterface;
167+
this.isQuotable = false;
168+
}
169+
170+
Builder(Body.Builder ancestorBody, FunctionType funcType, TypeElement functionalInterface,
171+
boolean isQuotable) {
172+
this.ancestorBody = ancestorBody;
173+
this.funcType = funcType;
174+
this.functionalInterface = functionalInterface;
175+
this.isQuotable = isQuotable;
166176
}
167177

168178
public LambdaOp body(Consumer<Block.Builder> c) {
169179
Body.Builder body = Body.Builder.of(ancestorBody, funcType);
170180
c.accept(body.entryBlock());
171-
return new LambdaOp(functionalInterface, body);
181+
return new LambdaOp(functionalInterface, body, isQuotable);
182+
}
183+
184+
public Builder quotable() {
185+
return new Builder(ancestorBody, funcType, functionalInterface, true);
172186
}
173187
}
174188

175189
static final String NAME = "lambda";
190+
static final String ATTRIBUTE_LAMBDA_IS_QUOTABLE = NAME + ".isQuotable";
176191

177192
final TypeElement functionalInterface;
178193
final Body body;
194+
final boolean isQuotable;
179195

180-
LambdaOp(ExternalizedOp def) {
181-
this(def.resultType(), def.bodyDefinitions().get(0));
196+
static LambdaOp create(ExternalizedOp def) {
197+
boolean isQuotable = def.extractAttributeValue(ATTRIBUTE_LAMBDA_IS_QUOTABLE,
198+
false, v -> switch (v) {
199+
case Boolean b -> b;
200+
case null, default -> false;
201+
});
202+
return new LambdaOp(def.resultType(), def.bodyDefinitions().get(0), isQuotable);
182203
}
183204

184205
LambdaOp(LambdaOp that, CopyContext cc, OpTransformer ot) {
185206
super(that, cc);
186207

187208
this.functionalInterface = that.functionalInterface;
188209
this.body = that.body.transform(cc, ot).build(this);
210+
this.isQuotable = that.isQuotable;
189211
}
190212

191213
@Override
192214
public LambdaOp transform(CopyContext cc, OpTransformer ot) {
193215
return new LambdaOp(this, cc, ot);
194216
}
195217

196-
LambdaOp(TypeElement functionalInterface, Body.Builder bodyC) {
218+
LambdaOp(TypeElement functionalInterface, Body.Builder bodyC, boolean isQuotable) {
197219
super(NAME,
198220
List.of());
199221

200222
this.functionalInterface = functionalInterface;
201223
this.body = bodyC.build(this);
224+
this.isQuotable = isQuotable;
202225
}
203226

204227
@Override
@@ -237,6 +260,15 @@ public TypeElement resultType() {
237260
return functionalInterface();
238261
}
239262

263+
public boolean isQuotable() {
264+
return isQuotable;
265+
}
266+
267+
@Override
268+
public Map<String, Object> externalize() {
269+
return Map.of(ATTRIBUTE_LAMBDA_IS_QUOTABLE, isQuotable);
270+
}
271+
240272
/**
241273
* Determines if this lambda operation could have originated from a
242274
* method reference declared in Java source code.
@@ -4975,7 +5007,7 @@ static Op createOp(ExternalizedOp def) {
49755007
case "java.try" -> TryOp.create(def);
49765008
case "java.while" -> new WhileOp(def);
49775009
case "java.yield" -> new YieldOp(def);
4978-
case "lambda" -> new LambdaOp(def);
5010+
case "lambda" -> LambdaOp.create(def);
49795011
case "le" -> new LeOp(def);
49805012
case "lshl" -> new LshlOp(def);
49815013
case "lshr" -> new LshrOp(def);
@@ -5039,7 +5071,19 @@ public static LambdaOp.Builder lambda(Body.Builder ancestorBody,
50395071
* @return the lambda operation
50405072
*/
50415073
public static LambdaOp lambda(TypeElement functionalInterface, Body.Builder body) {
5042-
return new LambdaOp(functionalInterface, body);
5074+
return new LambdaOp(functionalInterface, body, false);
5075+
}
5076+
5077+
/**
5078+
* Creates a lambda operation.
5079+
*
5080+
* @param functionalInterface the lambda operation's functional interface type
5081+
* @param body the body of the lambda operation
5082+
* @param isQuotable true if the lambda is quotable
5083+
* @return the lambda operation
5084+
*/
5085+
public static LambdaOp lambda(TypeElement functionalInterface, Body.Builder body, boolean isQuotable) {
5086+
return new LambdaOp(functionalInterface, body, isQuotable);
50435087
}
50445088

50455089
/**

src/jdk.incubator.code/share/classes/jdk/incubator/code/internal/ReflectMethods.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1520,7 +1520,7 @@ public void visitLambda(JCTree.JCLambda tree) {
15201520
// Get the functional interface type
15211521
JavaType fiType = typeToTypeElement(tree.target);
15221522
// build functional lambda
1523-
yield JavaOp.lambda(fiType, stack.body);
1523+
yield JavaOp.lambda(fiType, stack.body, kind == FunctionalExpressionKind.QUOTABLE);
15241524
}
15251525
};
15261526

src/jdk.incubator.code/share/classes/jdk/incubator/code/interpreter/Interpreter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,7 @@ static Object interpretOp(MethodHandles.Lookup l, OpContext oc, Op o) {
499499
Object fiInstance = MethodHandleProxies.asInterfaceInstance(fi, fProxy);
500500

501501
// If a quotable lambda proxy again to add method Quoted quoted()
502-
if (Quotable.class.isAssignableFrom(fi)) {
502+
if (lo.isQuotable()) {
503503
return Proxy.newProxyInstance(l.lookupClass().getClassLoader(), new Class<?>[]{fi},
504504
new InvocationHandler() {
505505
private final Quoted quoted = new Quoted(lo, capturedValuesAndArguments);

test/langtools/tools/javac/reflect/QuotableIntersectionTest.java

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
public class QuotableIntersectionTest {
4141
@IR("""
4242
func @"f" ()java.type:"void" -> {
43-
%0 : java.type:"jdk.incubator.code.Quotable" = lambda ()java.type:"void" -> {
43+
%0 : java.type:"jdk.incubator.code.Quotable" = lambda @lambda.isQuotable=true ()java.type:"void" -> {
4444
return;
4545
};
4646
return;
@@ -51,7 +51,7 @@ public class QuotableIntersectionTest {
5151

5252
@IR("""
5353
func @"f" ()java.type:"void" -> {
54-
%0 : java.type:"jdk.incubator.code.Quotable" = lambda ()java.type:"int" -> {
54+
%0 : java.type:"jdk.incubator.code.Quotable" = lambda @lambda.isQuotable=true ()java.type:"int" -> {
5555
%1 : java.type:"int" = constant @1;
5656
return %1;
5757
};
@@ -62,7 +62,7 @@ public class QuotableIntersectionTest {
6262

6363
@IR("""
6464
func @"f" ()java.type:"void" -> {
65-
%0 : java.type:"jdk.incubator.code.Quotable" = lambda (%1 : java.type:"int")java.type:"int" -> {
65+
%0 : java.type:"jdk.incubator.code.Quotable" = lambda @lambda.isQuotable=true (%1 : java.type:"int")java.type:"int" -> {
6666
%2 : Var<java.type:"int"> = var %1 @"x";
6767
%3 : java.type:"int" = var.load %2;
6868
return %3;
@@ -74,7 +74,7 @@ public class QuotableIntersectionTest {
7474

7575
@IR("""
7676
func @"f" ()java.type:"void" -> {
77-
%0 : java.type:"jdk.incubator.code.Quotable" = lambda (%1 : java.type:"int", %2 : java.type:"int")java.type:"int" -> {
77+
%0 : java.type:"jdk.incubator.code.Quotable" = lambda @lambda.isQuotable=true (%1 : java.type:"int", %2 : java.type:"int")java.type:"int" -> {
7878
%3 : Var<java.type:"int"> = var %1 @"x";
7979
%4 : Var<java.type:"int"> = var %2 @"y";
8080
%5 : java.type:"int" = var.load %3;
@@ -89,7 +89,7 @@ public class QuotableIntersectionTest {
8989

9090
@IR("""
9191
func @"f" ()java.type:"void" -> {
92-
%0 : java.type:"jdk.incubator.code.Quotable" = lambda ()java.type:"void" -> {
92+
%0 : java.type:"jdk.incubator.code.Quotable" = lambda @lambda.isQuotable=true ()java.type:"void" -> {
9393
%1 : java.type:"java.lang.AssertionError" = new @java.ref:"java.lang.AssertionError::()";
9494
throw %1;
9595
};
@@ -102,7 +102,7 @@ public class QuotableIntersectionTest {
102102

103103
@IR("""
104104
func @"f" (%0 : Var<java.type:"int">)java.type:"void" -> {
105-
%1 : java.type:"jdk.incubator.code.Quotable" = lambda (%2 : java.type:"int")java.type:"int" -> {
105+
%1 : java.type:"jdk.incubator.code.Quotable" = lambda @lambda.isQuotable=true (%2 : java.type:"int")java.type:"int" -> {
106106
%3 : Var<java.type:"int"> = var %2 @"y";
107107
%4 : java.type:"int" = var.load %0;
108108
%5 : java.type:"int" = var.load %3;
@@ -128,7 +128,7 @@ Quotable capture() {
128128

129129
@IR("""
130130
func @"f" (%0 : java.type:"QuotableIntersectionTest$Context")java.type:"void" -> {
131-
%1 : java.type:"jdk.incubator.code.Quotable" = lambda (%2 : java.type:"int")java.type:"int" -> {
131+
%1 : java.type:"jdk.incubator.code.Quotable" = lambda @lambda.isQuotable=true (%2 : java.type:"int")java.type:"int" -> {
132132
%3 : Var<java.type:"int"> = var %2 @"z";
133133
%4 : java.type:"int" = field.load %0 @java.ref:"QuotableIntersectionTest$Context::x:int";
134134
%5 : java.type:"int" = field.load %0 @java.ref:"QuotableIntersectionTest$Context::y:int";
@@ -146,7 +146,7 @@ Quotable capture() {
146146
@IR("""
147147
func @"captureParam" (%0 : java.type:"int")java.type:"void" -> {
148148
%1 : Var<java.type:"int"> = var %0 @"x";
149-
%2 : java.type:"java.util.function.IntUnaryOperator" = lambda (%3 : java.type:"int")java.type:"int" -> {
149+
%2 : java.type:"java.util.function.IntUnaryOperator" = lambda @lambda.isQuotable=true (%3 : java.type:"int")java.type:"int" -> {
150150
%4 : Var<java.type:"int"> = var %3 @"y";
151151
%5 : java.type:"int" = var.load %1;
152152
%6 : java.type:"int" = var.load %4;
@@ -166,7 +166,7 @@ static void captureParam(int x) {
166166
@CodeReflection
167167
@IR("""
168168
func @"captureField" (%0 : java.type:"QuotableIntersectionTest")java.type:"void" -> {
169-
%1 : java.type:"java.util.function.IntUnaryOperator" = lambda (%2 : java.type:"int")java.type:"int" -> {
169+
%1 : java.type:"java.util.function.IntUnaryOperator" = lambda @lambda.isQuotable=true (%2 : java.type:"int")java.type:"int" -> {
170170
%3 : Var<java.type:"int"> = var %2 @"z";
171171
%4 : java.type:"int" = field.load %0 @java.ref:"QuotableIntersectionTest::x:int";
172172
%5 : java.type:"int" = field.load %0 @java.ref:"QuotableIntersectionTest::y:int";
@@ -188,7 +188,7 @@ static void m() {
188188

189189
@IR("""
190190
func @"f" ()java.type:"void" -> {
191-
%0 : java.type:"jdk.incubator.code.Quotable" = lambda ()java.type:"void" -> {
191+
%0 : java.type:"jdk.incubator.code.Quotable" = lambda @lambda.isQuotable=true ()java.type:"void" -> {
192192
invoke @java.ref:"QuotableIntersectionTest::m():void";
193193
return;
194194
};
@@ -203,7 +203,7 @@ static int g(int i) {
203203

204204
@IR("""
205205
func @"f" ()java.type:"void" -> {
206-
%0 : java.type:"jdk.incubator.code.Quotable" = lambda (%1 : java.type:"int")java.type:"int" -> {
206+
%0 : java.type:"jdk.incubator.code.Quotable" = lambda @lambda.isQuotable=true (%1 : java.type:"int")java.type:"int" -> {
207207
%2 : Var<java.type:"int"> = var %1 @"x$0";
208208
%3 : java.type:"int" = var.load %2;
209209
%4 : java.type:"int" = invoke %3 @java.ref:"QuotableIntersectionTest::g(int):int";
@@ -216,7 +216,7 @@ static int g(int i) {
216216

217217
@IR("""
218218
func @"f" ()java.type:"void" -> {
219-
%0 : java.type:"jdk.incubator.code.Quotable" = lambda (%1 : java.type:"int")java.type:"int[]" -> {
219+
%0 : java.type:"jdk.incubator.code.Quotable" = lambda @lambda.isQuotable=true (%1 : java.type:"int")java.type:"int[]" -> {
220220
%2 : Var<java.type:"int"> = var %1 @"x$0";
221221
%3 : java.type:"int" = var.load %2;
222222
%4 : java.type:"int[]" = new %3 @java.ref:"int[]::(int)";
@@ -239,7 +239,7 @@ Quotable capture() {
239239

240240
@IR("""
241241
func @"f" (%0 : java.type:"QuotableIntersectionTest$ContextRef")java.type:"void" -> {
242-
%1 : java.type:"jdk.incubator.code.Quotable" = lambda (%2 : java.type:"int")java.type:"int" -> {
242+
%1 : java.type:"jdk.incubator.code.Quotable" = lambda @lambda.isQuotable=true (%2 : java.type:"int")java.type:"int" -> {
243243
%3 : Var<java.type:"int"> = var %2 @"x$0";
244244
%4 : java.type:"int" = var.load %3;
245245
%5 : java.type:"int" = invoke %0 %4 @java.ref:"QuotableIntersectionTest$ContextRef::g(int):int";

0 commit comments

Comments
 (0)