< prev index next >

src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/LayoutPath.java

Print this page

 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;
 27 
 28 import jdk.incubator.foreign.MemoryHandles;
 29 import jdk.incubator.foreign.MemoryLayout;
 30 import jdk.incubator.foreign.MemorySegment;
 31 import jdk.internal.access.JavaLangInvokeAccess;
 32 import jdk.internal.access.SharedSecrets;
 33 import jdk.internal.access.foreign.MemorySegmentProxy;
 34 
 35 import jdk.incubator.foreign.GroupLayout;
 36 import jdk.incubator.foreign.SequenceLayout;
 37 import jdk.incubator.foreign.ValueLayout;
 38 
 39 import java.lang.invoke.MethodHandle;
 40 import java.lang.invoke.MethodHandles;
 41 import java.lang.invoke.MethodType;
 42 import java.lang.invoke.VarHandle;
 43 import java.util.ArrayDeque;
 44 import java.util.ArrayList;
 45 import java.util.Deque;
 46 import java.util.List;
 47 import java.util.function.ToLongFunction;
 48 import java.util.function.UnaryOperator;
 49 
 50 /**
 51  * This class provide support for constructing layout paths; that is, starting from a root path (see {@link #rootPath(MemoryLayout, ToLongFunction)},
 52  * a path can be constructed by selecting layout elements using the selector methods provided by this class
 53  * (see {@link #sequenceElement()}, {@link #sequenceElement(long)}, {@link #sequenceElement(long, long)}, {@link #groupElement(String)}).
 54  * Once a path has been fully constructed, clients can ask for the offset associated with the layout element selected
 55  * by the path (see {@link #offset}), or obtain a memory access var handle to access the selected layout element
 56  * given an address pointing to a segment associated with the root layout (see {@link #dereferenceHandle(Class)}).
 57  */
 58 public class LayoutPath {
 59 
 60     private static final JavaLangInvokeAccess JLI = SharedSecrets.getJavaLangInvokeAccess();
 61 
 62     private static final MethodHandle ADD_STRIDE;
 63     private static final MethodHandle MH_ADD_SCALED_OFFSET;
 64     private static final MethodHandle MH_SLICE;
 65 
 66     private static final int UNSPECIFIED_ELEM_INDEX = -1;
 67 
 68     static {
 69         try {
 70             MethodHandles.Lookup lookup = MethodHandles.lookup();
 71             ADD_STRIDE = lookup.findStatic(LayoutPath.class, "addStride",
 72                     MethodType.methodType(long.class, MemorySegment.class, long.class, long.class, long.class));
 73             MH_ADD_SCALED_OFFSET = lookup.findStatic(LayoutPath.class, "addScaledOffset",
 74                     MethodType.methodType(long.class, long.class, long.class, long.class));
 75             MH_SLICE = lookup.findVirtual(MemorySegment.class, "asSlice",
 76                     MethodType.methodType(MemorySegment.class, long.class, long.class));
 77         } catch (Throwable ex) {
 78             throw new ExceptionInInitializerError(ex);
 79         }
 80     }
 81 

139                 l.name().get().equals(name)) {
140                 elem = l;
141                 index = i;
142                 break;
143             } else if (g.isStruct()) {
144                 offset += sizeFunc.applyAsLong(l);
145             }
146         }
147         if (elem == null) {
148             throw badLayoutPath("cannot resolve '" + name + "' in layout " + layout);
149         }
150         return LayoutPath.nestedPath(elem, this.offset + offset, strides, index, this);
151     }
152 
153     // Layout path projections
154 
155     public long offset() {
156         return offset;
157     }
158 
159     public VarHandle dereferenceHandle(Class<?> carrier) {
160         Utils.checkPrimitiveCarrierCompat(carrier, layout);


161         checkAlignment(this);
162 


163         List<Class<?>> expectedCoordinates = new ArrayList<>();
164         Deque<Integer> perms = new ArrayDeque<>();
165         perms.addFirst(0);
166         expectedCoordinates.add(MemorySegment.class);
167 
168         VarHandle handle = Utils.fixUpVarHandle(JLI.memoryAccessVarHandle(carrier, true, layout.byteAlignment() - 1,
169                 ((ValueLayout)layout).order()));
170 
171         for (int i = 0 ; i < strides.length ; i++) {
172             expectedCoordinates.add(long.class);
173             perms.addFirst(0);
174             perms.addLast(i + 1);
175             //add stride
176             handle = MemoryHandles.collectCoordinates(handle, 1 + i,
177                     MethodHandles.insertArguments(ADD_STRIDE, 1, Utils.bitsToBytesOrThrow(strides[strides.length - 1 - i], IllegalStateException::new))); // MS, long, MS_n, long_n, long
178         }
179         //add offset
180         handle = MemoryHandles.insertCoordinates(handle, 1 + strides.length, Utils.bitsToBytesOrThrow(offset, IllegalStateException::new));
181 
182         if (strides.length > 0) {
183             // remove duplicate MS args
184             handle = MemoryHandles.permuteCoordinates(handle, expectedCoordinates, perms.stream().mapToInt(i -> i).toArray());
185         }
186         return handle;
187     }
188 
189     private static long addScaledOffset(long base, long index, long stride) {

209         }
210 
211         MethodHandle offsetHandle = offsetHandle(); // bit offset
212         offsetHandle = MethodHandles.filterReturnValue(offsetHandle, Utils.MH_bitsToBytesOrThrowForOffset); // byte offset
213 
214         MethodHandle sliceHandle = MH_SLICE; // (MS, long, long) -> MS
215         sliceHandle = MethodHandles.insertArguments(sliceHandle, 2, layout.byteSize()); // (MS, long) -> MS
216         sliceHandle = MethodHandles.collectArguments(sliceHandle, 1, offsetHandle); // (MS, ...) -> MS
217 
218         return sliceHandle;
219     }
220 
221     public MemoryLayout layout() {
222         return layout;
223     }
224 
225     public MemoryLayout map(UnaryOperator<MemoryLayout> op) {
226         MemoryLayout newLayout = op.apply(layout);
227         if (enclosing == null) {
228             return newLayout;
229         } else if (enclosing.layout instanceof SequenceLayout) {
230             SequenceLayout seq = (SequenceLayout)enclosing.layout;
231             if (seq.elementCount().isPresent()) {
232                 return enclosing.map(l -> dup(l, MemoryLayout.sequenceLayout(seq.elementCount().getAsLong(), newLayout)));
233             } else {
234                 return enclosing.map(l -> dup(l, MemoryLayout.sequenceLayout(newLayout)));
235             }
236         } else if (enclosing.layout instanceof GroupLayout) {
237             GroupLayout g = (GroupLayout)enclosing.layout;
238             List<MemoryLayout> newElements = new ArrayList<>(g.memberLayouts());
239             //if we selected a layout in a group we must have a valid index
240             newElements.set((int)elementIndex, newLayout);
241             if (g.isUnion()) {
242                 return enclosing.map(l -> dup(l, MemoryLayout.unionLayout(newElements.toArray(new MemoryLayout[0]))));
243             } else {
244                 return enclosing.map(l -> dup(l, MemoryLayout.structLayout(newElements.toArray(new MemoryLayout[0]))));
245             }
246         } else {
247             return newLayout;
248         }
249     }
250 
251     private MemoryLayout dup(MemoryLayout oldLayout, MemoryLayout newLayout) {
252         newLayout = newLayout.withBitAlignment(oldLayout.bitAlignment());
253         if (oldLayout.name().isPresent()) {
254             newLayout.withName(oldLayout.name().get());
255         }
256         return newLayout;
257     }

 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;
 27 
 28 import jdk.incubator.foreign.MemoryHandles;
 29 import jdk.incubator.foreign.MemoryLayout;
 30 import jdk.incubator.foreign.MemorySegment;


 31 import jdk.internal.access.foreign.MemorySegmentProxy;
 32 
 33 import jdk.incubator.foreign.GroupLayout;
 34 import jdk.incubator.foreign.SequenceLayout;
 35 import jdk.incubator.foreign.ValueLayout;
 36 
 37 import java.lang.invoke.MethodHandle;
 38 import java.lang.invoke.MethodHandles;
 39 import java.lang.invoke.MethodType;
 40 import java.lang.invoke.VarHandle;
 41 import java.util.ArrayDeque;
 42 import java.util.ArrayList;
 43 import java.util.Deque;
 44 import java.util.List;
 45 import java.util.function.ToLongFunction;
 46 import java.util.function.UnaryOperator;
 47 
 48 /**
 49  * This class provide support for constructing layout paths; that is, starting from a root path (see {@link #rootPath(MemoryLayout, ToLongFunction)},
 50  * a path can be constructed by selecting layout elements using the selector methods provided by this class
 51  * (see {@link #sequenceElement()}, {@link #sequenceElement(long)}, {@link #sequenceElement(long, long)}, {@link #groupElement(String)}).
 52  * Once a path has been fully constructed, clients can ask for the offset associated with the layout element selected
 53  * by the path (see {@link #offset}), or obtain a memory access var handle to access the selected layout element
 54  * given an address pointing to a segment associated with the root layout (see {@link #dereferenceHandle()}).
 55  */
 56 public class LayoutPath {
 57 


 58     private static final MethodHandle ADD_STRIDE;
 59     private static final MethodHandle MH_ADD_SCALED_OFFSET;
 60     private static final MethodHandle MH_SLICE;
 61 
 62     private static final int UNSPECIFIED_ELEM_INDEX = -1;
 63 
 64     static {
 65         try {
 66             MethodHandles.Lookup lookup = MethodHandles.lookup();
 67             ADD_STRIDE = lookup.findStatic(LayoutPath.class, "addStride",
 68                     MethodType.methodType(long.class, MemorySegment.class, long.class, long.class, long.class));
 69             MH_ADD_SCALED_OFFSET = lookup.findStatic(LayoutPath.class, "addScaledOffset",
 70                     MethodType.methodType(long.class, long.class, long.class, long.class));
 71             MH_SLICE = lookup.findVirtual(MemorySegment.class, "asSlice",
 72                     MethodType.methodType(MemorySegment.class, long.class, long.class));
 73         } catch (Throwable ex) {
 74             throw new ExceptionInInitializerError(ex);
 75         }
 76     }
 77 

135                 l.name().get().equals(name)) {
136                 elem = l;
137                 index = i;
138                 break;
139             } else if (g.isStruct()) {
140                 offset += sizeFunc.applyAsLong(l);
141             }
142         }
143         if (elem == null) {
144             throw badLayoutPath("cannot resolve '" + name + "' in layout " + layout);
145         }
146         return LayoutPath.nestedPath(elem, this.offset + offset, strides, index, this);
147     }
148 
149     // Layout path projections
150 
151     public long offset() {
152         return offset;
153     }
154 
155     public VarHandle dereferenceHandle() {
156         if (!(layout instanceof ValueLayout)) {
157             throw new IllegalArgumentException("Path does not select a value layout");
158         }
159         checkAlignment(this);
160 
161         Class<?> carrier = ((ValueLayout)layout).carrier();
162 
163         List<Class<?>> expectedCoordinates = new ArrayList<>();
164         Deque<Integer> perms = new ArrayDeque<>();
165         perms.addFirst(0);
166         expectedCoordinates.add(MemorySegment.class);
167 
168         VarHandle handle = Utils.makeMemoryAccessVarHandle(carrier, true, layout.byteAlignment() - 1,
169                 ((ValueLayout)layout).order());
170 
171         for (int i = 0 ; i < strides.length ; i++) {
172             expectedCoordinates.add(long.class);
173             perms.addFirst(0);
174             perms.addLast(i + 1);
175             //add stride
176             handle = MemoryHandles.collectCoordinates(handle, 1 + i,
177                     MethodHandles.insertArguments(ADD_STRIDE, 1, Utils.bitsToBytesOrThrow(strides[strides.length - 1 - i], IllegalStateException::new))); // MS, long, MS_n, long_n, long
178         }
179         //add offset
180         handle = MemoryHandles.insertCoordinates(handle, 1 + strides.length, Utils.bitsToBytesOrThrow(offset, IllegalStateException::new));
181 
182         if (strides.length > 0) {
183             // remove duplicate MS args
184             handle = MemoryHandles.permuteCoordinates(handle, expectedCoordinates, perms.stream().mapToInt(i -> i).toArray());
185         }
186         return handle;
187     }
188 
189     private static long addScaledOffset(long base, long index, long stride) {

209         }
210 
211         MethodHandle offsetHandle = offsetHandle(); // bit offset
212         offsetHandle = MethodHandles.filterReturnValue(offsetHandle, Utils.MH_bitsToBytesOrThrowForOffset); // byte offset
213 
214         MethodHandle sliceHandle = MH_SLICE; // (MS, long, long) -> MS
215         sliceHandle = MethodHandles.insertArguments(sliceHandle, 2, layout.byteSize()); // (MS, long) -> MS
216         sliceHandle = MethodHandles.collectArguments(sliceHandle, 1, offsetHandle); // (MS, ...) -> MS
217 
218         return sliceHandle;
219     }
220 
221     public MemoryLayout layout() {
222         return layout;
223     }
224 
225     public MemoryLayout map(UnaryOperator<MemoryLayout> op) {
226         MemoryLayout newLayout = op.apply(layout);
227         if (enclosing == null) {
228             return newLayout;
229         } else if (enclosing.layout instanceof SequenceLayout seq) {

230             if (seq.elementCount().isPresent()) {
231                 return enclosing.map(l -> dup(l, MemoryLayout.sequenceLayout(seq.elementCount().getAsLong(), newLayout)));
232             } else {
233                 return enclosing.map(l -> dup(l, MemoryLayout.sequenceLayout(newLayout)));
234             }
235         } else if (enclosing.layout instanceof GroupLayout g) {

236             List<MemoryLayout> newElements = new ArrayList<>(g.memberLayouts());
237             //if we selected a layout in a group we must have a valid index
238             newElements.set((int)elementIndex, newLayout);
239             if (g.isUnion()) {
240                 return enclosing.map(l -> dup(l, MemoryLayout.unionLayout(newElements.toArray(new MemoryLayout[0]))));
241             } else {
242                 return enclosing.map(l -> dup(l, MemoryLayout.structLayout(newElements.toArray(new MemoryLayout[0]))));
243             }
244         } else {
245             return newLayout;
246         }
247     }
248 
249     private MemoryLayout dup(MemoryLayout oldLayout, MemoryLayout newLayout) {
250         newLayout = newLayout.withBitAlignment(oldLayout.bitAlignment());
251         if (oldLayout.name().isPresent()) {
252             newLayout.withName(oldLayout.name().get());
253         }
254         return newLayout;
255     }
< prev index next >