14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 *
25 */
26 package jdk.internal.foreign.abi.x64.sysv;
27
28 import jdk.incubator.foreign.CSupport;
29 import jdk.incubator.foreign.GroupLayout;
30 import jdk.incubator.foreign.MemoryAddress;
31 import jdk.incubator.foreign.MemoryHandles;
32 import jdk.incubator.foreign.MemoryLayout;
33 import jdk.incubator.foreign.MemorySegment;
34 import jdk.internal.foreign.Utils;
35 import jdk.internal.foreign.abi.SharedUtils;
36
37 import java.lang.invoke.VarHandle;
38 import java.nio.ByteOrder;
39 import java.util.ArrayList;
40 import java.util.List;
41
42 import static jdk.incubator.foreign.CSupport.SysV;
43 import static jdk.incubator.foreign.CSupport.VaList;
44 import static jdk.incubator.foreign.MemoryLayout.PathElement.groupElement;
45 import static jdk.internal.foreign.abi.SharedUtils.SimpleVaArg;
46 import static jdk.internal.foreign.abi.SharedUtils.checkCompatibleType;
47 import static jdk.internal.foreign.abi.SharedUtils.vhPrimitiveOrAddress;
48
49 // See https://software.intel.com/sites/default/files/article/402129/mpx-linux64-abi.pdf "3.5.7 Variable Argument Lists"
50 public class SysVVaList implements VaList {
51 static final Class<?> CARRIER = MemoryAddress.class;
52
53 // struct typedef __va_list_tag __va_list_tag {
54 // unsigned int gp_offset; /* 0 4 */
55 // unsigned int fp_offset; /* 4 4 */
56 // void * overflow_arg_area; /* 8 8 */
57 // void * reg_save_area; /* 16 8 */
94 // FP_REG.withName("%xmm13"),
95 // FP_REG.withName("%xmm14"),
96 // FP_REG.withName("%xmm15")
97 );
98
99 private static final long FP_OFFSET = LAYOUT_REG_SAVE_AREA.byteOffset(groupElement("%xmm0"));
100
101 private static final int GP_SLOT_SIZE = (int) GP_REG.byteSize();
102 private static final int FP_SLOT_SIZE = (int) FP_REG.byteSize();
103
104 private static final int MAX_GP_OFFSET = (int) FP_OFFSET; // 6 regs used
105 private static final int MAX_FP_OFFSET = (int) LAYOUT_REG_SAVE_AREA.byteSize(); // 8 16 byte regs
106
107 private static final VarHandle VH_fp_offset = LAYOUT.varHandle(int.class, groupElement("fp_offset"));
108 private static final VarHandle VH_gp_offset = LAYOUT.varHandle(int.class, groupElement("gp_offset"));
109 private static final VarHandle VH_overflow_arg_area
110 = MemoryHandles.asAddressVarHandle(LAYOUT.varHandle(long.class, groupElement("overflow_arg_area")));
111 private static final VarHandle VH_reg_save_area
112 = MemoryHandles.asAddressVarHandle(LAYOUT.varHandle(long.class, groupElement("reg_save_area")));
113
114 private final MemorySegment segment;
115 private final List<MemorySegment> slices = new ArrayList<>();
116 private final MemorySegment regSaveArea;
117
118 SysVVaList(MemorySegment segment) {
119 this.segment = segment;
120 regSaveArea = regSaveArea();
121 slices.add(regSaveArea);
122 }
123
124 private int currentGPOffset() {
125 return (int) VH_gp_offset.get(segment.baseAddress());
126 }
127
128 private void currentGPOffset(int i) {
129 VH_gp_offset.set(segment.baseAddress(), i);
130 }
131
132 private int currentFPOffset() {
133 return (int) VH_fp_offset.get(segment.baseAddress());
134 }
135
136 private void currentFPOffset(int i) {
137 VH_fp_offset.set(segment.baseAddress(), i);
138 }
139
140 private MemoryAddress stackPtr() {
141 return (MemoryAddress) VH_overflow_arg_area.get(segment.baseAddress());
142 }
143
252 for (MemoryLayout layout : layouts) {
253 TypeClass typeClass = TypeClass.classifyLayout(layout);
254 if (isRegOverflow(currentGPOffset(), currentFPOffset(), typeClass)) {
255 preAlignStack(layout);
256 postAlignStack(layout);
257 } else {
258 currentGPOffset(currentGPOffset() + (((int) typeClass.nIntegerRegs()) * GP_SLOT_SIZE));
259 currentFPOffset(currentFPOffset() + (((int) typeClass.nVectorRegs()) * FP_SLOT_SIZE));
260 }
261 }
262 }
263
264 static SysVVaList.Builder builder() {
265 return new SysVVaList.Builder();
266 }
267
268 public static VaList ofAddress(MemoryAddress ma) {
269 return new SysVVaList(MemorySegment.ofNativeRestricted(ma, LAYOUT.byteSize(), Thread.currentThread(), null, null));
270 }
271
272 MemorySegment getSegment() {
273 return segment;
274 }
275
276 @Override
277 public boolean isAlive() {
278 return segment.isAlive();
279 }
280
281 @Override
282 public void close() {
283 segment.close();
284 slices.forEach(MemorySegment::close);
285 }
286
287 @Override
288 public VaList copy() {
289 MemorySegment copy = MemorySegment.allocateNative(LAYOUT.byteSize());
290 copy.copyFrom(segment);
291 return new SysVVaList(copy);
292 }
293
294 @Override
295 public MemoryAddress address() {
366 currentGPOffset += GP_SLOT_SIZE;
367 }
368 offset += copy;
369 }
370 }
371 case POINTER, INTEGER -> {
372 VarHandle writer = SharedUtils.vhPrimitiveOrAddress(carrier, layout);
373 writer.set(reg_save_area.baseAddress().addOffset(currentGPOffset), value);
374 currentGPOffset += GP_SLOT_SIZE;
375 }
376 case FLOAT -> {
377 VarHandle writer = layout.varHandle(carrier);
378 writer.set(reg_save_area.baseAddress().addOffset(currentFPOffset), value);
379 currentFPOffset += FP_SLOT_SIZE;
380 }
381 }
382 }
383 return this;
384 }
385
386 public SysVVaList build() {
387 MemorySegment vaListSegment = MemorySegment.allocateNative(LAYOUT.byteSize());
388 SysVVaList res = new SysVVaList(vaListSegment);
389 MemoryAddress stackArgsPtr = MemoryAddress.NULL;
390 if (!stackArgs.isEmpty()) {
391 long stackArgsSize = stackArgs.stream().reduce(0L, (acc, e) -> acc + e.layout.byteSize(), Long::sum);
392 MemorySegment stackArgsSegment = MemorySegment.allocateNative(stackArgsSize, 16);
393 MemoryAddress maOverflowArgArea = stackArgsSegment.baseAddress();
394 for (SimpleVaArg arg : stackArgs) {
395 if (arg.layout.byteSize() > 8) {
396 maOverflowArgArea = Utils.alignUp(maOverflowArgArea, Math.min(16, arg.layout.byteSize()));
397 }
398 VarHandle writer = arg.varHandle();
399 writer.set(maOverflowArgArea, arg.value);
400 maOverflowArgArea = maOverflowArgArea.addOffset(arg.layout.byteSize());
401 }
402 stackArgsPtr = stackArgsSegment.baseAddress();
403 res.slices.add(stackArgsSegment);
404 }
405
406 MemoryAddress vaListAddr = vaListSegment.baseAddress();
|
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 *
25 */
26 package jdk.internal.foreign.abi.x64.sysv;
27
28 import jdk.incubator.foreign.CSupport;
29 import jdk.incubator.foreign.GroupLayout;
30 import jdk.incubator.foreign.MemoryAddress;
31 import jdk.incubator.foreign.MemoryHandles;
32 import jdk.incubator.foreign.MemoryLayout;
33 import jdk.incubator.foreign.MemorySegment;
34 import jdk.internal.foreign.AbstractMemorySegmentImpl;
35 import jdk.internal.foreign.NativeMemorySegmentImpl;
36 import jdk.internal.foreign.Utils;
37 import jdk.internal.foreign.abi.SharedUtils;
38
39 import java.lang.invoke.VarHandle;
40 import java.lang.ref.Cleaner;
41 import java.nio.ByteOrder;
42 import java.util.ArrayList;
43 import java.util.List;
44
45 import static jdk.incubator.foreign.CSupport.SysV;
46 import static jdk.incubator.foreign.CSupport.VaList;
47 import static jdk.incubator.foreign.MemoryLayout.PathElement.groupElement;
48 import static jdk.internal.foreign.abi.SharedUtils.SimpleVaArg;
49 import static jdk.internal.foreign.abi.SharedUtils.checkCompatibleType;
50 import static jdk.internal.foreign.abi.SharedUtils.vhPrimitiveOrAddress;
51
52 // See https://software.intel.com/sites/default/files/article/402129/mpx-linux64-abi.pdf "3.5.7 Variable Argument Lists"
53 public class SysVVaList implements VaList {
54 static final Class<?> CARRIER = MemoryAddress.class;
55
56 // struct typedef __va_list_tag __va_list_tag {
57 // unsigned int gp_offset; /* 0 4 */
58 // unsigned int fp_offset; /* 4 4 */
59 // void * overflow_arg_area; /* 8 8 */
60 // void * reg_save_area; /* 16 8 */
97 // FP_REG.withName("%xmm13"),
98 // FP_REG.withName("%xmm14"),
99 // FP_REG.withName("%xmm15")
100 );
101
102 private static final long FP_OFFSET = LAYOUT_REG_SAVE_AREA.byteOffset(groupElement("%xmm0"));
103
104 private static final int GP_SLOT_SIZE = (int) GP_REG.byteSize();
105 private static final int FP_SLOT_SIZE = (int) FP_REG.byteSize();
106
107 private static final int MAX_GP_OFFSET = (int) FP_OFFSET; // 6 regs used
108 private static final int MAX_FP_OFFSET = (int) LAYOUT_REG_SAVE_AREA.byteSize(); // 8 16 byte regs
109
110 private static final VarHandle VH_fp_offset = LAYOUT.varHandle(int.class, groupElement("fp_offset"));
111 private static final VarHandle VH_gp_offset = LAYOUT.varHandle(int.class, groupElement("gp_offset"));
112 private static final VarHandle VH_overflow_arg_area
113 = MemoryHandles.asAddressVarHandle(LAYOUT.varHandle(long.class, groupElement("overflow_arg_area")));
114 private static final VarHandle VH_reg_save_area
115 = MemoryHandles.asAddressVarHandle(LAYOUT.varHandle(long.class, groupElement("reg_save_area")));
116
117 private static final Cleaner cleaner = Cleaner.create();
118 private static final CSupport.VaList EMPTY = new SharedUtils.EmptyVaList(emptyListAddress());
119
120 private final MemorySegment segment;
121 private final List<MemorySegment> slices = new ArrayList<>();
122 private final MemorySegment regSaveArea;
123
124 SysVVaList(MemorySegment segment) {
125 this.segment = segment;
126 regSaveArea = regSaveArea();
127 slices.add(regSaveArea);
128 }
129
130 private static MemoryAddress emptyListAddress() {
131 MemorySegment ms = MemorySegment.allocateNative(LAYOUT);
132 cleaner.register(SysVVaList.class, ms::close);
133 MemoryAddress base = ms.baseAddress();
134 VH_gp_offset.set(base, MAX_GP_OFFSET);
135 VH_fp_offset.set(base, MAX_FP_OFFSET);
136 VH_overflow_arg_area.set(base, MemoryAddress.NULL);
137 VH_reg_save_area.set(base, MemoryAddress.NULL);
138 MemorySegment unconfined = NativeMemorySegmentImpl.makeNativeSegmentUnchecked(
139 base, ms.byteSize(), null, null, null).withAccessModes(0);
140 return unconfined.baseAddress();
141 }
142
143 public static CSupport.VaList empty() {
144 return EMPTY;
145 }
146
147 private int currentGPOffset() {
148 return (int) VH_gp_offset.get(segment.baseAddress());
149 }
150
151 private void currentGPOffset(int i) {
152 VH_gp_offset.set(segment.baseAddress(), i);
153 }
154
155 private int currentFPOffset() {
156 return (int) VH_fp_offset.get(segment.baseAddress());
157 }
158
159 private void currentFPOffset(int i) {
160 VH_fp_offset.set(segment.baseAddress(), i);
161 }
162
163 private MemoryAddress stackPtr() {
164 return (MemoryAddress) VH_overflow_arg_area.get(segment.baseAddress());
165 }
166
275 for (MemoryLayout layout : layouts) {
276 TypeClass typeClass = TypeClass.classifyLayout(layout);
277 if (isRegOverflow(currentGPOffset(), currentFPOffset(), typeClass)) {
278 preAlignStack(layout);
279 postAlignStack(layout);
280 } else {
281 currentGPOffset(currentGPOffset() + (((int) typeClass.nIntegerRegs()) * GP_SLOT_SIZE));
282 currentFPOffset(currentFPOffset() + (((int) typeClass.nVectorRegs()) * FP_SLOT_SIZE));
283 }
284 }
285 }
286
287 static SysVVaList.Builder builder() {
288 return new SysVVaList.Builder();
289 }
290
291 public static VaList ofAddress(MemoryAddress ma) {
292 return new SysVVaList(MemorySegment.ofNativeRestricted(ma, LAYOUT.byteSize(), Thread.currentThread(), null, null));
293 }
294
295 @Override
296 public boolean isAlive() {
297 return segment.isAlive();
298 }
299
300 @Override
301 public void close() {
302 segment.close();
303 slices.forEach(MemorySegment::close);
304 }
305
306 @Override
307 public VaList copy() {
308 MemorySegment copy = MemorySegment.allocateNative(LAYOUT.byteSize());
309 copy.copyFrom(segment);
310 return new SysVVaList(copy);
311 }
312
313 @Override
314 public MemoryAddress address() {
385 currentGPOffset += GP_SLOT_SIZE;
386 }
387 offset += copy;
388 }
389 }
390 case POINTER, INTEGER -> {
391 VarHandle writer = SharedUtils.vhPrimitiveOrAddress(carrier, layout);
392 writer.set(reg_save_area.baseAddress().addOffset(currentGPOffset), value);
393 currentGPOffset += GP_SLOT_SIZE;
394 }
395 case FLOAT -> {
396 VarHandle writer = layout.varHandle(carrier);
397 writer.set(reg_save_area.baseAddress().addOffset(currentFPOffset), value);
398 currentFPOffset += FP_SLOT_SIZE;
399 }
400 }
401 }
402 return this;
403 }
404
405 private boolean isEmpty() {
406 return currentGPOffset == 0 && currentFPOffset == FP_OFFSET && stackArgs.isEmpty();
407 }
408
409 public VaList build() {
410 if (isEmpty()) {
411 return EMPTY;
412 }
413
414 MemorySegment vaListSegment = MemorySegment.allocateNative(LAYOUT.byteSize());
415 SysVVaList res = new SysVVaList(vaListSegment);
416 MemoryAddress stackArgsPtr = MemoryAddress.NULL;
417 if (!stackArgs.isEmpty()) {
418 long stackArgsSize = stackArgs.stream().reduce(0L, (acc, e) -> acc + e.layout.byteSize(), Long::sum);
419 MemorySegment stackArgsSegment = MemorySegment.allocateNative(stackArgsSize, 16);
420 MemoryAddress maOverflowArgArea = stackArgsSegment.baseAddress();
421 for (SimpleVaArg arg : stackArgs) {
422 if (arg.layout.byteSize() > 8) {
423 maOverflowArgArea = Utils.alignUp(maOverflowArgArea, Math.min(16, arg.layout.byteSize()));
424 }
425 VarHandle writer = arg.varHandle();
426 writer.set(maOverflowArgArea, arg.value);
427 maOverflowArgArea = maOverflowArgArea.addOffset(arg.layout.byteSize());
428 }
429 stackArgsPtr = stackArgsSegment.baseAddress();
430 res.slices.add(stackArgsSegment);
431 }
432
433 MemoryAddress vaListAddr = vaListSegment.baseAddress();
|