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 ---