changeset 59333:3a85acb09a77 foreign

8222734: ABI cleanup Reviewed-by: hjen
author mcimadamore
date Thu, 18 Apr 2019 15:37:03 +0100
parents c46527a244ab
children eba5ab1f9cd7
files src/java.base/share/classes/jdk/internal/foreign/Util.java src/java.base/share/classes/jdk/internal/foreign/abi/Argument.java src/java.base/share/classes/jdk/internal/foreign/abi/ArgumentBinding.java src/java.base/share/classes/jdk/internal/foreign/abi/CallingSequence.java src/java.base/share/classes/jdk/internal/foreign/abi/CallingSequenceBuilder.java src/java.base/share/classes/jdk/internal/foreign/abi/DirectSignatureShuffler.java src/java.base/share/classes/jdk/internal/foreign/abi/ShuffleRecipe.java src/java.base/share/classes/jdk/internal/foreign/abi/ShuffleRecipeBuilder.java src/java.base/share/classes/jdk/internal/foreign/abi/ShuffleRecipeClass.java src/java.base/share/classes/jdk/internal/foreign/abi/ShuffleRecipeFieldHelper.java src/java.base/share/classes/jdk/internal/foreign/abi/ShuffleRecipeOperationCollector.java src/java.base/share/classes/jdk/internal/foreign/abi/Storage.java src/java.base/share/classes/jdk/internal/foreign/abi/StorageClass.java src/java.base/share/classes/jdk/internal/foreign/abi/UniversalAdapter.java src/java.base/share/classes/jdk/internal/foreign/abi/UniversalNativeInvoker.java src/java.base/share/classes/jdk/internal/foreign/abi/UniversalUpcallHandler.java src/java.base/share/classes/jdk/internal/foreign/abi/VarargsInvoker.java src/java.base/share/classes/jdk/internal/foreign/abi/x64/CallingSequenceBuilder.java src/java.base/share/classes/jdk/internal/foreign/abi/x64/SharedConstants.java src/java.base/share/classes/jdk/internal/foreign/abi/x64/SharedUtils.java src/java.base/share/classes/jdk/internal/foreign/abi/x64/sysv/CallingSequenceBuilderImpl.java src/java.base/share/classes/jdk/internal/foreign/abi/x64/sysv/Constants.java src/java.base/share/classes/jdk/internal/foreign/abi/x64/sysv/StandardCall.java src/java.base/share/classes/jdk/internal/foreign/abi/x64/sysv/SysVx64ABI.java src/java.base/share/classes/jdk/internal/foreign/abi/x64/sysv/UniversalNativeInvokerImpl.java src/java.base/share/classes/jdk/internal/foreign/abi/x64/sysv/UniversalUpcallHandlerImpl.java src/java.base/share/classes/jdk/internal/foreign/abi/x64/sysv/VarargsInvokerImpl.java src/java.base/share/classes/jdk/internal/foreign/abi/x64/windows/CallingSequenceBuilderImpl.java src/java.base/share/classes/jdk/internal/foreign/abi/x64/windows/Constants.java src/java.base/share/classes/jdk/internal/foreign/abi/x64/windows/UniversalNativeInvokerImpl.java src/java.base/share/classes/jdk/internal/foreign/abi/x64/windows/UniversalUpcallHandlerImpl.java src/java.base/share/classes/jdk/internal/foreign/abi/x64/windows/VarargsInvokerImpl.java src/java.base/share/classes/jdk/internal/foreign/abi/x64/windows/Windowsx64ABI.java test/jdk/java/foreign/UnalignedStructTest.java test/jdk/java/foreign/abi/x64/sysv/CallingSequenceTest.java test/jdk/java/foreign/abi/x64/sysv/StandardCallTest.java test/jdk/java/foreign/libUnalignedStruct.c
diffstat 37 files changed, 1879 insertions(+), 2298 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/jdk/internal/foreign/Util.java	Wed Apr 17 22:09:23 2019 +0200
+++ b/src/java.base/share/classes/jdk/internal/foreign/Util.java	Thu Apr 18 15:37:03 2019 +0100
@@ -125,25 +125,6 @@
         }
     }
 
