*** 29,14 *** --- 29,17 --- import jdk.incubator.foreign.GroupLayout; import jdk.incubator.foreign.MemoryAddress; import jdk.incubator.foreign.MemoryHandles; import jdk.incubator.foreign.MemoryLayout; import jdk.incubator.foreign.MemorySegment; + import jdk.internal.foreign.NativeMemorySegmentImpl; import jdk.internal.foreign.Utils; import jdk.internal.foreign.abi.SharedUtils; + import jdk.internal.misc.Unsafe; import java.lang.invoke.VarHandle; + import java.lang.ref.Cleaner; import java.nio.ByteOrder; import java.util.ArrayList; import java.util.List; import static jdk.incubator.foreign.CSupport.SysV;
*** 46,10 *** --- 49,12 --- import static jdk.internal.foreign.abi.SharedUtils.checkCompatibleType; import static jdk.internal.foreign.abi.SharedUtils.vhPrimitiveOrAddress; // See https://software.intel.com/sites/default/files/article/402129/mpx-linux64-abi.pdf "3.5.7 Variable Argument Lists" public class SysVVaList implements VaList { + private static final Unsafe U = Unsafe.getUnsafe(); + static final Class<?> CARRIER = MemoryAddress.class; // struct typedef __va_list_tag __va_list_tag { // unsigned int gp_offset; /* 0 4 */ // unsigned int fp_offset; /* 4 4 */
*** 109,20 *** --- 114,42 --- private static final VarHandle VH_overflow_arg_area = MemoryHandles.asAddressVarHandle(LAYOUT.varHandle(long.class, groupElement("overflow_arg_area"))); private static final VarHandle VH_reg_save_area = MemoryHandles.asAddressVarHandle(LAYOUT.varHandle(long.class, groupElement("reg_save_area"))); + private static final Cleaner cleaner = Cleaner.create(); + private static final CSupport.VaList EMPTY = new SharedUtils.EmptyVaList(emptyListAddress()); + private final MemorySegment segment; private final List<MemorySegment> slices = new ArrayList<>(); private final MemorySegment regSaveArea; SysVVaList(MemorySegment segment) { this.segment = segment; regSaveArea = regSaveArea(); slices.add(regSaveArea); } + private static MemoryAddress emptyListAddress() { + long ptr = U.allocateMemory(LAYOUT.byteSize()); + MemorySegment ms = NativeMemorySegmentImpl.makeNativeSegmentUnchecked( + MemoryAddress.ofLong(ptr), LAYOUT.byteSize(), null, () -> U.freeMemory(ptr), null); + cleaner.register(SysVVaList.class, ms::close); + MemoryAddress base = ms.baseAddress(); + VH_gp_offset.set(base, MAX_GP_OFFSET); + VH_fp_offset.set(base, MAX_FP_OFFSET); + VH_overflow_arg_area.set(base, MemoryAddress.NULL); + VH_reg_save_area.set(base, MemoryAddress.NULL); + MemorySegment unconfined = NativeMemorySegmentImpl.makeNativeSegmentUnchecked( + base, ms.byteSize(), null, null, null).withAccessModes(0); + return unconfined.baseAddress(); + } + + public static CSupport.VaList empty() { + return EMPTY; + } + private int currentGPOffset() { return (int) VH_gp_offset.get(segment.baseAddress()); } private void currentGPOffset(int i) {
*** 267,14 *** public static VaList ofAddress(MemoryAddress ma) { return new SysVVaList(MemorySegment.ofNativeRestricted(ma, LAYOUT.byteSize(), Thread.currentThread(), null, null)); } - MemorySegment getSegment() { - return segment; - } - @Override public boolean isAlive() { return segment.isAlive(); } --- 294,10 ---
*** 381,11 *** } } return this; } ! public SysVVaList build() { MemorySegment vaListSegment = MemorySegment.allocateNative(LAYOUT.byteSize()); SysVVaList res = new SysVVaList(vaListSegment); MemoryAddress stackArgsPtr = MemoryAddress.NULL; if (!stackArgs.isEmpty()) { long stackArgsSize = stackArgs.stream().reduce(0L, (acc, e) -> acc + e.layout.byteSize(), Long::sum); --- 404,19 --- } } return this; } ! private boolean isEmpty() { + return currentGPOffset == 0 && currentFPOffset == FP_OFFSET && stackArgs.isEmpty(); + } + + public VaList build() { + if (isEmpty()) { + return EMPTY; + } + MemorySegment vaListSegment = MemorySegment.allocateNative(LAYOUT.byteSize()); SysVVaList res = new SysVVaList(vaListSegment); MemoryAddress stackArgsPtr = MemoryAddress.NULL; if (!stackArgs.isEmpty()) { long stackArgsSize = stackArgs.stream().reduce(0L, (acc, e) -> acc + e.layout.byteSize(), Long::sum);