< prev index next >

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

Print this page
*** 28,20 ***
  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.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 java.lang.invoke.MethodHandle;
  import java.lang.invoke.MethodType;
  import java.util.List;
  import java.util.Optional;
--- 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.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 ***
  /**
   * 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.
   */
! public 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;
  
--- 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 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 ***
              this.callingSequence = callingSequence;
              this.isInMemoryReturn = isInMemoryReturn;
          }
      }
  
!     public static Bindings getBindings(MethodType mt, FunctionDescriptor cDesc, boolean forUpcall) {
!         SharedUtils.checkFunctionTypes(mt, cDesc, AArch64.C_POINTER.bitSize());
  
          CallingSequenceBuilder csb = new CallingSequenceBuilder(forUpcall);
  
          BindingCalculator argCalc = forUpcall ? new BoxBindingCalculator(true) : new UnboxBindingCalculator(true);
          BindingCalculator retCalc = forUpcall ? new UnboxBindingCalculator(false) : new BoxBindingCalculator(false);
  
--- 100,24 ---
              this.callingSequence = callingSequence;
              this.isInMemoryReturn = isInMemoryReturn;
          }
      }
  
!     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 ***
          }
  
          for (int i = 0; i < mt.parameterCount(); i++) {
              Class<?> carrier = mt.parameterType(i);
              MemoryLayout layout = cDesc.argumentLayouts().get(i);
              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) {
          Bindings bindings = getBindings(mt, cDesc, false);
  
          MethodHandle handle = new ProgrammableInvoker(C, bindings.callingSequence).getBoundMethodHandle();
  
          if (bindings.isInMemoryReturn) {
--- 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 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 ***
          }
  
          return handle;
      }
  
!     public static UpcallHandler arrangeUpcall(MethodHandle target, MethodType mt, FunctionDescriptor cDesc) {
          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);
      }
  
      private static boolean isInMemoryReturn(Optional<MemoryLayout> returnLayout) {
          return returnLayout
              .filter(GroupLayout.class::isInstance)
--- 155,18 ---
          }
  
          return handle;
      }
  
!     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,scope);
      }
  
      private static boolean isInMemoryReturn(Optional<MemoryLayout> returnLayout) {
          return returnLayout
              .filter(GroupLayout.class::isInstance)

*** 206,18 ***
              }
  
              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;
-             }
          }
      }
  
      static abstract class BindingCalculator {
          protected final StorageCalculator storageCalculator;
--- 227,15 ---
              }
  
              return storage[0];
          }
  
!         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 ***
  
          @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);
--- 304,10 ---

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

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

*** 389,11 ***
  
          @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(
--- 405,10 ---
< prev index next >