< prev index next >

src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/aarch64/CallArranger.java

Print this page
@@ -28,20 +28,23 @@
  import jdk.incubator.foreign.FunctionDescriptor;
  import jdk.incubator.foreign.GroupLayout;
  import jdk.incubator.foreign.MemoryAddress;
  import jdk.incubator.foreign.MemoryLayout;
  import jdk.incubator.foreign.MemorySegment;
+ import jdk.incubator.foreign.NativeSymbol;
+ import jdk.incubator.foreign.ResourceScope;
  import jdk.internal.foreign.Utils;
  import jdk.internal.foreign.abi.CallingSequenceBuilder;
- import jdk.internal.foreign.abi.UpcallHandler;
  import jdk.internal.foreign.abi.ABIDescriptor;
  import jdk.internal.foreign.abi.Binding;
  import jdk.internal.foreign.abi.CallingSequence;
  import jdk.internal.foreign.abi.ProgrammableInvoker;
  import jdk.internal.foreign.abi.ProgrammableUpcallHandler;
  import jdk.internal.foreign.abi.VMStorage;
  import jdk.internal.foreign.abi.SharedUtils;
+ import jdk.internal.foreign.abi.aarch64.linux.LinuxAArch64CallArranger;
+ import jdk.internal.foreign.abi.aarch64.macos.MacOsAArch64CallArranger;
  
  import java.lang.invoke.MethodHandle;
  import java.lang.invoke.MethodType;
  import java.util.List;
  import java.util.Optional;

@@ -52,12 +55,16 @@
  /**
   * For the AArch64 C ABI specifically, this class uses the ProgrammableInvoker API, namely CallingSequenceBuilder2
   * to translate a C FunctionDescriptor into a CallingSequence2, which can then be turned into a MethodHandle.
   *
   * This includes taking care of synthetic arguments like pointers to return buffers for 'in-memory' returns.
+  *
+  * There are minor differences between the ABIs implemented on Linux, macOS, and Windows
+  * which are handled in sub-classes. Clients should access these through the provided
+  * public constants CallArranger.LINUX and CallArranger.MACOS.
   */
- public class CallArranger {
+ public abstract class CallArranger {
      private static final int STACK_SLOT_SIZE = 8;
      public static final int MAX_REGISTER_ARGUMENTS = 8;
  
      private static final VMStorage INDIRECT_RESULT = r8;
  

@@ -93,13 +100,24 @@
              this.callingSequence = callingSequence;
              this.isInMemoryReturn = isInMemoryReturn;
          }
      }
  
-     public static Bindings getBindings(MethodType mt, FunctionDescriptor cDesc, boolean forUpcall) {
-         SharedUtils.checkFunctionTypes(mt, cDesc, AArch64.C_POINTER.bitSize());
+     public static final CallArranger LINUX = new LinuxAArch64CallArranger();
+     public static final CallArranger MACOS = new MacOsAArch64CallArranger();
+ 
+     /**
+      * Are variadic arguments assigned to registers as in the standard calling
+      * convention, or always passed on the stack?
+      *
+      * @returns true if variadic arguments should be spilled to the stack.
+      */
+     protected abstract boolean varArgsOnStack();
+ 
+     protected CallArranger() {}
  
+     public Bindings getBindings(MethodType mt, FunctionDescriptor cDesc, boolean forUpcall) {
          CallingSequenceBuilder csb = new CallingSequenceBuilder(forUpcall);
  
          BindingCalculator argCalc = forUpcall ? new BoxBindingCalculator(true) : new UnboxBindingCalculator(true);
          BindingCalculator retCalc = forUpcall ? new UnboxBindingCalculator(false) : new BoxBindingCalculator(false);
  

@@ -114,19 +132,22 @@
          }
  
          for (int i = 0; i < mt.parameterCount(); i++) {
              Class<?> carrier = mt.parameterType(i);
              MemoryLayout layout = cDesc.argumentLayouts().get(i);
+             if (varArgsOnStack() && SharedUtils.isVarargsIndex(cDesc, i)) {
+                 argCalc.storageCalculator.adjustForVarArgs();
+             }
              csb.addArgumentBindings(carrier, layout, argCalc.getBindings(carrier, layout));
          }
  
          csb.setTrivial(SharedUtils.isTrivial(cDesc));
  
          return new Bindings(csb.build(), returnInMemory);
      }
  
