changeset 59338:327e2aa993f0 foreign

8222739: Port CallingSequenceTest to Windows Reviewed-by: henryjen
author jvernee
date Sat, 27 Apr 2019 13:47:28 +0200
parents 40e71d36d71d
children c462b33549f4
files src/java.base/share/classes/jdk/internal/foreign/abi/x64/windows/CallingSequenceBuilderImpl.java test/jdk/java/foreign/abi/x64/CallingSequenceTestBase.java test/jdk/java/foreign/abi/x64/sysv/CallingSequenceTest.java test/jdk/java/foreign/abi/x64/windows/CallingSequenceTest.java
diffstat 4 files changed, 448 insertions(+), 371 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/x64/windows/CallingSequenceBuilderImpl.java	Fri Apr 26 13:38:23 2019 -0300
+++ b/src/java.base/share/classes/jdk/internal/foreign/abi/x64/windows/CallingSequenceBuilderImpl.java	Sat Apr 27 13:47:28 2019 +0200
@@ -34,7 +34,7 @@
 
 import static sun.security.action.GetBooleanAction.privilegedGetProperty;
 
-class CallingSequenceBuilderImpl extends CallingSequenceBuilder {
+public class CallingSequenceBuilderImpl extends CallingSequenceBuilder {
 
     private static final SharedUtils.StorageDebugHelper storageDbgHelper = new SharedUtils.StorageDebugHelper(
             new String[] { "rcx", "rdx", "r8", "r9" },
@@ -253,7 +253,7 @@
 
                         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));
+                            bindingConsumer.accept(extraStorage.getStorageClass(), new ArgumentBinding(extraStorage, info, i * 8));
 
                             if (DEBUG) {
                                 System.out.println("Argument " + info.name() + " will be passed in register " +
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/foreign/abi/x64/CallingSequenceTestBase.java	Sat Apr 27 13:47:28 2019 +0200
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ */
+
+import jdk.internal.foreign.abi.CallingSequence;
+import jdk.internal.foreign.abi.CallingSequenceBuilder;
+import jdk.internal.foreign.abi.StorageClass;
+import jdk.internal.foreign.memory.Types;
+
+import java.foreign.layout.Layout;
+import java.util.ArrayList;
+import java.util.EnumMap;
+import java.util.List;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+import static org.testng.Assert.assertEquals;
+import static jdk.internal.foreign.abi.StorageClass.*;
+
+public class CallingSequenceTestBase {
+
+    public static class Binding {
+        public final StorageClass cls;
+        public final long offset;
+
+        public Binding(StorageClass cls, long offset) {
+            this.cls = cls;
+            this.offset = offset;
+        }
+    }
+
+    public static class Verifier {
+        private final CallingSequenceBuilder csb;
+        private final List<Consumer<CallingSequence>> verifiers = new ArrayList<>();
+        private final EnumMap<StorageClass, Integer> classCounts = new EnumMap<>(StorageClass.class);
+
+        public Verifier(CallingSequenceBuilder csb) {
+            this.csb = csb;
+        }
+
+        public Verifier vararg(Layout arg, Binding...bindings) {
+            return argInternal(arg, true, bindings);
+        }
+
+        public Verifier args(int repeats, Layout arg, Binding...bindings) {
+            for(int i = 0; i < repeats; i++) {
+                arg(arg, bindings);
+            }
+            return this;
+        }
+
+        public Verifier arg(Layout arg, Binding...bindings) {
+            return argInternal(arg, false, bindings);
+        }
+
+        private Verifier argInternal(Layout arg, boolean varargs, Binding...bindings) {
+            csb.addArgument(arg, varargs);
+            for(Binding binding : bindings) {
+                StorageClass cls = binding.cls;
+                long offset = binding.offset;
+                int indexInClass = classCounts.getOrDefault(cls, 0);
+                verifiers.add(recipe -> {
+                    assertEquals(recipe.bindings(cls).get(indexInClass).argument().layout(), arg,
+                            "Unexpected argument layout");
+                    assertEquals(recipe.bindings(cls).get(indexInClass).offset(), offset,
+                            "Unexpected binding offset");
+                });
+                classCounts.put(cls, indexInClass + 1);
+            }
+            return this;
+        }
+
+        public void check(boolean returnsInMemory) {
+            CallingSequence recipe = csb.build();
+
+            // System.out.println(recipe.asString());
+
+            assertEquals(returnsInMemory, recipe.returnsInMemory());
+            classCounts.forEach((scls, count) -> assertEquals(recipe.bindings(scls).size(), (int) count,
+                    String.format("Unexpected argument class count for class %s", scls)));
+
+            for(var verifier : verifiers) {
+                verifier.accept(recipe);
+            }
+        }
+    }
+
+    public static Binding binding(StorageClass cls, int offset) {
+        return new Binding(cls, offset);
+    }
+
+    public void testInteger(Function<Layout, CallingSequenceBuilder> factory, int maxIntArgs) {
+        new Verifier(factory.apply(null))
+                .args(maxIntArgs, Types.INT64,
+                        binding(INTEGER_ARGUMENT_REGISTER, 0))
+                .args(2, Types.INT64,
+                        binding(STACK_ARGUMENT_SLOT, 0))
+                .check(false);
+    }
+
+    public void testSse(Function<Layout, CallingSequenceBuilder> factory, int maxSSEArgs) {
+        new Verifier(factory.apply(null))
+                .args(maxSSEArgs, Types.FLOAT,
+                        binding(VECTOR_ARGUMENT_REGISTER, 0))
+                .args(2, Types.FLOAT,
+                        binding(STACK_ARGUMENT_SLOT, 0))
+                .check(false);
+    }
+
+}
--- a/test/jdk/java/foreign/abi/x64/sysv/CallingSequenceTest.java	Fri Apr 26 13:38:23 2019 -0300
+++ b/test/jdk/java/foreign/abi/x64/sysv/CallingSequenceTest.java	Sat Apr 27 13:47:28 2019 +0200
@@ -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,127 +23,45 @@
 
 /*
  * @test
+ * @library ..
  * @modules java.base/jdk.internal.foreign.abi java.base/jdk.internal.foreign.memory java.base/jdk.internal.foreign.abi.x64.sysv
+ * @run testng CallingSequenceTest
  */
 
-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;
+import org.testng.annotations.Test;
 
-public class CallingSequenceTest {
+import static jdk.internal.foreign.abi.StorageClass.*;
 
+public class CallingSequenceTest extends CallingSequenceTestBase {
+
+    @Test
     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());
-        }
+        testInteger(CallingSequenceBuilderImpl::new, SysVx64ABI.MAX_INTEGER_ARGUMENT_REGISTERS);
     }
 
+    @Test
     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());
-        }
+        testSse(CallingSequenceBuilderImpl::new, SysVx64ABI.MAX_VECTOR_ARGUMENT_REGISTERS);
     }
 
