1 /* 2 * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 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.windows; 27 28 import jdk.incubator.foreign.CSupport; 29 import jdk.incubator.foreign.MemoryAddress; 30 import jdk.incubator.foreign.MemoryHandles; 31 import jdk.incubator.foreign.MemoryLayout; 32 import jdk.incubator.foreign.MemorySegment; 33 import jdk.internal.foreign.abi.SharedUtils; 34 import jdk.internal.foreign.abi.SharedUtils.SimpleVaArg; 35 36 import java.lang.invoke.VarHandle; 37 import java.util.ArrayList; 38 import java.util.List; 39 40 import static jdk.incubator.foreign.CSupport.Win64.C_POINTER; 41 import static jdk.incubator.foreign.MemorySegment.CLOSE; 42 import static jdk.incubator.foreign.MemorySegment.READ; 43 44 // see vadefs.h (VC header) 45 // 46 // in short 47 // -> va_list is just a pointer to a buffer with 64 bit entries. 48 // -> non-power-of-two-sized, or larger than 64 bit types passed by reference. 49 // -> other types passed in 64 bit slots by normal function calling convention. 50 // 51 // X64 va_arg impl: 52 // 53 // typedef char* va_list; 54 // 55 // #define __crt_va_arg(ap, t) \ 56 // ((sizeof(t) > sizeof(__int64) || (sizeof(t) & (sizeof(t) - 1)) != 0) \ 57 // ? **(t**)((ap += sizeof(__int64)) - sizeof(__int64)) \ 58 // : *(t* )((ap += sizeof(__int64)) - sizeof(__int64))) 59 // 60 class WinVaList implements CSupport.VaList { 61 public static final Class<?> CARRIER = MemoryAddress.class; 62 private static final long VA_SLOT_SIZE_BYTES = 8; 63 private static final VarHandle VH_address = MemoryHandles.asAddressVarHandle(C_POINTER.varHandle(long.class)); 64 65 private final MemorySegment segment; 66 private MemoryAddress ptr; 67 private final List<MemorySegment> copies; 68 69 WinVaList(MemorySegment segment) { 70 this(segment, new ArrayList<>()); 71 } 72 73 WinVaList(MemorySegment segment, List<MemorySegment> copies) { 74 this.segment = segment; 75 this.ptr = segment.baseAddress(); 76 this.copies = copies; 77 } 78 79 @Override 80 public int vargAsInt(MemoryLayout layout) { 81 return (int) read(int.class, layout); 82 } 83 84 @Override 85 public long vargAsLong(MemoryLayout layout) { 86 return (long) read(long.class, layout); 87 } 88 89 @Override 90 public double vargAsDouble(MemoryLayout layout) { 91 return (double) read(double.class, layout); 92 } 93 94 @Override 95 public MemoryAddress vargAsAddress(MemoryLayout layout) { 96 return (MemoryAddress) read(MemoryAddress.class, layout); 97 } 98 99 @Override 100 public MemorySegment vargAsSegment(MemoryLayout layout) { 101 return (MemorySegment) read(MemorySegment.class, layout); 102 } 103 104 private Object read(Class<?> carrier, MemoryLayout layout) { 105 SharedUtils.checkCompatibleType(carrier, layout, Windowsx64Linker.ADDRESS_SIZE); 106 Object res; 107 if (carrier == MemorySegment.class) { 108 TypeClass typeClass = TypeClass.typeClassFor(layout); 109 res = switch (typeClass) { 110 case STRUCT_REFERENCE -> { 111 MemoryAddress structAddr = (MemoryAddress) VH_address.get(ptr); 112 try (MemorySegment struct = MemorySegment.ofNativeRestricted(structAddr, layout.byteSize(), 113 segment.ownerThread(), null, null)) { 114 MemorySegment seg = MemorySegment.allocateNative(layout.byteSize()); 115 seg.copyFrom(struct); 116 yield seg; 117 } 118 } 119 case STRUCT_REGISTER -> { 120 MemorySegment struct = MemorySegment.allocateNative(layout); 121 struct.copyFrom(segment.asSlice(ptr.segmentOffset(), layout.byteSize())); 122 yield struct; 123 } 124 default -> throw new IllegalStateException("Unexpected TypeClass: " + typeClass); 125 }; 126 } else { 127 VarHandle reader = SharedUtils.vhPrimitiveOrAddress(carrier, layout); 128 res = reader.get(ptr); 129 } 130 ptr = ptr.addOffset(VA_SLOT_SIZE_BYTES); 131 return res; 132 } 133 134 @Override 135 public void skip(MemoryLayout... layouts) { 136 ptr = ptr.addOffset(layouts.length * VA_SLOT_SIZE_BYTES); 137 } 138 139 static WinVaList ofAddress(MemoryAddress addr) { 140 return new WinVaList(MemorySegment.ofNativeRestricted(addr, Long.MAX_VALUE, Thread.currentThread(), null, null)); 141 } 142 143 static Builder builder() { 144 return new Builder(); 145 } 146 147 MemorySegment getSegment() { 148 return segment; 149 } 150 151 @Override 152 public void close() { 153 segment.close(); 154 copies.forEach(MemorySegment::close); 155 } 156 157 @Override 158 public CSupport.VaList copy() { 159 return WinVaList.ofAddress(ptr); 160 } 161 162 @Override 163 public MemoryAddress address() { 164 return ptr; 165 } 166 167 @Override 168 public boolean isAlive() { 169 return segment.isAlive(); 170 } 171 172 static class Builder implements CSupport.VaList.Builder { 173 174 private final List<SimpleVaArg> args = new ArrayList<>(); 175 176 private Builder arg(Class<?> carrier, MemoryLayout layout, Object value) { 177 SharedUtils.checkCompatibleType(carrier, layout, Windowsx64Linker.ADDRESS_SIZE); 178 args.add(new SimpleVaArg(carrier, layout, value)); 179 return this; 180 } 181 182 @Override 183 public Builder vargFromInt(MemoryLayout layout, int value) { 184 return arg(int.class, layout, value); 185 } 186 187 @Override 188 public Builder vargFromLong(MemoryLayout layout, long value) { 189 return arg(long.class, layout, value); 190 } 191 192 @Override 193 public Builder vargFromDouble(MemoryLayout layout, double value) { 194 return arg(double.class, layout, value); 195 } 196 197 @Override 198 public Builder vargFromAddress(MemoryLayout layout, MemoryAddress value) { 199 return arg(MemoryAddress.class, layout, value); 200 } 201 202 @Override 203 public Builder vargFromSegment(MemoryLayout layout, MemorySegment value) { 204 return arg(MemorySegment.class, layout, value); 205 } 206 207 public WinVaList build() { 208 MemorySegment ms = MemorySegment.allocateNative(VA_SLOT_SIZE_BYTES * args.size()); 209 List<MemorySegment> copies = new ArrayList<>(); 210 211 MemoryAddress addr = ms.baseAddress(); 212 for (SimpleVaArg arg : args) { 213 if (arg.carrier == MemorySegment.class) { 214 MemorySegment msArg = ((MemorySegment) arg.value); 215 TypeClass typeClass = TypeClass.typeClassFor(arg.layout); 216 switch (typeClass) { 217 case STRUCT_REFERENCE -> { 218 MemorySegment copy = MemorySegment.allocateNative(arg.layout); 219 copy.copyFrom(msArg); // by-value 220 copies.add(copy); 221 VH_address.set(addr, copy.baseAddress()); 222 } 223 case STRUCT_REGISTER -> { 224 MemorySegment slice = ms.asSlice(addr.segmentOffset(), VA_SLOT_SIZE_BYTES); 225 slice.copyFrom(msArg); 226 } 227 default -> throw new IllegalStateException("Unexpected TypeClass: " + typeClass); 228 } 229 } else { 230 VarHandle writer = arg.varHandle(); 231 writer.set(addr, arg.value); 232 } 233 addr = addr.addOffset(VA_SLOT_SIZE_BYTES); 234 } 235 236 return new WinVaList(ms.withAccessModes(CLOSE | READ), copies); 237 } 238 } 239 }