< prev index next >

src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/AbstractLayout.java

Print this page

  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.incubator.foreign;
 27 



 28 import java.lang.constant.ClassDesc;
 29 import java.lang.constant.Constable;
 30 import java.lang.constant.ConstantDesc;
 31 import java.lang.constant.ConstantDescs;
 32 import java.lang.constant.DirectMethodHandleDesc;
 33 import java.lang.constant.DynamicConstantDesc;
 34 import java.lang.constant.MethodHandleDesc;
 35 import java.lang.constant.MethodTypeDesc;
 36 import java.nio.ByteOrder;
 37 import java.util.Collections;
 38 import java.util.HashMap;
 39 import java.util.Map;
 40 import java.util.Objects;
 41 import java.util.Optional;
 42 import java.util.OptionalLong;
 43 import java.util.stream.Collectors;
 44 import java.util.stream.Stream;
 45 
 46 import static java.lang.constant.ConstantDescs.BSM_GET_STATIC_FINAL;
 47 import static java.lang.constant.ConstantDescs.BSM_INVOKE;

 48 import static java.lang.constant.ConstantDescs.CD_String;
 49 import static java.lang.constant.ConstantDescs.CD_long;
 50 
 51 abstract non-sealed class AbstractLayout implements MemoryLayout {
 52 
 53     private final OptionalLong size;
 54     final long alignment;
 55     final Map<String, Constable> attributes;


 56 
 57     public AbstractLayout(OptionalLong size, long alignment, Map<String, Constable> attributes) {
 58         this.size = size;
 59         this.alignment = alignment;
 60         this.attributes = Collections.unmodifiableMap(attributes);
 61     }
 62 
 63     @Override
 64     public AbstractLayout withName(String name) {
 65         Objects.requireNonNull(name);
 66         return withAttribute(LAYOUT_NAME, name);
 67     }
 68 
 69     @Override
 70     public final Optional<String> name() {
 71         return attribute(LAYOUT_NAME).map(String.class::cast);
 72     }
 73 
 74     @Override
 75     public Optional<Constable> attribute(String name) {
 76         Objects.requireNonNull(name);
 77         return Optional.ofNullable(attributes.get(name));
 78     }
 79 
 80     @Override
 81     public Stream<String> attributes() {
 82         return attributes.keySet().stream();
 83     }
 84 
 85     @Override
 86     public AbstractLayout withAttribute(String name, Constable value) {
 87         Objects.requireNonNull(name);
 88         Map<String, Constable> newAttributes = new HashMap<>(attributes);
 89         newAttributes.put(name, value);
 90         return dup(alignment, newAttributes);
 91     }
 92 
 93     abstract AbstractLayout dup(long alignment, Map<String, Constable> annos);
 94 
 95     @Override
 96     public AbstractLayout withBitAlignment(long alignmentBits) {
 97         checkAlignment(alignmentBits);
 98         return dup(alignmentBits, attributes);
 99     }
100 
101     void checkAlignment(long alignmentBitCount) {
102         if (((alignmentBitCount & (alignmentBitCount - 1)) != 0L) || //alignment must be a power of two
103                 (alignmentBitCount < 8)) { //alignment must be greater than 8
104             throw new IllegalArgumentException("Invalid alignment: " + alignmentBitCount);
105         }
106     }
107 
108     static void checkSize(long size) {
109         checkSize(size, false);
110     }
111 
112     static void checkSize(long size, boolean includeZero) {
113         if (size < 0 || (!includeZero && size == 0)) {
114             throw new IllegalArgumentException("Invalid size for layout: " + size);
115         }
116     }
117 
118     @Override
119     public final long bitAlignment() {
120         return alignment;
121     }
122 









123     @Override
124     public boolean hasSize() {
125         return size.isPresent();
126     }
127 
128     @Override
129     public long bitSize() {
130         return size.orElseThrow(AbstractLayout::badSizeException);
131     }
132 
133     static OptionalLong optSize(MemoryLayout layout) {
134         return ((AbstractLayout)layout).size;
135     }
136 
137     private static UnsupportedOperationException badSizeException() {
138         return new UnsupportedOperationException("Cannot compute size of a layout which is, or depends on a sequence layout with unspecified size");
139     }
140 
141     String decorateLayoutString(String s) {
142         if (name().isPresent()) {
143             s = String.format("%s(%s)", s, name().get());
144         }
145         if (!hasNaturalAlignment()) {
146             s = alignment + "%" + s;
147         }
148         if (!attributes.isEmpty()) {
149             s += attributes.entrySet().stream()
150                                       .map(e -> e.getKey() + "=" + e.getValue())
151                                       .collect(Collectors.joining(",", "[", "]"));
152         }
153         return s;
154     }
155 
156     <T> DynamicConstantDesc<T> decorateLayoutConstant(DynamicConstantDesc<T> desc) {
157         if (!hasNaturalAlignment()) {
158             desc = DynamicConstantDesc.ofNamed(BSM_INVOKE, "withBitAlignment", desc.constantType(), MH_WITH_BIT_ALIGNMENT,
159                     desc, bitAlignment());
160         }
161         for (var e : attributes.entrySet()) {
162             desc = DynamicConstantDesc.ofNamed(BSM_INVOKE, "withAttribute", desc.constantType(), MH_WITH_ATTRIBUTE,
163                     desc, e.getKey(), e.getValue().describeConstable().orElseThrow());
164         }
165 
166         return desc;
167     }
168 
169     boolean hasNaturalAlignment() {
170         return size.isPresent() && size.getAsLong() == alignment;
171     }
172 
173     @Override
174     public boolean isPadding() {
175         return this instanceof PaddingLayout;
176     }
177 
178     @Override
179     public int hashCode() {
180         return attributes.hashCode() << Long.hashCode(alignment);
181     }
182 
183     @Override
184     public boolean equals(Object other) {
185         if (this == other) {
186             return true;
187         }
188 
189         if (!(other instanceof AbstractLayout)) {
190             return false;
191         }
192 
193         return Objects.equals(attributes, ((AbstractLayout) other).attributes) &&
194                 Objects.equals(alignment, ((AbstractLayout) other).alignment);
195     }
196 
197     /*** Helper constants for implementing Layout::describeConstable ***/
198 
199     static final ClassDesc CD_MEMORY_LAYOUT = MemoryLayout.class.describeConstable().get();
200 
201     static final ClassDesc CD_VALUE_LAYOUT = ValueLayout.class.describeConstable().get();
202 
203     static final ClassDesc CD_SEQUENCE_LAYOUT = SequenceLayout.class.describeConstable().get();
204 
205     static final ClassDesc CD_GROUP_LAYOUT = GroupLayout.class.describeConstable().get();
206 
207     static final ClassDesc CD_BYTEORDER = ByteOrder.class.describeConstable().get();
208 
209     static final ClassDesc CD_FUNCTION_DESC = FunctionDescriptor.class.describeConstable().get();
210 
211     static final ClassDesc CD_Constable = Constable.class.describeConstable().get();
212 
213     static final ConstantDesc BIG_ENDIAN = DynamicConstantDesc.ofNamed(BSM_GET_STATIC_FINAL, "BIG_ENDIAN", CD_BYTEORDER, CD_BYTEORDER);
214 
215     static final ConstantDesc LITTLE_ENDIAN = DynamicConstantDesc.ofNamed(BSM_GET_STATIC_FINAL, "LITTLE_ENDIAN", CD_BYTEORDER, CD_BYTEORDER);
216 
217     static final MethodHandleDesc MH_PADDING = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_MEMORY_LAYOUT, "paddingLayout",
218                 MethodTypeDesc.of(CD_MEMORY_LAYOUT, CD_long));
219 
220     static final MethodHandleDesc MH_VALUE = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_MEMORY_LAYOUT, "valueLayout",
221                 MethodTypeDesc.of(CD_VALUE_LAYOUT, CD_long, CD_BYTEORDER));
222 
223     static final MethodHandleDesc MH_SIZED_SEQUENCE = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_MEMORY_LAYOUT, "sequenceLayout",
224                 MethodTypeDesc.of(CD_SEQUENCE_LAYOUT, CD_long, CD_MEMORY_LAYOUT));
225 
226     static final MethodHandleDesc MH_UNSIZED_SEQUENCE = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_MEMORY_LAYOUT, "sequenceLayout",
227                 MethodTypeDesc.of(CD_SEQUENCE_LAYOUT, CD_MEMORY_LAYOUT));
228 
229     static final MethodHandleDesc MH_STRUCT = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_MEMORY_LAYOUT, "structLayout",
230                 MethodTypeDesc.of(CD_GROUP_LAYOUT, CD_MEMORY_LAYOUT.arrayType()));
231 
232     static final MethodHandleDesc MH_UNION = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_MEMORY_LAYOUT, "unionLayout",
233                 MethodTypeDesc.of(CD_GROUP_LAYOUT, CD_MEMORY_LAYOUT.arrayType()));
234 