-     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());
-        }
+    @Test
+    public void testMixed() {
+        new Verifier(new CallingSequenceBuilderImpl(null))
+                .args(SysVx64ABI.MAX_INTEGER_ARGUMENT_REGISTERS, Types.INT64,
+                        binding(INTEGER_ARGUMENT_REGISTER, 0))
+                .args(2, Types.INT64,
+                        binding(STACK_ARGUMENT_SLOT, 0))
+                .args(SysVx64ABI.MAX_VECTOR_ARGUMENT_REGISTERS, Types.FLOAT,
+                        binding(VECTOR_ARGUMENT_REGISTER, 0))
+                .args(2, Types.FLOAT,
+                        binding(STACK_ARGUMENT_SLOT, 0))
+                .check(false);
     }
 
     /**
@@ -155,75 +73,31 @@
      * 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);
+     * void m(e, f, s, g, h, ld, m, n, i, j, k);
      *
      * m(s);
      */
+    @Test
     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());
+        new Verifier(new CallingSequenceBuilderImpl(null))
+                .args(2, Types.INT32,
+                        binding(INTEGER_ARGUMENT_REGISTER, 0))
+                .arg(Group.struct(Types.INT32, Types.INT32, Types.DOUBLE),
+                        binding(INTEGER_ARGUMENT_REGISTER, 0), // s.a, s.b
+                        binding(VECTOR_ARGUMENT_REGISTER, 8)) // s.d
+                .args(2, Types.INT32,
+                        binding(INTEGER_ARGUMENT_REGISTER, 0))
+                .arg(Types.LONG_DOUBLE,
+                        binding(STACK_ARGUMENT_SLOT, 0),
+                        binding(STACK_ARGUMENT_SLOT, 8))
+                .args(2, Types.DOUBLE,
+                        binding(VECTOR_ARGUMENT_REGISTER, 0))
+                .arg(Types.INT32,
+                        binding(INTEGER_ARGUMENT_REGISTER, 0))
+                .args(2, Types.INT32,
+                        binding(STACK_ARGUMENT_SLOT, 0))
+                .check(false);
     }
 
     /**
@@ -238,44 +112,21 @@
      *
      * func(a, m, u, b, ld, y, n);
      */
