1 /* 2 * Copyright (c) 2019, 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.incubator.foreign; 27 28 import java.lang.constant.ConstantDesc; 29 import java.lang.constant.ConstantDescs; 30 import java.lang.constant.DynamicConstantDesc; 31 import java.lang.constant.MethodHandleDesc; 32 import java.util.Collections; 33 import java.util.List; 34 import java.util.Objects; 35 import java.util.Optional; 36 import java.util.OptionalLong; 37 import java.util.function.LongBinaryOperator; 38 import java.util.stream.Collectors; 39 40 /** 41 * A group layout is used to combine together multiple <em>member layouts</em>. There are two ways in which member layouts 42 * can be combined: if member layouts are laid out one after the other, the resulting group layout is said to be a <em>struct</em> 43 * (see {@link MemoryLayout#ofStruct(MemoryLayout...)}); conversely, if all member layouts are laid out at the same starting offset, 44 * the resulting group layout is said to be a <em>union</em> (see {@link MemoryLayout#ofUnion(MemoryLayout...)}). 45 * 46 * <p> 47 * This is a <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a> 48 * class; use of identity-sensitive operations (including reference equality 49 * ({@code ==}), identity hash code, or synchronization) on instances of 50 * {@code GroupLayout} may have unpredictable results and should be avoided. 51 * The {@code equals} method should be used for comparisons. 52 * 53 * @implSpec 54 * This class is immutable and thread-safe. 55 */ 56 public final class GroupLayout extends AbstractLayout { 57 58 /** 59 * The group kind. 60 */ 61 enum Kind { 62 /** 63 * A 'struct' kind. 64 */ 65 STRUCT("", MH_STRUCT, Long::sum), 66 /** 67 * A 'union' kind. 68 */ 69 UNION("|", MH_UNION, Math::max); 70 71 final String delimTag; 72 final MethodHandleDesc mhDesc; 73 final LongBinaryOperator sizeOp; 74 75 Kind(String delimTag, MethodHandleDesc mhDesc, LongBinaryOperator sizeOp) { 76 this.delimTag = delimTag; 77 this.mhDesc = mhDesc; 78 this.sizeOp = sizeOp; 79 } 80 81 OptionalLong sizeof(List<MemoryLayout> elems) { 82 long size = 0; 83 for (MemoryLayout elem : elems) { 84 if (AbstractLayout.optSize(elem).isPresent()) { 85 size = sizeOp.applyAsLong(size, elem.bitSize()); 86 } else { 87 return OptionalLong.empty(); 88 } 89 } 90 return OptionalLong.of(size); 91 } 92 93 long alignof(List<MemoryLayout> elems) { 94 return elems.stream().mapToLong(MemoryLayout::bitAlignment).max() // max alignment in case we have member layouts 95 .orElse(1); // or minimal alignment if no member layout is given 96 } 97 } 98 99 private final Kind kind; 100 private final List<MemoryLayout> elements; 101 102 GroupLayout(Kind kind, List<MemoryLayout> elements) { 103 this(kind, elements, kind.alignof(elements), Optional.empty()); 104 } 105 106 GroupLayout(Kind kind, List<MemoryLayout> elements, long alignment, Optional<String> name) { 107 super(kind.sizeof(elements), alignment, name); 108 this.kind = kind; 109 this.elements = elements; 110 } 111 112 /** 113 * Returns the member layouts associated with this group. 114 * 115 * @apiNote the order in which member layouts are returned is the same order in which member layouts have 116 * been passed to one of the group layout factory methods (see {@link MemoryLayout#ofStruct(MemoryLayout...)}, 117 * {@link MemoryLayout#ofUnion(MemoryLayout...)}). 118 * 119 * @return the member layouts associated with this group. 120 */ 121 public List<MemoryLayout> memberLayouts() { 122 return Collections.unmodifiableList(elements); 123 } 124 125 @Override 126 public String toString() { 127 return decorateLayoutString(elements.stream() 128 .map(Object::toString) 129 .collect(Collectors.joining(kind.delimTag, "[", "]"))); 130 } 131 132 /** 133 * Is this group layout a <em>struct</em>? 134 * 135 * @return true, if this group layout is a <em>struct</em>. 136 */ 137 public boolean isStruct() { 138 return kind == Kind.STRUCT; 139 } 140 141 /** 142 * Is this group layout a <em>union</em>? 143 * 144 * @return true, if this group layout is a <em>union</em>. 145 */ 146 public boolean isUnion() { 147 return kind == Kind.UNION; 148 } 149 150 @Override 151 public boolean equals(Object other) { 152 if (this == other) { 153 return true; 154 } 155 if (!super.equals(other)) { 156 return false; 157 } 158 if (!(other instanceof GroupLayout)) { 159 return false; 160 } 161 GroupLayout g = (GroupLayout)other; 162 return kind.equals(g.kind) && elements.equals(g.elements); 163 } 164 165 @Override 166 public int hashCode() { 167 return Objects.hash(super.hashCode(), kind, elements); 168 } 169 170 @Override 171 GroupLayout dup(long alignment, Optional<String> name) { 172 return new GroupLayout(kind, elements, alignment, name); 173 } 174 175 @Override 176 boolean hasNaturalAlignment() { 177 return alignment == kind.alignof(elements); 178 } 179 180 @Override 181 public Optional<DynamicConstantDesc<GroupLayout>> describeConstable() { 182 ConstantDesc[] constants = new ConstantDesc[1 + elements.size()]; 183 constants[0] = kind.mhDesc; 184 for (int i = 0 ; i < elements.size() ; i++) { 185 constants[i + 1] = elements.get(i).describeConstable().get(); 186 } 187 return Optional.of(DynamicConstantDesc.ofNamed( 188 ConstantDescs.BSM_INVOKE, kind.name().toLowerCase(), 189 CD_GROUP_LAYOUT, constants)); 190 } 191 192 //hack: the declarations below are to make javadoc happy; we could have used generics in AbstractLayout 193 //but that causes issues with javadoc, see JDK-8224052 194 195 /** 196 * {@inheritDoc} 197 */ 198 @Override 199 public GroupLayout withName(String name) { 200 return (GroupLayout)super.withName(name); 201 } 202 203 /** 204 * {@inheritDoc} 205 */ 206 @Override 207 public GroupLayout withBitAlignment(long alignmentBits) { 208 return (GroupLayout)super.withBitAlignment(alignmentBits); 209 } 210 }