1 /* 2 * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @modules jdk.incubator.code 27 * @run testng TestClosureOps 28 */ 29 30 import org.testng.Assert; 31 import org.testng.annotations.Test; 32 33 import jdk.incubator.code.Block; 34 import jdk.incubator.code.op.CoreOp; 35 import jdk.incubator.code.Op; 36 import jdk.incubator.code.Quoted; 37 import jdk.incubator.code.type.MethodRef; 38 import jdk.incubator.code.interpreter.Interpreter; 39 import java.lang.invoke.MethodHandles; 40 import jdk.incubator.code.type.JavaType; 41 import java.util.ArrayList; 42 import java.util.List; 43 44 import static jdk.incubator.code.op.CoreOp._return; 45 import static jdk.incubator.code.op.CoreOp.add; 46 import static jdk.incubator.code.op.CoreOp.closure; 47 import static jdk.incubator.code.op.CoreOp.closureCall; 48 import static jdk.incubator.code.op.CoreOp.constant; 49 import static jdk.incubator.code.op.CoreOp.func; 50 import static jdk.incubator.code.op.CoreOp.quoted; 51 import static jdk.incubator.code.type.FunctionType.functionType; 52 import static jdk.incubator.code.type.JavaType.INT; 53 import static jdk.incubator.code.type.JavaType.type; 54 55 public class TestClosureOps { 56 57 static class Builder { 58 static final MethodRef ACCEPT_METHOD = MethodRef.method(type(TestClosureOps.Builder.class), "accept", 59 INT, CoreOp.QuotedOp.QUOTED_TYPE); 60 61 static int accept(Quoted c) { 62 Assert.assertEquals(1, c.capturedValues().size()); 63 Assert.assertEquals(1, c.capturedValues().values().iterator().next()); 64 65 List<Object> arguments = new ArrayList<>(); 66 arguments.add(42); 67 arguments.addAll(c.capturedValues().values()); 68 int r = (int) Interpreter.invoke(MethodHandles.lookup(), (Op & Op.Invokable) c.op(), 69 arguments); 70 return r; 71 } 72 } 73 74 @Test 75 public void testQuotedWithCapture() { 76 // functional type = (int)int 77 CoreOp.FuncOp f = func("f", functionType(INT, INT)) 78 .body(block -> { 79 Block.Parameter i = block.parameters().get(0); 80 81 // functional type = (int)int 82 // op descriptor = ()Quoted<ClosureOp> 83 CoreOp.QuotedOp qop = quoted(block.parentBody(), qblock -> { 84 return closure(qblock.parentBody(), functionType(INT, INT)) 85 .body(cblock -> { 86 Block.Parameter ci = cblock.parameters().get(0); 87 88 cblock.op(_return( 89 // capture i from function's body 90 cblock.op(add(i, ci)) 91 )); 92 }); 93 }); 94 Op.Result cquoted = block.op(qop); 95 96 Op.Result or = block.op(CoreOp.invoke(TestClosureOps.Builder.ACCEPT_METHOD, cquoted)); 97 block.op(_return(or)); 98 }); 99 100 f.writeTo(System.out); 101 102 int ir = (int) Interpreter.invoke(MethodHandles.lookup(), f, 1); 103 Assert.assertEquals(ir, 43); 104 } 105 106 @Test 107 public void testWithCapture() { 108 // functional type = (int)int 109 CoreOp.FuncOp f = func("f", functionType(INT, INT)) 110 .body(block -> { 111 Block.Parameter i = block.parameters().get(0); 112 113 // functional type = (int)int 114 // captures i 115 CoreOp.ClosureOp closure = CoreOp.closure(block.parentBody(), 116 functionType(INT, INT)) 117 .body(cblock -> { 118 Block.Parameter ci = cblock.parameters().get(0); 119 120 cblock.op(_return( 121 cblock.op(add(i, ci)))); 122 }); 123 Op.Result c = block.op(closure); 124 125 Op.Result fortyTwo = block.op(constant(INT, 42)); 126 Op.Result or = block.op(closureCall(c, fortyTwo)); 127 block.op(_return(or)); 128 }); 129 130 f.writeTo(System.out); 131 132 int ir = (int) Interpreter.invoke(MethodHandles.lookup(), f, 1); 133 Assert.assertEquals(ir, 43); 134 } 135 136 @Test 137 public void testQuotableModel() { 138 Quoted quoted = () -> {}; 139 Op qop = quoted.op(); 140 Op top = qop.ancestorBody().parentOp().ancestorBody().parentOp(); 141 Assert.assertTrue(top instanceof CoreOp.FuncOp); 142 143 CoreOp.FuncOp fop = (CoreOp.FuncOp) top; 144 Assert.assertEquals(JavaType.type(Quoted.class), fop.invokableType().returnType()); 145 } 146 }