+    @Test
     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());
+        new Verifier(new CallingSequenceBuilderImpl(null))
+                .arg(Types.INT,
+                        binding(INTEGER_ARGUMENT_REGISTER, 0))
+                .arg(Types.DOUBLE,
+                        binding(VECTOR_ARGUMENT_REGISTER, 0))
+                .arg(Types.INT,
+                        binding(INTEGER_ARGUMENT_REGISTER, 0))
+                .arg(Types.LONG_DOUBLE,
+                        binding(STACK_ARGUMENT_SLOT, 0),
+                        binding(STACK_ARGUMENT_SLOT, 8))
+                .arg(Types.DOUBLE,
+                        binding(VECTOR_ARGUMENT_REGISTER, 0))
+                .check(false);
     }
 
 
@@ -288,21 +139,12 @@
      *
      * m(s);
      */
+    @Test
     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());
+        new Verifier(new CallingSequenceBuilderImpl(null))
+                .arg(Group.struct(Types.UNSIGNED.INT64),
+                        binding(INTEGER_ARGUMENT_REGISTER, 0))
+                .check(false);
     }
 
     /**
@@ -314,25 +156,13 @@
      *
      * m(s);
      */
+    @Test
     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());
+        new Verifier(new CallingSequenceBuilderImpl(null))
+                .arg(Group.struct(Types.UNSIGNED.INT64, Types.UNSIGNED.INT64),
+                        binding(INTEGER_ARGUMENT_REGISTER, 0),
+                        binding(INTEGER_ARGUMENT_REGISTER, 8))
+                .check(false);
     }
 
     /**
@@ -344,29 +174,14 @@
      *
      * m(s);
      */
+    @Test
     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());
+        new Verifier(new CallingSequenceBuilderImpl(null))
+                .arg(Group.struct(Types.UNSIGNED.INT64, Types.UNSIGNED.INT64, Types.UNSIGNED.INT64),
+                        binding(STACK_ARGUMENT_SLOT, 0),
+                        binding(STACK_ARGUMENT_SLOT, 8),
+                        binding(STACK_ARGUMENT_SLOT, 16))
+                .check(false);
     }
 
     /**
@@ -378,33 +193,15 @@
      *
      * m(s);
      */
+    @Test
     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());
+        new Verifier(new CallingSequenceBuilderImpl(null))
+                .arg(Layout.of("[u64u64u64u64]"),
+                        binding(STACK_ARGUMENT_SLOT, 0),
+                        binding(STACK_ARGUMENT_SLOT, 8),
+                        binding(STACK_ARGUMENT_SLOT, 16),
+                        binding(STACK_ARGUMENT_SLOT, 24))
+                .check(false);
     }
 
     /**
@@ -415,44 +212,25 @@
      *
      * m(f_impl);
      */
+    @Test
     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());
