< prev index next >

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

Print this page

 71     // This is derived from the AAPCS64 spec, restricted to what's
 72     // possible when calling to/from C code.
 73     //
 74     // The indirect result register, r8, is used to return a large
 75     // struct by value. It's treated as an input here as the caller is
 76     // responsible for allocating storage and passing this into the
 77     // function.
 78     //
 79     // Although the AAPCS64 says r0-7 and v0-7 are all valid return
 80     // registers, it's not possible to generate a C function that uses
 81     // r2-7 and v4-7 so they are omitted here.
 82     private static final ABIDescriptor C = AArch64Architecture.abiFor(
 83         new VMStorage[] { r0, r1, r2, r3, r4, r5, r6, r7, INDIRECT_RESULT},
 84         new VMStorage[] { v0, v1, v2, v3, v4, v5, v6, v7 },
 85         new VMStorage[] { r0, r1 },
 86         new VMStorage[] { v0, v1, v2, v3 },
 87         new VMStorage[] { r9, r10, r11, r12, r13, r14, r15 },
 88         new VMStorage[] { v16, v17, v18, v19, v20, v21, v22, v23, v25,
 89                           v26, v27, v28, v29, v30, v31 },
 90         16,  // Stack is always 16 byte aligned on AArch64
 91         0    // No shadow space


 92     );
 93 
 94     // record
 95     public static class Bindings {
 96         public final CallingSequence callingSequence;
 97         public final boolean isInMemoryReturn;
 98 
 99         Bindings(CallingSequence callingSequence, boolean isInMemoryReturn) {
100             this.callingSequence = callingSequence;
101             this.isInMemoryReturn = isInMemoryReturn;
102         }
103     }
104 
105     public static final CallArranger LINUX = new LinuxAArch64CallArranger();
106     public static final CallArranger MACOS = new MacOsAArch64CallArranger();
107 
108     /**
109      * Are variadic arguments assigned to registers as in the standard calling
110      * convention, or always passed on the stack?
111      *
112      * @returns true if variadic arguments should be spilled to the stack.
113      */
114     protected abstract boolean varArgsOnStack();
115 
116     protected CallArranger() {}
117 
118     public Bindings getBindings(MethodType mt, FunctionDescriptor cDesc, boolean forUpcall) {
119         CallingSequenceBuilder csb = new CallingSequenceBuilder(forUpcall);
120 
121         BindingCalculator argCalc = forUpcall ? new BoxBindingCalculator(true) : new UnboxBindingCalculator(true);
122         BindingCalculator retCalc = forUpcall ? new UnboxBindingCalculator(false) : new BoxBindingCalculator(false);
123 
124         boolean returnInMemory = isInMemoryReturn(cDesc.returnLayout());
125         if (returnInMemory) {
126             csb.addArgumentBindings(MemoryAddress.class, AArch64.C_POINTER,
127                     argCalc.getIndirectBindings());
128         } else if (cDesc.returnLayout().isPresent()) {
129             Class<?> carrier = mt.returnType();
130             MemoryLayout layout = cDesc.returnLayout().get();
131             csb.setReturnBindings(carrier, layout, retCalc.getBindings(carrier, layout));
132         }
133 
134         for (int i = 0; i < mt.parameterCount(); i++) {
135             Class<?> carrier = mt.parameterType(i);
136             MemoryLayout layout = cDesc.argumentLayouts().get(i);
137             if (varArgsOnStack() && SharedUtils.isVarargsIndex(cDesc, i)) {
138                 argCalc.storageCalculator.adjustForVarArgs();
139             }

220             return regAlloc(type, (int)Utils.alignUp(layout.byteSize(), 8) / 8);
221         }
222 
223         VMStorage nextStorage(int type, MemoryLayout layout) {
224             VMStorage[] storage = regAlloc(type, 1);
225             if (storage == null) {
226                 return stackAlloc(layout);
227             }
228 
229             return storage[0];
230         }
231 
232         void adjustForVarArgs() {
233             // This system passes all variadic parameters on the stack. Ensure
234             // no further arguments are allocated to registers.
235             nRegs[StorageClasses.INTEGER] = MAX_REGISTER_ARGUMENTS;
236             nRegs[StorageClasses.VECTOR] = MAX_REGISTER_ARGUMENTS;
237         }
238     }
239 
240     abstract static class BindingCalculator {
241         protected final StorageCalculator storageCalculator;
242 
243         protected BindingCalculator(boolean forArguments) {
244             this.storageCalculator = new StorageCalculator(forArguments);
245         }
246 
247         protected void spillStructUnbox(Binding.Builder bindings, MemoryLayout layout) {
248             // If a struct has been assigned register or HFA class but
249             // there are not enough free registers to hold the entire
250             // struct, it must be passed on the stack. I.e. not split
251             // between registers and stack.
252 
253             long offset = 0;
254             while (offset < layout.byteSize()) {
255                 long copy = Math.min(layout.byteSize() - offset, STACK_SLOT_SIZE);
256                 VMStorage storage =
257                     storageCalculator.stackAlloc(copy, STACK_SLOT_SIZE);
258                 if (offset + STACK_SLOT_SIZE < layout.byteSize()) {
259                     bindings.dup();
260                 }

 71     // This is derived from the AAPCS64 spec, restricted to what's
 72     // possible when calling to/from C code.
 73     //
 74     // The indirect result register, r8, is used to return a large
 75     // struct by value. It's treated as an input here as the caller is
 76     // responsible for allocating storage and passing this into the
 77     // function.
 78     //
 79     // Although the AAPCS64 says r0-7 and v0-7 are all valid return
 80     // registers, it's not possible to generate a C function that uses
 81     // r2-7 and v4-7 so they are omitted here.
 82     private static final ABIDescriptor C = AArch64Architecture.abiFor(
 83         new VMStorage[] { r0, r1, r2, r3, r4, r5, r6, r7, INDIRECT_RESULT},
 84         new VMStorage[] { v0, v1, v2, v3, v4, v5, v6, v7 },
 85         new VMStorage[] { r0, r1 },
 86         new VMStorage[] { v0, v1, v2, v3 },
 87         new VMStorage[] { r9, r10, r11, r12, r13, r14, r15 },
 88         new VMStorage[] { v16, v17, v18, v19, v20, v21, v22, v23, v25,
 89                           v26, v27, v28, v29, v30, v31 },
 90         16,  // Stack is always 16 byte aligned on AArch64
 91         0,   // No shadow space
 92         r9,  // target addr reg
 93         r10  // return buffer addr reg
 94     );
 95 
 96     // record
 97     public static class Bindings {
 98         public final CallingSequence callingSequence;
 99         public final boolean isInMemoryReturn;
100 
101         Bindings(CallingSequence callingSequence, boolean isInMemoryReturn) {
102             this.callingSequence = callingSequence;
103             this.isInMemoryReturn = isInMemoryReturn;
104         }
105     }
106 
107     public static final CallArranger LINUX = new LinuxAArch64CallArranger();
108     public static final CallArranger MACOS = new MacOsAArch64CallArranger();
109 
110     /**
111      * Are variadic arguments assigned to registers as in the standard calling
112      * convention, or always passed on the stack?
113      *
114      * @returns true if variadic arguments should be spilled to the stack.
115      */
116     protected abstract boolean varArgsOnStack();
117 
118     protected CallArranger() {}
119 
120     public Bindings getBindings(MethodType mt, FunctionDescriptor cDesc, boolean forUpcall) {
121         CallingSequenceBuilder csb = new CallingSequenceBuilder(C, forUpcall);
122 
123         BindingCalculator argCalc = forUpcall ? new BoxBindingCalculator(true) : new UnboxBindingCalculator(true);
124         BindingCalculator retCalc = forUpcall ? new UnboxBindingCalculator(false) : new BoxBindingCalculator(false);
125 
126         boolean returnInMemory = isInMemoryReturn(cDesc.returnLayout());
127         if (returnInMemory) {
128             csb.addArgumentBindings(MemoryAddress.class, AArch64.C_POINTER,
129                     argCalc.getIndirectBindings());
130         } else if (cDesc.returnLayout().isPresent()) {
131             Class<?> carrier = mt.returnType();
132             MemoryLayout layout = cDesc.returnLayout().get();
133             csb.setReturnBindings(carrier, layout, retCalc.getBindings(carrier, layout));
134         }
135 
136         for (int i = 0; i < mt.parameterCount(); i++) {
137             Class<?> carrier = mt.parameterType(i);
138             MemoryLayout layout = cDesc.argumentLayouts().get(i);
139             if (varArgsOnStack() && SharedUtils.isVarargsIndex(cDesc, i)) {
140                 argCalc.storageCalculator.adjustForVarArgs();
141             }

222             return regAlloc(type, (int)Utils.alignUp(layout.byteSize(), 8) / 8);
223         }
224 
225         VMStorage nextStorage(int type, MemoryLayout layout) {
226             VMStorage[] storage = regAlloc(type, 1);
227             if (storage == null) {
228                 return stackAlloc(layout);
229             }
230 
231             return storage[0];
232         }
233 
234         void adjustForVarArgs() {
235             // This system passes all variadic parameters on the stack. Ensure
236             // no further arguments are allocated to registers.
237             nRegs[StorageClasses.INTEGER] = MAX_REGISTER_ARGUMENTS;
238             nRegs[StorageClasses.VECTOR] = MAX_REGISTER_ARGUMENTS;
239         }
240     }
241 
242     static abstract class BindingCalculator {
243         protected final StorageCalculator storageCalculator;
244 
245         protected BindingCalculator(boolean forArguments) {
246             this.storageCalculator = new StorageCalculator(forArguments);
247         }
248 
249         protected void spillStructUnbox(Binding.Builder bindings, MemoryLayout layout) {
250             // If a struct has been assigned register or HFA class but
251             // there are not enough free registers to hold the entire
252             // struct, it must be passed on the stack. I.e. not split
253             // between registers and stack.
254 
255             long offset = 0;
256             while (offset < layout.byteSize()) {
257                 long copy = Math.min(layout.byteSize() - offset, STACK_SLOT_SIZE);
258                 VMStorage storage =
259                     storageCalculator.stackAlloc(copy, STACK_SLOT_SIZE);
260                 if (offset + STACK_SLOT_SIZE < layout.byteSize()) {
261                     bindings.dup();
262                 }
< prev index next >