< prev index next >

src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/x64/windows/CallArranger.java

Print this page

 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 package jdk.internal.foreign.abi.x64.windows;
 26 
 27 import jdk.incubator.foreign.FunctionDescriptor;
 28 import jdk.incubator.foreign.GroupLayout;
 29 import jdk.incubator.foreign.MemoryAddress;
 30 import jdk.incubator.foreign.MemoryLayout;
 31 import jdk.incubator.foreign.MemorySegment;


 32 import jdk.internal.foreign.Utils;
 33 import jdk.internal.foreign.abi.CallingSequenceBuilder;
 34 import jdk.internal.foreign.abi.UpcallHandler;
 35 import jdk.internal.foreign.abi.ABIDescriptor;
 36 import jdk.internal.foreign.abi.Binding;
 37 import jdk.internal.foreign.abi.CallingSequence;
 38 import jdk.internal.foreign.abi.ProgrammableInvoker;
 39 import jdk.internal.foreign.abi.ProgrammableUpcallHandler;
 40 import jdk.internal.foreign.abi.VMStorage;
 41 import jdk.internal.foreign.abi.x64.X86_64Architecture;
 42 import jdk.internal.foreign.abi.SharedUtils;
 43 
 44 import java.lang.invoke.MethodHandle;
 45 import java.lang.invoke.MethodType;
 46 import java.util.List;
 47 import java.util.Optional;
 48 
 49 import static jdk.internal.foreign.PlatformLayouts.*;
 50 import static jdk.internal.foreign.abi.x64.X86_64Architecture.*;
 51 
 52 /**
 53  * For the Windowx x64 C ABI specifically, this class uses the ProgrammableInvoker API, namely CallingSequenceBuilder2
 54  * to translate a C FunctionDescriptor into a CallingSequence2, which can then be turned into a MethodHandle.

 65         new VMStorage[] { xmm0 },
 66         0,
 67         new VMStorage[] { rax, r10, r11 },
 68         new VMStorage[] { xmm4, xmm5 },
 69         16,
 70         32
 71     );
 72 
 73     // record
 74     public static class Bindings {
 75         public final CallingSequence callingSequence;
 76         public final boolean isInMemoryReturn;
 77 
 78         Bindings(CallingSequence callingSequence, boolean isInMemoryReturn) {
 79             this.callingSequence = callingSequence;
 80             this.isInMemoryReturn = isInMemoryReturn;
 81         }
 82     }
 83 
 84     public static Bindings getBindings(MethodType mt, FunctionDescriptor cDesc, boolean forUpcall) {
 85         SharedUtils.checkFunctionTypes(mt, cDesc, Windowsx64Linker.ADDRESS_SIZE);
 86 
 87         class CallingSequenceBuilderHelper {
 88             final CallingSequenceBuilder csb = new CallingSequenceBuilder(forUpcall);
 89             final BindingCalculator argCalc =
 90                 forUpcall ? new BoxBindingCalculator(true) : new UnboxBindingCalculator(true);
 91             final BindingCalculator retCalc =
 92                 forUpcall ? new UnboxBindingCalculator(false) : new BoxBindingCalculator(false);
 93 
 94             void addArgumentBindings(Class<?> carrier, MemoryLayout layout) {
 95                 csb.addArgumentBindings(carrier, layout, argCalc.getBindings(carrier, layout));
 96             }
 97 
 98             void setReturnBindings(Class<?> carrier, MemoryLayout layout) {
 99                 csb.setReturnBindings(carrier, layout, retCalc.getBindings(carrier, layout));
100             }
101         }
102         var csb = new CallingSequenceBuilderHelper();
103 
104         boolean returnInMemory = isInMemoryReturn(cDesc.returnLayout());
105         if (returnInMemory) {
106             Class<?> carrier = MemoryAddress.class;
107             MemoryLayout layout = Win64.C_POINTER;
108             csb.addArgumentBindings(carrier, layout);
109             if (forUpcall) {
110                 csb.setReturnBindings(carrier, layout);
111             }
112         } else if (cDesc.returnLayout().isPresent()) {
113             csb.setReturnBindings(mt.returnType(), cDesc.returnLayout().get());
114         }
115 
116         for (int i = 0; i < mt.parameterCount(); i++) {
117             csb.addArgumentBindings(mt.parameterType(i), cDesc.argumentLayouts().get(i));
118         }
119 
120         csb.csb.setTrivial(SharedUtils.isTrivial(cDesc));
121 
122         return new Bindings(csb.csb.build(), returnInMemory);
123     }
124 
125     public static MethodHandle arrangeDowncall(MethodType mt, FunctionDescriptor cDesc) {
126         Bindings bindings = getBindings(mt, cDesc, false);
127 
128         MethodHandle handle = new ProgrammableInvoker(CWindows, bindings.callingSequence).getBoundMethodHandle();
129 
130         if (bindings.isInMemoryReturn) {
131             handle = SharedUtils.adaptDowncallForIMR(handle, cDesc);
132         }
133 
134         return handle;
135     }
136 
137     public static UpcallHandler arrangeUpcall(MethodHandle target, MethodType mt, FunctionDescriptor cDesc) {
138         Bindings bindings = getBindings(mt, cDesc, true);
139 
140         if (bindings.isInMemoryReturn) {
141             target = SharedUtils.adaptUpcallForIMR(target, false /* need the return value as well */);
142         }
143 
144         return ProgrammableUpcallHandler.make(CWindows, target, bindings.callingSequence);
145     }
146 
147     private static boolean isInMemoryReturn(Optional<MemoryLayout> returnLayout) {
148         return returnLayout
149                 .filter(GroupLayout.class::isInstance)
150                 .filter(g -> !TypeClass.isRegisterAggregate(g))
151                 .isPresent();
152     }
153 
154     static class StorageCalculator {
155         private final boolean forArguments;
156 
157         private int nRegs = 0;
158         private long stackOffset = 0;
159 
160         public StorageCalculator(boolean forArguments) {
161             this.forArguments = forArguments;
162         }
163 
164         VMStorage nextStorage(int type, MemoryLayout layout) {

168                 long alignment = Math.max(SharedUtils.alignment(layout, true), STACK_SLOT_SIZE);
169                 stackOffset = Utils.alignUp(stackOffset, alignment);
170 
171                 VMStorage storage = X86_64Architecture.stackStorage((int) (stackOffset / STACK_SLOT_SIZE));
172                 stackOffset += STACK_SLOT_SIZE;
173                 return storage;
174             }
175             return (forArguments
176                     ? CWindows.inputStorage
177                     : CWindows.outputStorage)
178                  [type][nRegs++];
179         }
180 
181         public VMStorage extraVarargsStorage() {
182             assert forArguments;
183             return CWindows.inputStorage[StorageClasses.INTEGER][nRegs - 1];
184         }
185     }
186 
187     private interface BindingCalculator {
188         List<Binding> getBindings(Class<?> carrier, MemoryLayout layout);
189     }
190 
191     static class UnboxBindingCalculator implements BindingCalculator {
192         private final StorageCalculator storageCalculator;
193 
194         UnboxBindingCalculator(boolean forArguments) {
195             this.storageCalculator = new StorageCalculator(forArguments);
196         }
197 
198         @Override
199         public List<Binding> getBindings(Class<?> carrier, MemoryLayout layout) {
200             TypeClass argumentClass = TypeClass.typeClassFor(layout);
201             Binding.Builder bindings = Binding.builder();
202             switch (argumentClass) {
203                 case STRUCT_REGISTER: {
204                     assert carrier == MemorySegment.class;
205                     VMStorage storage = storageCalculator.nextStorage(StorageClasses.INTEGER, layout);
206                     Class<?> type = SharedUtils.primitiveCarrierForSize(layout.byteSize(), false);
207                     bindings.bufferLoad(0, type)
208                             .vmStore(storage, type);
209                     break;
210                 }
211                 case STRUCT_REFERENCE: {
212                     assert carrier == MemorySegment.class;
213                     bindings.copy(layout)
214                             .baseAddress()
215                             .unboxAddress();
216                     VMStorage storage = storageCalculator.nextStorage(StorageClasses.INTEGER, layout);
217                     bindings.vmStore(storage, long.class);
218                     break;
219                 }
220                 case POINTER: {
221                     bindings.unboxAddress();
222                     VMStorage storage = storageCalculator.nextStorage(StorageClasses.INTEGER, layout);
223                     bindings.vmStore(storage, long.class);
224                     break;
225                 }
226                 case INTEGER: {
227                     VMStorage storage = storageCalculator.nextStorage(StorageClasses.INTEGER, layout);
228                     bindings.vmStore(storage, carrier);
229                     break;
230                 }
231                 case FLOAT: {
232                     VMStorage storage = storageCalculator.nextStorage(StorageClasses.VECTOR, layout);
233                     bindings.vmStore(storage, carrier);
234                     break;
235                 }
236                 case VARARG_FLOAT: {
237                     VMStorage storage = storageCalculator.nextStorage(StorageClasses.VECTOR, layout);
238                     if (!INSTANCE.isStackType(storage.type())) { // need extra for register arg
239                         VMStorage extraStorage = storageCalculator.extraVarargsStorage();
240                         bindings.dup()
241                                 .vmStore(extraStorage, carrier);
242                     }
243 
244                     bindings.vmStore(storage, carrier);
245                     break;
246                 }
247                 default:
248                     throw new UnsupportedOperationException("Unhandled class " + argumentClass);
249             }
250             return bindings.build();
251         }
252     }
253 
254     static class BoxBindingCalculator implements BindingCalculator {
255         private final StorageCalculator storageCalculator;
256 
257         BoxBindingCalculator(boolean forArguments) {
258             this.storageCalculator = new StorageCalculator(forArguments);
259         }
260 
261         @Override
262         public List<Binding> getBindings(Class<?> carrier, MemoryLayout layout) {
263             TypeClass argumentClass = TypeClass.typeClassFor(layout);
264             Binding.Builder bindings = Binding.builder();
265             switch (argumentClass) {
266                 case STRUCT_REGISTER: {
267                     assert carrier == MemorySegment.class;
268                     bindings.allocate(layout)
269                             .dup();
270                     VMStorage storage = storageCalculator.nextStorage(StorageClasses.INTEGER, layout);
271                     Class<?> type = SharedUtils.primitiveCarrierForSize(layout.byteSize(), false);
272                     bindings.vmLoad(storage, type)
273                             .bufferStore(0, type);
274                     break;
275                 }
276                 case STRUCT_REFERENCE: {
277                     assert carrier == MemorySegment.class;
278                     VMStorage storage = storageCalculator.nextStorage(StorageClasses.INTEGER, layout);
279                     bindings.vmLoad(storage, long.class)
280                             .boxAddress()
281                             .toSegment(layout);
282                     break;
283                 }

 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 package jdk.internal.foreign.abi.x64.windows;
 26 
 27 import jdk.incubator.foreign.FunctionDescriptor;
 28 import jdk.incubator.foreign.GroupLayout;
 29 import jdk.incubator.foreign.MemoryAddress;
 30 import jdk.incubator.foreign.MemoryLayout;
 31 import jdk.incubator.foreign.MemorySegment;
 32 import jdk.incubator.foreign.NativeSymbol;
 33 import jdk.incubator.foreign.ResourceScope;
 34 import jdk.internal.foreign.Utils;
 35 import jdk.internal.foreign.abi.CallingSequenceBuilder;

 36 import jdk.internal.foreign.abi.ABIDescriptor;
 37 import jdk.internal.foreign.abi.Binding;
 38 import jdk.internal.foreign.abi.CallingSequence;
 39 import jdk.internal.foreign.abi.ProgrammableInvoker;
 40 import jdk.internal.foreign.abi.ProgrammableUpcallHandler;
 41 import jdk.internal.foreign.abi.VMStorage;
 42 import jdk.internal.foreign.abi.x64.X86_64Architecture;
 43 import jdk.internal.foreign.abi.SharedUtils;
 44 
 45 import java.lang.invoke.MethodHandle;
 46 import java.lang.invoke.MethodType;
 47 import java.util.List;
 48 import java.util.Optional;
 49 
 50 import static jdk.internal.foreign.PlatformLayouts.*;
 51 import static jdk.internal.foreign.abi.x64.X86_64Architecture.*;
 52 
 53 /**
 54  * For the Windowx x64 C ABI specifically, this class uses the ProgrammableInvoker API, namely CallingSequenceBuilder2
 55  * to translate a C FunctionDescriptor into a CallingSequence2, which can then be turned into a MethodHandle.

 66         new VMStorage[] { xmm0 },
 67         0,
 68         new VMStorage[] { rax, r10, r11 },
 69         new VMStorage[] { xmm4, xmm5 },
 70         16,
 71         32
 72     );
 73 
 74     // record
 75     public static class Bindings {
 76         public final CallingSequence callingSequence;
 77         public final boolean isInMemoryReturn;
 78 
 79         Bindings(CallingSequence callingSequence, boolean isInMemoryReturn) {
 80             this.callingSequence = callingSequence;
 81             this.isInMemoryReturn = isInMemoryReturn;
 82         }
 83     }
 84 
 85     public static Bindings getBindings(MethodType mt, FunctionDescriptor cDesc, boolean forUpcall) {


 86         class CallingSequenceBuilderHelper {
 87             final CallingSequenceBuilder csb = new CallingSequenceBuilder(forUpcall);
 88             final BindingCalculator argCalc =
 89                 forUpcall ? new BoxBindingCalculator(true) : new UnboxBindingCalculator(true);
 90             final BindingCalculator retCalc =
 91                 forUpcall ? new UnboxBindingCalculator(false) : new BoxBindingCalculator(false);
 92 
 93             void addArgumentBindings(Class<?> carrier, MemoryLayout layout, boolean isVararg) {
 94                 csb.addArgumentBindings(carrier, layout, argCalc.getBindings(carrier, layout, isVararg));
 95             }
 96 
 97             void setReturnBindings(Class<?> carrier, MemoryLayout layout) {
 98                 csb.setReturnBindings(carrier, layout, retCalc.getBindings(carrier, layout, false));
 99             }
100         }
101         var csb = new CallingSequenceBuilderHelper();
102 
103         boolean returnInMemory = isInMemoryReturn(cDesc.returnLayout());
104         if (returnInMemory) {
105             Class<?> carrier = MemoryAddress.class;
106             MemoryLayout layout = Win64.C_POINTER;
107             csb.addArgumentBindings(carrier, layout, false);
108             if (forUpcall) {
109                 csb.setReturnBindings(carrier, layout);
110             }
111         } else if (cDesc.returnLayout().isPresent()) {
112             csb.setReturnBindings(mt.returnType(), cDesc.returnLayout().get());
113         }
114 
115         for (int i = 0; i < mt.parameterCount(); i++) {
116             csb.addArgumentBindings(mt.parameterType(i), cDesc.argumentLayouts().get(i), SharedUtils.isVarargsIndex(cDesc, i));
117         }
118 
119         csb.csb.setTrivial(SharedUtils.isTrivial(cDesc));
120 
121         return new Bindings(csb.csb.build(), returnInMemory);
122     }
123 
124     public static MethodHandle arrangeDowncall(MethodType mt, FunctionDescriptor cDesc) {
125         Bindings bindings = getBindings(mt, cDesc, false);
126 
127         MethodHandle handle = new ProgrammableInvoker(CWindows, bindings.callingSequence).getBoundMethodHandle();
128 
129         if (bindings.isInMemoryReturn) {
130             handle = SharedUtils.adaptDowncallForIMR(handle, cDesc);
131         }
132 
133         return handle;
134     }
135 
136     public static NativeSymbol arrangeUpcall(MethodHandle target, MethodType mt, FunctionDescriptor cDesc, ResourceScope scope) {
137         Bindings bindings = getBindings(mt, cDesc, true);
138 
139         if (bindings.isInMemoryReturn) {
140             target = SharedUtils.adaptUpcallForIMR(target, false /* need the return value as well */);
141         }
142 
143         return ProgrammableUpcallHandler.make(CWindows, target, bindings.callingSequence, scope);
144     }
145 
146     private static boolean isInMemoryReturn(Optional<MemoryLayout> returnLayout) {
147         return returnLayout
148                 .filter(GroupLayout.class::isInstance)
149                 .filter(g -> !TypeClass.isRegisterAggregate(g))
150                 .isPresent();
151     }
152 
153     static class StorageCalculator {
154         private final boolean forArguments;
155 
156         private int nRegs = 0;
157         private long stackOffset = 0;
158 
159         public StorageCalculator(boolean forArguments) {
160             this.forArguments = forArguments;
161         }
162 
163         VMStorage nextStorage(int type, MemoryLayout layout) {

167                 long alignment = Math.max(SharedUtils.alignment(layout, true), STACK_SLOT_SIZE);
168                 stackOffset = Utils.alignUp(stackOffset, alignment);
169 
170                 VMStorage storage = X86_64Architecture.stackStorage((int) (stackOffset / STACK_SLOT_SIZE));
171                 stackOffset += STACK_SLOT_SIZE;
172                 return storage;
173             }
174             return (forArguments
175                     ? CWindows.inputStorage
176                     : CWindows.outputStorage)
177                  [type][nRegs++];
178         }
179 
180         public VMStorage extraVarargsStorage() {
181             assert forArguments;
182             return CWindows.inputStorage[StorageClasses.INTEGER][nRegs - 1];
183         }
184     }
185 
186     private interface BindingCalculator {
187         List<Binding> getBindings(Class<?> carrier, MemoryLayout layout, boolean isVararg);
188     }
189 
190     static class UnboxBindingCalculator implements BindingCalculator {
191         private final StorageCalculator storageCalculator;
192 
193         UnboxBindingCalculator(boolean forArguments) {
194             this.storageCalculator = new StorageCalculator(forArguments);
195         }
196 
197         @Override
198         public List<Binding> getBindings(Class<?> carrier, MemoryLayout layout, boolean isVararg) {
199             TypeClass argumentClass = TypeClass.typeClassFor(layout, isVararg);
200             Binding.Builder bindings = Binding.builder();
201             switch (argumentClass) {
202                 case STRUCT_REGISTER: {
203                     assert carrier == MemorySegment.class;
204                     VMStorage storage = storageCalculator.nextStorage(StorageClasses.INTEGER, layout);
205                     Class<?> type = SharedUtils.primitiveCarrierForSize(layout.byteSize(), false);
206                     bindings.bufferLoad(0, type)
207                             .vmStore(storage, type);
208                     break;
209                 }
210                 case STRUCT_REFERENCE: {
211                     assert carrier == MemorySegment.class;
212                     bindings.copy(layout)
213                             .unboxAddress(MemorySegment.class);

214                     VMStorage storage = storageCalculator.nextStorage(StorageClasses.INTEGER, layout);
215                     bindings.vmStore(storage, long.class);
216                     break;
217                 }
218                 case POINTER: {
219                     bindings.unboxAddress(carrier);
220                     VMStorage storage = storageCalculator.nextStorage(StorageClasses.INTEGER, layout);
221                     bindings.vmStore(storage, long.class);
222                     break;
223                 }
224                 case INTEGER: {
225                     VMStorage storage = storageCalculator.nextStorage(StorageClasses.INTEGER, layout);
226                     bindings.vmStore(storage, carrier);
227                     break;
228                 }
229                 case FLOAT: {
230                     VMStorage storage = storageCalculator.nextStorage(StorageClasses.VECTOR, layout);
231                     bindings.vmStore(storage, carrier);
232                     break;
233                 }
234                 case VARARG_FLOAT: {
235                     VMStorage storage = storageCalculator.nextStorage(StorageClasses.VECTOR, layout);
236                     if (!INSTANCE.isStackType(storage.type())) { // need extra for register arg
237                         VMStorage extraStorage = storageCalculator.extraVarargsStorage();
238                         bindings.dup()
239                                 .vmStore(extraStorage, carrier);
240                     }
241 
242                     bindings.vmStore(storage, carrier);
243                     break;
244                 }
245                 default:
246                     throw new UnsupportedOperationException("Unhandled class " + argumentClass);
247             }
248             return bindings.build();
249         }
250     }
251 
252     static class BoxBindingCalculator implements BindingCalculator {
253         private final StorageCalculator storageCalculator;
254 
255         BoxBindingCalculator(boolean forArguments) {
256             this.storageCalculator = new StorageCalculator(forArguments);
257         }
258 
259         @Override
260         public List<Binding> getBindings(Class<?> carrier, MemoryLayout layout, boolean isVararg) {
261             TypeClass argumentClass = TypeClass.typeClassFor(layout, isVararg);
262             Binding.Builder bindings = Binding.builder();
263             switch (argumentClass) {
264                 case STRUCT_REGISTER: {
265                     assert carrier == MemorySegment.class;
266                     bindings.allocate(layout)
267                             .dup();
268                     VMStorage storage = storageCalculator.nextStorage(StorageClasses.INTEGER, layout);
269                     Class<?> type = SharedUtils.primitiveCarrierForSize(layout.byteSize(), false);
270                     bindings.vmLoad(storage, type)
271                             .bufferStore(0, type);
272                     break;
273                 }
274                 case STRUCT_REFERENCE: {
275                     assert carrier == MemorySegment.class;
276                     VMStorage storage = storageCalculator.nextStorage(StorageClasses.INTEGER, layout);
277                     bindings.vmLoad(storage, long.class)
278                             .boxAddress()
279                             .toSegment(layout);
280                     break;
281                 }
< prev index next >