+        new Verifier(new CallingSequenceBuilderImpl(null))
+                .arg(Layout.of("u64:()v"),
+                        binding(INTEGER_ARGUMENT_REGISTER, 0))
+                .check(false);
     }
 
     /**
      * void f(int64_t l0, float f0, __m256 m0);
      */
+    @Test
     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());
+        new Verifier(new CallingSequenceBuilderImpl(null))
+                .arg(Types.INT64,
+                        binding(INTEGER_ARGUMENT_REGISTER, 0))
+                .arg(Types.FLOAT,
+                        binding(VECTOR_ARGUMENT_REGISTER, 0))
+                .check(false);
     }
 
     /**
@@ -463,59 +241,13 @@
      *
      * void f(struct s s1);
      */
+    @Test
     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());
+        new Verifier(new CallingSequenceBuilderImpl(null))
+                .arg(Layout.of("[i64i64]"),
+                        binding(INTEGER_ARGUMENT_REGISTER, 0),
+                        binding(INTEGER_ARGUMENT_REGISTER, 8))
+                .check(false);
     }
 
-    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();
-    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/foreign/abi/x64/windows/CallingSequenceTest.java	Sat Apr 27 13:47:28 2019 +0200
@@ -0,0 +1,216 @@
+/*
+ * 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
+ * @library ..
+ * @modules java.base/jdk.internal.foreign.abi java.base/jdk.internal.foreign.memory java.base/jdk.internal.foreign.abi.x64.windows
+ * @run testng CallingSequenceTest
+ */
+
+import jdk.internal.foreign.abi.x64.windows.CallingSequenceBuilderImpl;
+import jdk.internal.foreign.abi.x64.windows.Windowsx64ABI;
+import jdk.internal.foreign.memory.Types;
+import org.testng.annotations.Test;
+
+import java.foreign.layout.Group;
+import java.foreign.layout.Layout;
+
+import static jdk.internal.foreign.abi.StorageClass.*;
+
+public class CallingSequenceTest extends CallingSequenceTestBase {
+
+    @Test
+    public void testInteger() {
+        testInteger(CallingSequenceBuilderImpl::new, Windowsx64ABI.MAX_INTEGER_ARGUMENT_REGISTERS);
+    }
+
+    @Test
+    public void testSse() {
+        testSse(CallingSequenceBuilderImpl::new, Windowsx64ABI.MAX_VECTOR_ARGUMENT_REGISTERS);
+    }
+
+    @Test
+    public void testMixed() {
+        new Verifier(new CallingSequenceBuilderImpl(null))
+                .args(2, Types.INT64,
+                        binding(INTEGER_ARGUMENT_REGISTER, 0))
+                .args(2, Types.FLOAT,
+                        binding(VECTOR_ARGUMENT_REGISTER, 0))
+                .args(2, Types.INT64,
+                        binding(STACK_ARGUMENT_SLOT, 0))
+                .args(2, Types.FLOAT,
+                        binding(STACK_ARGUMENT_SLOT, 0))
+                .check(false);
+    }
+
+    @Test
+    public void testAbiExample() {
+        new Verifier(new CallingSequenceBuilderImpl(null))
+                .args(2, Types.INT32,
+                        binding(INTEGER_ARGUMENT_REGISTER, 0))
+                .arg(Group.struct(Types.INT32, Types.INT32, Types.DOUBLE),
+                        binding(INTEGER_ARGUMENT_REGISTER, 0))
+                .arg(Types.INT32,
+                        binding(INTEGER_ARGUMENT_REGISTER, 0))
+                .arg(Types.INT32,
+                        binding(STACK_ARGUMENT_SLOT, 0))
+                .args(3, Types.DOUBLE,
+                        binding(STACK_ARGUMENT_SLOT, 0))
+                .args(3, Types.INT32,
+                        binding(STACK_ARGUMENT_SLOT, 0))
+                .check(false);
+    }
+
+    @Test
+    public void testAbiExampleVarargs() {
+        new Verifier(new CallingSequenceBuilderImpl(null))
+                .arg(Types.INT,
+                        binding(INTEGER_ARGUMENT_REGISTER, 0))
+                .arg(Types.DOUBLE,
+                        binding(VECTOR_ARGUMENT_REGISTER, 0))
+                .vararg(Types.INT,
+                        binding(INTEGER_ARGUMENT_REGISTER, 0))
+                .vararg(Types.DOUBLE,
+                        binding(INTEGER_ARGUMENT_REGISTER, 0),
+                        binding(VECTOR_ARGUMENT_REGISTER, 0))
+                .vararg(Types.DOUBLE,
+                        binding(STACK_ARGUMENT_SLOT, 0))
+                .check(false);
+    }
+
+
+    /**
+     * struct s {
+     *   uint64_t u0;
+     * } s;
+     *
+     * void m(struct s s);
+     *
+     * m(s);
+     */
+    @Test
+    public void testStruct8() {
+        new Verifier(new CallingSequenceBuilderImpl(null))
+                .arg(Group.struct(Types.UNSIGNED.INT64),
+                        binding(INTEGER_ARGUMENT_REGISTER, 0))
+                .check(false);
+    }
+
+    /**
+     * struct s {
+     *   uint64_t u0, u1;
+     * } s;
+     *
+     * void m(struct s s);
+     *
+     * m(s);
+     */
+    @Test
+    public void testStruct16() {
+        new Verifier(new CallingSequenceBuilderImpl(null))
+                .arg(Group.struct(Types.UNSIGNED.INT64, Types.UNSIGNED.INT64),
+                        binding(INTEGER_ARGUMENT_REGISTER, 0))
+                .check(false);
+    }
+
+    /**
+     * struct s {
+     *   uint64_t u0, u1, u2;
+     * } s;
+     *
+     * void m(struct s s);
+     *
+     * m(s);
+     */
+    @Test
+    public void testStruct24() {
+        new Verifier(new CallingSequenceBuilderImpl(null))
+                .arg(Group.struct(Types.UNSIGNED.INT64, Types.UNSIGNED.INT64, Types.UNSIGNED.INT64),
+                        binding(INTEGER_ARGUMENT_REGISTER, 0))
+                .check(false);
+    }
+
+    /**
+     * struct s {
+     *   uint64_t u0, u1, u2, u3;
+     * } s;
+     *
+     * void m(struct s s);
+     *
+     * m(s);
+     */
+    @Test
+    public void testStruct32() {
+        new Verifier(new CallingSequenceBuilderImpl(null))
+                .arg(Layout.of("[u64u64u64u64]"),
+                        binding(INTEGER_ARGUMENT_REGISTER, 0))
+                .check(false);
+    }
+
+    /**
+     * typedef void (*f)(void);
+     *
+     * void m(f f);
+     * void f_impl(void);
+     *
+     * m(f_impl);
+     */
+    @Test
+    public void testFunctionType() {
+        new Verifier(new CallingSequenceBuilderImpl(null))
+                .arg(Layout.of("u64:()v"),
+                        binding(INTEGER_ARGUMENT_REGISTER, 0))
+                .check(false);
+    }
+
+    /**
+     * void f(int64_t l0, float f0, __m256 m0);
+     */
+    @Test
+    public void testMixedArgs() {
+        new Verifier(new CallingSequenceBuilderImpl(null))
+                .arg(Types.INT64,
+                        binding(INTEGER_ARGUMENT_REGISTER, 0))
+                .arg(Types.FLOAT,
+                        binding(VECTOR_ARGUMENT_REGISTER, 0))
+                .check(false);
+    }
+
+    /**
+     * struct s {
+     *    int64_t l0;
+     *    int64_t l1;
+     * };
+     *
+     * void f(struct s s1);
+     */
+    @Test
+    public void testIntegerStruct() {
+        new Verifier(new CallingSequenceBuilderImpl(null))
+                .arg(Layout.of("[i64i64]"),
+                        binding(INTEGER_ARGUMENT_REGISTER, 0))
+                .check(false);
+    }
+
+}