-     public static MethodHandle arrangeDowncall(MethodType mt, FunctionDescriptor cDesc) {
+     public MethodHandle arrangeDowncall(MethodType mt, FunctionDescriptor cDesc) {
          Bindings bindings = getBindings(mt, cDesc, false);
  
          MethodHandle handle = new ProgrammableInvoker(C, bindings.callingSequence).getBoundMethodHandle();
  
          if (bindings.isInMemoryReturn) {

@@ -134,18 +155,18 @@
          }
  
          return handle;
      }
  
-     public static UpcallHandler arrangeUpcall(MethodHandle target, MethodType mt, FunctionDescriptor cDesc) {
+     public NativeSymbol arrangeUpcall(MethodHandle target, MethodType mt, FunctionDescriptor cDesc, ResourceScope scope) {
          Bindings bindings = getBindings(mt, cDesc, true);
  
          if (bindings.isInMemoryReturn) {
              target = SharedUtils.adaptUpcallForIMR(target, true /* drop return, since we don't have bindings for it */);
          }
  
-         return ProgrammableUpcallHandler.make(C, target, bindings.callingSequence);
+         return ProgrammableUpcallHandler.make(C, target, bindings.callingSequence,scope);
      }
  
      private static boolean isInMemoryReturn(Optional<MemoryLayout> returnLayout) {
          return returnLayout
              .filter(GroupLayout.class::isInstance)

@@ -206,18 +227,15 @@
              }
  
              return storage[0];
          }
  
-         void adjustForVarArgs(MemoryLayout layout) {
-             if (layout.attribute(AArch64.STACK_VARARGS_ATTRIBUTE_NAME)
-                     .map(Boolean.class::cast).orElse(false)) {
-                 // This system passes all variadic parameters on the stack. Ensure
-                 // no further arguments are allocated to registers.
-                 nRegs[StorageClasses.INTEGER] = MAX_REGISTER_ARGUMENTS;
-                 nRegs[StorageClasses.VECTOR] = MAX_REGISTER_ARGUMENTS;
-             }
+         void adjustForVarArgs() {
+             // This system passes all variadic parameters on the stack. Ensure
+             // no further arguments are allocated to registers.
+             nRegs[StorageClasses.INTEGER] = MAX_REGISTER_ARGUMENTS;
+             nRegs[StorageClasses.VECTOR] = MAX_REGISTER_ARGUMENTS;
          }
      }
  
      static abstract class BindingCalculator {
          protected final StorageCalculator storageCalculator;

@@ -286,11 +304,10 @@
  
          @Override
          List<Binding> getBindings(Class<?> carrier, MemoryLayout layout) {
              TypeClass argumentClass = TypeClass.classifyLayout(layout);
              Binding.Builder bindings = Binding.builder();
-             storageCalculator.adjustForVarArgs(layout);
              switch (argumentClass) {
                  case STRUCT_REGISTER: {
                      assert carrier == MemorySegment.class;
                      VMStorage[] regs = storageCalculator.regAlloc(
                          StorageClasses.INTEGER, layout);

@@ -315,12 +332,11 @@
                      break;
                  }
                  case STRUCT_REFERENCE: {
                      assert carrier == MemorySegment.class;
                      bindings.copy(layout)
-                             .baseAddress()
-                             .unboxAddress();
+                             .unboxAddress(MemorySegment.class);
                      VMStorage storage = storageCalculator.nextStorage(
                          StorageClasses.INTEGER, AArch64.C_POINTER);
                      bindings.vmStore(storage, long.class);
                      break;
                  }

@@ -347,11 +363,11 @@
                          spillStructUnbox(bindings, layout);
                      }
                      break;
                  }
                  case POINTER: {
-                     bindings.unboxAddress();
+                     bindings.unboxAddress(carrier);
                      VMStorage storage =
                          storageCalculator.nextStorage(StorageClasses.INTEGER, layout);
                      bindings.vmStore(storage, long.class);
                      break;
                  }

@@ -389,11 +405,10 @@
  
          @Override
          List<Binding> getBindings(Class<?> carrier, MemoryLayout layout) {
              TypeClass argumentClass = TypeClass.classifyLayout(layout);
              Binding.Builder bindings = Binding.builder();
-             assert !layout.attribute(AArch64.STACK_VARARGS_ATTRIBUTE_NAME).isPresent() : "no variadic upcalls";
              switch (argumentClass) {
                  case STRUCT_REGISTER: {
                      assert carrier == MemorySegment.class;
                      bindings.allocate(layout);
                      VMStorage[] regs = storageCalculator.regAlloc(
< prev index next >