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 * @run testng TestClosureOps 27 */ 28 29 import org.testng.Assert; 30 import org.testng.annotations.Test; 31 32 import java.lang.reflect.code.Block; 33 import java.lang.reflect.code.op.CoreOp; 34 import java.lang.reflect.code.Op; 35 import java.lang.reflect.code.Quoted; 36 import java.lang.reflect.code.type.MethodRef; 37 import java.lang.reflect.code.interpreter.Interpreter; 38 import java.lang.invoke.MethodHandles; 39 import java.lang.reflect.code.type.JavaType; 40 41 import static java.lang.reflect.code.op.CoreOp._return; 42 import static java.lang.reflect.code.op.CoreOp.add; 43 import static java.lang.reflect.code.op.CoreOp.closure; 44 import static java.lang.reflect.code.op.CoreOp.closureCall; 45 import static java.lang.reflect.code.op.CoreOp.constant; 46 import static java.lang.reflect.code.op.CoreOp.func; 47 import static java.lang.reflect.code.op.CoreOp.quoted; 48 import static java.lang.reflect.code.type.FunctionType.functionType; 49 import static java.lang.reflect.code.type.JavaType.INT; 50 import static java.lang.reflect.code.type.JavaType.type; 51 52 public class TestClosureOps { 53 54 static class Builder { 55 static final MethodRef ACCEPT_METHOD = MethodRef.method(type(TestClosureOps.Builder.class), "accept", 56 INT, CoreOp.QuotedOp.QUOTED_TYPE); 57 58 static int accept(Quoted c) { 59 Assert.assertEquals(1, c.capturedValues().size()); 60 Assert.assertEquals(1, c.capturedValues().values().iterator().next()); 61 62 int r = (int) Interpreter.invoke(MethodHandles.lookup(), (Op & Op.Invokable) c.op(), 63 c.capturedValues(), 42); 64 return r; 65 } 66 } 67 68 @Test 69 public void testQuotedWithCapture() { 70 // functional type = (int)int 71 CoreOp.FuncOp f = func("f", functionType(INT, INT)) 72 .body(block -> { 73 Block.Parameter i = block.parameters().get(0); 74 75 // functional type = (int)int 76 // op descriptor = ()Quoted<ClosureOp> 77 CoreOp.QuotedOp qop = quoted(block.parentBody(), qblock -> { 78 return closure(qblock.parentBody(), functionType(INT, INT)) 79 .body(cblock -> { 80 Block.Parameter ci = cblock.parameters().get(0); 81 82 cblock.op(_return( 83 // capture i from function's body 84 cblock.op(add(i, ci)) 85 )); 86 }); 87 }); 88 Op.Result cquoted = block.op(qop); 89 90 Op.Result or = block.op(CoreOp.invoke(TestClosureOps.Builder.ACCEPT_METHOD, cquoted)); 91 block.op(_return(or)); 92 }); 93 94 f.writeTo(System.out); 95 96 int ir = (int) Interpreter.invoke(MethodHandles.lookup(), f, 1); 97 Assert.assertEquals(ir, 43); 98 } 99 100 @Test 101 public void testWithCapture() { 102 // functional type = (int)int 103 CoreOp.FuncOp f = func("f", functionType(INT, INT)) 104 .body(block -> { 105 Block.Parameter i = block.parameters().get(0); 106 107 // functional type = (int)int 108 // captures i 109 CoreOp.ClosureOp closure = CoreOp.closure(block.parentBody(), 110 functionType(INT, INT)) 111 .body(cblock -> { 112 Block.Parameter ci = cblock.parameters().get(0); 113 114 cblock.op(_return( 115 cblock.op(add(i, ci)))); 116 }); 117 Op.Result c = block.op(closure); 118 119 Op.Result fortyTwo = block.op(constant(INT, 42)); 120 Op.Result or = block.op(closureCall(c, fortyTwo)); 121 block.op(_return(or)); 122 }); 123 124 f.writeTo(System.out); 125 126 int ir = (int) Interpreter.invoke(MethodHandles.lookup(), f, 1); 127 Assert.assertEquals(ir, 43); 128 } 129 130 @Test 131 public void testQuotableModel() { 132 Quoted quoted = () -> {}; 133 Op qop = quoted.op(); 134 Op top = qop.ancestorBody().parentOp().ancestorBody().parentOp(); 135 Assert.assertTrue(top instanceof CoreOp.FuncOp); 136 137 CoreOp.FuncOp fop = (CoreOp.FuncOp) top; 138 Assert.assertEquals(JavaType.type(Quoted.class), fop.invokableType().returnType()); 139 } 140 }