1 /*
  2  * Copyright (c) 2020, 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.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 
 26 package jdk.internal.jextract.impl;
 27 
 28 import jdk.incubator.foreign.*;
 29 
 30 import jdk.internal.jextract.impl.ConstantBuilder.Constant;
 31 
 32 import java.lang.invoke.MethodType;
 33 import java.util.function.Consumer;
 34 import java.util.stream.Collectors;
 35 import java.util.stream.IntStream;
 36 
 37 public class FunctionalInterfaceBuilder extends ClassSourceBuilder {
 38 
 39     private static final String MEMBER_MODS = "static";
 40 
 41     private final MethodType fiType;
 42     private final FunctionDescriptor fiDesc;
 43 
 44     FunctionalInterfaceBuilder(JavaSourceBuilder enclosing, String className,
 45                                MethodType fiType, FunctionDescriptor fiDesc) {
 46         super(enclosing, Kind.INTERFACE, className);
 47         this.fiType = fiType;
 48         this.fiDesc = fiDesc;
 49     }
 50 
 51     @Override
 52     JavaSourceBuilder classEnd() {
 53         emitFunctionalInterfaceMethod();
 54         emitFunctionalFactories();
 55         emitFunctionalFactoryForPointer();
 56         return super.classEnd();
 57     }
 58 
 59     // private generation
 60 
 61     private void emitFunctionalInterfaceMethod() {
 62         incrAlign();
 63         indent();
 64         append(fiType.returnType().getName() + " apply(");
 65         String delim = "";
 66         for (int i = 0 ; i < fiType.parameterCount(); i++) {
 67             append(delim + fiType.parameterType(i).getName() + " x" + i);
 68             delim = ", ";
 69         }
 70         append(");\n");
 71         decrAlign();
 72     }
 73 
 74     private void emitFunctionalFactories() {
 75         emitWithConstantClass(constantBuilder -> {
 76             Constant functionDesc = constantBuilder.addFunctionDesc(className(), fiDesc);
 77             incrAlign();
 78             indent();
 79             append(MEMBER_MODS + " NativeSymbol allocate(" + className() + " fi, ResourceScope scope) {\n");
 80             incrAlign();
 81             indent();
 82             append("return RuntimeHelper.upcallStub(" + className() + ".class, fi, " + functionDesc.accessExpression() + ", " +
 83                     "\"" + fiType.toMethodDescriptorString() + "\", scope);\n");
 84             decrAlign();
 85             indent();
 86             append("}\n");
 87             decrAlign();
 88         });
 89     }
 90 
 91     private void emitFunctionalFactoryForPointer() {
 92         emitWithConstantClass(constantBuilder -> {
 93             Constant mhConstant = constantBuilder.addMethodHandle(className(), className(), FunctionInfo.ofFunctionPointer(fiType, fiDesc), true);
 94             incrAlign();
 95             indent();
 96             append(MEMBER_MODS + " " + className() + " ofAddress(MemoryAddress addr, ResourceScope scope) {\n");
 97             incrAlign();
 98             indent();
 99             append("NativeSymbol symbol = NativeSymbol.ofAddress(");
100             append("\"" + className() + "::\" + Long.toHexString(addr.toRawLongValue()), addr, scope);");
101             append("return (");
102             String delim = "";
103             for (int i = 0 ; i < fiType.parameterCount(); i++) {
104                 append(delim + fiType.parameterType(i).getName() + " x" + i);
105                 delim = ", ";
106             }
107             append(") -> {\n");
108             incrAlign();
109             indent();
110             append("try {\n");
111             incrAlign();
112             indent();
113             if (!fiType.returnType().equals(void.class)) {
114                 append("return (" + fiType.returnType().getName() + ")");
115             }
116             append(mhConstant.accessExpression() + ".invokeExact(symbol");
117             if (fiType.parameterCount() > 0) {
118                 String params = IntStream.range(0, fiType.parameterCount())
119                         .mapToObj(i -> "x" + i)
120                         .collect(Collectors.joining(", "));
121                 append(", " + params);
122             }
123             append(");\n");
124             decrAlign();
125             indent();
126             append("} catch (Throwable ex$) {\n");
127             incrAlign();
128             indent();
129             append("throw new AssertionError(\"should not reach here\", ex$);\n");
130             decrAlign();
131             indent();
132             append("}\n");
133             decrAlign();
134             indent();
135             append("};\n");
136             decrAlign();
137             indent();
138             append("}\n");
139             decrAlign();
140         });
141     }
142 
143     @Override
144     protected void emitWithConstantClass(Consumer<ConstantBuilder> constantConsumer) {
145         enclosing.emitWithConstantClass(constantConsumer);
146     }
147 }