< prev index next >

src/java.base/share/classes/jdk/internal/foreign/abi/DirectSignatureShuffler.java

Print this page


   1 /*
   2  * Copyright (c) 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  */


  74             STRUCT_TO_LONG = MethodHandles.lookup().findStatic(DirectSignatureShuffler.class, "structToLong", MethodType.methodType(long.class, Struct.class));
  75             STRUCT_TO_DOUBLE = MethodHandles.lookup().findStatic(DirectSignatureShuffler.class, "structToDouble", MethodType.methodType(double.class, Struct.class));
  76             LONG_TO_STRUCT = MethodHandles.lookup().findStatic(DirectSignatureShuffler.class, "longToStruct", MethodType.methodType(Struct.class, Class.class, long.class));
  77             DOUBLE_TO_STRUCT = MethodHandles.lookup().findStatic(DirectSignatureShuffler.class, "doubleToStruct", MethodType.methodType(Struct.class, Class.class, double.class));
  78         } catch (ReflectiveOperationException e) {
  79             throw new RuntimeException(e);
  80         }
  81     }
  82 
  83     private final ShuffleDirection direction;
  84     private final MethodType javaMethodType;
  85     private MethodType erasedMethodType = MethodType.methodType(void.class);
  86     private List<UnaryOperator<MethodHandle>> adapters = new ArrayList<>();
  87     private List<Integer> longPerms = new ArrayList<>();
  88     private List<Integer> doublePerms = new ArrayList<>();
  89 
  90     private DirectSignatureShuffler(CallingSequence callingSequence, NativeMethodType nmt, ShuffleDirection direction) {
  91         checkCallingSequence(callingSequence);
  92         this.direction = direction;
  93         this.javaMethodType = nmt.methodType();
  94         processType(RET_POS, nmt.returnType(), callingSequence.getReturnBindings(), direction.flip());
  95         for (int i = 0 ; i < javaMethodType.parameterCount() ; i++) {
  96             processType(i, nmt.parameterType(i), callingSequence.getArgumentBindings(i), direction);
  97         }
  98     }
  99 
 100     static DirectSignatureShuffler javaToNativeShuffler(CallingSequence callingSequence, NativeMethodType nmt) {
 101         return new DirectSignatureShuffler(callingSequence, nmt, ShuffleDirection.JAVA_TO_NATIVE);
 102     }
 103 
 104     static DirectSignatureShuffler nativeToJavaShuffler(CallingSequence callingSequence, NativeMethodType nmt) {
 105         return new DirectSignatureShuffler(callingSequence, nmt, ShuffleDirection.NATIVE_TO_JAVA);
 106     }
 107 
 108     MethodHandle adapt(MethodHandle mh) {
 109         if (direction == ShuffleDirection.JAVA_TO_NATIVE) {
 110             mh = MethodHandles.permuteArguments(mh, erasedMethodType, forwardPermutations());
 111         }
 112 
 113         for (UnaryOperator<MethodHandle> adapter : adapters) {
 114             mh = adapter.apply(mh);
 115         }
 116 


 125         mt = mt.appendParameterTypes(Collections.nCopies(longPerms.size(), long.class));
 126         return mt.appendParameterTypes(Collections.nCopies(doublePerms.size(), double.class));
 127     }
 128 
 129     MethodType javaMethodType() {
 130         return javaMethodType;
 131     }
 132 
 133     String nativeSigSuffix() {
 134         MethodType mt = nativeMethodType();
 135         return String.format("%s_%s",
 136                 desc(mt.returnType()),
 137                 mt.parameterCount() > 0 ?
 138                         mt.parameterList().stream().map(this::desc).collect(Collectors.joining()) :
 139                         "V");
 140 
 141     }
 142 
 143     private static void checkCallingSequence(CallingSequence callingSequence) {
 144         if (callingSequence.returnsInMemory() ||
 145                 !callingSequence.getBindings(StorageClass.STACK_ARGUMENT_SLOT).isEmpty()) {
 146             throw new IllegalArgumentException("Unsupported non-scalarized calling sequence!");
 147         }
 148     }
 149 
 150     private void processType(int sigPos, LayoutType<?> lt, List<ArgumentBinding> bindings, ShuffleDirection direction) {
 151         Class<?> carrier = (Class<?>) Util.unboxIfNeeded(((LayoutTypeImpl<?>)lt).carrier());
 152         if (carrier.isPrimitive()) {
 153             if (carrier == long.class) {
 154                 updateNativeMethodType(sigPos, long.class);
 155             } else if (carrier == double.class) {
 156                 updateNativeMethodType(sigPos, double.class);
 157             } else if (carrier == float.class) {
 158                 updateNativeMethodType(sigPos, double.class);
 159                 adapters.add(direction.doubleAdapter(sigPos, carrier));
 160             } else if (carrier == boolean.class) {
 161                 updateNativeMethodType(sigPos, long.class);
 162                 adapters.add(direction.booleanAdapter(sigPos));
 163             } else if (carrier == void.class) {
 164                 assert sigPos == -1;
 165             } else {
 166                 updateNativeMethodType(sigPos, long.class);
 167                 adapters.add(direction.longAdapter(sigPos, carrier));
 168             }
 169         } else if (carrier == Pointer.class) {
 170             updateNativeMethodType(sigPos, long.class);
 171             adapters.add(direction.pointerAdapter(sigPos, lt));
 172         } else if (carrier == Callback.class) {
 173             updateNativeMethodType(sigPos, long.class);
 174             adapters.add(direction.callbackAdapter(sigPos, lt));
 175         } else if (Util.isCStruct(carrier)) {
 176             if (bindings.size() == 1) {
 177                 ArgumentBinding binding = bindings.get(0);
 178                 switch (binding.getStorage().getStorageClass()) {
 179                     case INTEGER_ARGUMENT_REGISTER:
 180                     case INTEGER_RETURN_REGISTER:
 181                         updateNativeMethodType(sigPos, long.class);
 182                         adapters.add(direction.longStructAdapter(sigPos, carrier));
 183                         break;
 184                     case VECTOR_ARGUMENT_REGISTER:
 185                     case VECTOR_RETURN_REGISTER:
 186                         updateNativeMethodType(sigPos, double.class);
 187                         adapters.add(direction.doubleStructAdapter(sigPos, carrier));
 188                         break;
 189                     default:
 190                         //non-register bindings should have already been discarded by now
 191                         throw new IllegalStateException("Cannot get here!");
 192                 }
 193             } else {
 194                 throw new IllegalArgumentException("Multi-value struct!");
 195             }
 196         } else {
 197             throw new IllegalArgumentException("Unsupported carrier: " + carrier);
 198         }


 372         MethodHandle mh = MethodHandles.identity(double.class);
 373         return MethodHandles.explicitCastArguments(mh, MethodType.methodType(double.class, carrier));
 374     }
 375 
 376     private static MethodHandle doubleToPrimitive(Class<?> carrier) {
 377         MethodHandle mh = MethodHandles.identity(double.class);
 378         return MethodHandles.explicitCastArguments(mh, MethodType.methodType(carrier, double.class));
 379     }
 380 
 381     // predicate: is fast path applicable?
 382 
 383     public static boolean acceptDowncall(NativeMethodType nmt, CallingSequence callingSequence) {
 384         return accept(nmt, callingSequence, ShuffleDirection.JAVA_TO_NATIVE);
 385     }
 386 
 387     public static boolean acceptUpcall(NativeMethodType nmt, CallingSequence callingSequence) {
 388         return accept(nmt, callingSequence, ShuffleDirection.NATIVE_TO_JAVA);
 389     }
 390 
 391     private static boolean accept(NativeMethodType nmt, CallingSequence callingSequence, ShuffleDirection direction) {
 392         if (nmt.parameterCount() > direction.maxArity) return false;



 393         for (int i = 0 ; i < nmt.parameterCount(); i++) {
 394             List<ArgumentBinding> argumentBindings = callingSequence.getArgumentBindings(i);
 395             if (argumentBindings.size() != 1 ||
 396                     !isDirectBinding(argumentBindings.get(0))) {
 397                 return false;
 398             }
 399         }
 400 
 401         List<ArgumentBinding> returnBindings = callingSequence.getReturnBindings();
 402         if (returnBindings.isEmpty()) {
 403             return true;
 404         } else {
 405             return !callingSequence.returnsInMemory() &&
 406                     returnBindings.size() == 1 && isDirectBinding(returnBindings.get(0));
 407         }
 408     }
 409 
 410     private static boolean isDirectBinding(ArgumentBinding binding) {
 411         switch (binding.getStorage().getStorageClass()) {
 412             case X87_RETURN_REGISTER:
 413             case STACK_ARGUMENT_SLOT:
 414                 //arguments passed in memory not supported
 415                 return false;
 416             case VECTOR_ARGUMENT_REGISTER:
 417             case VECTOR_RETURN_REGISTER:
 418                 //avoid passing around floats as doubles as that leads to trouble
 419                 return (binding.getMember().getType().bitsSize() / 8) == binding.getStorage().getSize();
 420             default:
 421                 return true;
 422         }
 423     }
 424 }
   1 /*
   2  * Copyright (c) 2018, 2019, 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  */


  74             STRUCT_TO_LONG = MethodHandles.lookup().findStatic(DirectSignatureShuffler.class, "structToLong", MethodType.methodType(long.class, Struct.class));
  75             STRUCT_TO_DOUBLE = MethodHandles.lookup().findStatic(DirectSignatureShuffler.class, "structToDouble", MethodType.methodType(double.class, Struct.class));
  76             LONG_TO_STRUCT = MethodHandles.lookup().findStatic(DirectSignatureShuffler.class, "longToStruct", MethodType.methodType(Struct.class, Class.class, long.class));
  77             DOUBLE_TO_STRUCT = MethodHandles.lookup().findStatic(DirectSignatureShuffler.class, "doubleToStruct", MethodType.methodType(Struct.class, Class.class, double.class));
  78         } catch (ReflectiveOperationException e) {
  79             throw new RuntimeException(e);
  80         }
  81     }
  82 
  83     private final ShuffleDirection direction;
  84     private final MethodType javaMethodType;
  85     private MethodType erasedMethodType = MethodType.methodType(void.class);
  86     private List<UnaryOperator<MethodHandle>> adapters = new ArrayList<>();
  87     private List<Integer> longPerms = new ArrayList<>();
  88     private List<Integer> doublePerms = new ArrayList<>();
  89 
  90     private DirectSignatureShuffler(CallingSequence callingSequence, NativeMethodType nmt, ShuffleDirection direction) {
  91         checkCallingSequence(callingSequence);
  92         this.direction = direction;
  93         this.javaMethodType = nmt.methodType();
  94         processType(RET_POS, nmt.returnType(), callingSequence.returnBindings(), direction.flip());
  95         for (int i = 0 ; i < javaMethodType.parameterCount() ; i++) {
  96             processType(i, nmt.parameterType(i), callingSequence.argumentBindings(i), direction);
  97         }
  98     }
  99 
 100     static DirectSignatureShuffler javaToNativeShuffler(CallingSequence callingSequence, NativeMethodType nmt) {
 101         return new DirectSignatureShuffler(callingSequence, nmt, ShuffleDirection.JAVA_TO_NATIVE);
 102     }
 103 
 104     static DirectSignatureShuffler nativeToJavaShuffler(CallingSequence callingSequence, NativeMethodType nmt) {
 105         return new DirectSignatureShuffler(callingSequence, nmt, ShuffleDirection.NATIVE_TO_JAVA);
 106     }
 107 
 108     MethodHandle adapt(MethodHandle mh) {
 109         if (direction == ShuffleDirection.JAVA_TO_NATIVE) {
 110             mh = MethodHandles.permuteArguments(mh, erasedMethodType, forwardPermutations());
 111         }
 112 
 113         for (UnaryOperator<MethodHandle> adapter : adapters) {
 114             mh = adapter.apply(mh);
 115         }
 116 


 125         mt = mt.appendParameterTypes(Collections.nCopies(longPerms.size(), long.class));
 126         return mt.appendParameterTypes(Collections.nCopies(doublePerms.size(), double.class));
 127     }
 128 
 129     MethodType javaMethodType() {
 130         return javaMethodType;
 131     }
 132 
 133     String nativeSigSuffix() {
 134         MethodType mt = nativeMethodType();
 135         return String.format("%s_%s",
 136                 desc(mt.returnType()),
 137                 mt.parameterCount() > 0 ?
 138                         mt.parameterList().stream().map(this::desc).collect(Collectors.joining()) :
 139                         "V");
 140 
 141     }
 142 
 143     private static void checkCallingSequence(CallingSequence callingSequence) {
 144         if (callingSequence.returnsInMemory() ||
 145                 !callingSequence.bindings(StorageClass.STACK_ARGUMENT_SLOT).isEmpty()) {
 146             throw new IllegalArgumentException("Unsupported non-scalarized calling sequence!");
 147         }
 148     }
 149 
 150     private void processType(int sigPos, LayoutType<?> lt, List<ArgumentBinding> bindings, ShuffleDirection direction) {
 151         Class<?> carrier = (Class<?>) Util.unboxIfNeeded(((LayoutTypeImpl<?>)lt).carrier());
 152         if (carrier.isPrimitive()) {
 153             if (carrier == long.class) {
 154                 updateNativeMethodType(sigPos, long.class);
 155             } else if (carrier == double.class) {
 156                 updateNativeMethodType(sigPos, double.class);
 157             } else if (carrier == float.class) {
 158                 updateNativeMethodType(sigPos, double.class);
 159                 adapters.add(direction.doubleAdapter(sigPos, carrier));
 160             } else if (carrier == boolean.class) {
 161                 updateNativeMethodType(sigPos, long.class);
 162                 adapters.add(direction.booleanAdapter(sigPos));
 163             } else if (carrier == void.class) {
 164                 assert sigPos == -1;
 165             } else {
 166                 updateNativeMethodType(sigPos, long.class);
 167                 adapters.add(direction.longAdapter(sigPos, carrier));
 168             }
 169         } else if (carrier == Pointer.class) {
 170             updateNativeMethodType(sigPos, long.class);
 171             adapters.add(direction.pointerAdapter(sigPos, lt));
 172         } else if (carrier == Callback.class) {
 173             updateNativeMethodType(sigPos, long.class);
 174             adapters.add(direction.callbackAdapter(sigPos, lt));
 175         } else if (Util.isCStruct(carrier)) {
 176             if (bindings.size() == 1) {
 177                 ArgumentBinding binding = bindings.get(0);
 178                 switch (binding.storage().getStorageClass()) {
 179                     case INTEGER_ARGUMENT_REGISTER:
 180                     case INTEGER_RETURN_REGISTER:
 181                         updateNativeMethodType(sigPos, long.class);
 182                         adapters.add(direction.longStructAdapter(sigPos, carrier));
 183                         break;
 184                     case VECTOR_ARGUMENT_REGISTER:
 185                     case VECTOR_RETURN_REGISTER:
 186                         updateNativeMethodType(sigPos, double.class);
 187                         adapters.add(direction.doubleStructAdapter(sigPos, carrier));
 188                         break;
 189                     default:
 190                         //non-register bindings should have already been discarded by now
 191                         throw new IllegalStateException("Cannot get here!");
 192                 }
 193             } else {
 194                 throw new IllegalArgumentException("Multi-value struct!");
 195             }
 196         } else {
 197             throw new IllegalArgumentException("Unsupported carrier: " + carrier);
 198         }


 372         MethodHandle mh = MethodHandles.identity(double.class);
 373         return MethodHandles.explicitCastArguments(mh, MethodType.methodType(double.class, carrier));
 374     }
 375 
 376     private static MethodHandle doubleToPrimitive(Class<?> carrier) {
 377         MethodHandle mh = MethodHandles.identity(double.class);
 378         return MethodHandles.explicitCastArguments(mh, MethodType.methodType(carrier, double.class));
 379     }
 380 
 381     // predicate: is fast path applicable?
 382 
 383     public static boolean acceptDowncall(NativeMethodType nmt, CallingSequence callingSequence) {
 384         return accept(nmt, callingSequence, ShuffleDirection.JAVA_TO_NATIVE);
 385     }
 386 
 387     public static boolean acceptUpcall(NativeMethodType nmt, CallingSequence callingSequence) {
 388         return accept(nmt, callingSequence, ShuffleDirection.NATIVE_TO_JAVA);
 389     }
 390 
 391     private static boolean accept(NativeMethodType nmt, CallingSequence callingSequence, ShuffleDirection direction) {
 392         if (nmt.isVarArgs() ||
 393                 callingSequence.returnsInMemory() ||
 394                 nmt.parameterCount() > direction.maxArity) return false;
 395 
 396         for (int i = 0 ; i < nmt.parameterCount(); i++) {
 397             List<ArgumentBinding> argumentBindings = callingSequence.argumentBindings(i);
 398             if (argumentBindings.size() != 1 ||
 399                     !isDirectBinding(argumentBindings.get(0))) {
 400                 return false;
 401             }
 402         }
 403 
 404         List<ArgumentBinding> returnBindings = callingSequence.returnBindings();
 405         return returnBindings.isEmpty() ||
 406                 (returnBindings.size() == 1 && isDirectBinding(returnBindings.get(0)));




 407     }
 408 
 409     private static boolean isDirectBinding(ArgumentBinding binding) {
 410         switch (binding.storage().getStorageClass()) {
 411             case X87_RETURN_REGISTER:
 412             case STACK_ARGUMENT_SLOT:
 413                 //arguments passed in memory not supported
 414                 return false;
 415             case VECTOR_ARGUMENT_REGISTER:
 416             case VECTOR_RETURN_REGISTER:
 417                 //avoid passing around floats as doubles as that leads to trouble
 418                 return (binding.argument().layout().bitsSize() / 8) == binding.storage().getSize();
 419             default:
 420                 return true;
 421         }
 422     }
 423 }
< prev index next >