235     static final MethodHandleDesc MH_VOID_FUNCTION = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.STATIC, CD_FUNCTION_DESC, "ofVoid",
236                 MethodTypeDesc.of(CD_FUNCTION_DESC, CD_MEMORY_LAYOUT.arrayType()));
237 
238     static final MethodHandleDesc MH_FUNCTION = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.STATIC, CD_FUNCTION_DESC, "of",
239                 MethodTypeDesc.of(CD_FUNCTION_DESC, CD_MEMORY_LAYOUT, CD_MEMORY_LAYOUT.arrayType()));
240 
241     static final MethodHandleDesc MH_WITH_BIT_ALIGNMENT = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_VIRTUAL, CD_MEMORY_LAYOUT, "withBitAlignment",
242                 MethodTypeDesc.of(CD_MEMORY_LAYOUT, CD_long));
243 
244     static final MethodHandleDesc MH_WITH_ATTRIBUTE = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_VIRTUAL, CD_MEMORY_LAYOUT, "withAttribute",
245                 MethodTypeDesc.of(CD_MEMORY_LAYOUT, CD_String, CD_Constable));
246 }

  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.incubator.foreign;
 27 
 28 import jdk.internal.foreign.Utils;
 29 import jdk.internal.vm.annotation.Stable;
 30 
 31 import java.lang.constant.ClassDesc;

 32 import java.lang.constant.ConstantDesc;

 33 import java.lang.constant.DirectMethodHandleDesc;
 34 import java.lang.constant.DynamicConstantDesc;
 35 import java.lang.constant.MethodHandleDesc;
 36 import java.lang.constant.MethodTypeDesc;
 37 import java.nio.ByteOrder;



 38 import java.util.Objects;
 39 import java.util.Optional;
 40 import java.util.OptionalLong;


 41 
 42 import static java.lang.constant.ConstantDescs.BSM_GET_STATIC_FINAL;
 43 import static java.lang.constant.ConstantDescs.BSM_INVOKE;
 44 import static java.lang.constant.ConstantDescs.CD_Class;
 45 import static java.lang.constant.ConstantDescs.CD_String;
 46 import static java.lang.constant.ConstantDescs.CD_long;
 47 
 48 abstract non-sealed class AbstractLayout implements MemoryLayout {
 49 
 50     private final OptionalLong size;
 51     final long alignment;
 52     private final Optional<String> name;
 53     @Stable
 54     long cachedSize;
 55 
 56     public AbstractLayout(OptionalLong size, long alignment, Optional<String> name) {
 57         this.size = size;
 58         this.alignment = alignment;
 59         this.name = name;
 60     }
 61 
 62     @Override
 63     public AbstractLayout withName(String name) {
 64         Objects.requireNonNull(name);
 65         return dup(alignment, Optional.of(name));
 66     }
 67 
 68     @Override
 69     public final Optional<String> name() {
 70         return name;



















 71     }
 72 
 73     abstract AbstractLayout dup(long alignment, Optional<String> name);
 74 
 75     @Override
 76     public AbstractLayout withBitAlignment(long alignmentBits) {
 77         checkAlignment(alignmentBits);
 78         return dup(alignmentBits, name);
 79     }
 80 
 81     void checkAlignment(long alignmentBitCount) {
 82         if (((alignmentBitCount & (alignmentBitCount - 1)) != 0L) || //alignment must be a power of two
 83                 (alignmentBitCount < 8)) { //alignment must be greater than 8
 84             throw new IllegalArgumentException("Invalid alignment: " + alignmentBitCount);
 85         }
 86     }
 87 
 88     static void checkSize(long size) {
 89         checkSize(size, false);
 90     }
 91 
 92     static void checkSize(long size, boolean includeZero) {
 93         if (size < 0 || (!includeZero && size == 0)) {
 94             throw new IllegalArgumentException("Invalid size for layout: " + size);
 95         }
 96     }
 97 
 98     @Override
 99     public final long bitAlignment() {
100         return alignment;
101     }
102 
103     @Override
104     public long byteSize() {
105         if (cachedSize == 0) {
106             cachedSize = Utils.bitsToBytesOrThrow(bitSize(),
107                     () -> new UnsupportedOperationException("Cannot compute byte size; bit size is not a multiple of 8"));
108         }
109         return cachedSize;
110     }
111 
112     @Override
113     public boolean hasSize() {
114         return size.isPresent();
115     }
116 
117     @Override
118     public long bitSize() {
119         return size.orElseThrow(AbstractLayout::badSizeException);
120     }
121 
122     static OptionalLong optSize(MemoryLayout layout) {
123         return ((AbstractLayout)layout).size;
124     }
125 
126     private static UnsupportedOperationException badSizeException() {
127         return new UnsupportedOperationException("Cannot compute size of a layout which is, or depends on a sequence layout with unspecified size");
128     }
129 
130     String decorateLayoutString(String s) {
131         if (name().isPresent()) {
132             s = String.format("%s(%s)", s, name().get());
133         }
134         if (!hasNaturalAlignment()) {
135             s = alignment + "%" + s;
136         }





137         return s;
138     }
139 
140     <T> DynamicConstantDesc<T> decorateLayoutConstant(DynamicConstantDesc<T> desc) {
141         if (!hasNaturalAlignment()) {
142             desc = DynamicConstantDesc.ofNamed(BSM_INVOKE, "withBitAlignment", desc.constantType(), MH_WITH_BIT_ALIGNMENT,
143                     desc, bitAlignment());
144         }
145         if (name().isPresent()) {
146             desc = DynamicConstantDesc.ofNamed(BSM_INVOKE, "withName", desc.constantType(), MH_WITH_NAME,
147                     desc, name().get().describeConstable().orElseThrow());
148         }
149 
150         return desc;
151     }
152 
153     boolean hasNaturalAlignment() {
154         return size.isPresent() && size.getAsLong() == alignment;
155     }
156 
157     @Override
158     public boolean isPadding() {
159         return this instanceof PaddingLayout;
160     }
161 
162     @Override
163     public int hashCode() {
164         return name.hashCode() << Long.hashCode(alignment);
165     }
166 
167     @Override
168     public boolean equals(Object other) {
169         if (this == other) {
170             return true;
171         }
172 
173         if (!(other instanceof AbstractLayout)) {
174             return false;
175         }
176 
177         return Objects.equals(name, ((AbstractLayout) other).name) &&
178                 Objects.equals(alignment, ((AbstractLayout) other).alignment);
179     }
180 
181     /*** Helper constants for implementing Layout::describeConstable ***/
182 
183     static final ClassDesc CD_MEMORY_LAYOUT = MemoryLayout.class.describeConstable().get();
184 
185     static final ClassDesc CD_VALUE_LAYOUT = ValueLayout.class.describeConstable().get();
186 
187     static final ClassDesc CD_SEQUENCE_LAYOUT = SequenceLayout.class.describeConstable().get();
188 
189     static final ClassDesc CD_GROUP_LAYOUT = GroupLayout.class.describeConstable().get();
190 
191     static final ClassDesc CD_BYTEORDER = ByteOrder.class.describeConstable().get();
192 
193     static final ClassDesc CD_FUNCTION_DESC = FunctionDescriptor.class.describeConstable().get();
194 


195     static final ConstantDesc BIG_ENDIAN = DynamicConstantDesc.ofNamed(BSM_GET_STATIC_FINAL, "BIG_ENDIAN", CD_BYTEORDER, CD_BYTEORDER);
196 
197     static final ConstantDesc LITTLE_ENDIAN = DynamicConstantDesc.ofNamed(BSM_GET_STATIC_FINAL, "LITTLE_ENDIAN", CD_BYTEORDER, CD_BYTEORDER);
198 
199     static final MethodHandleDesc MH_PADDING = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_MEMORY_LAYOUT, "paddingLayout",
200                 MethodTypeDesc.of(CD_MEMORY_LAYOUT, CD_long));
201 



