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