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 package jdk.internal.jextract.impl; 26 27 import jdk.incubator.foreign.GroupLayout; 28 import jdk.incubator.foreign.MemoryLayout; 29 import jdk.incubator.foreign.MemorySegment; 30 import jdk.incubator.jextract.Declaration; 31 import jdk.incubator.jextract.Type; 32 33 import java.util.ArrayDeque; 34 import java.util.ArrayList; 35 import java.util.Collections; 36 import java.util.Deque; 37 import java.util.List; 38 39 /** 40 * This class generates static utilities class for C structs, unions. 41 */ 42 class StructBuilder extends ConstantBuilder { 43 44 private static final String MEMBER_MODS = "public static"; 45 46 private final GroupLayout structLayout; 47 private final Type structType; 48 private final Deque<String> prefixElementNames; 49 50 StructBuilder(JavaSourceBuilder enclosing, String name, GroupLayout structLayout, Type structType) { 51 super(enclosing, name); 52 this.structLayout = structLayout; 53 this.structType = structType; 54 prefixElementNames = new ArrayDeque<>(); 55 } 56 57 private String safeParameterName(String paramName) { 58 return isEnclosedBySameName(paramName)? paramName + "$" : paramName; 59 } 60 61 void pushPrefixElement(String prefixElementName) { 62 prefixElementNames.push(prefixElementName); 63 } 64 65 void popPrefixElement() { 66 prefixElementNames.pop(); 67 } 68 69 private List<String> prefixNamesList() { 70 List<String> prefixes = new ArrayList<>(prefixElementNames); 71 Collections.reverse(prefixes); 72 return Collections.unmodifiableList(prefixes); 73 } 74 75 @Override 76 void classBegin() { 77 if (!inAnonymousNested()) { 78 super.classBegin(); 79 addLayout(layoutField(), ((Type.Declared) structType).tree().layout().get()) 80 .emitGetter(this, MEMBER_MODS, Constant.SUFFIX_ONLY); 81 } 82 } 83 84 @Override 85 JavaSourceBuilder classEnd() { 86 if (!inAnonymousNested()) { 87 emitSizeof(); 88 emitAllocatorAllocate(); 89 emitAllocatorAllocateArray(); 90 emitScopeAllocate(); 91 emitScopeAllocateArray(); 92 emitOfAddressScoped(); 93 return super.classEnd(); 94 } else { 95 // we're in an anonymous struct which got merged into this one, return this very builder and keep it open 96 popPrefixElement(); 97 return this; 98 } 99 } 100 101 boolean inAnonymousNested() { 102 return !prefixElementNames.isEmpty(); 103 } 104 105 @Override 106 public StructBuilder addStruct(String name, Declaration parent, GroupLayout layout, Type type) { 107 if (name.isEmpty() && (parent instanceof Declaration.Scoped)) { 108 //nested anon struct - merge into this builder! 109 String anonName = layout.name().orElseThrow(); 110 pushPrefixElement(anonName); 111 return this; 112 } else { 113 return new StructBuilder(this, name.isEmpty() ? parent.name() : name, layout, type); 114 } 115 } 116 117 @Override 118 public String addFunctionalInterface(String name, FunctionInfo functionInfo) { 119 FunctionalInterfaceBuilder builder = new FunctionalInterfaceBuilder(this, name, functionInfo); 120 builder.classBegin(); 121 builder.classEnd(); 122 return builder.className(); 123 } 124 125 @Override 126 public void addVar(String javaName, String nativeName, VarInfo varInfo) { 127 try { 128 structLayout.byteOffset(elementPaths(nativeName)); 129 } catch (UnsupportedOperationException uoe) { 130 // bad layout - do nothing 131 OutputFactory.warn("skipping '" + className() + "." + nativeName + "' : " + uoe.toString()); 132 return; 133 } 134 if (varInfo.carrier().equals(MemorySegment.class)) { 135 emitSegmentGetter(javaName, nativeName, varInfo.layout()); 136 } else { 137 Constant vhConstant = addFieldVarHandle(javaName, nativeName, varInfo, layoutField(), prefixNamesList()) 138 .emitGetter(this, MEMBER_MODS, Constant.QUALIFIED_NAME); 139 emitFieldGetter(vhConstant, javaName, varInfo.carrier()); 140 emitFieldSetter(vhConstant, javaName, varInfo.carrier()); 141 emitIndexedFieldGetter(vhConstant, javaName, varInfo.carrier()); 142 emitIndexedFieldSetter(vhConstant, javaName, varInfo.carrier()); 143 if (varInfo.fiName().isPresent()) { 144 emitFunctionalInterfaceGetter(varInfo.fiName().get(), javaName); 145 } 146 } 147 } 148 149 private void emitFunctionalInterfaceGetter(String fiName, String javaName) { 150 incrAlign(); 151 indent(); 152 append(MEMBER_MODS + " "); 153 append(fiName + " " + javaName + " (MemorySegment segment, ResourceScope scope) {\n"); 154 incrAlign(); 155 indent(); 156 append("return " + fiName + ".ofAddress(" + javaName + "$get(segment), scope);\n"); 157 decrAlign(); 158 indent(); 159 append("}\n"); 160 decrAlign(); 161 } 162 163 private void emitFieldGetter(Constant vhConstant, String javaName, Class<?> type) { 164 incrAlign(); 165 indent(); 166 String seg = safeParameterName("seg"); 167 append(MEMBER_MODS + " " + type.getSimpleName() + " " + javaName + "$get(MemorySegment " + seg + ") {\n"); 168 incrAlign(); 169 indent(); 170 append("return (" + type.getName() + ")" 171 + vhConstant.accessExpression() + ".get(" + seg + ");\n"); 172 decrAlign(); 173 indent(); 174 append("}\n"); 175 decrAlign(); 176 } 177 178 private void emitFieldSetter(Constant vhConstant, String javaName, Class<?> type) { 179 incrAlign(); 180 indent(); 181 String seg = safeParameterName("seg"); 182 String x = safeParameterName("x"); 183 String param = MemorySegment.class.getSimpleName() + " " + seg; 184 append(MEMBER_MODS + " void " + javaName + "$set( " + param + ", " + type.getSimpleName() + " " + x + ") {\n"); 185 incrAlign(); 186 indent(); 187 append(vhConstant.accessExpression() + ".set(" + seg + ", " + x + ");\n"); 188 decrAlign(); 189 indent(); 190 append("}\n"); 191 decrAlign(); 192 } 193 194 private MemoryLayout.PathElement[] elementPaths(String nativeFieldName) { 195 List<String> prefixElements = prefixNamesList(); 196 MemoryLayout.PathElement[] elems = new MemoryLayout.PathElement[prefixElements.size() + 1]; 197 int i = 0; 198 for (; i < prefixElements.size(); i++) { 199 elems[i] = MemoryLayout.PathElement.groupElement(prefixElements.get(i)); 200 } 201 elems[i] = MemoryLayout.PathElement.groupElement(nativeFieldName); 202 return elems; 203 } 204 205 private void emitSegmentGetter(String javaName, String nativeName, MemoryLayout layout) { 206 incrAlign(); 207 indent(); 208 String seg = safeParameterName("seg"); 209 append(MEMBER_MODS + " MemorySegment " + javaName + "$slice(MemorySegment " + seg + ") {\n"); 210 incrAlign(); 211 indent(); 212 append("return " + seg + ".asSlice("); 213 append(structLayout.byteOffset(elementPaths(nativeName))); 214 append(", "); 215 append(layout.byteSize()); 216 append(");\n"); 217 decrAlign(); 218 indent(); 219 append("}\n"); 220 decrAlign(); 221 } 222 223 private void emitSizeof() { 224 incrAlign(); 225 indent(); 226 append(MEMBER_MODS); 227 append(" long sizeof() { return $LAYOUT().byteSize(); }\n"); 228 decrAlign(); 229 } 230 231 private void emitAllocatorAllocate() { 232 incrAlign(); 233 indent(); 234 append(MEMBER_MODS); 235 append(" MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); }\n"); 236 decrAlign(); 237 } 238 239 private void emitAllocatorAllocateArray() { 240 incrAlign(); 241 indent(); 242 append(MEMBER_MODS); 243 append(" MemorySegment allocateArray(int len, SegmentAllocator allocator) {\n"); 244 incrAlign(); 245 indent(); 246 append("return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT()));\n"); 247 decrAlign(); 248 indent(); 249 append("}\n"); 250 decrAlign(); 251 } 252 253 private void emitScopeAllocate() { 254 incrAlign(); 255 indent(); 256 append(MEMBER_MODS); 257 append(" MemorySegment allocate(ResourceScope scope) { return allocate(SegmentAllocator.nativeAllocator(scope)); }\n"); 258 decrAlign(); 259 } 260 261 private void emitScopeAllocateArray() { 262 incrAlign(); 263 indent(); 264 append(MEMBER_MODS); 265 append(" MemorySegment allocateArray(int len, ResourceScope scope) {\n"); 266 incrAlign(); 267 indent(); 268 append("return allocateArray(len, SegmentAllocator.nativeAllocator(scope));\n"); 269 decrAlign(); 270 indent(); 271 append("}\n"); 272 decrAlign(); 273 } 274 275 private void emitOfAddressScoped() { 276 incrAlign(); 277 indent(); 278 append(MEMBER_MODS); 279 append(" MemorySegment ofAddress(MemoryAddress addr, ResourceScope scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); }\n"); 280 decrAlign(); 281 } 282 283 private void emitIndexedFieldGetter(Constant vhConstant, String javaName, Class<?> type) { 284 incrAlign(); 285 indent(); 286 String index = safeParameterName("index"); 287 String seg = safeParameterName("seg"); 288 String params = MemorySegment.class.getSimpleName() + " " + seg + ", long " + index; 289 append(MEMBER_MODS + " " + type.getSimpleName() + " " + javaName + "$get(" + params + ") {\n"); 290 incrAlign(); 291 indent(); 292 append("return (" + type.getName() + ")"); 293 append(vhConstant.accessExpression()); 294 append(".get("); 295 append(seg); 296 append(".asSlice("); 297 append(index); 298 append("*sizeof()));\n"); 299 decrAlign(); 300 indent(); 301 append("}\n"); 302 decrAlign(); 303 } 304 305 private void emitIndexedFieldSetter(Constant vhConstant, String javaName, Class<?> type) { 306 incrAlign(); 307 indent(); 308 String index = safeParameterName("index"); 309 String seg = safeParameterName("seg"); 310 String x = safeParameterName("x"); 311 String params = MemorySegment.class.getSimpleName() + " " + seg + 312 ", long " + index + ", " + type.getSimpleName() + " " + x; 313 append(MEMBER_MODS + " void " + javaName + "$set(" + params + ") {\n"); 314 incrAlign(); 315 indent(); 316 append(vhConstant.accessExpression()); 317 append(".set("); 318 append(seg); 319 append(".asSlice("); 320 append(index); 321 append("*sizeof()), "); 322 append(x); 323 append(");\n"); 324 decrAlign(); 325 indent(); 326 append("}\n"); 327 decrAlign(); 328 } 329 330 private String qualifiedName(ClassSourceBuilder builder) { 331 if (builder.isNested()) { 332 String prefix = qualifiedName((ClassSourceBuilder)builder.enclosing); 333 return prefix.isEmpty() ? 334 builder.className() : 335 prefix + "$" + builder.className(); 336 } else { 337 return ""; 338 } 339 } 340 341 private String layoutField() { 342 String suffix = structLayout.isUnion() ? "union" : "struct"; 343 return qualifiedName(this) + "$" + suffix; 344 } 345 }