< prev index next >

src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/aarch64/macos/MacOsAArch64VaList.java

Print this page

  9  * particular file as subject to the "Classpath" exception as provided
 10  * by Oracle in the LICENSE file that accompanied this code.
 11  *
 12  * This code is distributed in the hope that it will be useful, but WITHOUT
 13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 15  * version 2 for more details (a copy is included in the LICENSE file that
 16  * accompanied this code).
 17  *
 18  * You should have received a copy of the GNU General Public License version
 19  * 2 along with this work; if not, write to the Free Software Foundation,
 20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 21  *
 22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 23  * or visit www.oracle.com if you need additional information or have any
 24  * questions.
 25  */
 26 package jdk.internal.foreign.abi.aarch64.macos;
 27 
 28 import jdk.incubator.foreign.*;
 29 import jdk.incubator.foreign.CLinker.VaList;
 30 import jdk.internal.foreign.ResourceScopeImpl;
 31 import jdk.internal.foreign.abi.SharedUtils;
 32 import jdk.internal.foreign.abi.SharedUtils.SimpleVaArg;
 33 import jdk.internal.foreign.abi.aarch64.*;
 34 
 35 import java.lang.invoke.VarHandle;
 36 import java.util.ArrayList;
 37 import java.util.List;
 38 import java.util.Objects;
 39 
 40 import static jdk.internal.foreign.PlatformLayouts.AArch64.C_POINTER;
 41 import static jdk.internal.foreign.abi.SharedUtils.alignUp;
 42 
 43 /**
 44  * Simplified va_list implementation used on macOS where all variadic
 45  * parameters are passed on the stack and the type of va_list decays to
 46  * char* instead of the structure defined in the AAPCS.
 47  */
 48 public non-sealed class MacOsAArch64VaList implements VaList {
 49     public static final Class<?> CARRIER = MemoryAddress.class;
 50     private static final long VA_SLOT_SIZE_BYTES = 8;
 51     private static final VarHandle VH_address = MemoryHandles.asAddressVarHandle(C_POINTER.varHandle(long.class));
 52 
 53     private static final VaList EMPTY = new SharedUtils.EmptyVaList(MemoryAddress.NULL);
 54 
 55     private MemorySegment segment;
 56     private final ResourceScope scope;
 57 
 58     private MacOsAArch64VaList(MemorySegment segment, ResourceScope scope) {
 59         this.segment = segment;
 60         this.scope = scope;
 61     }
 62 
 63     public static final VaList empty() {
 64         return EMPTY;
 65     }
 66 
 67     @Override
 68     public int vargAsInt(MemoryLayout layout) {
 69         return (int) read(int.class, layout);
 70     }
 71 
 72     @Override
 73     public long vargAsLong(MemoryLayout layout) {
 74         return (long) read(long.class, layout);
 75     }
 76 
 77     @Override
 78     public double vargAsDouble(MemoryLayout layout) {
 79         return (double) read(double.class, layout);
 80     }
 81 
 82     @Override
 83     public MemoryAddress vargAsAddress(MemoryLayout layout) {
 84         return (MemoryAddress) read(MemoryAddress.class, layout);
 85     }
 86 
 87     @Override
 88     public MemorySegment vargAsSegment(MemoryLayout layout, SegmentAllocator allocator) {
 89         Objects.requireNonNull(allocator);
 90         return (MemorySegment) read(MemorySegment.class, layout, allocator);
 91     }
 92 
 93     @Override
 94     public MemorySegment vargAsSegment(MemoryLayout layout, ResourceScope scope) {
 95         return vargAsSegment(layout, SegmentAllocator.ofScope(scope));
 96     }
 97 
 98     private Object read(Class<?> carrier, MemoryLayout layout) {
 99         return read(carrier, layout, SharedUtils.THROWING_ALLOCATOR);
100     }
101 
102     private Object read(Class<?> carrier, MemoryLayout layout, SegmentAllocator allocator) {
103         Objects.requireNonNull(layout);
104         SharedUtils.checkCompatibleType(carrier, layout, MacOsAArch64Linker.ADDRESS_SIZE);
105         Object res;
106         if (carrier == MemorySegment.class) {
107             TypeClass typeClass = TypeClass.classifyLayout(layout);
108             res = switch (typeClass) {
109                 case STRUCT_REFERENCE -> {
110                     MemoryAddress structAddr = (MemoryAddress) VH_address.get(segment);
111                     MemorySegment struct = structAddr.asSegment(layout.byteSize(), scope());
112                     MemorySegment seg = allocator.allocate(layout);
113                     seg.copyFrom(struct);
114                     segment = segment.asSlice(VA_SLOT_SIZE_BYTES);
115                     yield seg;
116                 }
117                 case STRUCT_REGISTER, STRUCT_HFA -> {
118                     MemorySegment struct = allocator.allocate(layout);
119                     struct.copyFrom(segment.asSlice(0L, layout.byteSize()));
120                     segment = segment.asSlice(alignUp(layout.byteSize(), VA_SLOT_SIZE_BYTES));
121                     yield struct;
122                 }
123                 default -> throw new IllegalStateException("Unexpected TypeClass: " + typeClass);
124             };
125         } else {
126             VarHandle reader = SharedUtils.vhPrimitiveOrAddress(carrier, layout);
127             res = reader.get(segment);
128             segment = segment.asSlice(VA_SLOT_SIZE_BYTES);
129         }
130         return res;
131     }
132 
133     @Override
134     public void skip(MemoryLayout... layouts) {
135         Objects.requireNonNull(layouts);

136 
137         for (MemoryLayout layout : layouts) {
138             Objects.requireNonNull(layout);
139             segment = segment.asSlice(switch (TypeClass.classifyLayout(layout)) {
140                 case STRUCT_REGISTER, STRUCT_HFA -> alignUp(layout.byteSize(), VA_SLOT_SIZE_BYTES);
141                 default -> VA_SLOT_SIZE_BYTES;
142             });
143         }
144     }
145 
146     static MacOsAArch64VaList ofAddress(MemoryAddress addr, ResourceScope scope) {
147         MemorySegment segment = addr.asSegment(Long.MAX_VALUE, scope);
148         return new MacOsAArch64VaList(segment, scope);
149     }
150 
151     static Builder builder(ResourceScope scope) {
152         return new Builder(scope);
153     }
154 
155     @Override
156     public ResourceScope scope() {
157         return scope;
158     }
159 
160     @Override
161     public VaList copy() {
162         ((ResourceScopeImpl)scope).checkValidStateSlow();
163         return new MacOsAArch64VaList(segment, scope);
164     }
165 
166     @Override
167     public MemoryAddress address() {
168         return segment.address();
169     }
170 
171     public static non-sealed class Builder implements VaList.Builder {
172 
173         private final ResourceScope scope;
174         private final List<SimpleVaArg> args = new ArrayList<>();
175 
176         public Builder(ResourceScope scope) {
177             ((ResourceScopeImpl)scope).checkValidStateSlow();
178             this.scope = scope;
179         }
180 
181         private Builder arg(Class<?> carrier, MemoryLayout layout, Object value) {
182             Objects.requireNonNull(layout);
183             Objects.requireNonNull(value);
184             SharedUtils.checkCompatibleType(carrier, layout, MacOsAArch64Linker.ADDRESS_SIZE);
185             args.add(new SimpleVaArg(carrier, layout, value));
186             return this;
187         }
188 
189         @Override
190         public Builder vargFromInt(ValueLayout layout, int value) {
191             return arg(int.class, layout, value);
192         }
193 
194         @Override
195         public Builder vargFromLong(ValueLayout layout, long value) {
196             return arg(long.class, layout, value);
197         }
198 
199         @Override
200         public Builder vargFromDouble(ValueLayout layout, double value) {
201             return arg(double.class, layout, value);
202         }
203 
204         @Override
205         public Builder vargFromAddress(ValueLayout layout, Addressable value) {
206             return arg(MemoryAddress.class, layout, value.address());
207         }
208 
209         @Override
210         public Builder vargFromSegment(GroupLayout layout, MemorySegment value) {
211             return arg(MemorySegment.class, layout, value);
212         }
213 
214         public VaList build() {
215             if (args.isEmpty()) {
216                 return EMPTY;
217             }
218 
219             SegmentAllocator allocator = SegmentAllocator.arenaAllocator(scope);
220 
221             // Each argument may occupy up to four slots
222             MemorySegment segment = allocator.allocate(VA_SLOT_SIZE_BYTES * args.size() * 4);
223 
224             List<MemorySegment> attachedSegments = new ArrayList<>();
225             attachedSegments.add(segment);
226             MemorySegment cursor = segment;
227 
228             for (SimpleVaArg arg : args) {
229                 if (arg.carrier == MemorySegment.class) {
230                     MemorySegment msArg = ((MemorySegment) arg.value);
231                     TypeClass typeClass = TypeClass.classifyLayout(arg.layout);
232                     switch (typeClass) {
233                         case STRUCT_REFERENCE -> {
234                             MemorySegment copy = allocator.allocate(arg.layout);
235                             copy.copyFrom(msArg); // by-value
236                             attachedSegments.add(copy);
237                             VH_address.set(cursor, copy.address());
238                             cursor = cursor.asSlice(VA_SLOT_SIZE_BYTES);
239                         }
240                         case STRUCT_REGISTER, STRUCT_HFA -> {
241                             cursor.copyFrom(msArg.asSlice(0, arg.layout.byteSize()));
242                             cursor = cursor.asSlice(alignUp(arg.layout.byteSize(), VA_SLOT_SIZE_BYTES));
243                         }
244                         default -> throw new IllegalStateException("Unexpected TypeClass: " + typeClass);
245                     }
246                 } else {
247                     VarHandle writer = arg.varHandle();
248                     writer.set(cursor, arg.value);
249                     cursor = cursor.asSlice(VA_SLOT_SIZE_BYTES);
250                 }
251             }
252 
253             return new MacOsAArch64VaList(segment, scope);
254         }
255     }
256 }

  9  * particular file as subject to the "Classpath" exception as provided
 10  * by Oracle in the LICENSE file that accompanied this code.
 11  *
 12  * This code is distributed in the hope that it will be useful, but WITHOUT
 13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 15  * version 2 for more details (a copy is included in the LICENSE file that
 16  * accompanied this code).
 17  *
 18  * You should have received a copy of the GNU General Public License version
 19  * 2 along with this work; if not, write to the Free Software Foundation,
 20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 21  *
 22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 23  * or visit www.oracle.com if you need additional information or have any
 24  * questions.
 25  */
 26 package jdk.internal.foreign.abi.aarch64.macos;
 27 
 28 import jdk.incubator.foreign.*;
 29 import jdk.internal.foreign.Scoped;
 30 import jdk.internal.foreign.ResourceScopeImpl;
 31 import jdk.internal.foreign.abi.SharedUtils;
 32 import jdk.internal.foreign.abi.SharedUtils.SimpleVaArg;
 33 import jdk.internal.foreign.abi.aarch64.*;
 34 
 35 import java.lang.invoke.VarHandle;
 36 import java.util.ArrayList;
 37 import java.util.List;
 38 import java.util.Objects;
 39 
 40 import static jdk.internal.foreign.PlatformLayouts.AArch64.C_POINTER;
 41 import static jdk.internal.foreign.abi.SharedUtils.alignUp;
 42 
 43 /**
 44  * Simplified va_list implementation used on macOS where all variadic
 45  * parameters are passed on the stack and the type of va_list decays to
 46  * char* instead of the structure defined in the AAPCS.
 47  */
 48 public non-sealed class MacOsAArch64VaList implements VaList, Scoped {
 49     public static final Class<?> CARRIER = MemoryAddress.class;
 50     private static final long VA_SLOT_SIZE_BYTES = 8;
 51     private static final VarHandle VH_address = C_POINTER.varHandle();
 52 
 53     private static final VaList EMPTY = new SharedUtils.EmptyVaList(MemoryAddress.NULL);
 54 
 55     private MemorySegment segment;
 56     private final ResourceScope scope;
 57 
 58     private MacOsAArch64VaList(MemorySegment segment, ResourceScope scope) {
 59         this.segment = segment;
 60         this.scope = scope;
 61     }
 62 
 63     public static final VaList empty() {
 64         return EMPTY;
 65     }
 66 
 67     @Override
 68     public int nextVarg(ValueLayout.OfInt layout) {
 69         return (int) read(int.class, layout);
 70     }
 71 
 72     @Override
 73     public long nextVarg(ValueLayout.OfLong layout) {
 74         return (long) read(long.class, layout);
 75     }
 76 
 77     @Override
 78     public double nextVarg(ValueLayout.OfDouble layout) {
 79         return (double) read(double.class, layout);
 80     }
 81 
 82     @Override
 83     public MemoryAddress nextVarg(ValueLayout.OfAddress layout) {
 84         return (MemoryAddress) read(MemoryAddress.class, layout);
 85     }
 86 
 87     @Override
 88     public MemorySegment nextVarg(GroupLayout layout, SegmentAllocator allocator) {
 89         Objects.requireNonNull(allocator);
 90         return (MemorySegment) read(MemorySegment.class, layout, allocator);
 91     }
 92 





 93     private Object read(Class<?> carrier, MemoryLayout layout) {
 94         return read(carrier, layout, SharedUtils.THROWING_ALLOCATOR);
 95     }
 96 
 97     private Object read(Class<?> carrier, MemoryLayout layout, SegmentAllocator allocator) {
 98         Objects.requireNonNull(layout);

 99         Object res;
100         if (carrier == MemorySegment.class) {
101             TypeClass typeClass = TypeClass.classifyLayout(layout);
102             res = switch (typeClass) {
103                 case STRUCT_REFERENCE -> {
104                     MemoryAddress structAddr = (MemoryAddress) VH_address.get(segment);
105                     MemorySegment struct = MemorySegment.ofAddressNative(structAddr, layout.byteSize(), scope());
106                     MemorySegment seg = allocator.allocate(layout);
107                     seg.copyFrom(struct);
108                     segment = segment.asSlice(VA_SLOT_SIZE_BYTES);
109                     yield seg;
110                 }
111                 case STRUCT_REGISTER, STRUCT_HFA -> {
112                     MemorySegment struct = allocator.allocate(layout)
113                             .copyFrom(segment.asSlice(0, layout.byteSize()));
114                     segment = segment.asSlice(alignUp(layout.byteSize(), VA_SLOT_SIZE_BYTES));
115                     yield struct;
116                 }
117                 default -> throw new IllegalStateException("Unexpected TypeClass: " + typeClass);
118             };
119         } else {
120             VarHandle reader = layout.varHandle();
121             res = reader.get(segment);
122             segment = segment.asSlice(VA_SLOT_SIZE_BYTES);
123         }
124         return res;
125     }
126 
127     @Override
128     public void skip(MemoryLayout... layouts) {
129         Objects.requireNonNull(layouts);
130         ((ResourceScopeImpl)scope).checkValidStateSlow();
131 
132         for (MemoryLayout layout : layouts) {
133             Objects.requireNonNull(layout);
134             segment = segment.asSlice(switch (TypeClass.classifyLayout(layout)) {
135                 case STRUCT_REGISTER, STRUCT_HFA -> alignUp(layout.byteSize(), VA_SLOT_SIZE_BYTES);
136                 default -> VA_SLOT_SIZE_BYTES;
137             });
138         }
139     }
140 
141     static MacOsAArch64VaList ofAddress(MemoryAddress addr, ResourceScope scope) {
142         MemorySegment segment = MemorySegment.ofAddressNative(addr, Long.MAX_VALUE, scope);
143         return new MacOsAArch64VaList(segment, scope);
144     }
145 
146     static Builder builder(ResourceScope scope) {
147         return new Builder(scope);
148     }
149 
150     @Override
151     public ResourceScope scope() {
152         return scope;
153     }
154 
155     @Override
156     public VaList copy() {
157         ((ResourceScopeImpl)scope).checkValidStateSlow();
158         return new MacOsAArch64VaList(segment, scope);
159     }
160 
161     @Override
162     public MemoryAddress address() {
163         return segment.address();
164     }
165 
166     public static non-sealed class Builder implements VaList.Builder {
167 
168         private final ResourceScope scope;
169         private final List<SimpleVaArg> args = new ArrayList<>();
170 
171         public Builder(ResourceScope scope) {
172             ((ResourceScopeImpl)scope).checkValidStateSlow();
173             this.scope = scope;
174         }
175 
176         private Builder arg(Class<?> carrier, MemoryLayout layout, Object value) {
177             Objects.requireNonNull(layout);
178             Objects.requireNonNull(value);

179             args.add(new SimpleVaArg(carrier, layout, value));
180             return this;
181         }
182 
183         @Override
184         public Builder addVarg(ValueLayout.OfInt layout, int value) {
185             return arg(int.class, layout, value);
186         }
187 
188         @Override
189         public Builder addVarg(ValueLayout.OfLong layout, long value) {
190             return arg(long.class, layout, value);
191         }
192 
193         @Override
194         public Builder addVarg(ValueLayout.OfDouble layout, double value) {
195             return arg(double.class, layout, value);
196         }
197 
198         @Override
199         public Builder addVarg(ValueLayout.OfAddress layout, Addressable value) {
200             return arg(MemoryAddress.class, layout, value.address());
201         }
202 
203         @Override
204         public Builder addVarg(GroupLayout layout, MemorySegment value) {
205             return arg(MemorySegment.class, layout, value);
206         }
207 
208         public VaList build() {
209             if (args.isEmpty()) {
210                 return EMPTY;
211             }
212 
213             SegmentAllocator allocator = SegmentAllocator.newNativeArena(scope);
214 
215             // Each argument may occupy up to four slots
216             MemorySegment segment = allocator.allocate(VA_SLOT_SIZE_BYTES * args.size() * 4);
217 
218             List<MemorySegment> attachedSegments = new ArrayList<>();
219             attachedSegments.add(segment);
220             MemorySegment cursor = segment;
221 
222             for (SimpleVaArg arg : args) {
223                 if (arg.carrier == MemorySegment.class) {
224                     MemorySegment msArg = ((MemorySegment) arg.value);
225                     TypeClass typeClass = TypeClass.classifyLayout(arg.layout);
226                     switch (typeClass) {
227                         case STRUCT_REFERENCE -> {
228                             MemorySegment copy = allocator.allocate(arg.layout);
229                             copy.copyFrom(msArg); // by-value
230                             attachedSegments.add(copy);
231                             VH_address.set(cursor, copy.address());
232                             cursor = cursor.asSlice(VA_SLOT_SIZE_BYTES);
233                         }
234                         case STRUCT_REGISTER, STRUCT_HFA ->
235                             cursor.copyFrom(msArg.asSlice(0, arg.layout.byteSize()))
236                                     .asSlice(alignUp(arg.layout.byteSize(), VA_SLOT_SIZE_BYTES));

237                         default -> throw new IllegalStateException("Unexpected TypeClass: " + typeClass);
238                     }
239                 } else {
240                     VarHandle writer = arg.varHandle();
241                     writer.set(cursor, arg.value);
242                     cursor = cursor.asSlice(VA_SLOT_SIZE_BYTES);
243                 }
244             }
245 
246             return new MacOsAArch64VaList(segment, scope);
247         }
248     }
249 }
< prev index next >