202     static final MethodHandleDesc MH_SIZED_SEQUENCE = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_MEMORY_LAYOUT, "sequenceLayout",
203                 MethodTypeDesc.of(CD_SEQUENCE_LAYOUT, CD_long, CD_MEMORY_LAYOUT));
204 
205     static final MethodHandleDesc MH_UNSIZED_SEQUENCE = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_MEMORY_LAYOUT, "sequenceLayout",
206                 MethodTypeDesc.of(CD_SEQUENCE_LAYOUT, CD_MEMORY_LAYOUT));
207 
208     static final MethodHandleDesc MH_STRUCT = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_MEMORY_LAYOUT, "structLayout",
209                 MethodTypeDesc.of(CD_GROUP_LAYOUT, CD_MEMORY_LAYOUT.arrayType()));
210 
211     static final MethodHandleDesc MH_UNION = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_MEMORY_LAYOUT, "unionLayout",
212                 MethodTypeDesc.of(CD_GROUP_LAYOUT, CD_MEMORY_LAYOUT.arrayType()));
213 
214     static final MethodHandleDesc MH_VALUE = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_MEMORY_LAYOUT, "valueLayout",
215             MethodTypeDesc.of(CD_VALUE_LAYOUT, CD_Class, CD_BYTEORDER));
216 
217     static final MethodHandleDesc MH_VOID_FUNCTION = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.STATIC, CD_FUNCTION_DESC, "ofVoid",
218                 MethodTypeDesc.of(CD_FUNCTION_DESC, CD_MEMORY_LAYOUT.arrayType()));
219 
220     static final MethodHandleDesc MH_FUNCTION = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.STATIC, CD_FUNCTION_DESC, "of",
221                 MethodTypeDesc.of(CD_FUNCTION_DESC, CD_MEMORY_LAYOUT, CD_MEMORY_LAYOUT.arrayType()));
222 
223     static final MethodHandleDesc MH_WITH_BIT_ALIGNMENT = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_VIRTUAL, CD_MEMORY_LAYOUT, "withBitAlignment",
224                 MethodTypeDesc.of(CD_MEMORY_LAYOUT, CD_long));
225 
226     static final MethodHandleDesc MH_WITH_NAME = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_VIRTUAL, CD_MEMORY_LAYOUT, "withName",
227                 MethodTypeDesc.of(CD_MEMORY_LAYOUT, CD_String));
228 }
< prev index next >