< prev index next >

src/java.base/share/classes/jdk/internal/foreign/abi/x64/sysv/CallingSequenceBuilderImpl.java

Print this page

        

*** 20,132 **** * or visit www.oracle.com if you need additional information or have any * questions. */ package jdk.internal.foreign.abi.x64.sysv; - import java.foreign.NativeMethodType; - import java.foreign.NativeTypes; import java.foreign.layout.Address; import java.foreign.layout.Group; import java.foreign.layout.Group.Kind; import java.foreign.layout.Layout; import java.foreign.layout.Padding; import java.foreign.layout.Sequence; import java.foreign.layout.Value; - import java.foreign.memory.LayoutType; import java.util.ArrayList; ! import java.util.stream.Stream; import jdk.internal.foreign.Util; import jdk.internal.foreign.abi.Argument; import jdk.internal.foreign.abi.ArgumentBinding; ! import jdk.internal.foreign.abi.CallingSequence; import jdk.internal.foreign.abi.Storage; import jdk.internal.foreign.abi.StorageClass; - import jdk.internal.foreign.abi.x64.CallingSequenceBuilder; import jdk.internal.foreign.abi.x64.ArgumentClass; ! import jdk.internal.foreign.abi.x64.SharedConstants; import static sun.security.action.GetBooleanAction.privilegedGetProperty; ! public class StandardCall extends CallingSequenceBuilder { ! private static final String[] INTEGER_ARGUMENT_REGISTER_NAMES = { "rdi", "rsi", "rdx", "rcx", "r8", "r9" }; ! private static final String[] INTEGER_RETURN_REGISTERS_NAMES = { "rax", "rdx" }; ! private static final String[] X87_RETURN_REGISTERS_NAMES = { "st0", "st1" }; private static final boolean DEBUG = privilegedGetProperty("jdk.internal.foreign.abi.x64.sysv.DEBUG"); // The AVX 512 enlightened ABI says "eight eightbytes" // Although AMD64 0.99.6 states 4 eightbytes private static final int MAX_AGGREGATE_REGS_SIZE = 8; private static final ArrayList<ArgumentClass> COMPLEX_X87_CLASSES; - private static final SysVx64ABI abi = SysVx64ABI.getInstance(); static { COMPLEX_X87_CLASSES = new ArrayList<>(); COMPLEX_X87_CLASSES.add(ArgumentClass.X87); COMPLEX_X87_CLASSES.add(ArgumentClass.X87UP); COMPLEX_X87_CLASSES.add(ArgumentClass.X87); COMPLEX_X87_CLASSES.add(ArgumentClass.X87UP); } ! public StandardCall() { ! super(INTEGER_ARGUMENT_REGISTER_NAMES, INTEGER_RETURN_REGISTERS_NAMES, X87_RETURN_REGISTERS_NAMES, ! Constants.MAX_VECTOR_ARGUMENT_REGISTERS, Constants.MAX_VECTOR_RETURN_REGISTERS); } ! static class ArgumentInfo { ! private final ArrayList<ArgumentClass> classes; ! private final int nIntegerRegs, nVectorRegs, nX87Regs; ! private final boolean inMemory; ! ! public ArgumentInfo(ArrayList<ArgumentClass> classes, int nIntegerRegs, int nVectorRegs, int nX87Regs) { ! this.classes = classes; ! ! this.nIntegerRegs = nIntegerRegs; ! this.nVectorRegs = nVectorRegs; ! this.nX87Regs = nX87Regs; ! ! this.inMemory = false; } ! public ArgumentInfo(int n) { ! this.classes = new ArrayList<>(); ! for (int i = 0; i < n; i++) { ! classes.add(ArgumentClass.MEMORY); } ! this.inMemory = true; ! this.nIntegerRegs = 0; ! this.nVectorRegs = 0; ! this.nX87Regs = 0; } public int getIntegerRegs() { ! return nIntegerRegs; } public int getVectorRegs() { ! return nVectorRegs; } ! public int getX87Regs() { ! return nX87Regs; } ! public boolean inMemory() { ! return inMemory; } ! public ArrayList<ArgumentClass> getClasses() { return classes; } - - static ArgumentInfo EMPTY = new ArgumentInfo(new ArrayList<>(), 0, 0, 0); } ! private ArrayList<ArgumentClass> classifyValueType(Value type) { ArrayList<ArgumentClass> classes = new ArrayList<>(); switch (type.kind()) { case INTEGRAL_SIGNED: case INTEGRAL_UNSIGNED: classes.add(ArgumentClass.INTEGER); --- 20,128 ---- * or visit www.oracle.com if you need additional information or have any * questions. */ package jdk.internal.foreign.abi.x64.sysv; import java.foreign.layout.Address; import java.foreign.layout.Group; import java.foreign.layout.Group.Kind; import java.foreign.layout.Layout; import java.foreign.layout.Padding; import java.foreign.layout.Sequence; import java.foreign.layout.Value; import java.util.ArrayList; ! import java.util.List; ! import java.util.function.BiConsumer; ! import jdk.internal.foreign.Util; import jdk.internal.foreign.abi.Argument; import jdk.internal.foreign.abi.ArgumentBinding; ! import jdk.internal.foreign.abi.CallingSequenceBuilder; import jdk.internal.foreign.abi.Storage; import jdk.internal.foreign.abi.StorageClass; import jdk.internal.foreign.abi.x64.ArgumentClass; ! import jdk.internal.foreign.abi.x64.SharedUtils; import static sun.security.action.GetBooleanAction.privilegedGetProperty; ! public class CallingSequenceBuilderImpl extends CallingSequenceBuilder { ! ! private static final SharedUtils.StorageDebugHelper storageDbgHelper = new SharedUtils.StorageDebugHelper( ! new String[] { "rdi", "rsi", "rdx", "rcx", "r8", "r9" }, ! new String[] { "rax", "rdx" }, ! new String[] { "st0", "st1" }, ! SysVx64ABI.MAX_VECTOR_ARGUMENT_REGISTERS, ! SysVx64ABI.MAX_VECTOR_RETURN_REGISTERS ! ); private static final boolean DEBUG = privilegedGetProperty("jdk.internal.foreign.abi.x64.sysv.DEBUG"); // The AVX 512 enlightened ABI says "eight eightbytes" // Although AMD64 0.99.6 states 4 eightbytes private static final int MAX_AGGREGATE_REGS_SIZE = 8; private static final ArrayList<ArgumentClass> COMPLEX_X87_CLASSES; static { COMPLEX_X87_CLASSES = new ArrayList<>(); COMPLEX_X87_CLASSES.add(ArgumentClass.X87); COMPLEX_X87_CLASSES.add(ArgumentClass.X87UP); COMPLEX_X87_CLASSES.add(ArgumentClass.X87); COMPLEX_X87_CLASSES.add(ArgumentClass.X87UP); } ! public CallingSequenceBuilderImpl(Layout layout) { ! this(layout, new StorageCalculator(false), new StorageCalculator(true)); } ! private CallingSequenceBuilderImpl(Layout layout, StorageCalculator retCalculator, StorageCalculator argCalculator) { ! super(layout, retCalculator::addBindings, argCalculator::addBindings, argCalculator::addBindings); } ! @Override ! protected ArgumentInfo makeArgument(Layout layout, int pos, String name) { ! return new ArgumentInfo(layout, pos, name); } ! static class ArgumentInfo extends Argument { ! private final List<ArgumentClass> classes; ! ! public ArgumentInfo(Layout layout, int argumentIndex, String debugName) { ! super(layout, argumentIndex, debugName); ! this.classes = classifyType(layout); } public int getIntegerRegs() { ! return (int)classes.stream() ! .filter(cl -> cl == ArgumentClass.INTEGER) ! .count(); } public int getVectorRegs() { ! return (int)classes.stream() ! .filter(cl -> cl == ArgumentClass.SSE) ! .count(); } ! @Override ! public boolean inMemory() { ! return classes.stream().allMatch(this::isMemoryClass); } ! private boolean isMemoryClass(ArgumentClass cl) { ! return cl == ArgumentClass.MEMORY || ! (argumentIndex() != -1 && ! (cl == ArgumentClass.X87 || cl == ArgumentClass.X87UP)); } ! public List<ArgumentClass> getClasses() { return classes; } } ! private static List<ArgumentClass> classifyValueType(Value type) { ArrayList<ArgumentClass> classes = new ArrayList<>(); switch (type.kind()) { case INTEGRAL_SIGNED: case INTEGRAL_UNSIGNED: classes.add(ArgumentClass.INTEGER);
*** 149,159 **** default: throw new IllegalArgumentException("Type " + type + " is not yet supported"); } } ! private ArrayList<ArgumentClass> classifyArrayType(Sequence type) { long nWords = Util.alignUp((type.bitsSize() / 8), 8) / 8; if (nWords > MAX_AGGREGATE_REGS_SIZE) { return createMemoryClassArray(nWords); } --- 145,155 ---- default: throw new IllegalArgumentException("Type " + type + " is not yet supported"); } } ! private static List<ArgumentClass> classifyArrayType(Sequence type) { long nWords = Util.alignUp((type.bitsSize() / 8), 8) / 8; if (nWords > MAX_AGGREGATE_REGS_SIZE) { return createMemoryClassArray(nWords); }
*** 165,176 **** long offset = 0; final long count = type.elementsSize(); for (long idx = 0; idx < count; idx++) { Layout t = type.element(); ! offset = align(t, false, offset); ! ArrayList<ArgumentClass> subclasses = classifyType(t); if (subclasses.isEmpty()) { return classes; } for (int i = 0; i < subclasses.size(); i++) { --- 161,172 ---- long offset = 0; final long count = type.elementsSize(); for (long idx = 0; idx < count; idx++) { Layout t = type.element(); ! offset = SharedUtils.align(t, false, offset); ! List<ArgumentClass> subclasses = classifyType(t); if (subclasses.isEmpty()) { return classes; } for (int i = 0; i < subclasses.size(); i++) {
*** 215,225 **** return classes; } // TODO: handle zero length arrays // TODO: Handle nested structs (and primitives) ! private ArrayList<ArgumentClass> classifyStructType(Group type) { long nWords = Util.alignUp((type.bitsSize() / 8), 8) / 8; if (nWords > MAX_AGGREGATE_REGS_SIZE) { return createMemoryClassArray(nWords); } --- 211,221 ---- return classes; } // TODO: handle zero length arrays // TODO: Handle nested structs (and primitives) ! private static List<ArgumentClass> classifyStructType(Group type) { long nWords = Util.alignUp((type.bitsSize() / 8), 8) / 8; if (nWords > MAX_AGGREGATE_REGS_SIZE) { return createMemoryClassArray(nWords); }
*** 241,252 **** if (t instanceof Sequence) { if (((Sequence) t).elementsSize() == 0) { continue; } } ! offset = align(t, false, offset); ! ArrayList<ArgumentClass> subclasses = classifyType(t); if (subclasses.isEmpty()) { return classes; } for (int i = 0; i < subclasses.size(); i++) { --- 237,248 ---- if (t instanceof Sequence) { if (((Sequence) t).elementsSize() == 0) { continue; } } ! offset = SharedUtils.align(t, false, offset); ! List<ArgumentClass> subclasses = classifyType(t); if (subclasses.isEmpty()) { return classes; } for (int i = 0; i < subclasses.size(); i++) {
*** 292,302 **** } return classes; } ! private ArrayList<ArgumentClass> classifyType(Layout type) { try { if (type instanceof Value) { return classifyValueType((Value) type); } else if (type instanceof Address) { ArrayList<ArgumentClass> classes = new ArrayList<>(); --- 288,298 ---- } return classes; } ! private static List<ArgumentClass> classifyType(Layout type) { try { if (type instanceof Value) { return classifyValueType((Value) type); } else if (type instanceof Address) { ArrayList<ArgumentClass> classes = new ArrayList<>();
*** 315,428 **** System.err.println("Failed to classify layout: " + type); throw e; } } ! private ArrayList<ArgumentClass> createMemoryClassArray(long n) { ArrayList<ArgumentClass> classes = new ArrayList<>(); for (int i = 0; i < n; i++) { classes.add(ArgumentClass.MEMORY); } return classes; } ! private ArgumentInfo examineArgument(boolean forArguments, Layout type) { ! ArrayList<ArgumentClass> classes = classifyType(type); ! if (classes.isEmpty()) { ! return ArgumentInfo.EMPTY; ! } ! ! int nIntegerRegs = 0; ! int nVectorRegs = 0; ! int nX87Regs = 0; ! ! for (ArgumentClass c : classes) { ! switch (c) { ! case INTEGER: ! nIntegerRegs++; ! break; ! case SSE: ! nVectorRegs++; ! break; ! case X87: ! case X87UP: ! if (forArguments) { ! return new ArgumentInfo(classes.size()); ! } else { ! nX87Regs++; ! break; ! } ! default: ! break; ! } ! } ! ! if (nIntegerRegs != 0 || nVectorRegs != 0 || nX87Regs != 0) { ! return new ArgumentInfo(classes, nIntegerRegs, nVectorRegs, nX87Regs); ! } else { ! return new ArgumentInfo(classes.size()); ! } ! } ! ! class StorageCalculator { ! private final ArrayList<ArgumentBinding>[] bindings; private final boolean forArguments; private int nIntegerRegs = 0; private int nVectorRegs = 0; private int nX87Regs = 0; private long stackOffset = 0; ! StorageCalculator(ArrayList<ArgumentBinding>[] bindings, boolean forArguments) { ! this.bindings = bindings; this.forArguments = forArguments; } ! void addBindings(Argument arg, ArgumentInfo info) { if (info.inMemory() || ! nIntegerRegs + info.getIntegerRegs() > (forArguments ? Constants.MAX_INTEGER_ARGUMENT_REGISTERS : Constants.MAX_INTEGER_RETURN_REGISTERS) || ! nVectorRegs + info.getVectorRegs() > (forArguments ? Constants.MAX_VECTOR_ARGUMENT_REGISTERS : Constants.MAX_VECTOR_RETURN_REGISTERS)) { // stack ! long alignment = Math.max(alignment(arg.getType(), true), 8); long newStackOffset = Util.alignUp(stackOffset, alignment); - - // fill holes on stack with nulls - for (int i = 0; i < (newStackOffset - stackOffset) / 8; i++) { - bindings[StorageClass.STACK_ARGUMENT_SLOT.ordinal()].add(null); - } stackOffset = newStackOffset; long tmpStackOffset = stackOffset; for (int i = 0; i < info.getClasses().size(); i++) { Storage storage = new Storage(StorageClass.STACK_ARGUMENT_SLOT, tmpStackOffset / 8, 8); ! bindings[StorageClass.STACK_ARGUMENT_SLOT.ordinal()].add(new ArgumentBinding(storage, arg, i * 8)); if (DEBUG) { ! System.out.println("Argument " + arg.getName() + " will be passed on stack at offset " + tmpStackOffset); } tmpStackOffset += 8; } ! stackOffset += arg.getType().bitsSize() / 8; } else { // regs for (int i = 0; i < info.getClasses().size(); i++) { Storage storage; ArgumentClass c = info.getClasses().get(i); switch (c) { case INTEGER: ! storage = new Storage(forArguments ? StorageClass.INTEGER_ARGUMENT_REGISTER : StorageClass.INTEGER_RETURN_REGISTER, nIntegerRegs++, SharedConstants.INTEGER_REGISTER_SIZE); ! bindings[storage.getStorageClass().ordinal()].add(new ArgumentBinding(storage, arg, i * 8)); if (DEBUG) { ! System.out.println("Argument " + arg.getName() + " will be passed in register " + getStorageName(storage)); } break; case SSE: { int width = 8; --- 311,381 ---- System.err.println("Failed to classify layout: " + type); throw e; } } ! private static List<ArgumentClass> createMemoryClassArray(long n) { ArrayList<ArgumentClass> classes = new ArrayList<>(); for (int i = 0; i < n; i++) { classes.add(ArgumentClass.MEMORY); } return classes; } ! static class StorageCalculator { private final boolean forArguments; private int nIntegerRegs = 0; private int nVectorRegs = 0; private int nX87Regs = 0; private long stackOffset = 0; ! StorageCalculator(boolean forArguments) { this.forArguments = forArguments; } ! public void addBindings(Argument arg, BiConsumer<StorageClass, ArgumentBinding> bindingConsumer) { ! ArgumentInfo info = (ArgumentInfo)arg; if (info.inMemory() || ! nIntegerRegs + info.getIntegerRegs() > (forArguments ? SysVx64ABI.MAX_INTEGER_ARGUMENT_REGISTERS : SysVx64ABI.MAX_INTEGER_RETURN_REGISTERS) || ! nVectorRegs + info.getVectorRegs() > (forArguments ? SysVx64ABI.MAX_VECTOR_ARGUMENT_REGISTERS : SysVx64ABI.MAX_VECTOR_RETURN_REGISTERS)) { // stack ! long alignment = Math.max(SharedUtils.alignment(info.layout(), true), 8); long newStackOffset = Util.alignUp(stackOffset, alignment); stackOffset = newStackOffset; long tmpStackOffset = stackOffset; for (int i = 0; i < info.getClasses().size(); i++) { Storage storage = new Storage(StorageClass.STACK_ARGUMENT_SLOT, tmpStackOffset / 8, 8); ! bindingConsumer.accept(StorageClass.STACK_ARGUMENT_SLOT, new ArgumentBinding(storage, info, i * 8)); if (DEBUG) { ! System.out.println("Argument " + info.name() + " will be passed on stack at offset " + tmpStackOffset); } tmpStackOffset += 8; } ! stackOffset += info.layout().bitsSize() / 8; } else { // regs for (int i = 0; i < info.getClasses().size(); i++) { Storage storage; ArgumentClass c = info.getClasses().get(i); switch (c) { case INTEGER: ! storage = new Storage(forArguments ? StorageClass.INTEGER_ARGUMENT_REGISTER : StorageClass.INTEGER_RETURN_REGISTER, nIntegerRegs++, SharedUtils.INTEGER_REGISTER_SIZE); ! bindingConsumer.accept(storage.getStorageClass(), new ArgumentBinding(storage, info, i * 8)); if (DEBUG) { ! System.out.println("Argument " + info.name() + " will be passed in register " + ! storageDbgHelper.getStorageName(storage)); } break; case SSE: { int width = 8;
*** 435,449 **** if (width > 64) { throw new IllegalArgumentException((width * 8) + "-bit vector arguments not supported"); } ! storage = new Storage(forArguments ? StorageClass.VECTOR_ARGUMENT_REGISTER : StorageClass.VECTOR_RETURN_REGISTER, nVectorRegs++, width); ! bindings[storage.getStorageClass().ordinal()].add(new ArgumentBinding(storage, arg, i * 8)); if (DEBUG) { ! System.out.println("Argument " + arg.getName() + " will be passed in register " + getStorageName(storage)); } break; } case SSEUP: --- 388,405 ---- if (width > 64) { throw new IllegalArgumentException((width * 8) + "-bit vector arguments not supported"); } ! storage = new Storage(forArguments ? StorageClass.VECTOR_ARGUMENT_REGISTER : StorageClass.VECTOR_RETURN_REGISTER, ! nVectorRegs++, width, SharedUtils.VECTOR_REGISTER_SIZE); ! ! bindingConsumer.accept(storage.getStorageClass(), new ArgumentBinding(storage, info, i * 8)); if (DEBUG) { ! System.out.println("Argument " + info.name() + " will be passed in register " + ! storageDbgHelper.getStorageName(storage)); } break; } case SSEUP:
*** 456,470 **** width += 8; } assert !forArguments; ! storage = new Storage(StorageClass.X87_RETURN_REGISTER, nX87Regs++, width); ! bindings[storage.getStorageClass().ordinal()].add(new ArgumentBinding(storage, arg, i * 8)); if (DEBUG) { ! System.out.println("Argument " + arg.getName() + " will be passed in register " + getStorageName(storage)); } break; } case X87UP: --- 412,427 ---- width += 8; } assert !forArguments; ! storage = new Storage(StorageClass.X87_RETURN_REGISTER, nX87Regs++, width, SharedUtils.X87_REGISTER_SIZE); ! bindingConsumer.accept(storage.getStorageClass(), new ArgumentBinding(storage, info, i * 8)); if (DEBUG) { ! System.out.println("Argument " + info.name() + " will be passed in register " + ! storageDbgHelper.getStorageName(storage)); } break; } case X87UP:
*** 475,526 **** } } } } } - - private void addBindings(ArrayList<Argument> members, StorageCalculator calculator) { - members.stream().forEach(arg -> calculator.addBindings(arg, examineArgument(calculator.forArguments, arg.getType()))); - } - - public CallingSequence arrangeCall(NativeMethodType nmt) { - return arrangeCall(nmt.returnType() == NativeTypes.VOID ? null : nmt.returnType().layout(), - Stream.of(nmt.parameterArray()).map(LayoutType::layout).toArray(Layout[]::new)); - } - - public CallingSequence arrangeCall(Layout ret, Layout... params) { - ArrayList<Argument> returns = new ArrayList<>(); - ArrayList<Argument> args = new ArrayList<>(); - boolean returnsInMemory = false; - - if (ret != null) { - returnsInMemory = examineArgument(false, ret).inMemory(); - - // In some cases the return is passed in as first implicit pointer argument, and a corresponding pointer type is returned - if (returnsInMemory) { - args = new ArrayList<>(); - - Argument returnPointer = new Argument(-1, Address.ofLayout(64, ret), "__retval"); - args.add(returnPointer); - returns.add(returnPointer); - } else { - returns.add(new Argument(-1, ret, "__retval")); - } - } - - for (int i = 0; i < params.length; i++) { - args.add(new Argument(i, params[i], "arg" + i)); - } - - @SuppressWarnings("unchecked") - ArrayList<ArgumentBinding>[] bindings = (ArrayList<ArgumentBinding>[]) new ArrayList<?>[StorageClass.values().length]; - - for (int i = 0; i < StorageClass.values().length; i++) { - bindings[i] = new ArrayList<>(); - } - - addBindings(args, new StorageCalculator(bindings, true)); - addBindings(returns, new StorageCalculator(bindings, false)); - - return new CallingSequence(params.length, bindings, returnsInMemory); - } } --- 432,437 ----
< prev index next >