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 27 package jdk.internal.jextract.impl; 28 29 import jdk.incubator.foreign.GroupLayout; 30 import jdk.incubator.foreign.MemoryLayout; 31 import jdk.incubator.jextract.Declaration; 32 import jdk.internal.clang.Cursor; 33 import jdk.internal.clang.Type; 34 35 import java.util.ArrayList; 36 import java.util.List; 37 38 /** 39 * MemoryLayout computer for C structs. 40 */ 41 final class StructLayoutComputer extends RecordLayoutComputer { 42 private long offset; 43 private long actualSize = 0L; 44 // List to collect bitfield fields to process later, may be null 45 private List<Declaration> bitfieldDecls; 46 private List<MemoryLayout> bitfieldLayouts; 47 48 StructLayoutComputer(TypeMaker typeMaker, long offsetInParent, Type parent, Type type) { 49 super(typeMaker, parent, type); 50 this.offset = offsetInParent; 51 } 52 53 @Override 54 void addField(Declaration declaration) { 55 if (bitfieldDecls != null) { 56 bitfieldDecls.add(declaration); 57 MemoryLayout layout = null; 58 if (declaration instanceof Declaration.Scoped scoped) { 59 layout = scoped.layout().orElse(null); 60 } else if (declaration instanceof Declaration.Variable var) { 61 layout = var.layout().orElse(null); 62 } 63 if (layout != null) { 64 bitfieldLayouts.add(declaration.name().isEmpty() ? layout : layout.withName(declaration.name())); 65 } 66 } else { 67 super.addField(declaration); 68 } 69 } 70 71 @Override 72 void addPadding(long bits) { 73 if (bitfieldDecls != null) { 74 bitfieldLayouts.add(MemoryLayout.paddingLayout(bits)); 75 } else { 76 super.addPadding(bits); 77 } 78 } 79 80 @Override 81 void startBitfield() { 82 /* 83 * In a struct, a bitfield field is seen after a non-bitfield. 84 * Initialize bitfieldLayouts list to collect this and subsequent 85 * bitfield layouts. 86 */ 87 if (bitfieldDecls == null) { 88 bitfieldDecls = new ArrayList<>(); 89 bitfieldLayouts = new ArrayList<>(); 90 } 91 } 92 93 @Override 94 void processField(Cursor c) { 95 boolean isBitfield = c.isBitField(); 96 long expectedOffset = offsetOf(parent, c); 97 if (expectedOffset > offset) { 98 addPadding(expectedOffset - offset); 99 actualSize += (expectedOffset - offset); 100 offset = expectedOffset; 101 } 102 103 if (isBitfield) { 104 startBitfield(); 105 } else { // !isBitfield 106 /* 107 * We may be crossing from bit fields to non-bitfield field. 108 * 109 * struct Foo { 110 * int i:12; 111 * int j:20; 112 * int k; // <-- processing this 113 * int m; 114 * } 115 */ 116 handleBitfields(); 117 } 118 119 addField(offset, parent, c); 120 long size = fieldSize(c); 121 offset += size; 122 actualSize += size; 123 } 124 125 @Override 126 jdk.incubator.jextract.Type.Declared finishRecord(String anonName) { 127 // pad at the end, if any 128 long expectedSize = type.size() * 8; 129 if (actualSize < expectedSize) { 130 addPadding(expectedSize - actualSize); 131 } 132 133 /* 134 * Handle bitfields at the end, if any. 135 * 136 * struct Foo { 137 * int i,j, k; 138 * int f:10; 139 * int pad:12; 140 * } 141 */ 142 handleBitfields(); 143 144 MemoryLayout[] fields = fieldLayouts.toArray(new MemoryLayout[0]); 145 GroupLayout g = MemoryLayout.structLayout(fields); 146 if (!cursor.spelling().isEmpty()) { 147 g = g.withName(cursor.spelling()); 148 } else if (anonName != null) { 149 g = g.withName(anonName); 150 } 151 return jdk.incubator.jextract.Type.declared(Declaration.struct(TreeMaker.CursorPosition.of(cursor), cursor.spelling(), g, fieldDecls.stream().toArray(Declaration[]::new))); 152 } 153 154 // process bitfields if any and clear bitfield layouts 155 private void handleBitfields() { 156 if (bitfieldDecls != null) { 157 List<MemoryLayout> prevBitfieldLayouts = bitfieldLayouts; 158 List<Declaration> prevBitfieldDecls = bitfieldDecls; 159 bitfieldDecls = null; 160 if (!prevBitfieldDecls.isEmpty()) { 161 addField(bitfield(prevBitfieldLayouts, prevBitfieldDecls.toArray(new Declaration.Variable[0]))); 162 } 163 } 164 } 165 }