< prev index next >

src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/x64/sysv/SysVVaList.java

Print this page

 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 */
 58 //
 59 //        /* size: 24, cachelines: 1, members: 4 */
 60 //        /* last cacheline: 24 bytes */
 61 //    };
 62     static final GroupLayout LAYOUT = MemoryLayout.ofStruct(
 63         SysV.C_INT.withName("gp_offset"),
 64         SysV.C_INT.withName("fp_offset"),
 65         SysV.C_POINTER.withName("overflow_arg_area"),
 66         SysV.C_POINTER.withName("reg_save_area")
 67     ).withName("__va_list_tag");
 68 
 69     private static final MemoryLayout GP_REG = MemoryLayout.ofValueBits(64, ByteOrder.nativeOrder());
 70     private static final MemoryLayout FP_REG = MemoryLayout.ofValueBits(128, ByteOrder.nativeOrder());

 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.NativeMemorySegmentImpl;
 35 import jdk.internal.foreign.Utils;
 36 import jdk.internal.foreign.abi.SharedUtils;
 37 import jdk.internal.misc.Unsafe;
 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     private static final Unsafe U = Unsafe.getUnsafe();
 55 
 56     static final Class<?> CARRIER = MemoryAddress.class;
 57 
 58 //    struct typedef __va_list_tag __va_list_tag {
 59 //        unsigned int               gp_offset;            /*     0     4 */
 60 //        unsigned int               fp_offset;            /*     4     4 */
 61 //        void *                     overflow_arg_area;    /*     8     8 */
 62 //        void *                     reg_save_area;        /*    16     8 */
 63 //
 64 //        /* size: 24, cachelines: 1, members: 4 */
 65 //        /* last cacheline: 24 bytes */
 66 //    };
 67     static final GroupLayout LAYOUT = MemoryLayout.ofStruct(
 68         SysV.C_INT.withName("gp_offset"),
 69         SysV.C_INT.withName("fp_offset"),
 70         SysV.C_POINTER.withName("overflow_arg_area"),
 71         SysV.C_POINTER.withName("reg_save_area")
 72     ).withName("__va_list_tag");
 73 
 74     private static final MemoryLayout GP_REG = MemoryLayout.ofValueBits(64, ByteOrder.nativeOrder());
 75     private static final MemoryLayout FP_REG = MemoryLayout.ofValueBits(128, ByteOrder.nativeOrder());

 99 //        FP_REG.withName("%xmm13"),
100 //        FP_REG.withName("%xmm14"),
101 //        FP_REG.withName("%xmm15")
102     );
103 
104     private static final long FP_OFFSET = LAYOUT_REG_SAVE_AREA.byteOffset(groupElement("%xmm0"));
105 
106     private static final int GP_SLOT_SIZE = (int) GP_REG.byteSize();
107     private static final int FP_SLOT_SIZE = (int) FP_REG.byteSize();
108 
109     private static final int MAX_GP_OFFSET = (int) FP_OFFSET; // 6 regs used
110     private static final int MAX_FP_OFFSET = (int) LAYOUT_REG_SAVE_AREA.byteSize(); // 8 16 byte regs
111 
112     private static final VarHandle VH_fp_offset = LAYOUT.varHandle(int.class, groupElement("fp_offset"));
113     private static final VarHandle VH_gp_offset = LAYOUT.varHandle(int.class, groupElement("gp_offset"));
114     private static final VarHandle VH_overflow_arg_area
115         = MemoryHandles.asAddressVarHandle(LAYOUT.varHandle(long.class, groupElement("overflow_arg_area")));
116     private static final VarHandle VH_reg_save_area
117         = MemoryHandles.asAddressVarHandle(LAYOUT.varHandle(long.class, groupElement("reg_save_area")));
118 
119     private static final Cleaner cleaner = Cleaner.create();
120     private static final CSupport.VaList EMPTY = new SharedUtils.EmptyVaList(emptyListAddress());
121 
122     private final MemorySegment segment;
123     private final List<MemorySegment> slices = new ArrayList<>();
124     private final MemorySegment regSaveArea;
125 
126     SysVVaList(MemorySegment segment) {
127         this.segment = segment;
128         regSaveArea = regSaveArea();
129         slices.add(regSaveArea);
130     }
131 
132     private static MemoryAddress emptyListAddress() {
133         long ptr = U.allocateMemory(LAYOUT.byteSize());
134         MemorySegment ms = NativeMemorySegmentImpl.makeNativeSegmentUnchecked(
135                 MemoryAddress.ofLong(ptr), LAYOUT.byteSize(), null, () -> U.freeMemory(ptr), null);
136         cleaner.register(SysVVaList.class, ms::close);
137         MemoryAddress base = ms.baseAddress();
138         VH_gp_offset.set(base, MAX_GP_OFFSET);
139         VH_fp_offset.set(base, MAX_FP_OFFSET);
140         VH_overflow_arg_area.set(base, MemoryAddress.NULL);
141         VH_reg_save_area.set(base, MemoryAddress.NULL);
142         return ms.withAccessModes(0).baseAddress();
143     }
144 
145     public static CSupport.VaList empty() {
146         return EMPTY;
147     }
148 
149     private int currentGPOffset() {
150         return (int) VH_gp_offset.get(segment.baseAddress());
151     }
152 
153     private void currentGPOffset(int i) {
154         VH_gp_offset.set(segment.baseAddress(), i);
155     }
156 
157     private int currentFPOffset() {
158         return (int) VH_fp_offset.get(segment.baseAddress());
159     }
160 
161     private void currentFPOffset(int i) {
162         VH_fp_offset.set(segment.baseAddress(), i);
163     }
164 
165     private MemoryAddress stackPtr() {
166         return (MemoryAddress) VH_overflow_arg_area.get(segment.baseAddress());
167     }
168 