-    public static Layout variadicLayout(Class<?> c) {
-        c = (Class<?>)unboxIfNeeded(c);
-        if (c == char.class || c == byte.class || c == short.class || c == int.class || c == long.class) {
-            //it is ok to approximate with a machine word here; numerics arguments in a prototype-less
-            //function call are always rounded up to a register size anyway.
-            return Types.INT64;
-        } else if (c == float.class || c == double.class) {
-            return Types.DOUBLE;
-        } else if (Pointer.class.isAssignableFrom(c)) {
-            return Types.POINTER;
-        } else if (isCallback(c)) {
-            return Types.POINTER;
-        } else if (isCStruct(c)) {
-            return layoutof(c);
-        } else {
-            throw new IllegalArgumentException("Unhandled variadic argument class: " + c);
-        }
-    }
-
     public static Layout layoutof(Class<?> c) {
         String layout;
         if (c.isAnnotationPresent(NativeStruct.class)) {
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/Argument.java	Wed Apr 17 22:09:23 2019 +0200
+++ b/src/java.base/share/classes/jdk/internal/foreign/abi/Argument.java	Thu Apr 18 15:37:03 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019 Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,41 +24,33 @@
 
 import java.foreign.layout.Layout;
 
-public class Argument {
+public abstract class Argument {
     private final int argumentIndex; // index of argument (in argument list)
-    private final Layout type;
+    private final Layout layout;
+    private final String debugName; //optional debug name
 
-    // for testing/debugging, also serves as indicator that argument is named (as opposed to elipsis/varargs arg)
-    private final String name;
-
-    public Argument(int argumentIndex, Layout type, String name) {
+    protected Argument(Layout layout, int argumentIndex, String debugName) {
         this.argumentIndex = argumentIndex;
-        this.type = type;
-        this.name = name;
+        this.layout = layout;
+        this.debugName = debugName;
     }
 
-    public Argument(int index, Layout type) {
-        this(index, type, null);
-    }
-
-    public int getArgumentIndex() {
+    public int argumentIndex() {
         return argumentIndex;
     }
 
-    public Layout getType() {
-        return type;
+    public Layout layout() {
+        return layout;
     }
 
-    public String getName() {
-        return name != null ? name : "<anonymous>";
+    public String name() {
+        return debugName != null ? debugName : "<anonymous>";
     }
 
-    public boolean isNamed() {
-        return name != null;
-    }
+    public abstract boolean inMemory();
 
     @Override
     public String toString() {
-        return "[" + type.toString() + " " + getName() + "]";
+        return "[" + layout.toString() + " " + name() + "]";
     }
 }
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/ArgumentBinding.java	Wed Apr 17 22:09:23 2019 +0200
+++ b/src/java.base/share/classes/jdk/internal/foreign/abi/ArgumentBinding.java	Thu Apr 18 15:37:03 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019 Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,37 +24,39 @@
 
 public class ArgumentBinding {
     private final Storage storage;
-    private final Argument member;
+    private final Argument argument;
     private final long offset;
 
-    public ArgumentBinding(Storage storage, Argument member, long offset) {
+    public ArgumentBinding(Storage storage, Argument argument, long offset) {
         this.storage = storage;
-        this.member = member;
+        this.argument = argument;
         this.offset = offset;
     }
 
-    public ArgumentBinding(Storage storage, Argument member) {
-        this(storage, member, 0);
+    public ArgumentBinding(Storage storage, Argument argument) {
+        this(storage, argument, 0);
     }
 
-    public Storage getStorage() {
+    public Storage storage() {
         return storage;
     }
 
-    public Argument getMember() {
-        return member;
+    public Argument argument() {
+        return argument;
     }
 
-    public long getOffset() {
+    public long offset() {
         return offset;
     }
 
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
-
-        sb.append(storage).append(" : ").append(member.getName()).append(" @ 0x").append(Long.toHexString(offset));
-
+        sb.append(storage)
+                .append(" : ")
+                .append(argument.name())
+                .append(" @ 0x")
+                .append(Long.toHexString(offset));
         return sb.toString();
     }
 }
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/CallingSequence.java	Wed Apr 17 22:09:23 2019 +0200
+++ b/src/java.base/share/classes/jdk/internal/foreign/abi/CallingSequence.java	Thu Apr 18 15:37:03 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,85 +22,54 @@
  */
 package jdk.internal.foreign.abi;
 
-import java.util.ArrayList;
+import java.util.EnumMap;
 import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 public class CallingSequence {
-    private final List<ArgumentBinding>[] bindings;
+    private final EnumMap<StorageClass, List<ArgumentBinding>> bindings;
     private final boolean returnsInMemory;
-    private final List<ArgumentBinding>[] argBindings;
-    private final List<ArgumentBinding> retBindings = new ArrayList<>();
-    private final int[] argsOffsets = new int[StorageClass.ARGUMENT_STORAGE_CLASSES.length];
-    private final int[] retOffsets = new int[StorageClass.values().length];
+    private final Map<Integer, List<ArgumentBinding>> bindingsByIndex;
 
-    @SuppressWarnings({"unchecked", "rawtypes"})
-    public CallingSequence(int argSize, ArrayList<ArgumentBinding>[] bindings, boolean returnsInMemory) {
-        this.bindings = bindings;
+    public CallingSequence(boolean returnsInMemory, EnumMap<StorageClass, List<ArgumentBinding>> bindings) {
+        this.bindings = new EnumMap<>(bindings);
         this.returnsInMemory = returnsInMemory;
-        argBindings = new List[argSize];
-        classifyBindings();
+        this.bindingsByIndex = Stream.of(StorageClass.values())
+                .flatMap(sc -> bindings(sc).stream())
+                .collect(Collectors.groupingBy(b -> b.argument().argumentIndex()));
     }
 
-    public List<ArgumentBinding> getBindings(StorageClass storageClass) {
-        return bindings[storageClass.ordinal()];
+    public List<ArgumentBinding> bindings(StorageClass storageClass) {
+        return bindings.getOrDefault(storageClass, List.of());
     }
 
     public boolean returnsInMemory() {
         return returnsInMemory;
     }
 
-    private void classifyBindings() {
-        for (StorageClass storageClass : StorageClass.values()) {
-            for (ArgumentBinding binding : getBindings(storageClass)) {
-                if (storageClass.isArgumentClass()) {
-                    //update offsets
-                    for (int i = storageClass.ordinal() + 1 ; i < argsOffsets.length ; i++) {
-                        argsOffsets[i]++;
-                    }
-                    //classify arguments
-                    if (storageClass == StorageClass.INTEGER_ARGUMENT_REGISTER &&
-                            returnsInMemory() && binding.getStorage().getStorageIndex() == 0) {
-                        retBindings.add(binding);
-                    } else {
-                        int index = binding.getMember().getArgumentIndex();
-                        List<ArgumentBinding> args = argBindings[index];
-                        if (args == null) {
-                            argBindings[index] = args = new ArrayList<>();
-                        }
-                        args.add(binding);
-                    }
-                } else {
-                    if (!returnsInMemory()) {
-                        //update offsets
-                        for (int i = storageClass.ordinal() + 1 ; i < retOffsets.length ; i++) {
-                            retOffsets[i]++;
-                        }
-                        //classify returns
-                        retBindings.add(binding);
-                    }
-                }
-            }
-        }
+    public List<ArgumentBinding> argumentBindings(int i) {
+        return bindingsByIndex.getOrDefault(i, List.of());
     }
 
-    public List<ArgumentBinding> getArgumentBindings(int i) {
-        return argBindings[i] == null ? List.of() : argBindings[i];
+    public List<ArgumentBinding> returnBindings() {
+        if (returnsInMemory) {
+            throw new IllegalStateException("Attempting to obtain return bindings for in-memory return!");
+        }
+        return bindingsByIndex.getOrDefault(-1, List.of());
     }
 
-    public List<ArgumentBinding> getReturnBindings() {
-        return retBindings == null ? List.of() : retBindings;
-    }
-
-    public long argumentStorageOffset(ArgumentBinding b) {
-        return argsOffsets[b.getStorage().getStorageClass().ordinal()] +
-            bindings[b.getStorage().getStorageClass().ordinal()].indexOf(b)
-            * b.getStorage().getSize() / 8;
-    }
-
-    public long returnStorageOffset(ArgumentBinding b) {
-        return retOffsets[b.getStorage().getStorageClass().ordinal()] +
-            bindings[b.getStorage().getStorageClass().ordinal()].indexOf(b)
-            * b.getStorage().getSize() / 8;
+    public ArgumentBinding returnInMemoryBinding() {
+        if (!returnsInMemory) {
+            throw new IllegalStateException("Attempting to obtain in-memory binding for regular return");
+        }
+        //if returns in memory, we have two bindings with position -1, the argument and the return.
+        //The code below filters out the return binding.
+        return bindingsByIndex.getOrDefault(-1, List.of()).stream()
+                .filter(b -> b.storage().getStorageClass() == StorageClass.INTEGER_ARGUMENT_REGISTER)
+                .findFirst()
+                .orElseThrow(IllegalStateException::new);
     }
 
     public String asString() {
@@ -111,7 +80,7 @@
         sb.append("  Classes:\n");
         for (StorageClass c : StorageClass.values()) {
             sb.append("    ").append(c).append("\n");
-            for (ArgumentBinding binding : getBindings(c)) {
+            for (ArgumentBinding binding : bindings(c)) {
                 if (binding != null) {
                     sb.append("      ").append(binding.toString()).append("\n");
                 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/foreign/abi/CallingSequenceBuilder.java	Thu Apr 18 15:37:03 2019 +0100
@@ -0,0 +1,99 @@
+/*
+ *  Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ *  DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ *  This code is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 only, as
+ *  published by the Free Software Foundation.
+ *
+ *  This code is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  version 2 for more details (a copy is included in the LICENSE file that
+ *  accompanied this code).
+ *
+ *  You should have received a copy of the GNU General Public License version
+ *  2 along with this work; if not, write to the Free Software Foundation,
+ *  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *  Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ *  or visit www.oracle.com if you need additional information or have any
+ *  questions.
+ */
+
+package jdk.internal.foreign.abi;
+
+import java.foreign.layout.Address;
+import java.foreign.layout.Layout;
+import java.util.ArrayList;
+import java.util.EnumMap;
+import java.util.List;
+import java.util.function.BiConsumer;
+
+public abstract class CallingSequenceBuilder {
+
+    private final EnumMap<StorageClass, List<ArgumentBinding>> bindings = new EnumMap<>(StorageClass.class);
+    private final boolean returnsInMemory;
+
+    private int argIndex = 0;
+
+    private final BindingsComputer returnBindgingsComputer;
+    private final BindingsComputer argumentBindgingsComputer;
+    private final BindingsComputer varargsBindgingsComputer;
+
+    protected CallingSequenceBuilder(Layout ret,
+                                     BindingsComputer returnBindgingsComputer,
+                                     BindingsComputer argumentBindgingsComputer,
+                                     BindingsComputer varargsBindgingsComputer) {
+        this.returnBindgingsComputer = returnBindgingsComputer;
+        this.argumentBindgingsComputer = argumentBindgingsComputer;
+        this.varargsBindgingsComputer = varargsBindgingsComputer;
+        if (ret != null) {
+            Argument retInfo = makeArgument(ret, -1, "__retval");
+            this.returnsInMemory = retInfo.inMemory();
+            if (returnsInMemory) {
+                retInfo = makeArgument(Address.ofLayout(64, ret), -1, "__retval");
+                addArgumentBindings(retInfo, false);
+            }
+            addReturnBindings(retInfo);
+        } else {
+            this.returnsInMemory = false;
+        }
+    }
+
+    public final CallingSequenceBuilder addArgument(Layout l) {
+        return addArgument(l, false);
+    }
+
+    public final CallingSequenceBuilder addArgument(Layout l, boolean isVarargs) {
+        addArgumentBindings(makeArgument(l, argIndex, "arg" + argIndex), isVarargs);
+        argIndex++;
+        return this;
+    }
+
+    public final CallingSequence build() {
+        return new CallingSequence(returnsInMemory, bindings);
+    }
+
+    protected abstract Argument makeArgument(Layout layout, int pos, String name);
+
+    private void addReturnBindings(Argument a) {
+        returnBindgingsComputer.computeBindings(a, this::addBinding);
+    }
+
+    private void addArgumentBindings(Argument a, boolean isVarargs) {
+        if (isVarargs) {
+            varargsBindgingsComputer.computeBindings(a, this::addBinding);
+        } else {
+            argumentBindgingsComputer.computeBindings(a, this::addBinding);
+        }
+    }
+
+    private void addBinding(StorageClass storageClass, ArgumentBinding binding) {
+        bindings.computeIfAbsent(storageClass, _unused -> new ArrayList<>()).add(binding);
+    }
+
+    public interface BindingsComputer {
+        void computeBindings(Argument argument, BiConsumer<StorageClass, ArgumentBinding> bindingConsumer);
+    }
+}
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/DirectSignatureShuffler.java	Wed Apr 17 22:09:23 2019 +0200
+++ b/src/java.base/share/classes/jdk/internal/foreign/abi/DirectSignatureShuffler.java	Thu Apr 18 15:37:03 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -91,9 +91,9 @@
         checkCallingSequence(callingSequence);
         this.direction = direction;
         this.javaMethodType = nmt.methodType();
-        processType(RET_POS, nmt.returnType(), callingSequence.getReturnBindings(), direction.flip());
+        processType(RET_POS, nmt.returnType(), callingSequence.returnBindings(), direction.flip());
         for (int i = 0 ; i < javaMethodType.parameterCount() ; i++) {
-            processType(i, nmt.parameterType(i), callingSequence.getArgumentBindings(i), direction);
+            processType(i, nmt.parameterType(i), callingSequence.argumentBindings(i), direction);
         }
     }
 
@@ -142,7 +142,7 @@
 
     private static void checkCallingSequence(CallingSequence callingSequence) {
         if (callingSequence.returnsInMemory() ||
-                !callingSequence.getBindings(StorageClass.STACK_ARGUMENT_SLOT).isEmpty()) {
+                !callingSequence.bindings(StorageClass.STACK_ARGUMENT_SLOT).isEmpty()) {
             throw new IllegalArgumentException("Unsupported non-scalarized calling sequence!");
         }
     }
@@ -175,7 +175,7 @@
         } else if (Util.isCStruct(carrier)) {
             if (bindings.size() == 1) {
                 ArgumentBinding binding = bindings.get(0);
-                switch (binding.getStorage().getStorageClass()) {
+                switch (binding.storage().getStorageClass()) {
                     case INTEGER_ARGUMENT_REGISTER:
                     case INTEGER_RETURN_REGISTER:
                         updateNativeMethodType(sigPos, long.class);
@@ -389,26 +389,25 @@
     }
 
     private static boolean accept(NativeMethodType nmt, CallingSequence callingSequence, ShuffleDirection direction) {
-        if (nmt.parameterCount() > direction.maxArity) return false;
+        if (nmt.isVarArgs() ||
+                callingSequence.returnsInMemory() ||
+                nmt.parameterCount() > direction.maxArity) return false;
+
         for (int i = 0 ; i < nmt.parameterCount(); i++) {
-            List<ArgumentBinding> argumentBindings = callingSequence.getArgumentBindings(i);
+            List<ArgumentBinding> argumentBindings = callingSequence.argumentBindings(i);
             if (argumentBindings.size() != 1 ||
                     !isDirectBinding(argumentBindings.get(0))) {
                 return false;
             }
         }
 
-        List<ArgumentBinding> returnBindings = callingSequence.getReturnBindings();
-        if (returnBindings.isEmpty()) {
-            return true;
-        } else {
-            return !callingSequence.returnsInMemory() &&
-                    returnBindings.size() == 1 && isDirectBinding(returnBindings.get(0));
-        }
+        List<ArgumentBinding> returnBindings = callingSequence.returnBindings();
+        return returnBindings.isEmpty() ||
+                (returnBindings.size() == 1 && isDirectBinding(returnBindings.get(0)));
     }
 
     private static boolean isDirectBinding(ArgumentBinding binding) {
-        switch (binding.getStorage().getStorageClass()) {
+        switch (binding.storage().getStorageClass()) {
             case X87_RETURN_REGISTER:
             case STACK_ARGUMENT_SLOT:
                 //arguments passed in memory not supported
@@ -416,7 +415,7 @@
             case VECTOR_ARGUMENT_REGISTER:
             case VECTOR_RETURN_REGISTER:
                 //avoid passing around floats as doubles as that leads to trouble
-                return (binding.getMember().getType().bitsSize() / 8) == binding.getStorage().getSize();
+                return (binding.argument().layout().bitsSize() / 8) == binding.storage().getSize();
             default:
                 return true;
         }
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/ShuffleRecipe.java	Wed Apr 17 22:09:23 2019 +0200
+++ b/src/java.base/share/classes/jdk/internal/foreign/abi/ShuffleRecipe.java	Thu Apr 18 15:37:03 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,6 +22,9 @@
  */
 package jdk.internal.foreign.abi;
 
+import java.foreign.memory.Pointer;
+import java.util.Map;
+
 import static sun.security.action.GetBooleanAction.privilegedGetProperty;
 
 public class ShuffleRecipe {
@@ -32,55 +35,44 @@
     private final int nArgumentPulls;
     private final int nReturnPulls;
 
-    ShuffleRecipe(long[] recipe, int nArgumentPulls, int nReturnPulls) {
+    private final Map<ArgumentBinding, Long> offsets;
+
+    ShuffleRecipe(long[] recipe, int nArgumentPulls, int nReturnPulls, Map<ArgumentBinding, Long> offsets) {
         this.recipe = recipe;
         this.nArgumentPulls = nArgumentPulls;
         this.nReturnPulls = nReturnPulls;
+        this.offsets = offsets;
     }
 
     public static ShuffleRecipe make(CallingSequence callingSequence) {
         ShuffleRecipeBuilder builder = new ShuffleRecipeBuilder();
 
-        // Arguments
-        callingSequence.getBindings(StorageClass.STACK_ARGUMENT_SLOT).stream().forEach(binding -> {
-            if (binding == null) {
-                builder.getArgumentsCollector().add(ShuffleRecipeClass.STACK, ShuffleRecipeOperation.SKIP);
-            } else {
-                builder.getArgumentsCollector().addPull(ShuffleRecipeClass.STACK);
+        for (int i = 0 ; i < 2; i++) {
+            boolean args = i == 0;
+            long offset = 0L;
+            for (ShuffleRecipeClass recipeClass : ShuffleRecipeClass.values()) {
+                StorageClass storageClass = recipeClass.storageClass(args);
+                if (storageClass != null) {
+                    int indexInClass = 0;
+                    for (ArgumentBinding binding : callingSequence.bindings(storageClass)) {
+                        while (indexInClass < binding.storage().getStorageIndex()) {
+                            builder.addSkip();
+                            indexInClass++;
+                        }
+                        long size = binding.storage().getSize() / 8;
+                        builder.addPulls(!args, size);
+                        if (binding.storage().getSize() < binding.storage().getMaxSize()) {
+                            builder.addSkip();
+                        }
+                        builder.addOffset(binding, offset);
+                        offset += size;
+                        indexInClass++;
+                    }
+                }
+                builder.addStop();
             }
-        });
-
-        int indexInClass = 0;
-        for(ArgumentBinding binding : callingSequence.getBindings(StorageClass.VECTOR_ARGUMENT_REGISTER)) {
-            while(indexInClass < binding.getStorage().getStorageIndex()) {
-                builder.getArgumentsCollector().add(ShuffleRecipeClass.VECTOR, ShuffleRecipeOperation.SKIP);
-                indexInClass++;
-            }
-            builder.getArgumentsCollector().addPulls(ShuffleRecipeClass.VECTOR, binding.getStorage().getSize() / 8);
-            indexInClass++;
         }
 
-        indexInClass = 0;
-        for(ArgumentBinding binding : callingSequence.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER)) {
-            while(indexInClass < binding.getStorage().getStorageIndex()) {
-                builder.getArgumentsCollector().add(ShuffleRecipeClass.INTEGER, ShuffleRecipeOperation.SKIP);
-                indexInClass++;
-            }
-            builder.getArgumentsCollector().addPull(ShuffleRecipeClass.INTEGER);
-            indexInClass++;
-        }
-
-        // Returns
-        builder.getReturnsCollector().addPulls(ShuffleRecipeClass.INTEGER, callingSequence.getBindings(StorageClass.INTEGER_RETURN_REGISTER).size());
-
-        callingSequence.getBindings(StorageClass.VECTOR_RETURN_REGISTER).stream().forEach(binding -> {
-            builder.getReturnsCollector().addPulls(ShuffleRecipeClass.VECTOR, binding.getStorage().getSize() / 8);
-        });
-
-        callingSequence.getBindings(StorageClass.X87_RETURN_REGISTER).stream().forEach(binding -> {
-            builder.getReturnsCollector().addPulls(ShuffleRecipeClass.X87, binding.getStorage().getSize() / 8);
-        });
-
         if(DEBUG) {
             System.out.println("Translating CallingSequence:");
             System.out.println(callingSequence.asString().indent(2));
@@ -103,11 +95,19 @@
         return nReturnPulls;
     }
 
+    public Pointer<?> offset(Pointer<?> ptr, ArgumentBinding binding) {
+        return ptr.offset(offsets.get(binding));
+    }
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
 
-        sb.append("ShuffleRecipe { nArgumentPulls: ").append(nArgumentPulls).append(" nReturnPulls: ").append(nReturnPulls).append("}\n");
+        sb.append("ShuffleRecipe { nArgumentPulls: ")
+                .append(nArgumentPulls)
+                .append(" nReturnPulls: ")
+                .append(nReturnPulls)
+                .append("}\n");
 
         return sb.toString();
     }
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/ShuffleRecipeBuilder.java	Wed Apr 17 22:09:23 2019 +0200
+++ b/src/java.base/share/classes/jdk/internal/foreign/abi/ShuffleRecipeBuilder.java	Thu Apr 18 15:37:03 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,28 +24,42 @@
 
 import jdk.internal.foreign.Util;
 import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 class ShuffleRecipeBuilder {
-    private final ShuffleRecipeOperationCollector arguments = new ShuffleRecipeOperationCollector();
-    private final ShuffleRecipeOperationCollector returns = new ShuffleRecipeOperationCollector();
 
-    ShuffleRecipeBuilder() {
+    List<ShuffleRecipeOperation> ops = new ArrayList<>();
+    Map<ArgumentBinding, Long> offsets = new HashMap<>();
+    int nArgPulls;
+    int nRetPulls;
+
+    void addSkip() {
+        ops.add(ShuffleRecipeOperation.SKIP);
     }
 
-    ShuffleRecipeOperationCollector getArgumentsCollector() {
-        return arguments;
+    void addStop() {
+        ops.add(ShuffleRecipeOperation.STOP);
     }
 
-    ShuffleRecipeOperationCollector getReturnsCollector() {
-        return returns;
+    void addPulls(boolean isReturn, long n) {
+        for (long i = 0; i < n; i++) {
+            ops.add(ShuffleRecipeOperation.PULL);
+            if (isReturn) {
+                nRetPulls++;
+            } else {
+                nArgPulls++;
+            }
+        }
     }
 
-    private int getTotalNumberOfOps() {
-        return arguments.getTotalNumberOfOps() + returns.getTotalNumberOfOps();
+    void addOffset(ArgumentBinding binding, long offset) {
+        offsets.put(binding, offset);
     }
 
     private long[] allocArray() {
-        long nOpBits = getTotalNumberOfOps() * ShuffleRecipeOperation.BITS_PER_OP;
+        long nOpBits = ops.size() * ShuffleRecipeOperation.BITS_PER_OP;
         long nOpWords = nOpBits / 64;
 
         long nBits = nOpBits + nOpWords; // MSB in each word is reserved
@@ -80,35 +94,24 @@
         }
 
         int i = 0;
-        for (ArrayList<ShuffleRecipeOperation> oparr : arguments.getOps()) {
-            for (ShuffleRecipeOperation op : oparr) {
-                encodeOp(arr, i++, op);
-            }
-            encodeOp(arr, i++, ShuffleRecipeOperation.STOP);
-        }
-        for (ArrayList<ShuffleRecipeOperation> oparr : returns.getOps()) {
-            for (ShuffleRecipeOperation op : oparr) {
-                encodeOp(arr, i++, op);
-            }
-            encodeOp(arr, i++, ShuffleRecipeOperation.STOP);
+
+        for (ShuffleRecipeOperation op : ops) {
+            encodeOp(arr, i++, op);
         }
 
         return arr;
     }
 
     ShuffleRecipe build() {
-        return new ShuffleRecipe(recipeToLongArray(), getArgumentsCollector().getNoofPulls(), getReturnsCollector().getNoofPulls());
+        return new ShuffleRecipe(recipeToLongArray(), nArgPulls, nRetPulls, offsets);
     }
 
     public String asString() {
         StringBuilder sb = new StringBuilder();
 
         sb.append("ShuffleRecipe: {\n");
-        sb.append("  Arguments: {\n");
-        sb.append(arguments.asString().indent(4));
-        sb.append("  }\n");
-        sb.append("  Returns: {\n");
-        sb.append(returns.asString().indent(4));
+        sb.append("  Operations: {\n");
+        sb.append(ops);
         sb.append("  }\n");
         sb.append("}\n");
 
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/ShuffleRecipeClass.java	Wed Apr 17 22:09:23 2019 +0200
+++ b/src/java.base/share/classes/jdk/internal/foreign/abi/ShuffleRecipeClass.java	Thu Apr 18 15:37:03 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,5 +23,21 @@
 package jdk.internal.foreign.abi;
 
 enum ShuffleRecipeClass {
-    BUFFER, STACK, VECTOR, INTEGER, X87
+    BUFFER(null, null),
+    STACK(StorageClass.STACK_ARGUMENT_SLOT, null),
+    VECTOR(StorageClass.VECTOR_ARGUMENT_REGISTER, StorageClass.VECTOR_RETURN_REGISTER),
+    INTEGER(StorageClass.INTEGER_ARGUMENT_REGISTER, StorageClass.INTEGER_RETURN_REGISTER),
+    X87(null, StorageClass.X87_RETURN_REGISTER);
+
+    private final StorageClass argumentStorageClass;
+    private final StorageClass returnStorageClass;
+
+    ShuffleRecipeClass(StorageClass argumentStorageClass, StorageClass returnStorageClass) {
+        this.argumentStorageClass = argumentStorageClass;
+        this.returnStorageClass = returnStorageClass;
+    }
+
+    public StorageClass storageClass(boolean args) {
+        return args ? argumentStorageClass : returnStorageClass;
+    }
 }
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/ShuffleRecipeFieldHelper.java	Wed Apr 17 22:09:23 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.internal.foreign.abi;
-
-class ShuffleRecipeFieldHelper {
-    private final String fieldName;
-    private final ShuffleRecipe recipe;
-
-    ShuffleRecipeFieldHelper(ShuffleRecipe recipe, int index) {
-        this.fieldName = "recipe_" + index;
-        this.recipe = recipe;
-    }
-
-    String getFieldName() {
-        return fieldName;
-    }
-
-    ShuffleRecipe getRecipe() {
-        return recipe;
-    }
-}
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/ShuffleRecipeOperationCollector.java	Wed Apr 17 22:09:23 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.internal.foreign.abi;
-
-import java.util.ArrayList;
-
-class ShuffleRecipeOperationCollector {
-    private static final int MAX_VECTOR_WIDTH_BITS = 256; // Look it up
-    private static final int MAX_VECTOR_WIDTH_LONGS = MAX_VECTOR_WIDTH_BITS / 64;
-
-    private final ArrayList<ShuffleRecipeOperation>[] ops;
-    private int nPulls;
-
-    @SuppressWarnings("unchecked")
-    ShuffleRecipeOperationCollector() {
-        ops = (ArrayList<ShuffleRecipeOperation>[])new ArrayList<?>[ShuffleRecipeClass.values().length];
-        for (ShuffleRecipeClass c : ShuffleRecipeClass.values()) {
-            ops[c.ordinal()] = new ArrayList<>();
-        }
-    }
-
-    ArrayList<ShuffleRecipeOperation>[] getOps() {
-        return ops;
-    }
-
-    int getNoofPulls() {
-        return nPulls;
-    }
-
-    int getTotalNumberOfOps() {
-        int n = 0;
-        for (ArrayList<ShuffleRecipeOperation> oparr : ops) {
-            n += oparr.size();
-            n++; // account for implicit STOP at the end of each class
-        }
-        return n;
-    }
-
-    void add(ShuffleRecipeClass c, ShuffleRecipeOperation op) {
-        if (op == ShuffleRecipeOperation.STOP) {
-            throw new IllegalArgumentException("STOP is implicit and must not be added explicitly");
-        }
-        ops[c.ordinal()].add(op);
-        if (op == ShuffleRecipeOperation.PULL) {
-            nPulls++;
-        }
-    }
-
-    void add(ShuffleRecipeClass c, ShuffleRecipeOperation op, long n) {
-        for (long i = 0; i < n; i++) {
-            add(c, op);
-        }
-    }
-
-    void addPull(ShuffleRecipeClass c) {
-        addPulls(c, 1);
-    }
-
-    void addPulls(ShuffleRecipeClass c, long n) {
-        add(c, ShuffleRecipeOperation.PULL, n);
-        if (c == ShuffleRecipeClass.VECTOR && n < MAX_VECTOR_WIDTH_LONGS) {
-            add(c, ShuffleRecipeOperation.SKIP);
-        }
-    }
-
-    public String asString() {
-        StringBuilder sb = new StringBuilder();
-        for(ShuffleRecipeClass cls : ShuffleRecipeClass.values()) {
-            sb.append(cls.name()).append(": ").append(ops[cls.ordinal()]).append("\n");
-        }
-        return sb.toString();
-    }
-}
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/Storage.java	Wed Apr 17 22:09:23 2019 +0200
+++ b/src/java.base/share/classes/jdk/internal/foreign/abi/Storage.java	Thu Apr 18 15:37:03 2019 +0100
@@ -26,11 +26,17 @@
     private final StorageClass storageClass;
     private final long storageIndex;
     private final long size;
+    private final long maxSize;
 
     public Storage(StorageClass storageClass, long storageIndex, long size) {
+        this(storageClass, storageIndex, size, size);
+    }
+
+    public Storage(StorageClass storageClass, long storageIndex, long size, long maxSize) {
         this.storageClass = storageClass;
         this.storageIndex = storageIndex;
         this.size = size;
+        this.maxSize = maxSize;
     }
 
     public StorageClass getStorageClass() {
@@ -45,6 +51,10 @@
         return size;
     }
 
+    public long getMaxSize() {
+        return maxSize;
+    }
+
     @Override
     public String toString() {
         return "Storage { " + storageClass + "[" + storageIndex + "] (size=" + size + ") }";
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/StorageClass.java	Wed Apr 17 22:09:23 2019 +0200
+++ b/src/java.base/share/classes/jdk/internal/foreign/abi/StorageClass.java	Thu Apr 18 15:37:03 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,8 +24,6 @@
 
 public enum StorageClass {
 
-    //Note: The order of the argument/return register classes is subtly relevant, as that is the order in which the
-    //binding words will be laid out in the input/output long arrays by the universal invoker.
     STACK_ARGUMENT_SLOT(true, false),
     VECTOR_ARGUMENT_REGISTER(true, false),
     INTEGER_ARGUMENT_REGISTER(true, false),
@@ -33,18 +31,6 @@
     INTEGER_RETURN_REGISTER(false, true),
     X87_RETURN_REGISTER(false, true);
 
-    public static final StorageClass[] ARGUMENT_STORAGE_CLASSES = {
-            StorageClass.STACK_ARGUMENT_SLOT,
-            StorageClass.VECTOR_ARGUMENT_REGISTER,
-            StorageClass.INTEGER_ARGUMENT_REGISTER
-    };
-
-    public static final StorageClass[] RETURN_STORAGE_CLASSES = {
-            StorageClass.VECTOR_RETURN_REGISTER,
-            StorageClass.INTEGER_RETURN_REGISTER,
-            StorageClass.X87_RETURN_REGISTER
-    };
-
     final boolean isArgumentClass;
     final boolean isReturnClass;
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/foreign/abi/UniversalAdapter.java	Thu Apr 18 15:37:03 2019 +0100
@@ -0,0 +1,38 @@
+/*
+ *  Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ *  DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ *  This code is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 only, as
+ *  published by the Free Software Foundation.
+ *
+ *  This code is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  version 2 for more details (a copy is included in the LICENSE file that
+ *  accompanied this code).
+ *
+ *  You should have received a copy of the GNU General Public License version
+ *  2 along with this work; if not, write to the Free Software Foundation,
+ *  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *  Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ *  or visit www.oracle.com if you need additional information or have any
+ *  questions.
+ */
+
+package jdk.internal.foreign.abi;
+
+import java.foreign.memory.LayoutType;
+import java.foreign.memory.Pointer;
+import java.util.List;
+import java.util.function.Function;
+
+public interface UniversalAdapter {
+
+    void unboxValue(Object o, LayoutType<?> type, Function<ArgumentBinding,
+            Pointer<?>> dstPtrFunc, List<ArgumentBinding> bindings) throws Throwable;
+
+    Object boxValue(LayoutType<?> type, Function<ArgumentBinding,
+            Pointer<?>> srcPtrFunc, List<ArgumentBinding> bindings) throws IllegalAccessException;
+}
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/UniversalNativeInvoker.java	Wed Apr 17 22:09:23 2019 +0200
+++ b/src/java.base/share/classes/jdk/internal/foreign/abi/UniversalNativeInvoker.java	Thu Apr 18 15:37:03 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,16 +25,15 @@
 import jdk.internal.foreign.ScopeImpl;
 import jdk.internal.foreign.memory.BoundedPointer;
 
+import java.foreign.Library;
 import java.foreign.NativeMethodType;
 import java.foreign.NativeTypes;
 import java.foreign.Scope;
-import java.foreign.memory.LayoutType;
 import java.foreign.memory.Pointer;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
 import java.util.List;
-import java.util.function.Function;
 
 import static sun.security.action.GetBooleanAction.privilegedGetProperty;
 
@@ -43,7 +42,7 @@
  * an array of longs together with a call 'recipe', which is used to move the arguments in the right places as
  * expected by the system ABI.
  */
-public abstract class UniversalNativeInvoker {
+public class UniversalNativeInvoker {
     private static final boolean DEBUG =
         privilegedGetProperty("jdk.internal.foreign.NativeInvoker.DEBUG");
 
@@ -66,10 +65,13 @@
     private final CallingSequence callingSequence;
     private final long addr;
     private final String methodName;
+    private final UniversalAdapter adapter;
 
-    protected UniversalNativeInvoker(long addr, String methodName, CallingSequence callingSequence, NativeMethodType nmt) {
-        this.addr = addr;
-        this.methodName = methodName;
+    public UniversalNativeInvoker(Library.Symbol symbol, CallingSequence callingSequence, NativeMethodType nmt,
+                                     UniversalAdapter adapter) throws IllegalAccessException {
+        this.adapter = adapter;
+        this.addr = symbol.getAddress().addr();
+        this.methodName = symbol.getName();
         this.callingSequence = callingSequence;
         this.nmt = nmt;
         this.shuffleRecipe = ShuffleRecipe.make(callingSequence);
@@ -90,8 +92,8 @@
 
         for (int i = 0; i < args.length; i++) {
             Object arg = args[i];
-            unboxValue(arg, nmt.parameterType(i), b -> argsPtr.offset(callingSequence.argumentStorageOffset(b)),
-                    callingSequence.getArgumentBindings(i));
+            adapter.unboxValue(arg, nmt.parameterType(i), b -> shuffleRecipe.offset(argsPtr, b),
+                    callingSequence.argumentBindings(i));
         }
 
         final Pointer<?> retPtr;
@@ -101,8 +103,8 @@
             // Leak the allocated structs for now until the life cycle has been figured out
             Scope scope = Scope.globalScope().fork();
             retPtr = ((ScopeImpl)scope).allocate(nmt.returnType(), 8);
-            unboxValue(retPtr, NativeTypes.UINT64.pointer(), b -> argsPtr.offset(callingSequence.argumentStorageOffset(b)),
-                    callingSequence.getReturnBindings());
+            adapter.unboxValue(retPtr, NativeTypes.UINT64.pointer(), b -> shuffleRecipe.offset(argsPtr, b),
+                    List.of(callingSequence.returnInMemoryBinding()));
         } else if (!isVoid && returnValues.length != 0) {
             retPtr = BoundedPointer.fromArray(NativeTypes.UINT64, returnValues);
         } else {
@@ -129,18 +131,12 @@
         if (isVoid) {
             return null;
         } else if (!callingSequence.returnsInMemory()) {
-            return boxValue(nmt.returnType(), b -> retPtr.offset(callingSequence.returnStorageOffset(b)), callingSequence.getReturnBindings());
+            return adapter.boxValue(nmt.returnType(), b -> shuffleRecipe.offset(retPtr, b), callingSequence.returnBindings());
         } else {
             return retPtr.get();
         }
     }
 
-    public abstract void unboxValue(Object o, LayoutType<?> type, Function<ArgumentBinding,
-                Pointer<?>> dstPtrFunc, List<ArgumentBinding> bindings) throws Throwable;
-
-    public abstract Object boxValue(LayoutType<?> type, Function<ArgumentBinding,
-            Pointer<?>> srcPtrFunc, List<ArgumentBinding> bindings) throws IllegalAccessException;
-
     //natives
 
     static native void invokeNative(long[] args, long[] rets, long[] recipe, long addr);
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/UniversalUpcallHandler.java	Wed Apr 17 22:09:23 2019 +0200
+++ b/src/java.base/share/classes/jdk/internal/foreign/abi/UniversalUpcallHandler.java	Thu Apr 18 15:37:03 2019 +0100
@@ -26,17 +26,14 @@
 import java.foreign.Library;
 import java.foreign.NativeMethodType;
 import java.foreign.NativeTypes;
-import java.foreign.Scope;
 import java.foreign.memory.LayoutType;
 import java.foreign.memory.Pointer;
 import java.lang.invoke.MethodHandle;
 import java.util.Arrays;
-import java.util.List;
-import java.util.function.Function;
 
 import jdk.internal.foreign.ScopeImpl;
 import jdk.internal.foreign.Util;
-import jdk.internal.foreign.abi.x64.SharedConstants;
+import jdk.internal.foreign.abi.x64.SharedUtils;
 import jdk.internal.foreign.memory.MemoryBoundInfo;
 import jdk.internal.foreign.memory.BoundedPointer;
 import jdk.internal.vm.annotation.Stable;
@@ -48,7 +45,7 @@
  * takes an array of storage pointers, which describes the state of the CPU at the time of the upcall. This can be used
  * by the Java code to fetch the upcall arguments and to store the results to the desired location, as per system ABI.
  */
-public abstract class UniversalUpcallHandler implements Library.Symbol {
+public class UniversalUpcallHandler implements Library.Symbol {
 
     private static final boolean DEBUG =
         privilegedGetProperty("jdk.internal.foreign.UpcallHandler.DEBUG");
@@ -58,8 +55,11 @@
     private final NativeMethodType nmt;
     private final CallingSequence callingSequence;
     private final Pointer<?> entryPoint;
+    private final UniversalAdapter adapter;
 
-    protected UniversalUpcallHandler(MethodHandle target, CallingSequence callingSequence, NativeMethodType nmt) {
+    public UniversalUpcallHandler(MethodHandle target, CallingSequence callingSequence, NativeMethodType nmt,
+                                     UniversalAdapter adapter) {
+        this.adapter = adapter;
         mh = target.asSpreader(Object[].class, nmt.parameterCount());
         this.nmt = nmt;
         this.callingSequence = callingSequence;
@@ -100,20 +100,20 @@
         }
 
         Pointer<Long> getPtr(ArgumentBinding binding) {
-            Storage storage = binding.getStorage();
+            Storage storage = binding.storage();
             switch (storage.getStorageClass()) {
             case INTEGER_ARGUMENT_REGISTER:
                 return integers.offset(storage.getStorageIndex());
             case VECTOR_ARGUMENT_REGISTER:
-                return vectors.offset(storage.getStorageIndex() * SharedConstants.VECTOR_REGISTER_SIZE / 8);
+                return vectors.offset(storage.getStorageIndex() * SharedUtils.VECTOR_REGISTER_SIZE / 8);
             case STACK_ARGUMENT_SLOT:
                 return stack.offset(storage.getStorageIndex());
             case INTEGER_RETURN_REGISTER:
                 return integerReturns.offset(storage.getStorageIndex());
             case VECTOR_RETURN_REGISTER:
-                return vectorReturns.offset(storage.getStorageIndex() * SharedConstants.VECTOR_REGISTER_SIZE / 8);
+                return vectorReturns.offset(storage.getStorageIndex() * SharedUtils.VECTOR_REGISTER_SIZE / 8);
             case X87_RETURN_REGISTER:
-                return x87Returns.offset(storage.getStorageIndex() * SharedConstants.X87_REGISTER_SIZE / 8);
+                return x87Returns.offset(storage.getStorageIndex() * SharedUtils.X87_REGISTER_SIZE / 8);
             default:
                 throw new Error("Unhandled storage: " + storage);
             }
@@ -122,7 +122,7 @@
         @SuppressWarnings("unchecked")
         Pointer<Object> inMemoryPtr() {
             assert callingSequence.returnsInMemory();
-            Pointer<Long> res = getPtr(callingSequence.getReturnBindings().get(0));
+            Pointer<Long> res = getPtr(callingSequence.returnInMemoryBinding());
             long structAddr = res.get();
             long size = Util.alignUp(nmt.returnType().bytesSize(), 8);
             return new BoundedPointer<Object>((LayoutType)nmt.returnType(), ScopeImpl.UNCHECKED, Pointer.AccessMode.READ_WRITE,
@@ -143,9 +143,9 @@
             }
             for (StorageClass cls : StorageClass.values()) {
                 result.append((cls + "\n").indent(2));
-                for (ArgumentBinding binding : callingSequence.getBindings(cls)) {
+                for (ArgumentBinding binding : callingSequence.bindings(cls)) {
                     BoundedPointer<?> argPtr = (BoundedPointer<?>) getPtr(binding);
-                    result.append(argPtr.dump((int) binding.getStorage().getSize()).indent(4));
+                    result.append(argPtr.dump((int) binding.storage().getSize()).indent(4));
                 }
             }
             return result.toString();
@@ -163,7 +163,7 @@
 
             Object[] args = new Object[nmt.parameterCount()];
             for (int i = 0 ; i < nmt.parameterCount() ; i++) {
-                args[i] = boxValue(nmt.parameterType(i), context::getPtr, callingSequence.getArgumentBindings(i));
+                args[i] = adapter.boxValue(nmt.parameterType(i), context::getPtr, callingSequence.argumentBindings(i));
             }
 
             if (DEBUG) {
@@ -180,8 +180,8 @@
 
             if (mh.type().returnType() != void.class) {
                 if (!callingSequence.returnsInMemory()) {
-                    unboxValue(o, nmt.returnType(), context::getPtr,
-                            callingSequence.getReturnBindings());
+                    adapter.unboxValue(o, nmt.returnType(), context::getPtr,
+                            callingSequence.returnBindings());
                 } else {
                     Pointer<Object> inMemPtr = context.inMemoryPtr();
                     inMemPtr.set(o);
@@ -198,12 +198,6 @@
         }
     }
 
-    public abstract void unboxValue(Object o, LayoutType<?> type, Function<ArgumentBinding,
-                Pointer<?>> dstPtrFunc, List<ArgumentBinding> bindings) throws Throwable;
-
-    public abstract Object boxValue(LayoutType<?> type, Function<ArgumentBinding,
-            Pointer<?>> srcPtrFunc, List<ArgumentBinding> bindings) throws IllegalAccessException;
-
     public native long allocateUpcallStub();
 
     private static native void registerNatives();
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/VarargsInvoker.java	Wed Apr 17 22:09:23 2019 +0200
+++ b/src/java.base/share/classes/jdk/internal/foreign/abi/VarargsInvoker.java	Thu Apr 18 15:37:03 2019 +0100
@@ -25,22 +25,31 @@
 
 import java.foreign.Library;
 import java.foreign.NativeMethodType;
+import java.foreign.layout.Layout;
 import java.foreign.memory.LayoutType;
 import java.foreign.memory.Pointer;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
+import java.util.function.Function;
+
 import jdk.internal.foreign.Util;
+import jdk.internal.foreign.memory.Types;
 
-public abstract class VarargsInvoker {
+public class VarargsInvoker {
 
-    protected static final MethodHandle INVOKE_MH;
-    protected final NativeMethodType nativeMethodType;
-    protected final Library.Symbol symbol;
+    private static final MethodHandle INVOKE_MH;
+    private final NativeMethodType nativeMethodType;
+    private final Library.Symbol symbol;
+    private final Function<Layout, CallingSequenceBuilder> seqBuilderFactory;
+    private final UniversalAdapter adapter;
 
-    protected VarargsInvoker(Library.Symbol symbol, NativeMethodType nativeMethodType) {
+    private VarargsInvoker(Library.Symbol symbol, NativeMethodType nativeMethodType,
+                           Function<Layout, CallingSequenceBuilder> seqBuilderFactory, UniversalAdapter adapter) {
         this.symbol = symbol;
         this.nativeMethodType = nativeMethodType;
+        this.seqBuilderFactory = seqBuilderFactory;
+        this.adapter = adapter;
     }
 
     static {
@@ -51,6 +60,14 @@
         }
     }
 
+    public static MethodHandle make(Library.Symbol symbol, NativeMethodType nativeMethodType,
+                                    Function<Layout, CallingSequenceBuilder> seqBuilder, UniversalAdapter adapter) {
+        VarargsInvoker invoker = new VarargsInvoker(symbol, nativeMethodType, seqBuilder, adapter);
+        MethodType methodType = nativeMethodType.methodType();
+        return INVOKE_MH.bindTo(invoker).asCollector(Object[].class, methodType.parameterCount())
+                .asType(methodType);
+    }
+
     private Object invoke(Object[] args) throws Throwable {
         // one trailing Object[]
         int nNamedArgs = nativeMethodType.parameterArray().length;
@@ -58,26 +75,39 @@
         // The last argument is the array of vararg collector
         Object[] unnamedArgs = (Object[]) args[args.length - 1];
 
+        CallingSequenceBuilder seqBuilder = seqBuilderFactory.apply(
+                nativeMethodType.function()
+                        .returnLayout()
+                        .orElse(null));
+
         LayoutType<?> retLayoutType = nativeMethodType.returnType();
         LayoutType<?>[] argLayoutTypes = new LayoutType<?>[nNamedArgs + unnamedArgs.length];
         System.arraycopy(nativeMethodType.parameterArray(), 0, argLayoutTypes, 0, nNamedArgs);
+
+        nativeMethodType.function().argumentLayouts().forEach(seqBuilder::addArgument);
+
         int pos = nNamedArgs;
         for (Object o: unnamedArgs) {
             Class<?> type = o.getClass();
-            argLayoutTypes[pos++] = Util.makeType(computeClass(type), Util.variadicLayout(type));
+            Layout layout = variadicLayout(type);
+            argLayoutTypes[pos++] = Util.makeType(computeClass(type), layout);
+            seqBuilder.addArgument(layout, true);
         }
-        MethodHandle delegate = specialize(NativeMethodType.of(retLayoutType, argLayoutTypes));
+
+        //build universal invoker used to dispatch the call
+        UniversalNativeInvoker delegate = new UniversalNativeInvoker(symbol,
+                seqBuilder.build(),
+                NativeMethodType.of(retLayoutType, argLayoutTypes),
+                adapter);
 
         // flatten argument list so that it can be passed to an asSpreader MH
         Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length];
         System.arraycopy(args, 0, allArgs, 0, nNamedArgs);
         System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length);
 
-        return delegate.invokeWithArguments(allArgs);
+        return delegate.invoke(allArgs);
     }
 
-    protected abstract MethodHandle specialize(NativeMethodType nmt);
-
     private Class<?> computeClass(Class<?> c) {
         if (c.isPrimitive()) {
             throw new IllegalArgumentException("Not expecting primitive type " + c.getName());
@@ -93,4 +123,23 @@
             throw new UnsupportedOperationException("Type unhandled: " + c.getName());
         }
     }
+
+    private Layout variadicLayout(Class<?> c) {
+        c = (Class<?>)Util.unboxIfNeeded(c);
+        if (c == char.class || c == byte.class || c == short.class || c == int.class || c == long.class) {
+            //it is ok to approximate with a machine word here; numerics arguments in a prototype-less
+            //function call are always rounded up to a register size anyway.
+            return Types.INT64;
+        } else if (c == float.class || c == double.class) {
+            return Types.DOUBLE;
+        } else if (Pointer.class.isAssignableFrom(c)) {
+            return Types.POINTER;
+        } else if (Util.isCallback(c)) {
+            return Types.POINTER;
+        } else if (Util.isCStruct(c)) {
+            return Util.layoutof(c);
+        } else {
+            throw new IllegalArgumentException("Unhandled variadic argument class: " + c);
+        }
+    }
 }
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/x64/CallingSequenceBuilder.java	Wed Apr 17 22:09:23 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,155 +0,0 @@
-/*
- * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.internal.foreign.abi.x64;
-
-import jdk.internal.foreign.abi.Storage;
-
-import java.foreign.layout.*;
-
-public abstract class CallingSequenceBuilder {
-    private final String[] integerArgumentRegisterNames;
-    private final String[] integerReturnRegisterNames;
-    private final String[] x87ReturnRegisterNames;
-    private final int maxVectorArgRegisters;
-    private final int maxVectorReturnRegisters;
-
-    protected CallingSequenceBuilder(String[] integerArgumentRegisterNames, String[] integerReturnRegisterNames,
-                                     String[]  x87ReturnRegisterNames, int maxVectorArgRegisters, int maxVectorReturnRegisters) {
-        this.integerArgumentRegisterNames = integerArgumentRegisterNames;
-        this.integerReturnRegisterNames = integerReturnRegisterNames;
-        this.x87ReturnRegisterNames = x87ReturnRegisterNames;
-        this.maxVectorArgRegisters = maxVectorArgRegisters;
-        this.maxVectorReturnRegisters = maxVectorReturnRegisters;
-    }
-
-    protected static long alignUp(long addr, long alignment) {
-        return ((addr - 1) | (alignment - 1)) + 1;
-    }
-
-    protected static long alignDown(long addr, long alignment) {
-        return addr & ~(alignment - 1);
-    }
-
-    protected static long alignmentOfScalar(Value st) {
-        return st.bitsSize() / 8;
-    }
-
-    protected static long alignmentOfArray(Sequence ar, boolean isVar) {
-        if (ar.elementsSize() == 0) {
-            // VLA or incomplete
-            return 16;
-        } else if ((ar.bitsSize() / 8) >= 16 && isVar) {
-            return 16;
-        } else {
-            // align as element type
-            Layout elementType = ar.element();
-            return alignment(elementType, false);
-        }
-    }
-
-    protected static long alignmentOfContainer(Group ct) {
-        // Most strict member
-        return ct.elements().stream().mapToLong(t -> alignment(t, false)).max().orElse(1);
-    }
-
-    /**
-     * The alignment requirement for a given type
-     * @param isVar indicate if the type is a standalone variable. This change how
-     * array is aligned. for example.
-     */
-    protected static long alignment(Layout t, boolean isVar) {
-        if (t instanceof Value) {
-            return alignmentOfScalar((Value) t);
-        } else if (t instanceof Sequence) {
-            // when array is used alone
-            return alignmentOfArray((Sequence) t, isVar);
-        } else if (t instanceof Group) {
-            return alignmentOfContainer((Group) t);
-        } else if (t instanceof Address) {
-            return 8;
-        } else if (t instanceof Padding) {
-            return 1;
-        } else {
-            throw new IllegalArgumentException("Invalid type: " + t);
-        }
-    }
-
-    /**
-     * Align the specified type from a given address
-     * @return The address the data should be at based on alignment requirement
-     */
-    protected static long align(Layout t, boolean isVar, long addr) {
-        return alignUp(addr, alignment(t, isVar));
-    }
-
-    private static String getVectorRegisterName(long index, long size) {
-        switch ((int)size) {
-            case 8: return "xmm" + index + "_8";
-            case 16: return "xmm" + index;
-            case 32: return "ymm" + index;
-            case 64: return "zmm" + index;
-            default: throw new IllegalArgumentException("Illegal vector size: " + size);
-        }
-    }
-
-    public String getStorageName(Storage storage) {
-        switch (storage.getStorageClass()) {
-            case INTEGER_ARGUMENT_REGISTER:
-                if (storage.getStorageIndex() > integerArgumentRegisterNames.length) {
-                    throw new IllegalArgumentException("Illegal storage: " + storage);
-                }
-                return integerArgumentRegisterNames[(int) storage.getStorageIndex()];
-
-            case VECTOR_ARGUMENT_REGISTER:
-                if (storage.getStorageIndex() > maxVectorArgRegisters) {
-                    throw new IllegalArgumentException("Illegal storage: " + storage);
-                }
-                return getVectorRegisterName(storage.getStorageIndex(), storage.getSize());
-
-            case INTEGER_RETURN_REGISTER:
-                if (storage.getStorageIndex() > integerReturnRegisterNames.length) {
-                    throw new IllegalArgumentException("Illegal storage: " + storage);
-                }
-
-                return integerReturnRegisterNames[(int) storage.getStorageIndex()];
-
-            case VECTOR_RETURN_REGISTER:
-                if (storage.getStorageIndex() > maxVectorReturnRegisters) {
-                    throw new IllegalArgumentException("Illegal storage: " + storage);
-                }
-                return getVectorRegisterName(storage.getStorageIndex(), storage.getSize());
-
-            case X87_RETURN_REGISTER:
-                if (storage.getStorageIndex() > x87ReturnRegisterNames.length) {
-                    throw new IllegalArgumentException("Illegal storage: " + storage);
-                }
-                return x87ReturnRegisterNames[(int) storage.getStorageIndex()];
-
-            case STACK_ARGUMENT_SLOT: return "[sp + " + Long.toHexString(8 * storage.getStorageIndex()) + "]";
-        }
-
-        throw new IllegalArgumentException("Unhandled storage type: " + storage.getStorageClass());
-    }
-}
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/x64/SharedConstants.java	Wed Apr 17 22:09:23 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-/*
- * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.internal.foreign.abi.x64;
-
-public class SharedConstants {
-    public static final int INTEGER_REGISTER_SIZE = 8;
-    public static final int VECTOR_REGISTER_SIZE = 64; // (maximum) vector size is 512 bits
-    public static final int X87_REGISTER_SIZE = 16; // x87 register is 128 bits
-
-    public static final int STACK_SLOT_SIZE = 8;
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/foreign/abi/x64/SharedUtils.java	Thu Apr 18 15:37:03 2019 +0100
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.foreign.abi.x64;
+
+import jdk.internal.foreign.abi.Storage;
+
+import java.foreign.layout.Address;
+import java.foreign.layout.Group;
+import java.foreign.layout.Layout;
+import java.foreign.layout.Padding;
+import java.foreign.layout.Sequence;
+import java.foreign.layout.Value;
+
+public class SharedUtils {
+    public static final int INTEGER_REGISTER_SIZE = 8;
+    public static final int VECTOR_REGISTER_SIZE = 64; // (maximum) vector size is 512 bits
+    public static final int X87_REGISTER_SIZE = 16; // x87 register is 128 bits
+
+    public static final int STACK_SLOT_SIZE = 8;
+
+    /**
+     * Align the specified type from a given address
+     * @return The address the data should be at based on alignment requirement
+     */
+    public static long align(Layout t, boolean isVar, long addr) {
+        return alignUp(addr, alignment(t, isVar));
+    }
+
+    public static long alignUp(long addr, long alignment) {
+        return ((addr - 1) | (alignment - 1)) + 1;
+    }
+
+    public static long alignDown(long addr, long alignment) {
+        return addr & ~(alignment - 1);
+    }
+
+    /**
+     * The alignment requirement for a given type
+     * @param isVar indicate if the type is a standalone variable. This change how
+     * array is aligned. for example.
+     */
+    public static long alignment(Layout t, boolean isVar) {
+        if (t instanceof Value) {
+            return alignmentOfScalar((Value) t);
+        } else if (t instanceof Sequence) {
+            // when array is used alone
+            return alignmentOfArray((Sequence) t, isVar);
+        } else if (t instanceof Group) {
+            return alignmentOfContainer((Group) t);
+        } else if (t instanceof Address) {
+            return 8;
+        } else if (t instanceof Padding) {
+            return 1;
+        } else {
+            throw new IllegalArgumentException("Invalid type: " + t);
+        }
+    }
+
+    private static long alignmentOfScalar(Value st) {
+        return st.bitsSize() / 8;
+    }
+
+    private static long alignmentOfArray(Sequence ar, boolean isVar) {
+        if (ar.elementsSize() == 0) {
+            // VLA or incomplete
+            return 16;
+        } else if ((ar.bitsSize() / 8) >= 16 && isVar) {
+            return 16;
+        } else {
+            // align as element type
+            Layout elementType = ar.element();
+            return alignment(elementType, false);
+        }
+    }
+
+    private static long alignmentOfContainer(Group ct) {
+        // Most strict member
+        return ct.elements().stream().mapToLong(t -> alignment(t, false)).max().orElse(1);
+    }
+
+    public static class StorageDebugHelper {
+
+        private final String[] integerArgumentRegisterNames;
+        private final String[] integerReturnRegisterNames;
+        private final String[] x87ReturnRegisterNames;
+        private final int maxVectorArgRegisters;
+        private final int maxVectorReturnRegisters;
+
+        public StorageDebugHelper(String[] integerArgumentRegisterNames, String[] integerReturnRegisterNames,
+                                         String[]  x87ReturnRegisterNames, int maxVectorArgRegisters, int maxVectorReturnRegisters) {
+            this.integerArgumentRegisterNames = integerArgumentRegisterNames;
+            this.integerReturnRegisterNames = integerReturnRegisterNames;
+            this.x87ReturnRegisterNames = x87ReturnRegisterNames;
+            this.maxVectorArgRegisters = maxVectorArgRegisters;
+            this.maxVectorReturnRegisters = maxVectorReturnRegisters;
+        }
+
+
+        private static String getVectorRegisterName(long index, long size) {
+            switch ((int)size) {
+                case 8: return "xmm" + index + "_8";
+                case 16: return "xmm" + index;
+                case 32: return "ymm" + index;
+                case 64: return "zmm" + index;
+                default: throw new IllegalArgumentException("Illegal vector size: " + size);
+            }
+        }
+
+        public String getStorageName(Storage storage) {
+            switch (storage.getStorageClass()) {
+                case INTEGER_ARGUMENT_REGISTER:
+                    if (storage.getStorageIndex() > integerArgumentRegisterNames.length) {
+                        throw new IllegalArgumentException("Illegal storage: " + storage);
+                    }
+                    return integerArgumentRegisterNames[(int) storage.getStorageIndex()];
+
+                case VECTOR_ARGUMENT_REGISTER:
+                    if (storage.getStorageIndex() > maxVectorArgRegisters) {
+                        throw new IllegalArgumentException("Illegal storage: " + storage);
+                    }
+                    return getVectorRegisterName(storage.getStorageIndex(), storage.getSize());
+
+                case INTEGER_RETURN_REGISTER:
+                    if (storage.getStorageIndex() > integerReturnRegisterNames.length) {
+                        throw new IllegalArgumentException("Illegal storage: " + storage);
+                    }
+
+                    return integerReturnRegisterNames[(int) storage.getStorageIndex()];
+
+                case VECTOR_RETURN_REGISTER:
+                    if (storage.getStorageIndex() > maxVectorReturnRegisters) {
+                        throw new IllegalArgumentException("Illegal storage: " + storage);
+                    }
+                    return getVectorRegisterName(storage.getStorageIndex(), storage.getSize());
+
+                case X87_RETURN_REGISTER:
+                    if (storage.getStorageIndex() > x87ReturnRegisterNames.length) {
+                        throw new IllegalArgumentException("Illegal storage: " + storage);
+                    }
+                    return x87ReturnRegisterNames[(int) storage.getStorageIndex()];
+
+                case STACK_ARGUMENT_SLOT: return "[sp + " + Long.toHexString(8 * storage.getStorageIndex()) + "]";
+            }
+
+            throw new IllegalArgumentException("Unhandled storage type: " + storage.getStorageClass());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/foreign/abi/x64/sysv/CallingSequenceBuilderImpl.java	Thu Apr 18 15:37:03 2019 +0100
@@ -0,0 +1,437 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * 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);
+                // int128
+                long left = (type.bitsSize() / 8) - 8;
+                while (left > 0) {
+                    classes.add(ArgumentClass.INTEGER);
+                    left -= 8;
+                }
+                return classes;
+            case FLOATING_POINT:
+                if ((type.bitsSize() / 8) > 8) {
+                    classes.add(ArgumentClass.X87);
+                    classes.add(ArgumentClass.X87UP);
+                    return classes;
+                } else {
+                    classes.add(ArgumentClass.SSE);
+                    return classes;
+                }
+            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);
+        }
+
+        ArrayList<ArgumentClass> classes = new ArrayList<>();
+
+        for (long i = 0; i < nWords; i++) {
+            classes.add(ArgumentClass.NO_CLASS);
+        }
+
+        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++) {
+                int pos = (int)(offset / 8);
+                ArgumentClass newClass = classes.get(i + pos).merge(subclasses.get(i));
+                classes.set(i + pos, newClass);
+            }
+
+            offset += t.bitsSize() / 8;
+        }
+
+        for (int i = 0; i < classes.size(); i++) {
+            ArgumentClass c = classes.get(i);
+
+            if (c == ArgumentClass.MEMORY) {
+                return createMemoryClassArray(classes.size());
+            }
+
+            if (c == ArgumentClass.X87UP) {
+                if (i == 0) {
+                    throw new IllegalArgumentException("Unexpected leading X87UP class");
+                }
+
+                if (classes.get(i - 1) != ArgumentClass.X87) {
+                    return createMemoryClassArray(classes.size());
+                }
+            }
+        }
+
+        if (classes.size() > 2) {
+            if (classes.get(0) != ArgumentClass.SSE) {
+                return createMemoryClassArray(classes.size());
+            }
+
+            for (int i = 1; i < classes.size(); i++) {
+                if (classes.get(i) != ArgumentClass.SSEUP) {
+                    return createMemoryClassArray(classes.size());
+                }
+            }
+        }
+
+        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);
+        }
+
+        ArrayList<ArgumentClass> classes = new ArrayList<>();
+
+        for (long i = 0; i < nWords; i++) {
+            classes.add(ArgumentClass.NO_CLASS);
+        }
+
+        long offset = 0;
+        final int count = type.elements().size();
+        for (int idx = 0; idx < count; idx++) {
+            Layout t = type.elements().get(idx);
+            if (t instanceof Padding) {
+                continue;
+            }
+            // ignore zero-length array for now
+            // TODO: handle zero length arrays here
+            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++) {
+                int pos = (int)(offset / 8);
+                ArgumentClass newClass = classes.get(i + pos).merge(subclasses.get(i));
+                classes.set(i + pos, newClass);
+            }
+
+            // TODO: validate union strategy is sound
+            if (type.kind() != Kind.UNION) {
+                offset += t.bitsSize() / 8;
+            }
+        }
+
+        for (int i = 0; i < classes.size(); i++) {
+            ArgumentClass c = classes.get(i);
+
+            if (c == ArgumentClass.MEMORY) {
+                return createMemoryClassArray(classes.size());
+            }
+
+            if (c == ArgumentClass.X87UP) {
+                if (i == 0) {
+                    throw new IllegalArgumentException("Unexpected leading X87UP class");
+                }
+
+                if (classes.get(i - 1) != ArgumentClass.X87) {
+                    return createMemoryClassArray(classes.size());
+                }
+            }
+        }
+
+        if (classes.size() > 2) {
+            if (classes.get(0) != ArgumentClass.SSE) {
+                return createMemoryClassArray(classes.size());
+            }
+
+            for (int i = 1; i < classes.size(); i++) {
+                if (classes.get(i) != ArgumentClass.SSEUP) {
+                    return createMemoryClassArray(classes.size());
+                }
+            }
+        }
+
+        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<>();
+                classes.add(ArgumentClass.INTEGER);
+                return classes;
+            } else if (type instanceof Sequence) {
+                return classifyArrayType((Sequence) type);
+            } else if (type instanceof Group) {
+                return type.name().isPresent() && type.name().get().equals("LongDoubleComplex") ?
+                        COMPLEX_X87_CLASSES :
+                        classifyStructType((Group) type);
+            } else {
+                throw new IllegalArgumentException("Unhandled type " + type);
+            }
+        } catch (UnsupportedOperationException e) {
+            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;
+
+                        for (int j = i + 1; j < info.getClasses().size(); j++) {
+                            if (info.getClasses().get(j) == ArgumentClass.SSEUP) {
+                                width += 8;
+                            }
+                        }
+
+                        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:
+                        break;
+
+                    case X87: {
+                        int width = 8;
+
+                        if (i < info.getClasses().size() && info.getClasses().get(i + 1) == ArgumentClass.X87UP) {
+                            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:
+                        break;
+
+                    default:
+                        throw new UnsupportedOperationException("Unhandled class " + c);
+                    }
+                }
+            }
+        }
+    }
+}
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/x64/sysv/Constants.java	Wed Apr 17 22:09:23 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.internal.foreign.abi.x64.sysv;
-
-public class Constants {
-    public static final int MAX_INTEGER_ARGUMENT_REGISTERS = 6;
-    public static final int MAX_INTEGER_RETURN_REGISTERS = 2;
-
-    public static final int MAX_VECTOR_ARGUMENT_REGISTERS = 8;
-    public static final int MAX_VECTOR_RETURN_REGISTERS = 2;
-    public static final int MAX_X87_RETURN_REGISTERS = 2;
-
-}
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/x64/sysv/StandardCall.java	Wed Apr 17 22:09:23 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,526 +0,0 @@
-/*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * 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);
-                // int128
-                long left = (type.bitsSize() / 8) - 8;
-                while (left > 0) {
-                    classes.add(ArgumentClass.INTEGER);
-                    left -= 8;
-                }
-                return classes;
-            case FLOATING_POINT:
-                if ((type.bitsSize() / 8) > 8) {
-                    classes.add(ArgumentClass.X87);
-                    classes.add(ArgumentClass.X87UP);
-                    return classes;
-                } else {
-                    classes.add(ArgumentClass.SSE);
-                    return classes;
-                }
-            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);
-        }
-
-        ArrayList<ArgumentClass> classes = new ArrayList<>();
-
-        for (long i = 0; i < nWords; i++) {
-            classes.add(ArgumentClass.NO_CLASS);
-        }
-
-        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++) {
-                int pos = (int)(offset / 8);
-                ArgumentClass newClass = classes.get(i + pos).merge(subclasses.get(i));
-                classes.set(i + pos, newClass);
-            }
-
-            offset += t.bitsSize() / 8;
-        }
-
-        for (int i = 0; i < classes.size(); i++) {
-            ArgumentClass c = classes.get(i);
-
-            if (c == ArgumentClass.MEMORY) {
-                return createMemoryClassArray(classes.size());
-            }
-
-            if (c == ArgumentClass.X87UP) {
-                if (i == 0) {
-                    throw new IllegalArgumentException("Unexpected leading X87UP class");
-                }
-
-                if (classes.get(i - 1) != ArgumentClass.X87) {
-                    return createMemoryClassArray(classes.size());
-                }
-            }
-        }
-
-        if (classes.size() > 2) {
-            if (classes.get(0) != ArgumentClass.SSE) {
-                return createMemoryClassArray(classes.size());
-            }
-
-            for (int i = 1; i < classes.size(); i++) {
-                if (classes.get(i) != ArgumentClass.SSEUP) {
-                    return createMemoryClassArray(classes.size());
-                }
-            }
-        }
-
-        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);
-        }
-
-        ArrayList<ArgumentClass> classes = new ArrayList<>();
-
-        for (long i = 0; i < nWords; i++) {
-            classes.add(ArgumentClass.NO_CLASS);
-        }
-
-        long offset = 0;
-        final int count = type.elements().size();
-        for (int idx = 0; idx < count; idx++) {
-            Layout t = type.elements().get(idx);
-            if (t instanceof Padding) {
-                continue;
-            }
-            // ignore zero-length array for now
-            // TODO: handle zero length arrays here
-            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++) {
-                int pos = (int)(offset / 8);
-                ArgumentClass newClass = classes.get(i + pos).merge(subclasses.get(i));
-                classes.set(i + pos, newClass);
-            }
-
-            // TODO: validate union strategy is sound
-            if (type.kind() != Kind.UNION) {
-                offset += t.bitsSize() / 8;
-            }
-        }
-
-        for (int i = 0; i < classes.size(); i++) {
-            ArgumentClass c = classes.get(i);
-
-            if (c == ArgumentClass.MEMORY) {
-                return createMemoryClassArray(classes.size());
-            }
-
-            if (c == ArgumentClass.X87UP) {
-                if (i == 0) {
-                    throw new IllegalArgumentException("Unexpected leading X87UP class");
-                }
-
-                if (classes.get(i - 1) != ArgumentClass.X87) {
-                    return createMemoryClassArray(classes.size());
-                }
-            }
-        }
-
-        if (classes.size() > 2) {
-            if (classes.get(0) != ArgumentClass.SSE) {
-                return createMemoryClassArray(classes.size());
-            }
-
-            for (int i = 1; i < classes.size(); i++) {
-                if (classes.get(i) != ArgumentClass.SSEUP) {
-                    return createMemoryClassArray(classes.size());
-                }
-            }
-        }
-
-        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<>();
-                classes.add(ArgumentClass.INTEGER);
-                return classes;
-            } else if (type instanceof Sequence) {
-                return classifyArrayType((Sequence) type);
-            } else if (type instanceof Group) {
-                return type.name().isPresent() && type.name().get().equals("LongDoubleComplex") ?
-                        COMPLEX_X87_CLASSES :
-                        classifyStructType((Group) type);
-            } else {
-                throw new IllegalArgumentException("Unhandled type " + type);
-            }
-        } catch (UnsupportedOperationException e) {
-            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;
-
-                        for (int j = i + 1; j < info.getClasses().size(); j++) {
-                            if (info.getClasses().get(j) == ArgumentClass.SSEUP) {
-                                width += 8;
-                            }
-                        }
-
-                        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:
-                        break;
-
-                    case X87: {
-                        int width = 8;
-
-                        if (i < info.getClasses().size() && info.getClasses().get(i + 1) == ArgumentClass.X87UP) {
-                            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:
-                        break;
-
-                    default:
-                        throw new UnsupportedOperationException("Unhandled class " + c);
-                    }
-                }
-            }
-        }
-    }
-
-    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);
-    }
-}
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/x64/sysv/SysVx64ABI.java	Wed Apr 17 22:09:23 2019 +0200
+++ b/src/java.base/share/classes/jdk/internal/foreign/abi/x64/sysv/SysVx64ABI.java	Thu Apr 18 15:37:03 2019 +0100
@@ -33,13 +33,13 @@
 import java.foreign.NativeMethodType;
 import java.foreign.NativeTypes;
 import java.foreign.Scope;
-import java.foreign.layout.*;
 import java.foreign.memory.LayoutType;
 import java.foreign.memory.Pointer;
 import java.foreign.memory.Struct;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.WrongMethodTypeException;
 import java.util.*;
+import java.util.function.Function;
 
 import static sun.security.action.GetPropertyAction.privilegedGetProperty;
 
@@ -47,6 +47,12 @@
  * ABI implementation based on System V ABI AMD64 supplement v.0.99.6
  */
 public class SysVx64ABI implements SystemABI {
+    public static final int MAX_INTEGER_ARGUMENT_REGISTERS = 6;
+    public static final int MAX_INTEGER_RETURN_REGISTERS = 2;
+    public static final int MAX_VECTOR_ARGUMENT_REGISTERS = 8;
+    public static final int MAX_VECTOR_RETURN_REGISTERS = 2;
+    public static final int MAX_X87_RETURN_REGISTERS = 2;
+
     private static final String fastPath = privilegedGetProperty("jdk.internal.foreign.NativeInvoker.FASTPATH");
     private static SysVx64ABI instance;
 
@@ -60,12 +66,10 @@
     @Override
     public MethodHandle downcallHandle(CallingConvention cc, Library.Symbol symbol, NativeMethodType nmt) {
         if (nmt.isVarArgs()) {
-            return VarargsInvokerImpl.make(symbol, nmt);
+            return VarargsInvoker.make(symbol, nmt, CallingSequenceBuilderImpl::new, adapter);
         }
 
-        StandardCall sc = new StandardCall();
-        CallingSequence callingSequence = sc.arrangeCall(nmt);
-
+        CallingSequence callingSequence = arrangeCall(nmt);
         if (fastPath == null || !fastPath.equals("none")) {
             if (DirectSignatureShuffler.acceptDowncall(nmt, callingSequence)) {
                 return DirectNativeInvoker.make(symbol, callingSequence, nmt);
@@ -74,7 +78,12 @@
                         String.format("No fast path for: %s", symbol.getName()));
             }
         }
-        return UniversalNativeInvokerImpl.make(symbol, callingSequence, nmt).getBoundMethodHandle();
+        try {
+            return new UniversalNativeInvoker(symbol, callingSequence, nmt,
+                    adapter).getBoundMethodHandle();
+        } catch (IllegalAccessException ex) {
+            throw new IllegalStateException(ex);
+        }
     }
 
     @Override
@@ -82,8 +91,7 @@
         if (!target.type().equals(nmt.methodType())) {
             throw new WrongMethodTypeException("Native method type has wrong type: " + nmt.methodType());
         }
-        StandardCall sc = new StandardCall();
-        CallingSequence callingSequence = sc.arrangeCall(nmt);
+        CallingSequence callingSequence = arrangeCall(nmt);
         if (fastPath == null || !fastPath.equals("none")) {
             if (DirectSignatureShuffler.acceptUpcall(nmt, callingSequence)) {
                 return UpcallStubs.registerUpcallStub(new DirectUpcallHandler(target, callingSequence, nmt));
@@ -92,7 +100,14 @@
                         String.format("No fast path for function type %s", nmt.function()));
             }
         }
-        return UpcallStubs.registerUpcallStub(new UniversalUpcallHandlerImpl(target, callingSequence, nmt));
+        return UpcallStubs.registerUpcallStub(new UniversalUpcallHandler(target, callingSequence, nmt,
+                adapter));
+    }
+
+    CallingSequence arrangeCall(NativeMethodType nmt) {
+        CallingSequenceBuilder stdc = new CallingSequenceBuilderImpl(nmt.function().returnLayout().orElse(null));
+        nmt.function().argumentLayouts().forEach(stdc::addArgument);
+        return stdc.build();
     }
 
     private static final Map<String, CallingConvention> SysVCallingConventions = new HashMap<>();
@@ -121,53 +136,56 @@
         return Collections.unmodifiableCollection(SysVCallingConventions.values());
     }
 
-    static void unboxValue(Object o, LayoutType<?> type, java.util.function.Function<ArgumentBinding, Pointer<?>> dstPtrFunc,
+    UniversalAdapter adapter = new UniversalAdapter() {
+        @Override
+        public void unboxValue(Object o, LayoutType<?> type, java.util.function.Function<ArgumentBinding, Pointer<?>> dstPtrFunc,
                            List<ArgumentBinding> bindings) throws Throwable {
-        if (o instanceof Struct) {
-            Struct<?> struct = (Struct<?>) o;
-            if (struct.ptr().type().bytesSize() != 0) {
-                Pointer<Long> src = Util.unsafeCast(struct.ptr(), NativeTypes.UINT64);
+            if (o instanceof Struct) {
+                Struct<?> struct = (Struct<?>) o;
+                if (struct.ptr().type().bytesSize() != 0) {
+                    Pointer<Long> src = Util.unsafeCast(struct.ptr(), NativeTypes.UINT64);
+                    for (ArgumentBinding binding : bindings) {
+                        Pointer<?> dst = dstPtrFunc.apply(binding);
+                        Pointer<Long> srcPtr = src.offset(binding.offset() / NativeTypes.UINT64.bytesSize());
+                        Pointer.copy(srcPtr, dst, binding.storage().getSize());
+                    }
+                }
+            } else {
+                assert bindings.size() <= 2;
+                Pointer<?> dst = Util.unsafeCast(dstPtrFunc.apply(bindings.get(0)), type);
+                dst.type().setter().invoke(dst, o);
+            }
+        }
+
+        @SuppressWarnings("unchecked")
+        public Object boxValue(LayoutType<?> type, java.util.function.Function<ArgumentBinding, Pointer<?>> srcPtrFunc,
+                               List<ArgumentBinding> bindings) throws IllegalAccessException {
+            Class<?> carrier = ((LayoutTypeImpl<?>)type).carrier();
+            if (Util.isCStruct(carrier)) {
+                /*
+                 * Leak memory for now
+                 */
+                Scope scope = Scope.globalScope().fork();
+
+                if (type.bytesSize() == 0) {
+                    //empty struct!
+                    return scope.allocateStruct((Class)carrier);
+                }
+
+                @SuppressWarnings({"rawtypes", "unchecked"})
+                Pointer<?> rtmp = ((ScopeImpl)scope).allocate(type, 8);
+
                 for (ArgumentBinding binding : bindings) {
-                    Pointer<?> dst = dstPtrFunc.apply(binding);
-                    Pointer<Long> srcPtr = src.offset(binding.getOffset() / NativeTypes.UINT64.bytesSize());
-                    Pointer.copy(srcPtr, dst, binding.getStorage().getSize());
+                    Pointer<Long> dst = Util.unsafeCast(rtmp, NativeTypes.UINT64).offset(binding.offset() / NativeTypes.UINT64.bytesSize());
+                    Pointer.copy(srcPtrFunc.apply(binding), dst, binding.storage().getSize());
                 }
+
+                return rtmp.get();
+            } else {
+                assert bindings.size() <= 2;
+                return Util.unsafeCast(srcPtrFunc.apply(bindings.get(0)), type).get();
             }
-        } else {
-            assert bindings.size() <= 2;
-            Pointer<?> dst = Util.unsafeCast(dstPtrFunc.apply(bindings.get(0)), type);
-            dst.type().setter().invoke(dst, o);
         }
-    }
-
-    @SuppressWarnings("unchecked")
-    static Object boxValue(LayoutType<?> type, java.util.function.Function<ArgumentBinding, Pointer<?>> srcPtrFunc,
-                           List<ArgumentBinding> bindings) throws IllegalAccessException {
-        Class<?> carrier = ((LayoutTypeImpl<?>)type).carrier();
-        if (Util.isCStruct(carrier)) {
-            /*
-             * Leak memory for now
-             */
-            Scope scope = Scope.globalScope().fork();
-
-            if (type.bytesSize() == 0) {
-                //empty struct!
-                return scope.allocateStruct((Class)carrier);
-            }
-
-            @SuppressWarnings({"rawtypes", "unchecked"})
-            Pointer<?> rtmp = ((ScopeImpl)scope).allocate(type, 8);
-
-            for (ArgumentBinding binding : bindings) {
-                Pointer<Long> dst = Util.unsafeCast(rtmp, NativeTypes.UINT64).offset(binding.getOffset() / NativeTypes.UINT64.bytesSize());
-                Pointer.copy(srcPtrFunc.apply(binding), dst, binding.getStorage().getSize());
-            }
-
-            return rtmp.get();
-        } else {
-            assert bindings.size() <= 2;
-            return Util.unsafeCast(srcPtrFunc.apply(bindings.get(0)), type).get();
-        }
-    }
+    };
 }
 
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/x64/sysv/UniversalNativeInvokerImpl.java	Wed Apr 17 22:09:23 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.internal.foreign.abi.x64.sysv;
-
-import jdk.internal.foreign.abi.ArgumentBinding;
-import jdk.internal.foreign.abi.CallingSequence;
-import jdk.internal.foreign.abi.UniversalNativeInvoker;
-
-import java.foreign.Library;
-import java.foreign.NativeMethodType;
-import java.foreign.memory.LayoutType;
-import java.foreign.memory.Pointer;
-import java.util.List;
-import java.util.function.Function;
-
-class UniversalNativeInvokerImpl extends UniversalNativeInvoker {
-
-    public UniversalNativeInvokerImpl(long addr, String methodName, CallingSequence callingSequence, NativeMethodType nmt) {
-        super(addr, methodName, callingSequence, nmt);
-    }
-
-    public static UniversalNativeInvoker make(Library.Symbol symbol, CallingSequence callingSequence, NativeMethodType nmt) {
-        try {
-            return new UniversalNativeInvokerImpl(symbol.getAddress().addr(), symbol.getName(), callingSequence, nmt);
-        } catch (IllegalAccessException iae) {
-            throw new IllegalStateException(iae);
-        }
-    }
-
-    @Override
-    public void unboxValue(Object o, LayoutType<?> type, Function<ArgumentBinding, Pointer<?>> dstPtrFunc,
-                           List<ArgumentBinding> bindings) throws Throwable {
-        SysVx64ABI.unboxValue(o, type, dstPtrFunc, bindings);
-    }
-
-    @Override
-    public Object boxValue(LayoutType<?> type, Function<ArgumentBinding, Pointer<?>> srcPtrFunc,
-                           List<ArgumentBinding> bindings) throws IllegalAccessException {
-        return SysVx64ABI.boxValue(type, srcPtrFunc, bindings);
-    }
-}
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/x64/sysv/UniversalUpcallHandlerImpl.java	Wed Apr 17 22:09:23 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*
- * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.internal.foreign.abi.x64.sysv;
-
-import jdk.internal.foreign.abi.ArgumentBinding;
-import jdk.internal.foreign.abi.CallingSequence;
-import jdk.internal.foreign.abi.UniversalUpcallHandler;
-
-import java.foreign.NativeMethodType;
-import java.foreign.memory.LayoutType;
-import java.foreign.memory.Pointer;
-import java.lang.invoke.MethodHandle;
-import java.util.List;
-import java.util.function.Function;
-
-class UniversalUpcallHandlerImpl extends UniversalUpcallHandler {
-
-    public UniversalUpcallHandlerImpl(MethodHandle target, CallingSequence callingSequence, NativeMethodType nmt) {
-        super(target, callingSequence, nmt);
-    }
-
-    @Override
-    public void unboxValue(Object o, LayoutType<?> type, Function<ArgumentBinding, Pointer<?>> dstPtrFunc,
-                           List<ArgumentBinding> bindings) throws Throwable {
-        SysVx64ABI.unboxValue(o, type, dstPtrFunc, bindings);
-    }
-
-    @Override
-    public Object boxValue(LayoutType<?> type, Function<ArgumentBinding, Pointer<?>> srcPtrFunc,
-                           List<ArgumentBinding> bindings) throws IllegalAccessException {
-        return SysVx64ABI.boxValue(type, srcPtrFunc, bindings);
-    }
-}
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/x64/sysv/VarargsInvokerImpl.java	Wed Apr 17 22:09:23 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-/*
- * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.internal.foreign.abi.x64.sysv;
-
-import jdk.internal.foreign.abi.SystemABI;
-import jdk.internal.foreign.abi.VarargsInvoker;
-
-import java.foreign.Library;
-import java.foreign.NativeMethodType;
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodType;
-
-class VarargsInvokerImpl extends VarargsInvoker {
-
-    private VarargsInvokerImpl(Library.Symbol symbol, NativeMethodType nativeMethodType) {
-        super(symbol, nativeMethodType);
-    }
-
-    public static MethodHandle make(Library.Symbol symbol, NativeMethodType nativeMethodType) {
-        VarargsInvokerImpl invoker = new VarargsInvokerImpl(symbol, nativeMethodType);
-        MethodType methodType = nativeMethodType.methodType();
-        return INVOKE_MH.bindTo(invoker).asCollector(Object[].class, methodType.parameterCount())
-                .asType(methodType);
-    }
-
-    @Override
-    protected MethodHandle specialize(NativeMethodType newNativeMethodType){
-        return SystemABI.getInstance().downcallHandle(symbol, newNativeMethodType);
-    }
-
-}
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/x64/windows/CallingSequenceBuilderImpl.java	Wed Apr 17 22:09:23 2019 +0200
+++ b/src/java.base/share/classes/jdk/internal/foreign/abi/x64/windows/CallingSequenceBuilderImpl.java	Thu Apr 18 15:37:03 2019 +0100
@@ -24,74 +24,73 @@
 
 import jdk.internal.foreign.Util;
 import jdk.internal.foreign.abi.*;
-import jdk.internal.foreign.abi.x64.CallingSequenceBuilder;
 import jdk.internal.foreign.abi.x64.ArgumentClass;
-import jdk.internal.foreign.abi.x64.SharedConstants;
+import jdk.internal.foreign.abi.x64.SharedUtils;
 
 import java.foreign.layout.*;
 import java.util.ArrayList;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Set;
+import java.util.function.BiConsumer;
 
 import static sun.security.action.GetBooleanAction.privilegedGetProperty;
 
 class CallingSequenceBuilderImpl extends CallingSequenceBuilder {
-    private static final String[] INTEGER_ARGUMENT_REGISTER_NAMES = { "rcx", "rdx", "r8", "r9" };
-    private static final String[] INTEGER_RETURN_REGISTERS_NAMES = { "rax" };
-    private static final String[] X87_RETURN_REGISTERS_NAMES = { }; // TODO find out if Windows ABI actually uses these
+
+    private static final SharedUtils.StorageDebugHelper storageDbgHelper = new SharedUtils.StorageDebugHelper(
+            new String[] { "rcx", "rdx", "r8", "r9" },
+            new String[] { "rax" },
+            new String[0],
+            Windowsx64ABI.MAX_VECTOR_ARGUMENT_REGISTERS,
+            Windowsx64ABI.MAX_VECTOR_RETURN_REGISTERS
+    );
 
     private static final boolean DEBUG =
             privilegedGetProperty("jdk.internal.foreign.abi.windows.x64.DEBUG");
 
-    private int curArgIndex = 0;
-
-    private final Argument returned;
-    private final List<Argument> arguments = new ArrayList<>();;
-    private final Set<Argument> varargs = new HashSet<>();
-
-    public CallingSequenceBuilderImpl(Argument returned) {
-        super(INTEGER_ARGUMENT_REGISTER_NAMES, INTEGER_RETURN_REGISTERS_NAMES, X87_RETURN_REGISTERS_NAMES,
-                Constants.MAX_VECTOR_ARGUMENT_REGISTERS, Constants.MAX_VECTOR_RETURN_REGISTERS);
-        this.returned = returned;
+    public CallingSequenceBuilderImpl(Layout layout) {
+        this(layout, new StorageCalculator(false), new StorageCalculator(true));
     }
 
-    public void addArgument(Layout type, boolean isVarArg, String name) {
-        Argument arg = new Argument(curArgIndex++, type, name);
-        arguments.add(arg);
-        if(isVarArg) {
-            varargs.add(arg);
-        }
+    private CallingSequenceBuilderImpl(Layout layout, StorageCalculator retCalculator, StorageCalculator argCalculator) {
+        super(layout,
+                (a, c) -> retCalculator.addBindings(a, c, false),
+                (a, c) -> argCalculator.addBindings(a, c, false),
+                (a, c) -> argCalculator.addBindings(a, c, true));
     }
 
-    static class ArgumentInfo {
+    @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;
-        private final int nRegs;
-        private final boolean inMemory;
-
-        public ArgumentInfo(List<ArgumentClass> classes, int nRegs) {
-            this.classes = classes;
-
-            this.inMemory = false;
-            this.nRegs = nRegs;
-        }
-
-        public ArgumentInfo(int n) {
-            this.classes = new ArrayList<>();
-            for (int i = 0; i < n; i++) {
-                classes.add(ArgumentClass.MEMORY);
-            }
-
-            this.inMemory = true;
-            this.nRegs = 0;
+        
+        ArgumentInfo(Layout layout, int argumentIndex, String debugName) {
+            super(layout, argumentIndex, debugName);
+            this.classes = classifyType(layout, argumentIndex == -1);
         }
 
         public int getRegs() {
-            return nRegs;
+            return (int)classes.stream()
+                    .filter(this::isRegisterClass)
+                    .count();
         }
 
+        @Override
         public boolean inMemory() {
-            return inMemory;
+            return classes.stream().allMatch(this::isMemoryClass);
+        }
+
+        private boolean isMemoryClass(ArgumentClass cl) {
+            return cl == ArgumentClass.MEMORY ||
+                    cl == ArgumentClass.X87 ||
+                    cl == ArgumentClass.X87UP;
+        }
+
+        private boolean isRegisterClass(ArgumentClass cl) {
+            return cl == ArgumentClass.INTEGER ||
+                    cl == ArgumentClass.SSE;
         }
 
         public List<ArgumentClass> getClasses() {
@@ -135,7 +134,7 @@
             || size == 8;
     }
     
-    private List<ArgumentClass> createMemoryClassArray(long n) {
+    private static List<ArgumentClass> createMemoryClassArray(long n) {
         ArrayList<ArgumentClass> classes = new ArrayList<>();
         for (int i = 0; i < n; i++) {
             classes.add(ArgumentClass.MEMORY);
@@ -144,7 +143,7 @@
         return classes;
     }
 
-    private List<ArgumentClass> classifyStructType(Group type, boolean isReturn) {
+    private static List<ArgumentClass> classifyStructType(Group type, boolean isReturn) {
         ArrayList<ArgumentClass> classes = new ArrayList<>();
         
         if(isRegisterAggregate(type)) {
@@ -160,7 +159,7 @@
         return classes;
     }
 
-    private List<ArgumentClass> classifyType(Layout type, boolean isReturn) {
+    private static List<ArgumentClass> classifyType(Layout type, boolean isReturn) {
         if (type instanceof Value) {
             return classifyValueType((Value) type);
         } else if (type instanceof Address) {
@@ -178,75 +177,40 @@
         }
     }
 
-    private ArgumentInfo examineArgument(Layout type, boolean isReturn) {
-        List<ArgumentClass> classes = classifyType(type, isReturn);
-        if (classes.isEmpty()) {
-            return null;
-        }
-
-        int nRegs = 0;
-
-        for (ArgumentClass c : classes) {
-            switch (c) {
-            case INTEGER:
-            case SSE:
-                nRegs++;
-                break;
-            case X87:
-            case X87UP:
-                return new ArgumentInfo(classes.size());
-            default:
-                break;
-            }
-        }
-
-        if (nRegs != 0) {
-            return new ArgumentInfo(classes, nRegs);
-        } else {
-            return new ArgumentInfo(classes.size());
-        }
-    }
-
-    class StorageCalculator {
-        private final ArrayList<ArgumentBinding>[] bindings;
+    static class StorageCalculator {
         private final boolean forArguments;
 
         private int nRegs = 0;
         private long stackOffset = 0;
 
-        StorageCalculator(ArrayList<ArgumentBinding>[] bindings, boolean forArguments) {
-            this.bindings = bindings;
+        StorageCalculator(boolean forArguments) {
             this.forArguments = forArguments;
         }
 
-        void addBindings(Argument arg, ArgumentInfo info) {
+        void addBindings(Argument arg, BiConsumer<StorageClass, ArgumentBinding> bindingConsumer, boolean forVarargs) {
+            ArgumentInfo info = (ArgumentInfo)arg;
             if (info.inMemory() ||
-                nRegs + info.getRegs() > (forArguments ? Constants.MAX_REGISTER_ARGUMENTS : Constants.MAX_REGISTER_RETURNS)) {
+                nRegs + info.getRegs() > (forArguments ? Windowsx64ABI.MAX_REGISTER_ARGUMENTS : Windowsx64ABI.MAX_REGISTER_RETURNS)) {
                 // stack
 
-                long alignment = Math.max(alignment(arg.getType(), true), 8);
+                long alignment = Math.max(SharedUtils.alignment(info.layout(), 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));
+                    bindingConsumer.accept(StorageClass.STACK_ARGUMENT_SLOT, new ArgumentBinding(storage, info, i * 8));
 
                     if (DEBUG) {
-                        System.out.println("Argument " + arg.getName() + " will be passed on stack at offset " + tmpStackOffset);
+                        System.out.println("Argument " + info.name() + " will be passed on stack at offset " + tmpStackOffset);
                     }
 
                     tmpStackOffset += 8;
                 }
 
-                stackOffset += arg.getType().bitsSize() / 8;
+                stackOffset += info.layout().bitsSize() / 8;
             } else {
                 // regs
                 for (int i = 0; i < info.getClasses().size(); i++) {
@@ -256,11 +220,12 @@
 
                     switch (c) {
                     case INTEGER:
-                        storage = new Storage(forArguments ? StorageClass.INTEGER_ARGUMENT_REGISTER : StorageClass.INTEGER_RETURN_REGISTER, nRegs++, SharedConstants.INTEGER_REGISTER_SIZE);
-                        bindings[storage.getStorageClass().ordinal()].add(new ArgumentBinding(storage, arg, i * 8));
+                        storage = new Storage(forArguments ? StorageClass.INTEGER_ARGUMENT_REGISTER : StorageClass.INTEGER_RETURN_REGISTER, nRegs++, SharedUtils.INTEGER_REGISTER_SIZE);
+                        bindingConsumer.accept(storage.getStorageClass(), new ArgumentBinding(storage, info, i * 8));
 
                         if (DEBUG) {
-                            System.out.println("Argument " + arg.getName() + " will be passed in register " + getStorageName(storage));
+                            System.out.println("Argument " + info.name() + " will be passed in register " +
+                                    storageDbgHelper.getStorageName(storage));
                         }
                         break;
 
@@ -277,19 +242,22 @@
                             throw new IllegalArgumentException((width * 8) + "-bit vector arguments not supported");
                         }
 
-                        storage = new Storage(forArguments ? StorageClass.VECTOR_ARGUMENT_REGISTER : StorageClass.VECTOR_RETURN_REGISTER, nRegs, width);
-                        bindings[storage.getStorageClass().ordinal()].add(new ArgumentBinding(storage, arg, i * 8));
+                        storage = new Storage(forArguments ? StorageClass.VECTOR_ARGUMENT_REGISTER : StorageClass.VECTOR_RETURN_REGISTER,
+                                nRegs, width, SharedUtils.VECTOR_REGISTER_SIZE);
+                        bindingConsumer.accept(storage.getStorageClass(), new ArgumentBinding(storage, info, i * 8));
 
                         if (DEBUG) {
-                            System.out.println("Argument " + arg.getName() + " will be passed in register " + getStorageName(storage));
+                            System.out.println("Argument " + info.name() + " will be passed in register " +
+                                    storageDbgHelper.getStorageName(storage));
                         }
 
-                        if(width == 8 && storage.getStorageClass() == StorageClass.VECTOR_ARGUMENT_REGISTER && varargs.contains(arg)) {
-                            Storage extraStorage = new Storage(StorageClass.INTEGER_ARGUMENT_REGISTER, nRegs, SharedConstants.INTEGER_REGISTER_SIZE);
-                            bindings[StorageClass.INTEGER_ARGUMENT_REGISTER.ordinal()].add(new ArgumentBinding(extraStorage, arg, i * 8));
+                        if(width == 8 && storage.getStorageClass() == StorageClass.VECTOR_ARGUMENT_REGISTER && forVarargs) {
+                            Storage extraStorage = new Storage(StorageClass.INTEGER_ARGUMENT_REGISTER, nRegs, SharedUtils.INTEGER_REGISTER_SIZE);
+                            bindingConsumer.accept(storage.getStorageClass(), new ArgumentBinding(extraStorage, info, i * 8));
 
                             if (DEBUG) {
-                                System.out.println("Argument " + arg.getName() + " will be passed in register " + getStorageName(extraStorage));
+                                System.out.println("Argument " + info.name() + " will be passed in register " +
+                                        storageDbgHelper.getStorageName(extraStorage));
                             }
                         }
 
@@ -306,45 +274,4 @@
             }
         }
     }
-
-    private void addBindings(List<Argument> members, StorageCalculator calculator, boolean isReturn) {
-        members.stream().forEach(arg -> calculator.addBindings(arg, examineArgument(arg.getType(), isReturn)));
-    }
-
-    public CallingSequence build() {
-        List<Argument> returns = new ArrayList<>();
-        List<Argument> args = this.arguments;
-        boolean returnsInMemory = false;
-
-        if (returned != null) {
-            Layout returnType = returned.getType();
-
-            returnsInMemory = examineArgument(returnType, true).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, returned.getType()), returned.getName());
-                args.add(returnPointer);
-                args.addAll(this.arguments);
-
-                returns.add(returnPointer);
-            } else {
-                returns.add(returned);
-            }
-        }
-
-        @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), false);
-        addBindings(returns, new StorageCalculator(bindings, false), true);
-
-        return new CallingSequence(this.arguments.size(), bindings, returnsInMemory);
-    }
 }
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/x64/windows/Constants.java	Wed Apr 17 22:09:23 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.internal.foreign.abi.x64.windows;
-
-class Constants {
-    public static final int MAX_INTEGER_ARGUMENT_REGISTERS = 4;
-    public static final int MAX_INTEGER_RETURN_REGISTERS = 1;
-
-    public static final int MAX_VECTOR_ARGUMENT_REGISTERS = 4;
-    public static final int MAX_VECTOR_RETURN_REGISTERS = 1;
-
-    public static final int MAX_REGISTER_ARGUMENTS = 4;
-    public static final int MAX_REGISTER_RETURNS = 1;
-
-}
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/x64/windows/UniversalNativeInvokerImpl.java	Wed Apr 17 22:09:23 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.internal.foreign.abi.x64.windows;
-
-import jdk.internal.foreign.abi.ArgumentBinding;
-import jdk.internal.foreign.abi.CallingSequence;
-import jdk.internal.foreign.abi.UniversalNativeInvoker;
-
-import java.foreign.Library;
-import java.foreign.NativeMethodType;
-import java.foreign.memory.LayoutType;
-import java.foreign.memory.Pointer;
-import java.util.List;
-import java.util.function.Function;
-
-class UniversalNativeInvokerImpl extends UniversalNativeInvoker {
-
-    public UniversalNativeInvokerImpl(long addr, String methodName, CallingSequence callingSequence, NativeMethodType nmt) {
-        super(addr, methodName, callingSequence, nmt);
-    }
-
-    public static UniversalNativeInvoker make(Library.Symbol symbol, CallingSequence callingSequence, NativeMethodType nmt) {
-        try {
-            return new UniversalNativeInvokerImpl(symbol.getAddress().addr(), symbol.getName(), callingSequence, nmt);
-        } catch (IllegalAccessException iae) {
-            throw new IllegalStateException(iae);
-        }
-    }
-
-    @Override
-    public void unboxValue(Object o, LayoutType<?> type, Function<ArgumentBinding, Pointer<?>> dstPtrFunc,
-                           List<ArgumentBinding> bindings) throws Throwable {
-        Windowsx64ABI.unboxValue(o, type, dstPtrFunc, bindings);
-    }
-
-    @Override
-    public Object boxValue(LayoutType<?> type, Function<ArgumentBinding, Pointer<?>> srcPtrFunc,
-                           List<ArgumentBinding> bindings) throws IllegalAccessException {
-        return Windowsx64ABI.boxValue(type, srcPtrFunc, bindings);
-    }
-}
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/x64/windows/UniversalUpcallHandlerImpl.java	Wed Apr 17 22:09:23 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.internal.foreign.abi.x64.windows;
-
-import jdk.internal.foreign.abi.ArgumentBinding;
-import jdk.internal.foreign.abi.CallingSequence;
-import jdk.internal.foreign.abi.UniversalUpcallHandler;
-
-import java.foreign.NativeMethodType;
-import java.foreign.memory.LayoutType;
-import java.foreign.memory.Pointer;
-import java.lang.invoke.MethodHandle;
-import java.util.List;
-import java.util.function.Function;
-
-class UniversalUpcallHandlerImpl extends UniversalUpcallHandler {
-
-    public UniversalUpcallHandlerImpl(MethodHandle target, CallingSequence callingSequence, NativeMethodType nmt) {
-        super(target, callingSequence, nmt);
-    }
-
-    @Override
-    public void unboxValue(Object o, LayoutType<?> type, Function<ArgumentBinding, Pointer<?>> dstPtrFunc,
-                           List<ArgumentBinding> bindings) throws Throwable {
-        Windowsx64ABI.unboxValue(o, type, dstPtrFunc, bindings);
-    }
-
-    @Override
-    public Object boxValue(LayoutType<?> type, Function<ArgumentBinding, Pointer<?>> srcPtrFunc,
-                           List<ArgumentBinding> bindings) throws IllegalAccessException {
-        return Windowsx64ABI.boxValue(type, srcPtrFunc, bindings);
-    }
-
-}
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/x64/windows/VarargsInvokerImpl.java	Wed Apr 17 22:09:23 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*
- * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.internal.foreign.abi.x64.windows;
-
-import jdk.internal.foreign.abi.CallingSequence;
-import jdk.internal.foreign.abi.VarargsInvoker;
-
-import java.foreign.Library;
-import java.foreign.NativeMethodType;
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodType;
-
-class VarargsInvokerImpl extends VarargsInvoker {
-
-    private VarargsInvokerImpl(Library.Symbol symbol, NativeMethodType nativeMethodType) {
-        super(symbol, nativeMethodType);
-    }
-
-    public static MethodHandle make(Library.Symbol symbol, NativeMethodType nativeMethodType) {
-        VarargsInvokerImpl invoker = new VarargsInvokerImpl(symbol, nativeMethodType);
-        MethodType methodType = nativeMethodType.methodType();
-        return INVOKE_MH.bindTo(invoker).asCollector(Object[].class, methodType.parameterCount())
-                .asType(methodType);
-    }
-
-    @Override
-    protected MethodHandle specialize(NativeMethodType newNativeMethodType) {
-        CallingSequence cs = Windowsx64ABI.arrangeCall(newNativeMethodType, nativeMethodType.parameterCount());
-        return UniversalNativeInvokerImpl.make(symbol, cs, newNativeMethodType).getBoundMethodHandle();
-    }
-
-}
-
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/x64/windows/Windowsx64ABI.java	Wed Apr 17 22:09:23 2019 +0200
+++ b/src/java.base/share/classes/jdk/internal/foreign/abi/x64/windows/Windowsx64ABI.java	Thu Apr 18 15:37:03 2019 +0100
@@ -28,15 +28,12 @@
 import jdk.internal.foreign.Util;
 import jdk.internal.foreign.abi.*;
 import jdk.internal.foreign.memory.LayoutTypeImpl;
-import jdk.internal.foreign.memory.Types;
 
 import java.foreign.Library;
 import java.foreign.NativeMethodType;
 import java.foreign.NativeTypes;
 import java.foreign.Scope;
 import java.foreign.layout.Function;
-import java.foreign.layout.Layout;
-import java.foreign.layout.Value;
 import java.foreign.memory.LayoutType;
 import java.foreign.memory.Pointer;
 import java.foreign.memory.Struct;
@@ -50,6 +47,13 @@
  */
 public class Windowsx64ABI implements SystemABI {
 
+    public static final int MAX_INTEGER_ARGUMENT_REGISTERS = 4;
+    public static final int MAX_INTEGER_RETURN_REGISTERS = 1;
+    public static final int MAX_VECTOR_ARGUMENT_REGISTERS = 4;
+    public static final int MAX_VECTOR_RETURN_REGISTERS = 1;
+    public static final int MAX_REGISTER_ARGUMENTS = 4;
+    public static final int MAX_REGISTER_RETURNS = 1;
+
     private static Windowsx64ABI instance;
 
     public static Windowsx64ABI getInstance() {
@@ -60,21 +64,10 @@
     }
 
     static CallingSequence arrangeCall(NativeMethodType nmt) {
-        return arrangeCall(nmt, Integer.MAX_VALUE);
-    }
-
-    static CallingSequence arrangeCall(NativeMethodType nmt, int varArgsStart) {
         Function f = nmt.function();
-        CallingSequenceBuilderImpl builder = new CallingSequenceBuilderImpl(
-                f.returnLayout().map(x -> new Argument(-1, x, "__retval")).orElse(null));
-        for (int i = 0; i < f.argumentLayouts().size(); i++) {
-            Layout type = f.argumentLayouts().get(i);
-            builder.addArgument(type, i >= varArgsStart, "arg" + i);
-        }
-        if (f.isVariadic()) {
-            builder.addArgument(Types.POINTER, false, null);
-        }
-
+        CallingSequenceBuilder builder = new CallingSequenceBuilderImpl(
+                f.returnLayout().orElse(null));
+        f.argumentLayouts().forEach(builder::addArgument);
         return builder.build();
     }
 
@@ -82,10 +75,14 @@
     public MethodHandle downcallHandle(CallingConvention cc, Library.Symbol symbol, NativeMethodType nmt) {
         Util.checkNoArrays(nmt.methodType());
         if (nmt.isVarArgs()) {
-            return VarargsInvokerImpl.make(symbol, nmt);
+            return VarargsInvoker.make(symbol, nmt, CallingSequenceBuilderImpl::new, adapter);
         }
 
-        return UniversalNativeInvokerImpl.make(symbol, arrangeCall(nmt), nmt).getBoundMethodHandle();
+        try {
+            return new UniversalNativeInvoker(symbol, arrangeCall(nmt), nmt, adapter).getBoundMethodHandle();
+        } catch (IllegalAccessException ex) {
+            throw new IllegalStateException(ex);
+        }
     }
 
     @Override
@@ -95,7 +92,7 @@
             throw new WrongMethodTypeException("Native method type has wrong type: " + nmt.methodType());
         }
 
-        return UpcallStubs.registerUpcallStub(new UniversalUpcallHandlerImpl(target, arrangeCall(nmt), nmt));
+        return UpcallStubs.registerUpcallStub(new UniversalUpcallHandler(target, arrangeCall(nmt), nmt, adapter));
     }
 
     @Override
@@ -113,63 +110,66 @@
         return null;
     }
 
-    static void unboxValue(Object o, LayoutType<?> type, java.util.function.Function<ArgumentBinding, Pointer<?>> dstPtrFunc,
+    UniversalAdapter adapter = new UniversalAdapter() {
+        @Override
+        public void unboxValue(Object o, LayoutType<?> type, java.util.function.Function<ArgumentBinding, Pointer<?>> dstPtrFunc,
                            List<ArgumentBinding> bindings) throws Throwable {
-        if (o instanceof Struct) {
-            assert (bindings.size() == 1); // always for structs on windows
+            if (o instanceof Struct) {
+                assert (bindings.size() == 1); // always for structs on windows
 
-            Pointer<?> structPtr = ((Struct<?>) o).ptr();
-            LayoutType<?> structType = structPtr.type();
-            Pointer<Long> src = Util.unsafeCast(structPtr, NativeTypes.UINT64);
+                Pointer<?> structPtr = ((Struct<?>) o).ptr();
+                LayoutType<?> structType = structPtr.type();
+                Pointer<Long> src = Util.unsafeCast(structPtr, NativeTypes.UINT64);
+                ArgumentBinding binding = bindings.get(0);
+
+                if (CallingSequenceBuilderImpl.isRegisterAggregate(binding.argument().layout())) { // pass value
+                    Pointer.copy(src, dstPtrFunc.apply(binding), structType.bytesSize());
+                } else { // pass a pointer
+                    /*
+                     * Leak memory for now
+                     */
+                    Scope scope = Scope.globalScope().fork();
+                    Pointer<?> copy = scope.allocate(structType);
+                    Pointer.copy(src, copy, structType.bytesSize());
+
+                    Pointer<?> dst = dstPtrFunc.apply(binding);
+                    Util.unsafeCast(dst, NativeTypes.UINT64).type().setter().invoke(dst, copy.addr());
+                }
+            } else {
+                assert bindings.size() <= 2;
+                Pointer<?> dst = Util.unsafeCast(dstPtrFunc.apply(bindings.get(0)), type);
+                dst.type().setter().invoke(dst, o);
+            }
+        }
+
+        @Override
+        public Object boxValue(LayoutType<?> type, java.util.function.Function<ArgumentBinding, Pointer<?>> srcPtrFunc,
+                               List<ArgumentBinding> bindings) throws IllegalAccessException {
+            assert (bindings.size() == 1); // always on windows
             ArgumentBinding binding = bindings.get(0);
+            Class<?> carrier = ((LayoutTypeImpl<?>) type).carrier();
+            if (Util.isCStruct(carrier)) {
 
-            if (CallingSequenceBuilderImpl.isRegisterAggregate(binding.getMember().getType())) { // pass value
-                Pointer.copy(src, dstPtrFunc.apply(binding), structType.bytesSize());
-            } else { // pass a pointer
                 /*
                  * Leak memory for now
                  */
                 Scope scope = Scope.globalScope().fork();
-                Pointer<?> copy = scope.allocate(structType);
-                Pointer.copy(src, copy, structType.bytesSize());
 
-                Pointer<?> dst = dstPtrFunc.apply(binding);
-                Util.unsafeCast(dst, NativeTypes.UINT64).type().setter().invoke(dst, copy.addr());
+                @SuppressWarnings({"rawtypes", "unchecked"})
+                Pointer<?> rtmp = ((ScopeImpl) scope).allocate(type, 8);
+
+                if (CallingSequenceBuilderImpl.isRegisterAggregate(type.layout())) {
+                    Pointer<Long> dst = Util.unsafeCast(rtmp, NativeTypes.UINT64).offset(binding.offset() / NativeTypes.UINT64.bytesSize());
+                    Pointer.copy(srcPtrFunc.apply(binding), dst, binding.storage().getSize());
+                } else {
+                    Pointer<?> local = Util.unsafeCast(srcPtrFunc.apply(binding), type.pointer()).get();
+                    // need defensive copy since Structs don't have value semantics on the Java side.
+                    Pointer.copy(local, rtmp, type.bytesSize());
+                }
+
+                return rtmp.get();
             }
-        } else {
-            assert bindings.size() <= 2;
-            Pointer<?> dst = Util.unsafeCast(dstPtrFunc.apply(bindings.get(0)), type);
-            dst.type().setter().invoke(dst, o);
+            return Util.unsafeCast(srcPtrFunc.apply(binding), type).get();
         }
-    }
-
-    static Object boxValue(LayoutType<?> type, java.util.function.Function<ArgumentBinding, Pointer<?>> srcPtrFunc,
-                           List<ArgumentBinding> bindings) throws IllegalAccessException {
-        assert (bindings.size() == 1); // always on windows
-        ArgumentBinding binding = bindings.get(0);
-        Class<?> carrier = ((LayoutTypeImpl<?>) type).carrier();
-        if (Util.isCStruct(carrier)) {
-
-            /*
-             * Leak memory for now
-             */
-            Scope scope = Scope.globalScope().fork();
-
-            @SuppressWarnings({"rawtypes", "unchecked"})
-            Pointer<?> rtmp = ((ScopeImpl) scope).allocate(type, 8);
-
-            if (CallingSequenceBuilderImpl.isRegisterAggregate(type.layout())) {
-                Pointer<Long> dst = Util.unsafeCast(rtmp, NativeTypes.UINT64).offset(binding.getOffset() / NativeTypes.UINT64.bytesSize());
-                Pointer.copy(srcPtrFunc.apply(binding), dst, binding.getStorage().getSize());
-            } else {
-                Pointer<?> local = Util.unsafeCast(srcPtrFunc.apply(binding), type.pointer()).get();
-                // need defensive copy since Structs don't have value semantics on the Java side.
-                Pointer.copy(local, rtmp, type.bytesSize());
-            }
-
-            return rtmp.get();
-        }
-        return Util.unsafeCast(srcPtrFunc.apply(binding), type).get();
-    }
-
+    };
 }
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/foreign/UnalignedStructTest.java	Thu Apr 18 15:37:03 2019 +0100
@@ -0,0 +1,105 @@
+/*
+ *  Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ *  DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ *  This code is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 only, as
+ *  published by the Free Software Foundation.
+ *
+ *  This code is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  version 2 for more details (a copy is included in the LICENSE file that
+ *  accompanied this code).
+ *
+ *  You should have received a copy of the GNU General Public License version
+ *  2 along with this work; if not, write to the Free Software Foundation,
+ *  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *  Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ *  or visit www.oracle.com if you need additional information or have any
+ *  questions.
+ */
+
+/*
+ * @test
+ * @requires os.family != "windows"
+ * @run testng UnalignedStructTest
+ */
+
+import org.testng.annotations.*;
+
+import java.foreign.Libraries;
+import java.foreign.Scope;
+import java.foreign.annotations.NativeFunction;
+import java.foreign.annotations.NativeGetter;
+import java.foreign.annotations.NativeHeader;
+import java.foreign.annotations.NativeSetter;
+import java.foreign.annotations.NativeStruct;
+import java.foreign.memory.Struct;
+import java.lang.invoke.MethodHandles;
+import java.util.Random;
+import java.util.stream.IntStream;
+
+import static org.testng.Assert.*;
+
+@Test
+public class UnalignedStructTest {
+
+    @NativeHeader
+    interface unaligned {
+        @NativeFunction("(${str} ${str})i16")
+        short unaligned_sum_i1(Str str, Str str2);
+        @NativeFunction("(${str} ${str})i16")
+        short unaligned_sum_i2(Str str1, Str str2);
+
+        @NativeStruct("[ f128 i16(i1) i16(i2) ](str)")
+        interface Str extends Struct<Str> {
+            @NativeGetter("i1")
+            short i1$get();
+            @NativeGetter("i2")
+            short i2$get();
+            @NativeSetter("i1")
+            void i1$set(short i1);
+            @NativeSetter("i2")
+            void i2$set(short i2);
+        }
+    }
+
+    static unaligned lib =
+            Libraries.bind(unaligned.class,
+                    Libraries.loadLibrary(MethodHandles.lookup(), "UnalignedStruct"));
+
+
+    @Test(dataProvider = "pairs")
+    public void testUnalignedCalls(short i1, short i2) {
+        try (Scope sc = Scope.globalScope().fork()) {
+            unaligned.Str str = sc.allocateStruct(unaligned.Str.class);
+            str.i1$set(i1);
+            str.i2$set(i2);
+            //sanity check
+            assertEquals(str.i1$get(), i1);
+            assertEquals(str.i2$get(), i2);
+            //real check
+            assertEquals(lib.unaligned_sum_i1(str, str), i1 + i1);
+            assertEquals(lib.unaligned_sum_i2(str, str), i2 + i2);
+        }
+    }
+
+    static IntStream intStream() {
+        //avoid overflow
+        return new Random().ints(Byte.MIN_VALUE, Byte.MAX_VALUE)
+                .limit(100);
+    }
+
+    @DataProvider
+    public static Object[][] pairs() {
+        int[] i1Arr = intStream().toArray();
+        int[] i2Arr = intStream().toArray();
+        Object[][] res = new Object[i1Arr.length][];
+        for (int i = 0 ; i < i1Arr.length ; i++) {
+            res[i] = new Object[] { (short)i1Arr[i], (short)i2Arr[i]};
+        }
+        return res;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/foreign/abi/x64/sysv/CallingSequenceTest.java	Thu Apr 18 15:37:03 2019 +0100
@@ -0,0 +1,521 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @modules java.base/jdk.internal.foreign.abi java.base/jdk.internal.foreign.memory java.base/jdk.internal.foreign.abi.x64.sysv
+ */
+
+import java.foreign.NativeTypes;
+import java.foreign.layout.Group;
+import java.foreign.layout.Layout;
+import java.foreign.memory.LayoutType;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Stream;
+
+import jdk.internal.foreign.abi.CallingSequence;
+import jdk.internal.foreign.abi.StorageClass;
+import jdk.internal.foreign.abi.x64.sysv.CallingSequenceBuilderImpl;
+import jdk.internal.foreign.abi.x64.sysv.SysVx64ABI;
+import jdk.internal.foreign.memory.Types;
+
+public class CallingSequenceTest {
+
+    public void testInteger() {
+        CallingSequenceBuilderImpl sc = new CallingSequenceBuilderImpl(null);
+
+        // Fill registers and spill over with 2 args on stack
+        LayoutType<?> args[] = new LayoutType<?>[SysVx64ABI.MAX_INTEGER_ARGUMENT_REGISTERS + 2];
+        for (int i = 0; i < SysVx64ABI.MAX_INTEGER_ARGUMENT_REGISTERS + 2; i++) {
+            args[i] = NativeTypes.INT64;
+        }
+
+        Stream.of(args).map(LayoutType::layout).forEach(sc::addArgument);
+        CallingSequence recipe = sc.build();
+
+        assertEquals(false, recipe.returnsInMemory());
+        assertEquals(SysVx64ABI.MAX_INTEGER_ARGUMENT_REGISTERS, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).size());
+        assertEquals(0, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).size());
+        assertEquals(2, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).size());
+
+        for (int i = 0; i < SysVx64ABI.MAX_INTEGER_ARGUMENT_REGISTERS; i++) {
+            assertEquals(args[i].layout(), recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(i).argument().layout());
+            assertEquals(0, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(i).offset());
+        }
+
+        for (int i = 0; i < 2; i++) {
+            assertEquals(args[SysVx64ABI.MAX_INTEGER_ARGUMENT_REGISTERS + i].layout(),
+                    recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(i).argument().layout());
+            assertEquals(0, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(i).offset());
+        }
+    }
+
+    public void testSse() {
+        CallingSequenceBuilderImpl sc = new CallingSequenceBuilderImpl(null);
+
+        // Fill registers and spill over with 2 args on stack
+        LayoutType<?> args[] = new LayoutType<?>[SysVx64ABI.MAX_VECTOR_ARGUMENT_REGISTERS + 2];
+        for (int i = 0; i < SysVx64ABI.MAX_VECTOR_ARGUMENT_REGISTERS + 2; i++) {
+            args[i] = NativeTypes.IEEE_FLOAT32;
+        }
+
+        Stream.of(args).map(LayoutType::layout).forEach(sc::addArgument);
+
+        CallingSequence recipe = sc.build();
+
+        assertEquals(false, recipe.returnsInMemory());
+        assertEquals(0, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).size());
+        assertEquals(SysVx64ABI.MAX_VECTOR_ARGUMENT_REGISTERS, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).size());
+        assertEquals(2, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).size());
+
+        for (int i = 0; i < SysVx64ABI.MAX_VECTOR_ARGUMENT_REGISTERS; i++) {
+            assertEquals(args[i].layout(), recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(i).argument().layout());
+            assertEquals(0, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(i).offset());
+        }
+
+        for (int i = 0; i < 2; i++) {
+            assertEquals(args[SysVx64ABI.MAX_VECTOR_ARGUMENT_REGISTERS + i].layout(),
+                    recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(i).argument().layout());
+            assertEquals(0, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(i).offset());
+        }
+    }
+
+     public void testMixed() {
+        CallingSequenceBuilderImpl sc = new CallingSequenceBuilderImpl(null);
+
+        // Fill GP registers + 2 on stack
+        List<LayoutType<?>> args = new ArrayList<>();
+        for (int i = 0; i < SysVx64ABI.MAX_INTEGER_ARGUMENT_REGISTERS + 2; i++) {
+            args.add(NativeTypes.INT64);
+        }
+
+        // Fill SSE registers + 2 on stack
+        for (int i = 0; i < SysVx64ABI.MAX_VECTOR_ARGUMENT_REGISTERS + 2; i++) {
+            args.add(NativeTypes.IEEE_FLOAT32);
+        }
+
+        args.stream().map(LayoutType::layout).forEach(sc::addArgument);
+
+        CallingSequence recipe = sc.build();
+
+        assertEquals(false, recipe.returnsInMemory());
+        assertEquals(SysVx64ABI.MAX_INTEGER_ARGUMENT_REGISTERS, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).size());
+        assertEquals(SysVx64ABI.MAX_VECTOR_ARGUMENT_REGISTERS, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).size());
+        assertEquals(4, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).size());
+
+        int arg = 0;
+        for (int i = 0; i < SysVx64ABI.MAX_INTEGER_ARGUMENT_REGISTERS; i++, arg++) {
+            assertEquals(args.get(arg).layout(), recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(i).argument().layout());
+            assertEquals(0, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(i).offset());
+        }
+
+        for (int i = 0; i < 2; i++, arg++) {
+            assertEquals(args.get(arg).layout(), recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(i).argument().layout());
+            assertEquals(0, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(i).offset());
+        }
+
+        for (int i = 0; i < SysVx64ABI.MAX_VECTOR_ARGUMENT_REGISTERS; i++, arg++) {
+            assertEquals(args.get(arg).layout(), recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(i).argument().layout());
+            assertEquals(0, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(i).offset());
+        }
+
+        for (int i = 2; i < 4; i++, arg++) {
+            assertEquals(args.get(arg).layout(), recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(i).argument().layout());
+            assertEquals(0, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(i).offset());
+        }
+    }
+
+    /**
+     * This is the example from the System V ABI AMD64 document
+     *
+     * struct structparm {
+     *   int32_t a, int32_t b, double d;
+     * } s;
+     * int32_t e, f, g, h, i, j, k;
+     * long double ld;
+     * double m, n;
+     * __m256 y;
+     *
+     * void m(e, f, s, g, h, ld, m, y, n, i, j, k);
+     *
+     * m(s);
+     */
+    public void testAbiExample() {
+        Layout[] args = { Types.INT32, Types.INT32, Group.struct(Types.INT32, Types.INT32, Types.DOUBLE),
+                Types.INT32, Types.INT32, Types.LONG_DOUBLE, Types.DOUBLE,
+                Types.DOUBLE, Types.INT32, Types.INT32, Types.INT32 };
+
+        CallingSequenceBuilderImpl sc = new CallingSequenceBuilderImpl(null);
+        Stream.of(args).forEach(sc::addArgument);
+        CallingSequence recipe = sc.build();
+
+        assertEquals(false, recipe.returnsInMemory());
+        assertEquals(6, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).size());
+        assertEquals(3, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).size());
+        assertEquals(4, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).size());
+
+        // e
+        assertEquals(args[0], recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).argument().layout());
+        assertEquals(0, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).offset());
+
+        // f
+        assertEquals(args[1], recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(1).argument().layout());
+        assertEquals(0, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(1).offset());
+
+        // s.a & s.b
+        assertEquals(args[2], recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(2).argument().layout());
+        assertEquals(0, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(2).offset());
+
+        // s.d
+        assertEquals(args[2], recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(0).argument().layout());
+        assertEquals(8, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(0).offset());
+
+        // g
+        assertEquals(args[3], recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(3).argument().layout());
+        assertEquals(0, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(3).offset());
+
+        // h
+        assertEquals(args[4], recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(4).argument().layout());
+        assertEquals(0, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(4).offset());
+
+        // ld
+        assertEquals(args[5], recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(0).argument().layout());
+        assertEquals(0, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(0).offset());
+        assertEquals(args[5], recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(1).argument().layout());
+        assertEquals(8, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(1).offset());
+
+        // m
+        assertEquals(args[6], recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(1).argument().layout());
+        assertEquals(0, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(1).offset());
+
+        // n
+        assertEquals(args[7], recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(2).argument().layout());
+        assertEquals(0, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(2).offset());
+
+        // i
+        assertEquals(args[8], recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(5).argument().layout());
+        assertEquals(0, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(5).offset());
+
+        // j
+        assertEquals(args[9], recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(2).argument().layout());
+        assertEquals(0, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(2).offset());
+
+        // k
+        assertEquals(args[10], recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(3).argument().layout());
+        assertEquals(0, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(3).offset());
+    }
+
+    /**
+     * This is a varargs example from the System V ABI AMD64 document
+     *
+     * int a, b;
+     * long double ld;
+     * double m, n;
+     * __m256 u, y;
+     *
+     * extern void func (int a, double m, __m256 u, ...);
+     *
+     * func(a, m, u, b, ld, y, n);
+     */
+    public void testAbiExampleVarargs() {
+        Layout[] args = {
+                Types.INT,
+                Types.DOUBLE,
+                Types.INT,
+                Types.LONG_DOUBLE,
+                Types.DOUBLE };
+        CallingSequenceBuilderImpl sc = new CallingSequenceBuilderImpl(null);
+        Stream.of(args).forEach(sc::addArgument);
+        CallingSequence recipe = sc.build();
+
+        assertEquals(false, recipe.returnsInMemory());
+        assertEquals(2, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).size());
+        assertEquals(2, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).size());
+        assertEquals(2, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).size());
+
+
+        // a
+        assertEquals(args[0], recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).argument().layout());
+        assertEquals(0, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).offset());
+
+        // m
+        assertEquals(args[1], recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(0).argument().layout());
+        assertEquals(0, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(0).offset());
+
+        // b
+        assertEquals(args[2], recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(1).argument().layout());
+        assertEquals(0, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(1).offset());
+
+        // ld
+        assertEquals(args[3], recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(0).argument().layout());
+        assertEquals(0, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(0).offset());
+        assertEquals(args[3], recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(1).argument().layout());
+        assertEquals(8, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(1).offset());
+
+        // n
+        assertEquals(args[4], recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(1).argument().layout());
+        assertEquals(0, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(1).offset());
+    }
+
+
+    /**
+     * struct s {
+     *   uint64_t u0;
+     * } s;
+     *
+     * void m(struct s s);
+     *
+     * m(s);
+     */
+    public void testStruct8() {
+        Group structparm = Group.struct(Types.UNSIGNED.INT64);
+
+        CallingSequence recipe = new CallingSequenceBuilderImpl(null)
+                .addArgument(structparm)
+                .build();
+
+        assertEquals(false, recipe.returnsInMemory());
+        assertEquals(1, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).size());
+        assertEquals(0, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).size());
+        assertEquals(0, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).size());
+
+        // s.u0
+        assertEquals(structparm, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).argument().layout());
+        assertEquals(0, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).offset());
+    }
+
+    /**
+     * struct s {
+     *   uint64_t u0, u1;
+     * } s;
+     *
+     * void m(struct s s);
+     *
+     * m(s);
+     */
+    public void testStruct16() {
+        Group structparm = Group.struct(Types.UNSIGNED.INT64, Types.UNSIGNED.INT64);
+
+        CallingSequence recipe = new CallingSequenceBuilderImpl(null)
+                .addArgument(structparm)
+                .build();
+
+        assertEquals(false, recipe.returnsInMemory());
+        assertEquals(2, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).size());
+        assertEquals(0, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).size());
+        assertEquals(0, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).size());
+
+        // s.u0
+        assertEquals(structparm, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).argument().layout());
+        assertEquals(0, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).offset());
+
+        // s.u1
+        assertEquals(structparm, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(1).argument().layout());
+        assertEquals(8, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(1).offset());
+    }
+
+    /**
+     * struct s {
+     *   uint64_t u0, u1, u2;
+     * } s;
+     *
+     * void m(struct s s);
+     *
+     * m(s);
+     */
+    public void testStruct24() {
+        Group structparm = Group.struct(Types.UNSIGNED.INT64, Types.UNSIGNED.INT64, Types.UNSIGNED.INT64);
+
+        CallingSequence recipe = new CallingSequenceBuilderImpl(null)
+                .addArgument(structparm)
+                .build();
+
+        assertEquals(false, recipe.returnsInMemory());
+        assertEquals(0, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).size());
+        assertEquals(0, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).size());
+        assertEquals(3, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).size());
+
+        // s.u0
+        assertEquals(structparm, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(0).argument().layout());
+        assertEquals(0, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(0).offset());
+
+        // s.u1
+        assertEquals(structparm, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(1).argument().layout());
+        assertEquals(8, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(1).offset());
+
+        // s.u2
+        assertEquals(structparm, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(2).argument().layout());
+        assertEquals(16, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(2).offset());
+    }
+
+    /**
+     * struct s {
+     *   uint64_t u0, u1, u2, u3;
+     * } s;
+     *
+     * void m(struct s s);
+     *
+     * m(s);
+     */
+    public void testStruct32() {
+        Layout structparm = Layout.of("[u64u64u64u64]");
+
+        CallingSequence recipe = new CallingSequenceBuilderImpl(null)
+                .addArgument(structparm)
+                .build();
+
+        assertEquals(false, recipe.returnsInMemory());
+        assertEquals(0, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).size());
+        assertEquals(0, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).size());
+        assertEquals(4, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).size());
+
+        // s.u0
+        assertEquals(structparm, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(0).argument().layout());
+        assertEquals(0, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(0).offset());
+
+        // s.u1
+        assertEquals(structparm, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(1).argument().layout());
+        assertEquals(8, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(1).offset());
+
+        // s.u2
+        assertEquals(structparm, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(2).argument().layout());
+        assertEquals(16, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(2).offset());
+
+        // s.u3
+        assertEquals(structparm, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(3).argument().layout());
+        assertEquals(24, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(3).offset());
+    }
+
+    /**
+     * typedef void (*f)(void);
+     *
+     * void m(f f);
+     * void f_impl(void);
+     *
+     * m(f_impl);
+     */
+    public void testFunctionType() {
+        Layout arg = Layout.of("u64:()v");
+
+        CallingSequence recipe = new CallingSequenceBuilderImpl(null)
+                .addArgument(arg)
+                .build();
+
+        assertEquals(false, recipe.returnsInMemory());
+        assertEquals(1, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).size());
+        assertEquals(0, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).size());
+        assertEquals(0, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).size());
+
+        // s.u0
+        assertEquals(arg, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).argument().layout());
+        assertEquals(0, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).offset());
+    }
+
+    /**
+     * void f(int64_t l0, float f0, __m256 m0);
+     */
+    public void testMixedArgs() {
+        CallingSequence recipe = new CallingSequenceBuilderImpl(null)
+                .addArgument(Types.INT64)
+                .addArgument(Types.FLOAT)
+                .build();
+
+        assertEquals(false, recipe.returnsInMemory());
+        assertEquals(1, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).size());
+        assertEquals(1, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).size());
+        assertEquals(0, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).size());
+
+        // l0
+        assertEquals(Types.INT64, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).argument().layout());
+        assertEquals(0, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).offset());
+
+        // f0
+        assertEquals(Types.FLOAT, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(0).argument().layout());
+        assertEquals(0, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(0).offset());
+    }
+
+    /**
+     * struct s {
+     *    int64_t l0;
+     *    int64_t l1;
+     * };
+     *
+     * void f(struct s s1);
+     */
+    public void testIntegerStruct() {
+        Layout arg = Layout.of("[i64i64]");
+
+        CallingSequence recipe = new CallingSequenceBuilderImpl(null)
+                .addArgument(arg)
+                .build();
+
+        assertEquals(false, recipe.returnsInMemory());
+        assertEquals(2, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).size());
+        assertEquals(0, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).size());
+        assertEquals(0, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).size());
+
+        // s.l0
+        assertEquals(arg, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).argument().layout());
+        assertEquals(0, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).offset());
+
+        // s.l1
+        assertEquals(arg, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(1).argument().layout());
+        assertEquals(8, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(1).offset());
+    }
+
+    static void assertEquals(long expected, long actual) {
+        if (expected != actual) {
+            throw new RuntimeException("expected: " + expected + " does not match actual: " + actual);
+        }
+    }
+
+    static void assertEquals(boolean expected, boolean actual) {
+        if (expected != actual) {
+            throw new RuntimeException("expected: " + expected + " does not match actual: " + actual);
+        }
+    }
+
+    static void assertEquals(Object expected, Object actual) {
+        if (expected != actual) {
+            throw new RuntimeException("expected: " + expected + " does not match actual: " + actual);
+        }
+    }
+
+    public static void main(String[] args) {
+        CallingSequenceTest t = new CallingSequenceTest();
+
+        t.testInteger();
+        t.testSse();
+        t.testMixed();
+        t.testAbiExample();
+        t.testAbiExampleVarargs();
+        t.testStruct8();
+        t.testStruct16();
+        t.testStruct24();
+        t.testStruct32();
+        t.testFunctionType();
+        t.testMixedArgs();
+        t.testIntegerStruct();
+    }
+}
--- a/test/jdk/java/foreign/abi/x64/sysv/StandardCallTest.java	Wed Apr 17 22:09:23 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,508 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @modules java.base/jdk.internal.foreign.abi java.base/jdk.internal.foreign.memory java.base/jdk.internal.foreign.abi.x64.sysv
- */
-
-import java.foreign.NativeTypes;
-import java.foreign.layout.Group;
-import java.foreign.layout.Layout;
-import java.foreign.memory.LayoutType;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Stream;
-
-import jdk.internal.foreign.abi.CallingSequence;
-import jdk.internal.foreign.abi.StorageClass;
-import jdk.internal.foreign.abi.x64.sysv.Constants;
-import jdk.internal.foreign.abi.x64.sysv.StandardCall;
-import jdk.internal.foreign.memory.Types;
-
-public class StandardCallTest {
-    public StandardCallTest() {
-    }
-
-    public void testInteger() {
-        StandardCall sc = new StandardCall();
-
-        // Fill registers and spill over with 2 args on stack
-        LayoutType<?> args[] = new LayoutType<?>[Constants.MAX_INTEGER_ARGUMENT_REGISTERS + 2];
-        for (int i = 0; i < Constants.MAX_INTEGER_ARGUMENT_REGISTERS + 2; i++) {
-            args[i] = NativeTypes.INT64;
-        }
-
-        CallingSequence recipe = sc.arrangeCall(null,
-                Stream.of(args).map(LayoutType::layout).toArray(Layout[]::new));
-
-        assertEquals(false, recipe.returnsInMemory());
-        assertEquals(Constants.MAX_INTEGER_ARGUMENT_REGISTERS, recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).size());
-        assertEquals(0, recipe.getBindings(StorageClass.VECTOR_ARGUMENT_REGISTER).size());
-        assertEquals(2, recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).size());
-
-        for (int i = 0; i < Constants.MAX_INTEGER_ARGUMENT_REGISTERS; i++) {
-            assertEquals(args[i].layout(), recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(i).getMember().getType());
-            assertEquals(0, recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(i).getOffset());
-        }
-
-        for (int i = 0; i < 2; i++) {
-            assertEquals(args[Constants.MAX_INTEGER_ARGUMENT_REGISTERS + i].layout(),
-                    recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).get(i).getMember().getType());
-            assertEquals(0, recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).get(i).getOffset());
-        }
-    }
-
-    public void testSse() {
-        StandardCall sc = new StandardCall();
-
-        // Fill registers and spill over with 2 args on stack
-        LayoutType<?> args[] = new LayoutType<?>[Constants.MAX_VECTOR_ARGUMENT_REGISTERS + 2];
-        for (int i = 0; i < Constants.MAX_VECTOR_ARGUMENT_REGISTERS + 2; i++) {
-            args[i] = NativeTypes.IEEE_FLOAT32;
-        }
-
-        CallingSequence recipe = sc.arrangeCall(null,
-                Stream.of(args).map(LayoutType::layout).toArray(Layout[]::new));
-
-        assertEquals(false, recipe.returnsInMemory());
-        assertEquals(0, recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).size());
-        assertEquals(Constants.MAX_VECTOR_ARGUMENT_REGISTERS, recipe.getBindings(StorageClass.VECTOR_ARGUMENT_REGISTER).size());
-        assertEquals(2, recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).size());
-
-        for (int i = 0; i < Constants.MAX_VECTOR_ARGUMENT_REGISTERS; i++) {
-            assertEquals(args[i].layout(), recipe.getBindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(i).getMember().getType());
-            assertEquals(0, recipe.getBindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(i).getOffset());
-        }
-
-        for (int i = 0; i < 2; i++) {
-            assertEquals(args[Constants.MAX_VECTOR_ARGUMENT_REGISTERS + i].layout(),
-                    recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).get(i).getMember().getType());
-            assertEquals(0, recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).get(i).getOffset());
-        }
-    }
-
-     public void testMixed() {
-        StandardCall sc = new StandardCall();
-
-        // Fill GP registers + 2 on stack
-        List<LayoutType<?>> args = new ArrayList<>();
-        for (int i = 0; i < Constants.MAX_INTEGER_ARGUMENT_REGISTERS + 2; i++) {
-            args.add(NativeTypes.INT64);
-        }
-
-        // Fill SSE registers + 2 on stack
-        for (int i = 0; i < Constants.MAX_VECTOR_ARGUMENT_REGISTERS + 2; i++) {
-            args.add(NativeTypes.IEEE_FLOAT32);
-        }
-
-        CallingSequence recipe = sc.arrangeCall(null,
-                args.stream().map(LayoutType::layout).toArray(Layout[]::new));
-
-        assertEquals(false, recipe.returnsInMemory());
-        assertEquals(Constants.MAX_INTEGER_ARGUMENT_REGISTERS, recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).size());
-        assertEquals(Constants.MAX_VECTOR_ARGUMENT_REGISTERS, recipe.getBindings(StorageClass.VECTOR_ARGUMENT_REGISTER).size());
-        assertEquals(4, recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).size());
-
-        int arg = 0;
-        for (int i = 0; i < Constants.MAX_INTEGER_ARGUMENT_REGISTERS; i++, arg++) {
-            assertEquals(args.get(arg).layout(), recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(i).getMember().getType());
-            assertEquals(0, recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(i).getOffset());
-        }
-
-        for (int i = 0; i < 2; i++, arg++) {
-            assertEquals(args.get(arg).layout(), recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).get(i).getMember().getType());
-            assertEquals(0, recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).get(i).getOffset());
-        }
-
-        for (int i = 0; i < Constants.MAX_VECTOR_ARGUMENT_REGISTERS; i++, arg++) {
-            assertEquals(args.get(arg).layout(), recipe.getBindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(i).getMember().getType());
-            assertEquals(0, recipe.getBindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(i).getOffset());
-        }
-
-        for (int i = 2; i < 4; i++, arg++) {
-            assertEquals(args.get(arg).layout(), recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).get(i).getMember().getType());
-            assertEquals(0, recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).get(i).getOffset());
-        }
-    }
-
-    /**
-     * This is the example from the System V ABI AMD64 document
-     *
-     * struct structparm {
-     *   int32_t a, int32_t b, double d;
-     * } s;
-     * int32_t e, f, g, h, i, j, k;
-     * long double ld;
-     * double m, n;
-     * __m256 y;
-     *
-     * void m(e, f, s, g, h, ld, m, y, n, i, j, k);
-     *
-     * m(s);
-     */
-    public void testAbiExample() {
-        Layout[] args = { Types.INT32, Types.INT32, Group.struct(Types.INT32, Types.INT32, Types.DOUBLE),
-                Types.INT32, Types.INT32, Types.LONG_DOUBLE, Types.DOUBLE,
-                Types.DOUBLE, Types.INT32, Types.INT32, Types.INT32 };
-
-        StandardCall sc = new StandardCall();
-        CallingSequence recipe = sc.arrangeCall(null, args);
-
-        assertEquals(false, recipe.returnsInMemory());
-        assertEquals(6, recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).size());
-        assertEquals(3, recipe.getBindings(StorageClass.VECTOR_ARGUMENT_REGISTER).size());
-        assertEquals(4, recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).size());
-
-        // e
-        assertEquals(args[0], recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).getMember().getType());
-        assertEquals(0, recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).getOffset());
-
-        // f
-        assertEquals(args[1], recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(1).getMember().getType());
-        assertEquals(0, recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(1).getOffset());
-
-        // s.a & s.b
-        assertEquals(args[2], recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(2).getMember().getType());
-        assertEquals(0, recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(2).getOffset());
-
-        // s.d
-        assertEquals(args[2], recipe.getBindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(0).getMember().getType());
-        assertEquals(8, recipe.getBindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(0).getOffset());
-
-        // g
-        assertEquals(args[3], recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(3).getMember().getType());
-        assertEquals(0, recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(3).getOffset());
-
-        // h
-        assertEquals(args[4], recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(4).getMember().getType());
-        assertEquals(0, recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(4).getOffset());
-
-        // ld
-        assertEquals(args[5], recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).get(0).getMember().getType());
-        assertEquals(0, recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).get(0).getOffset());
-        assertEquals(args[5], recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).get(1).getMember().getType());
-        assertEquals(8, recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).get(1).getOffset());
-
-        // m
-        assertEquals(args[6], recipe.getBindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(1).getMember().getType());
-        assertEquals(0, recipe.getBindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(1).getOffset());
-
-        // n
-        assertEquals(args[7], recipe.getBindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(2).getMember().getType());
-        assertEquals(0, recipe.getBindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(2).getOffset());
-
-        // i
-        assertEquals(args[8], recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(5).getMember().getType());
-        assertEquals(0, recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(5).getOffset());
-
-        // j
-        assertEquals(args[9], recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).get(2).getMember().getType());
-        assertEquals(0, recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).get(2).getOffset());
-
-        // k
-        assertEquals(args[10], recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).get(3).getMember().getType());
-        assertEquals(0, recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).get(3).getOffset());
-    }
-
-    /**
-     * This is a varargs example from the System V ABI AMD64 document
-     *
-     * int a, b;
-     * long double ld;
-     * double m, n;
-     * __m256 u, y;
-     *
-     * extern void func (int a, double m, __m256 u, ...);
-     *
-     * func(a, m, u, b, ld, y, n);
-     */
-    public void testAbiExampleVarargs() {
-        Layout[] args = {
-                Types.INT,
-                Types.DOUBLE,
-                Types.INT,
-                Types.LONG_DOUBLE,
-                Types.DOUBLE };
-        StandardCall sc = new StandardCall();
-        CallingSequence recipe = sc.arrangeCall(null, args);
-
-        assertEquals(false, recipe.returnsInMemory());
-        assertEquals(2, recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).size());
-        assertEquals(2, recipe.getBindings(StorageClass.VECTOR_ARGUMENT_REGISTER).size());
-        assertEquals(2, recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).size());
-
-
-        // a
-        assertEquals(args[0], recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).getMember().getType());
-        assertEquals(0, recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).getOffset());
-
-        // m
-        assertEquals(args[1], recipe.getBindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(0).getMember().getType());
-        assertEquals(0, recipe.getBindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(0).getOffset());
-
-        // b
-        assertEquals(args[2], recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(1).getMember().getType());
-        assertEquals(0, recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(1).getOffset());
-
-        // ld
-        assertEquals(args[3], recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).get(0).getMember().getType());
-        assertEquals(0, recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).get(0).getOffset());
-        assertEquals(args[3], recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).get(1).getMember().getType());
-        assertEquals(8, recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).get(1).getOffset());
-
-        // n
-        assertEquals(args[4], recipe.getBindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(1).getMember().getType());
-        assertEquals(0, recipe.getBindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(1).getOffset());
-    }
-
-
-    /**
-     * struct s {
-     *   uint64_t u0;
-     * } s;
-     *
-     * void m(struct s s);
-     *
-     * m(s);
-     */
-    public void testStruct8() {
-        Group structparm = Group.struct(Types.UNSIGNED.INT64);
-
-        StandardCall sc = new StandardCall();
-        CallingSequence recipe = sc.arrangeCall(null, structparm);
-
-        assertEquals(false, recipe.returnsInMemory());
-        assertEquals(1, recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).size());
-        assertEquals(0, recipe.getBindings(StorageClass.VECTOR_ARGUMENT_REGISTER).size());
-        assertEquals(0, recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).size());
-
-        // s.u0
-        assertEquals(structparm, recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).getMember().getType());
-        assertEquals(0, recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).getOffset());
-    }
-
-    /**
-     * struct s {
-     *   uint64_t u0, u1;
-     * } s;
-     *
-     * void m(struct s s);
-     *
-     * m(s);
-     */
-    public void testStruct16() {
-        Group structparm = Group.struct(Types.UNSIGNED.INT64, Types.UNSIGNED.INT64);
-
-        StandardCall sc = new StandardCall();
-        CallingSequence recipe = sc.arrangeCall(null, structparm);
-
-        assertEquals(false, recipe.returnsInMemory());
-        assertEquals(2, recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).size());
-        assertEquals(0, recipe.getBindings(StorageClass.VECTOR_ARGUMENT_REGISTER).size());
-        assertEquals(0, recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).size());
-
-        // s.u0
-        assertEquals(structparm, recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).getMember().getType());
-        assertEquals(0, recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).getOffset());
-
-        // s.u1
-        assertEquals(structparm, recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(1).getMember().getType());
-        assertEquals(8, recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(1).getOffset());
-    }
-
-    /**
-     * struct s {
-     *   uint64_t u0, u1, u2;
-     * } s;
-     *
-     * void m(struct s s);
-     *
-     * m(s);
-     */
-    public void testStruct24() {
-        Group structparm = Group.struct(Types.UNSIGNED.INT64, Types.UNSIGNED.INT64, Types.UNSIGNED.INT64);
-
-        StandardCall sc = new StandardCall();
-        CallingSequence recipe = sc.arrangeCall(null, structparm);
-
-        assertEquals(false, recipe.returnsInMemory());
-        assertEquals(0, recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).size());
-        assertEquals(0, recipe.getBindings(StorageClass.VECTOR_ARGUMENT_REGISTER).size());
-        assertEquals(3, recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).size());
-
-        // s.u0
-        assertEquals(structparm, recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).get(0).getMember().getType());
-        assertEquals(0, recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).get(0).getOffset());
-
-        // s.u1
-        assertEquals(structparm, recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).get(1).getMember().getType());
-        assertEquals(8, recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).get(1).getOffset());
-
-        // s.u2
-        assertEquals(structparm, recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).get(2).getMember().getType());
-        assertEquals(16, recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).get(2).getOffset());
-    }
-
-    /**
-     * struct s {
-     *   uint64_t u0, u1, u2, u3;
-     * } s;
-     *
-     * void m(struct s s);
-     *
-     * m(s);
-     */
-    public void testStruct32() {
-        Layout structparm = Layout.of("[u64u64u64u64]");
-
-        StandardCall sc = new StandardCall();
-        CallingSequence recipe = sc.arrangeCall(null, structparm);
-
-        assertEquals(false, recipe.returnsInMemory());
-        assertEquals(0, recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).size());
-        assertEquals(0, recipe.getBindings(StorageClass.VECTOR_ARGUMENT_REGISTER).size());
-        assertEquals(4, recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).size());
-
-        // s.u0
-        assertEquals(structparm, recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).get(0).getMember().getType());
-        assertEquals(0, recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).get(0).getOffset());
-
-        // s.u1
-        assertEquals(structparm, recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).get(1).getMember().getType());
-        assertEquals(8, recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).get(1).getOffset());
-
-        // s.u2
-        assertEquals(structparm, recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).get(2).getMember().getType());
-        assertEquals(16, recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).get(2).getOffset());
-
-        // s.u3
-        assertEquals(structparm, recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).get(3).getMember().getType());
-        assertEquals(24, recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).get(3).getOffset());
-    }
-
-    /**
-     * typedef void (*f)(void);
-     *
-     * void m(f f);
-     * void f_impl(void);
-     *
-     * m(f_impl);
-     */
-    public void testFunctionType() {
-        Layout arg = Layout.of("u64:()v");
-        CallingSequence recipe = new StandardCall().arrangeCall(null, arg);
-
-        assertEquals(false, recipe.returnsInMemory());
-        assertEquals(1, recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).size());
-        assertEquals(0, recipe.getBindings(StorageClass.VECTOR_ARGUMENT_REGISTER).size());
-        assertEquals(0, recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).size());
-
-        // s.u0
-        assertEquals(arg, recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).getMember().getType());
-        assertEquals(0, recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).getOffset());
-    }
-
-    /**
-     * void f(int64_t l0, float f0, __m256 m0);
-     */
-    public void testMixedArgs() {
-        CallingSequence recipe = new StandardCall().arrangeCall(null,
-                Types.INT64, Types.FLOAT);
-
-        assertEquals(false, recipe.returnsInMemory());
-        assertEquals(1, recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).size());
-        assertEquals(1, recipe.getBindings(StorageClass.VECTOR_ARGUMENT_REGISTER).size());
-        assertEquals(0, recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).size());
-
-        // l0
-        assertEquals(Types.INT64, recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).getMember().getType());
-        assertEquals(0, recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).getOffset());
-
-        // f0
-        assertEquals(Types.FLOAT, recipe.getBindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(0).getMember().getType());
-        assertEquals(0, recipe.getBindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(0).getOffset());
-    }
-
-    /**
-     * struct s {
-     *    int64_t l0;
-     *    int64_t l1;
-     * };
-     *
-     * void f(struct s s1);
-     */
-    public void testIntegerStruct() {
-        Layout arg = Layout.of("[i64i64]");
-
-        CallingSequence recipe = new StandardCall().arrangeCall(null, arg);
-
-        assertEquals(false, recipe.returnsInMemory());
-        assertEquals(2, recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).size());
-        assertEquals(0, recipe.getBindings(StorageClass.VECTOR_ARGUMENT_REGISTER).size());
-        assertEquals(0, recipe.getBindings(StorageClass.STACK_ARGUMENT_SLOT).size());
-
-        // s.l0
-        assertEquals(arg, recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).getMember().getType());
-        assertEquals(0, recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).getOffset());
-
-        // s.l1
-        assertEquals(arg, recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(1).getMember().getType());
-        assertEquals(8, recipe.getBindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(1).getOffset());
-    }
-
-    static void assertEquals(long expected, long actual) {
-        if (expected != actual) {
-            throw new RuntimeException("expected: " + expected + " does not match actual: " + actual);
-        }
-    }
-
-    static void assertEquals(boolean expected, boolean actual) {
-        if (expected != actual) {
-            throw new RuntimeException("expected: " + expected + " does not match actual: " + actual);
-        }
-    }
-
-    static void assertEquals(Object expected, Object actual) {
-        if (expected != actual) {
-            throw new RuntimeException("expected: " + expected + " does not match actual: " + actual);
-        }
-    }
-
-    public static void main(String[] args) {
-        StandardCallTest t = new StandardCallTest();
-
-        t.testInteger();
-        t.testSse();
-        t.testMixed();
-        t.testAbiExample();
-        t.testAbiExampleVarargs();
-        t.testStruct8();
-        t.testStruct16();
-        t.testStruct24();
-        t.testStruct32();
-        t.testFunctionType();
-        t.testMixedArgs();
-        t.testIntegerStruct();
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/foreign/libUnalignedStruct.c	Thu Apr 18 15:37:03 2019 +0100
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+struct unaligned {
+   long double x1; //unused
+   short i1;
+   short i2;
+   //padding here?
+};
+
+short unaligned_sum_i1(struct unaligned u1, struct unaligned u2) {
+   return u1.i1 + u2.i1;
+}
+
+short unaligned_sum_i2(struct unaligned u1, struct unaligned u2) {
+   return u1.i2 + u2.i2;
+}