1 /* 2 * Copyright (c) 2015, 2018, 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 package jdk.internal.foreign; 24 25 import jdk.internal.foreign.memory.BoundedMemoryRegion; 26 import jdk.internal.foreign.memory.BoundedPointer; 27 import jdk.internal.foreign.memory.DescriptorParser; 28 import jdk.internal.org.objectweb.asm.MethodVisitor; 29 30 import java.foreign.Scope; 31 import java.lang.invoke.MethodHandle; 32 import java.lang.invoke.MethodHandles; 33 import java.lang.invoke.MethodType; 34 import java.lang.reflect.Method; 35 import java.foreign.layout.Function; 36 import java.foreign.layout.Layout; 37 import java.foreign.annotations.*; 38 import java.foreign.memory.LayoutType; 39 import java.foreign.memory.Pointer; 40 import java.util.HashMap; 41 import java.util.Map; 42 43 import static jdk.internal.org.objectweb.asm.Opcodes.*; 44 45 class HeaderImplGenerator extends BinderClassGenerator { 46 47 // lookup helper to use for looking up symbols 48 private final SymbolLookup lookup; 49 50 // dictionary from method name to member info 51 final Map<String, MemberInfo<?>> nameToInfo = new HashMap<>(); 52 53 // global scope for this library 54 private final Scope libScope; 55 56 HeaderImplGenerator(Class<?> hostClass, String implClassName, Class<?> c, SymbolLookup lookup, Scope libScope) { 57 super(hostClass, implClassName, new Class<?>[] { c }); 58 this.lookup = lookup; 59 this.libScope = libScope; 60 } 61 62 abstract class MemberInfo<D> { 63 String symbolName; 64 D descriptor; 65 66 MemberInfo(String symbolName, D descriptor) { 67 this.symbolName = symbolName; 68 this.descriptor = descriptor; 69 } 70 } 71 72 class GlobalVarInfo extends MemberInfo<Layout> { 73 74 AccessorKind accessorKind; 75 76 GlobalVarInfo(String symbolName, Layout layout, AccessorKind accessorKind) { 77 super(symbolName, layout); 78 this.accessorKind = accessorKind; 79 } 80 } 81 82 class FunctionInfo extends MemberInfo<Function> { 83 public FunctionInfo(String symbolName, Function descriptor) { 84 super(symbolName, descriptor); 85 } 86 } 87 88 @Override 89 protected void generateMembers(BinderClassWriter cw) { 90 Class<?> headerClass = interfaces[0]; 91 handleDeclarations(headerClass); 92 super.generateMembers(cw); 93 } 94 95 private void handleDeclarations(Class<?> cls) { 96 for (Class<?> si : cls.getInterfaces()) { 97 handleDeclarations(si); 98 } 99 if (!cls.isAnnotationPresent(NativeHeader.class)) { 100 // nothing to do! 101 return; 102 } 103 String declarations = cls.getAnnotation(NativeHeader.class).declarations(); 104 for (Map.Entry<String, Object> declEntry : DescriptorParser.parseHeaderDeclarations(declarations).entrySet()) { 105 if (declEntry.getValue() instanceof Layout) { 106 Layout l = (Layout)declEntry.getValue(); 107 for (Map.Entry<AccessorKind, String> accessorEntry : AccessorKind.from(l).entrySet()) { 108 nameToInfo.put(accessorEntry.getValue(), new GlobalVarInfo(declEntry.getKey(), l, accessorEntry.getKey())); 109 } 110 } else { 111 Function f = (Function)declEntry.getValue(); 112 nameToInfo.put(declEntry.getKey(), new FunctionInfo(declEntry.getKey(), f)); 113 } 114 } 115 } 116 117 @Override 118 protected void generateConstructor(BinderClassWriter cw) { 119 MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); 120 mv.visitCode(); 121 mv.visitVarInsn(ALOAD, 0); 122 mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); 123 mv.visitInsn(RETURN); 124 mv.visitMaxs(1,1); 125 mv.visitEnd(); 126 } 127 128 @Override 129 protected void generateMethodImplementation(BinderClassWriter cw, Method method) { 130 MemberInfo<?> memberInfo = nameToInfo.get(method.getName()); 131 if (memberInfo instanceof FunctionInfo) { 132 generateFunctionMethod(cw, method, (FunctionInfo)memberInfo); 133 } else if (memberInfo instanceof GlobalVarInfo) { 134 generateGlobalVariableMethod(cw, method, (GlobalVarInfo)memberInfo); 135 } 136 } 137 138 void generateFunctionMethod(BinderClassWriter cw, Method method, FunctionInfo info) { 139 MethodType methodType = Util.methodTypeFor(method); 140 Function function = info.descriptor; 141 try { 142 NativeInvoker invoker = new NativeInvoker(layoutResolver.resolve(function), methodType, method.isVarArgs(), method.toString(), method.getGenericReturnType()); 143 long addr = lookup.lookup(info.symbolName).getAddress().addr(); 144 addMethodFromHandle(cw, method.getName(), methodType, method.isVarArgs(), invoker.getBoundMethodHandle(), 145 mv -> mv.visitLdcInsn(addr)); 146 } catch (ReflectiveOperationException e) { 147 throw new IllegalStateException(e); 148 } 149 } 150 151 private void generateGlobalVariableMethod(BinderClassWriter cw, Method method, GlobalVarInfo info) { 152 java.lang.reflect.Type type = info.accessorKind.carrier(method); 153 Class<?> c = Util.erasure(type); 154 Layout l = info.descriptor; 155 LayoutType<?> lt = Util.makeType(type, l); 156 157 String methodName = method.getName(); 158 Pointer<?> p; 159 160 try { 161 p = BoundedPointer.createNativeVoidPointer(libScope, 162 lookup.lookup(info.symbolName).getAddress().addr(), BoundedMemoryRegion.MODE_RW). 163 cast(lt).limit(1); 164 } catch (IllegalAccessException | NoSuchMethodException e) { 165 throw new IllegalStateException(e); 166 } 167 168 MethodHandle target; 169 AccessorKind kind = info.accessorKind; 170 switch (kind) { 171 case GET: 172 target = lt.getter(); 173 target = target.bindTo(p).asType(MethodType.methodType(c)); 174 break; 175 176 case SET: 177 target = lt.setter(); 178 target = target.bindTo(p).asType(MethodType.methodType(void.class, c)); 179 break; 180 181 case PTR: 182 target = MethodHandles.constant(Pointer.class, p); 183 break; 184 185 default: 186 throw new InternalError("Unexpected access method type: " + kind); 187 } 188 189 addMethodFromHandle(cw, methodName, kind.getMethodType(c), false, target, mv -> {}); 190 } 191 } --- EOF ---