277         for (MemoryLayout layout : layouts) {
278             TypeClass typeClass = TypeClass.classifyLayout(layout);
279             if (isRegOverflow(currentGPOffset(), currentFPOffset(), typeClass)) {
280                 preAlignStack(layout);
281                 postAlignStack(layout);
282             } else {
283                 currentGPOffset(currentGPOffset() + (((int) typeClass.nIntegerRegs()) * GP_SLOT_SIZE));
284                 currentFPOffset(currentFPOffset() + (((int) typeClass.nVectorRegs()) * FP_SLOT_SIZE));
285             }
286         }
287     }
288 
289     static SysVVaList.Builder builder() {
290         return new SysVVaList.Builder();
291     }
292 
293     public static VaList ofAddress(MemoryAddress ma) {
294         return new SysVVaList(MemorySegment.ofNativeRestricted(ma, LAYOUT.byteSize(), Thread.currentThread(), null, null));
295     }
296 




297     @Override
298     public boolean isAlive() {
299         return segment.isAlive();
300     }
301 
302     @Override
303     public void close() {
304         segment.close();
305         slices.forEach(MemorySegment::close);
306     }
307 
308     @Override
309     public VaList copy() {
310         MemorySegment copy = MemorySegment.allocateNative(LAYOUT.byteSize());
311         copy.copyFrom(segment);
312         return new SysVVaList(copy);
313     }
314 
315     @Override
316     public MemoryAddress address() {

387                                 currentGPOffset += GP_SLOT_SIZE;
388                             }
389                             offset += copy;
390                         }
391                     }
392                     case POINTER, INTEGER -> {
393                         VarHandle writer = SharedUtils.vhPrimitiveOrAddress(carrier, layout);
394                         writer.set(reg_save_area.baseAddress().addOffset(currentGPOffset), value);
395                         currentGPOffset += GP_SLOT_SIZE;
396                     }
397                     case FLOAT -> {
398                         VarHandle writer = layout.varHandle(carrier);
399                         writer.set(reg_save_area.baseAddress().addOffset(currentFPOffset), value);
400                         currentFPOffset += FP_SLOT_SIZE;
401                     }
402                 }
403             }
404             return this;
405         }
406 
407         private boolean isEmpty() {
408             return currentGPOffset == 0 && currentFPOffset == FP_OFFSET && stackArgs.isEmpty();
409         }
410 
411         public VaList build() {
412             if (isEmpty()) {
413                 return EMPTY;
414             }
415 
416             MemorySegment vaListSegment = MemorySegment.allocateNative(LAYOUT.byteSize());
417             SysVVaList res = new SysVVaList(vaListSegment);
418             MemoryAddress stackArgsPtr = MemoryAddress.NULL;
419             if (!stackArgs.isEmpty()) {
420                 long stackArgsSize = stackArgs.stream().reduce(0L, (acc, e) -> acc + e.layout.byteSize(), Long::sum);
421                 MemorySegment stackArgsSegment = MemorySegment.allocateNative(stackArgsSize, 16);
422                 MemoryAddress maOverflowArgArea = stackArgsSegment.baseAddress();
423                 for (SimpleVaArg arg : stackArgs) {
424                     if (arg.layout.byteSize() > 8) {
425                         maOverflowArgArea = Utils.alignUp(maOverflowArgArea, Math.min(16, arg.layout.byteSize()));
426                     }
427                     VarHandle writer = arg.varHandle();
428                     writer.set(maOverflowArgArea, arg.value);
429                     maOverflowArgArea = maOverflowArgArea.addOffset(arg.layout.byteSize());
430                 }
431                 stackArgsPtr = stackArgsSegment.baseAddress();
432                 res.slices.add(stackArgsSegment);
433             }
434 
435             MemoryAddress vaListAddr = vaListSegment.baseAddress();
< prev index next >