detached 749871c

all: use structs.HostLayout on structs that must match the C ABI (#502)

Go 1.23 added structs.HostLayout, a zero-sized marker field that tells
the compiler a struct must be laid out the way the host's C ABI expects
rather than by Go's own rules. Until now purego relied on Go's current
layout happening to match C.

Declare the marker on every struct that stands in for a C one: objc_super,
MethodDescription, PropertyAttribute, blockDescriptor and blockLayout in
package objc; G, ThreadStart, the Darwin pthread types, the NetBSD stack_t
and argset in internal/fakecgo; syscallArgs, which internal/cgo hands to C
as a struct syscallArgs; the window example's NSPoint/NSSize/NSRect and
WNDCLASSEX/RECT/POINT/MSG; and the C-representative structs in the tests.
Structs that never cross into C, such as MethodDef, FieldDef and the
callback argument block filled in by Go assembly, are left alone.

The marker field is zero-sized, so it takes no part in the C ABI. Teach
the argument classification to skip zero-sized fields, otherwise a struct
that declares it is misclassified: isAllSameFloat would panic descending
into the marker, isHFA/isHVA would stop recognizing homogeneous
aggregates, and objc's @encode would emit the marker as a member.

Closes #259

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
commit
749871c21fc2230bc35b5b99b17828ad61cedddd
author
TotallyGamerJet · · 2026-08-26 13:15 UTC
committer
GitHub · · 2026-08-26 13:15 UTC
parent
a66c0b0
signature
GPG UnverifiedB5690EEEBB952194 The key is unknown
refs
tag: v0.11.0-alpha.10
20 files · +437 -130
M examples/window/main_darwin.go +5 -1
@@ -5,6 +5,7 @@ package main
55
66 import (
77 "runtime"
8+ "structs"
89
910 "github.com/ebitengine/purego"
1011 "github.com/ebitengine/purego/objc"
@@ -17,14 +18,17 @@ const (
1718 )
1819
1920 type NSPoint struct {
21+ _ structs.HostLayout
2022 X, Y float64
2123 }
2224
2325 type NSSize struct {
26+ _ structs.HostLayout
2427 Width, Height float64
2528 }
2629
2730 type NSRect struct {
31+ _ structs.HostLayout
2832 Origin NSPoint
2933 Size NSSize
3034 }
@@ -56,5 +60,5 @@ func main() {
5660 }
5761
5862 func NSMakeRect(x, y, width, height float64) NSRect {
59- return NSRect{Origin: NSPoint{x, y}, Size: NSSize{width, height}}
63+ return NSRect{Origin: NSPoint{X: x, Y: y}, Size: NSSize{Width: width, Height: height}}
6064 }
@@ -5,6 +5,7 @@ package main
5 5
6 import (6 import (
7 "runtime"7 "runtime"
8+ "structs"
8 9
9 "github.com/ebitengine/purego"10 "github.com/ebitengine/purego"
10 "github.com/ebitengine/purego/objc"11 "github.com/ebitengine/purego/objc"
@@ -17,14 +18,17 @@ const (
17 )18 )
18 19
19 type NSPoint struct {20 type NSPoint struct {
21+ _ structs.HostLayout
20 X, Y float6422 X, Y float64
21 }23 }
22 24
23 type NSSize struct {25 type NSSize struct {
26+ _ structs.HostLayout
24 Width, Height float6427 Width, Height float64
25 }28 }
26 29
27 type NSRect struct {30 type NSRect struct {
31+ _ structs.HostLayout
28 Origin NSPoint32 Origin NSPoint
29 Size NSSize33 Size NSSize
30 }34 }
@@ -56,5 +60,5 @@ func main() {
56 }60 }
57 61
58 func NSMakeRect(x, y, width, height float64) NSRect {62 func NSMakeRect(x, y, width, height float64) NSRect {
59- return NSRect{Origin: NSPoint{x, y}, Size: NSSize{width, height}}63+ return NSRect{Origin: NSPoint{X: x, Y: y}, Size: NSSize{Width: width, Height: height}}
60 }64 }
M examples/window/main_windows.go +5 -0
@@ -5,6 +5,7 @@ package main
55
66 import (
77 "runtime"
8+ "structs"
89 "syscall"
910 "unsafe"
1011
@@ -30,6 +31,7 @@ type (
3031 )
3132
3233 type WNDCLASSEX struct {
34+ _ structs.HostLayout
3335 Size uint32
3436 Style uint32
3537 WndProc uintptr
@@ -45,14 +47,17 @@ type WNDCLASSEX struct {
4547 }
4648
4749 type RECT struct {
50+ _ structs.HostLayout
4851 Left, Top, Right, Bottom int32
4952 }
5053
5154 type POINT struct {
55+ _ structs.HostLayout
5256 X, Y int32
5357 }
5458
5559 type MSG struct {
60+ _ structs.HostLayout
5661 Hwnd HWND
5762 Message uint32
5863 WParam uintptr
@@ -5,6 +5,7 @@ package main
5 5
6 import (6 import (
7 "runtime"7 "runtime"
8+ "structs"
8 "syscall"9 "syscall"
9 "unsafe"10 "unsafe"
10 11
@@ -30,6 +31,7 @@ type (
30 )31 )
31 32
32 type WNDCLASSEX struct {33 type WNDCLASSEX struct {
34+ _ structs.HostLayout
33 Size uint3235 Size uint32
34 Style uint3236 Style uint32
35 WndProc uintptr37 WndProc uintptr
@@ -45,14 +47,17 @@ type WNDCLASSEX struct {
45 }47 }
46 48
47 type RECT struct {49 type RECT struct {
50+ _ structs.HostLayout
48 Left, Top, Right, Bottom int3251 Left, Top, Right, Bottom int32
49 }52 }
50 53
51 type POINT struct {54 type POINT struct {
55+ _ structs.HostLayout
52 X, Y int3256 X, Y int32
53 }57 }
54 58
55 type MSG struct {59 type MSG struct {
60+ _ structs.HostLayout
56 Hwnd HWND61 Hwnd HWND
57 Message uint3262 Message uint32
58 WParam uintptr63 WParam uintptr
M func.go +50 -2
@@ -10,6 +10,7 @@ import (
1010 "math"
1111 "reflect"
1212 "runtime"
13+ "structs"
1314 "sync"
1415 "unsafe"
1516
@@ -555,17 +556,61 @@ func addValue(v reflect.Value, keepAlive []any, addInt func(x uintptr), addFloat
555556 // If you change this make sure to update it in objc_runtime_darwin.go
556557 const maxRegAllocStructSize = 16
557558
559+var hostLayoutType = reflect.TypeFor[structs.HostLayout]()
560+
561+// isABIField reports whether f takes part in the C ABI of the struct that
562+// contains it. Only the structs.HostLayout marker does not.
563+func isABIField(f reflect.StructField) bool {
564+ return !f.Type.ConvertibleTo(hostLayoutType)
565+}
566+
567+// numABIFields returns how many of ty's fields take part in the C ABI.
568+func numABIFields(ty reflect.Type) int {
569+ var n int
570+ for i := range ty.NumField() {
571+ if isABIField(ty.Field(i)) {
572+ n++
573+ }
574+ }
575+ return n
576+}
577+
578+// abiField returns the i'th field of ty that takes part in the C ABI. It panics
579+// if ty has fewer than i+1 such fields.
580+func abiField(ty reflect.Type, i int) reflect.StructField {
581+ for j := range ty.NumField() {
582+ f := ty.Field(j)
583+ if !isABIField(f) {
584+ continue
585+ }
586+ if i == 0 {
587+ return f
588+ }
589+ i--
590+ }
591+ panic("purego: struct field index out of range")
592+}
593+
558594 func isAllSameFloat(ty reflect.Type) (allFloats bool, numFields int) {
559595 allFloats = true
560- root := ty.Field(0).Type
596+ if numABIFields(ty) == 0 {
597+ return false, 0
598+ }
599+ root := abiField(ty, 0).Type
561600 for root.Kind() == reflect.Struct {
562- root = root.Field(0).Type
601+ if numABIFields(root) == 0 {
602+ return false, 0
603+ }
604+ root = abiField(root, 0).Type
563605 }
564606 first := root.Kind()
565607 if first != reflect.Float32 && first != reflect.Float64 {
566608 allFloats = false
567609 }
568610 for i := 0; i < ty.NumField(); i++ {
611+ if !isABIField(ty.Field(i)) {
612+ continue
613+ }
569614 f := ty.Field(i).Type
570615 if f.Kind() == reflect.Struct {
571616 var structNumFields int
@@ -583,6 +628,9 @@ func isAllSameFloat(ty reflect.Type) (allFloats bool, numFields int) {
583628
584629 func checkStructFieldsSupported(ty reflect.Type) {
585630 for i := 0; i < ty.NumField(); i++ {
631+ if !isABIField(ty.Field(i)) {
632+ continue
633+ }
586634 f := ty.Field(i).Type
587635 if f.Kind() == reflect.Array {
588636 f = f.Elem()
@@ -10,6 +10,7 @@ import (
10 "math"10 "math"
11 "reflect"11 "reflect"
12 "runtime"12 "runtime"
13+ "structs"
13 "sync"14 "sync"
14 "unsafe"15 "unsafe"
15 16
@@ -555,17 +556,61 @@ func addValue(v reflect.Value, keepAlive []any, addInt func(x uintptr), addFloat
555 // If you change this make sure to update it in objc_runtime_darwin.go556 // If you change this make sure to update it in objc_runtime_darwin.go
556 const maxRegAllocStructSize = 16557 const maxRegAllocStructSize = 16
557 558
559+var hostLayoutType = reflect.TypeFor[structs.HostLayout]()
560+
561+// isABIField reports whether f takes part in the C ABI of the struct that
562+// contains it. Only the structs.HostLayout marker does not.
563+func isABIField(f reflect.StructField) bool {
564+ return !f.Type.ConvertibleTo(hostLayoutType)
565+}
566+
567+// numABIFields returns how many of ty's fields take part in the C ABI.
568+func numABIFields(ty reflect.Type) int {
569+ var n int
570+ for i := range ty.NumField() {
571+ if isABIField(ty.Field(i)) {
572+ n++
573+ }
574+ }
575+ return n
576+}
577+
578+// abiField returns the i'th field of ty that takes part in the C ABI. It panics
579+// if ty has fewer than i+1 such fields.
580+func abiField(ty reflect.Type, i int) reflect.StructField {
581+ for j := range ty.NumField() {
582+ f := ty.Field(j)
583+ if !isABIField(f) {
584+ continue
585+ }
586+ if i == 0 {
587+ return f
588+ }
589+ i--
590+ }
591+ panic("purego: struct field index out of range")
592+}
593+
558 func isAllSameFloat(ty reflect.Type) (allFloats bool, numFields int) {594 func isAllSameFloat(ty reflect.Type) (allFloats bool, numFields int) {
559 allFloats = true595 allFloats = true
560- root := ty.Field(0).Type596+ if numABIFields(ty) == 0 {
597+ return false, 0
598+ }
599+ root := abiField(ty, 0).Type
561 for root.Kind() == reflect.Struct {600 for root.Kind() == reflect.Struct {
562- root = root.Field(0).Type601+ if numABIFields(root) == 0 {
602+ return false, 0
603+ }
604+ root = abiField(root, 0).Type
563 }605 }
564 first := root.Kind()606 first := root.Kind()
565 if first != reflect.Float32 && first != reflect.Float64 {607 if first != reflect.Float32 && first != reflect.Float64 {
566 allFloats = false608 allFloats = false
567 }609 }
568 for i := 0; i < ty.NumField(); i++ {610 for i := 0; i < ty.NumField(); i++ {
611+ if !isABIField(ty.Field(i)) {
612+ continue
613+ }
569 f := ty.Field(i).Type614 f := ty.Field(i).Type
570 if f.Kind() == reflect.Struct {615 if f.Kind() == reflect.Struct {
571 var structNumFields int616 var structNumFields int
@@ -583,6 +628,9 @@ func isAllSameFloat(ty reflect.Type) (allFloats bool, numFields int) {
583 628
584 func checkStructFieldsSupported(ty reflect.Type) {629 func checkStructFieldsSupported(ty reflect.Type) {
585 for i := 0; i < ty.NumField(); i++ {630 for i := 0; i < ty.NumField(); i++ {
631+ if !isABIField(ty.Field(i)) {
632+ continue
633+ }
586 f := ty.Field(i).Type634 f := ty.Field(i).Type
587 if f.Kind() == reflect.Array {635 if f.Kind() == reflect.Array {
588 f = f.Elem()636 f = f.Elem()
M func_test.go +17 -4
@@ -15,6 +15,7 @@ import (
1515 "runtime"
1616 "strconv"
1717 "strings"
18+ "structs"
1819 "sync"
1920 "testing"
2021 "unsafe"
@@ -393,11 +394,20 @@ func TestABI_ArgumentPassing(t *testing.T) {
393394 },
394395 {
395396 name: "8int_hfa4_stack",
396- fn: new(func(*byte, uintptr, int32, int32, int32, int32, int32, int32, int32, int32, struct{ x, y, z, w float32 })),
397- cFn: "stack_8int_hfa4_stack",
397+ fn: new(func(*byte, uintptr, int32, int32, int32, int32, int32, int32, int32, int32, struct {
398+ _ structs.HostLayout
399+ x, y, z, w float32
400+ })),
401+ cFn: "stack_8int_hfa4_stack",
398402 call: func(f any) string {
399403 buf := make([]byte, 256)
400- (*f.(*func(*byte, uintptr, int32, int32, int32, int32, int32, int32, int32, int32, struct{ x, y, z, w float32 })))(&buf[0], 256, 1, 2, 3, 4, 5, 6, 7, 8, struct{ x, y, z, w float32 }{10.0, 20.0, 30.0, 40.0})
404+ (*f.(*func(*byte, uintptr, int32, int32, int32, int32, int32, int32, int32, int32, struct {
405+ _ structs.HostLayout
406+ x, y, z, w float32
407+ })))(&buf[0], 256, 1, 2, 3, 4, 5, 6, 7, 8, struct {
408+ _ structs.HostLayout
409+ x, y, z, w float32
410+ }{x: 10.0, y: 20.0, z: 30.0, w: 40.0})
401411 return string(buf[:bytes.IndexByte(buf, 0)])
402412 },
403413 want: "1:2:3:4:5:6:7:8:10.0:20.0:30.0:40.0",
@@ -405,6 +415,7 @@ func TestABI_ArgumentPassing(t *testing.T) {
405415 {
406416 name: "8int_mixed_struct",
407417 fn: new(func(*byte, uintptr, int32, int32, int32, int32, int32, int32, int32, int32, struct {
418+ _ structs.HostLayout
408419 a int32
409420 b float32
410421 })),
@@ -412,12 +423,14 @@ func TestABI_ArgumentPassing(t *testing.T) {
412423 call: func(f any) string {
413424 buf := make([]byte, 256)
414425 (*f.(*func(*byte, uintptr, int32, int32, int32, int32, int32, int32, int32, int32, struct {
426+ _ structs.HostLayout
415427 a int32
416428 b float32
417429 })))(&buf[0], 256, 1, 2, 3, 4, 5, 6, 7, 8, struct {
430+ _ structs.HostLayout
418431 a int32
419432 b float32
420- }{9, 10.0})
433+ }{a: 9, b: 10.0})
421434 return string(buf[:bytes.IndexByte(buf, 0)])
422435 },
423436 want: "1:2:3:4:5:6:7:8:9:10.0",
@@ -15,6 +15,7 @@ import (
15 "runtime"15 "runtime"
16 "strconv"16 "strconv"
17 "strings"17 "strings"
18+ "structs"
18 "sync"19 "sync"
19 "testing"20 "testing"
20 "unsafe"21 "unsafe"
@@ -393,11 +394,20 @@ func TestABI_ArgumentPassing(t *testing.T) {
393 },394 },
394 {395 {
395 name: "8int_hfa4_stack",396 name: "8int_hfa4_stack",
396- fn: new(func(*byte, uintptr, int32, int32, int32, int32, int32, int32, int32, int32, struct{ x, y, z, w float32 })),397+ fn: new(func(*byte, uintptr, int32, int32, int32, int32, int32, int32, int32, int32, struct {
397- cFn: "stack_8int_hfa4_stack",398+ _ structs.HostLayout
399+ x, y, z, w float32
400+ })),
401+ cFn: "stack_8int_hfa4_stack",
398 call: func(f any) string {402 call: func(f any) string {
399 buf := make([]byte, 256)403 buf := make([]byte, 256)
400- (*f.(*func(*byte, uintptr, int32, int32, int32, int32, int32, int32, int32, int32, struct{ x, y, z, w float32 })))(&buf[0], 256, 1, 2, 3, 4, 5, 6, 7, 8, struct{ x, y, z, w float32 }{10.0, 20.0, 30.0, 40.0})404+ (*f.(*func(*byte, uintptr, int32, int32, int32, int32, int32, int32, int32, int32, struct {
405+ _ structs.HostLayout
406+ x, y, z, w float32
407+ })))(&buf[0], 256, 1, 2, 3, 4, 5, 6, 7, 8, struct {
408+ _ structs.HostLayout
409+ x, y, z, w float32
410+ }{x: 10.0, y: 20.0, z: 30.0, w: 40.0})
401 return string(buf[:bytes.IndexByte(buf, 0)])411 return string(buf[:bytes.IndexByte(buf, 0)])
402 },412 },
403 want: "1:2:3:4:5:6:7:8:10.0:20.0:30.0:40.0",413 want: "1:2:3:4:5:6:7:8:10.0:20.0:30.0:40.0",
@@ -405,6 +415,7 @@ func TestABI_ArgumentPassing(t *testing.T) {
405 {415 {
406 name: "8int_mixed_struct",416 name: "8int_mixed_struct",
407 fn: new(func(*byte, uintptr, int32, int32, int32, int32, int32, int32, int32, int32, struct {417 fn: new(func(*byte, uintptr, int32, int32, int32, int32, int32, int32, int32, int32, struct {
418+ _ structs.HostLayout
408 a int32419 a int32
409 b float32420 b float32
410 })),421 })),
@@ -412,12 +423,14 @@ func TestABI_ArgumentPassing(t *testing.T) {
412 call: func(f any) string {423 call: func(f any) string {
413 buf := make([]byte, 256)424 buf := make([]byte, 256)
414 (*f.(*func(*byte, uintptr, int32, int32, int32, int32, int32, int32, int32, int32, struct {425 (*f.(*func(*byte, uintptr, int32, int32, int32, int32, int32, int32, int32, int32, struct {
426+ _ structs.HostLayout
415 a int32427 a int32
416 b float32428 b float32
417 })))(&buf[0], 256, 1, 2, 3, 4, 5, 6, 7, 8, struct {429 })))(&buf[0], 256, 1, 2, 3, 4, 5, 6, 7, 8, struct {
430+ _ structs.HostLayout
418 a int32431 a int32
419 b float32432 b float32
420- }{9, 10.0})433+ }{a: 9, b: 10.0})
421 return string(buf[:bytes.IndexByte(buf, 0)])434 return string(buf[:bytes.IndexByte(buf, 0)])
422 },435 },
423 want: "1:2:3:4:5:6:7:8:9:10.0",436 want: "1:2:3:4:5:6:7:8:9:10.0",
M internal/fakecgo/libcgo.go +4 -0
@@ -5,6 +5,8 @@
55
66 package fakecgo
77
8+import "structs"
9+
810 type (
911 size_t uintptr
1012 // Sources:
@@ -28,11 +30,13 @@ const (
2830 )
2931
3032 type G struct {
33+ _ structs.HostLayout
3134 stacklo uintptr
3235 stackhi uintptr
3336 }
3437
3538 type ThreadStart struct {
39+ _ structs.HostLayout
3640 g *G
3741 tls *uintptr
3842 fn uintptr
@@ -5,6 +5,8 @@
5 5
6 package fakecgo6 package fakecgo
7 7
8+import "structs"
9+
8 type (10 type (
9 size_t uintptr11 size_t uintptr
10 // Sources:12 // Sources:
@@ -28,11 +30,13 @@ const (
28 )30 )
29 31
30 type G struct {32 type G struct {
33+ _ structs.HostLayout
31 stacklo uintptr34 stacklo uintptr
32 stackhi uintptr35 stackhi uintptr
33 }36 }
34 37
35 type ThreadStart struct {38 type ThreadStart struct {
39+ _ structs.HostLayout
36 g *G40 g *G
37 tls *uintptr41 tls *uintptr
38 fn uintptr42 fn uintptr
M internal/fakecgo/libcgo_darwin.go +4 -0
@@ -5,12 +5,16 @@
55
66 package fakecgo
77
8+import "structs"
9+
810 type (
911 pthread_mutex_t struct {
12+ _ structs.HostLayout
1013 sig int64
1114 opaque [56]byte
1215 }
1316 pthread_cond_t struct {
17+ _ structs.HostLayout
1418 sig int64
1519 opaque [40]byte
1620 }
@@ -5,12 +5,16 @@
5 5
6 package fakecgo6 package fakecgo
7 7
8+import "structs"
9+
8 type (10 type (
9 pthread_mutex_t struct {11 pthread_mutex_t struct {
12+ _ structs.HostLayout
10 sig int6413 sig int64
11 opaque [56]byte14 opaque [56]byte
12 }15 }
13 pthread_cond_t struct {16 pthread_cond_t struct {
17+ _ structs.HostLayout
14 sig int6418 sig int64
15 opaque [40]byte19 opaque [40]byte
16 }20 }
M internal/fakecgo/libcgo_netbsd.go +3 -0
@@ -5,6 +5,8 @@
55
66 package fakecgo
77
8+import "structs"
9+
810 type (
911 pthread_cond_t uintptr
1012 pthread_mutex_t uintptr
@@ -17,6 +19,7 @@ var (
1719
1820 // Source: https://github.com/NetBSD/src/blob/613e27c65223fd2283b6ed679da1197e12f50e27/sys/sys/signal.h#L225
1921 type stack_t struct {
22+ _ structs.HostLayout
2023 ss_sp uintptr
2124 ss_size uintptr
2225 ss_flags int32
@@ -5,6 +5,8 @@
5 5
6 package fakecgo6 package fakecgo
7 7
8+import "structs"
9+
8 type (10 type (
9 pthread_cond_t uintptr11 pthread_cond_t uintptr
10 pthread_mutex_t uintptr12 pthread_mutex_t uintptr
@@ -17,6 +19,7 @@ var (
17 19
18 // Source: https://github.com/NetBSD/src/blob/613e27c65223fd2283b6ed679da1197e12f50e27/sys/sys/signal.h#L22520 // Source: https://github.com/NetBSD/src/blob/613e27c65223fd2283b6ed679da1197e12f50e27/sys/sys/signal.h#L225
19 type stack_t struct {21 type stack_t struct {
22+ _ structs.HostLayout
20 ss_sp uintptr23 ss_sp uintptr
21 ss_size uintptr24 ss_size uintptr
22 ss_flags int3225 ss_flags int32
M internal/fakecgo/linux.go +7 -2
@@ -6,10 +6,15 @@
66
77 package fakecgo
88
9-import "unsafe"
9+import (
10+ "structs"
11+ "unsafe"
12+)
1013
11-// argset matches runtime/cgocall.go:argset.
14+// argset matches runtime/cgocall.go:argset, which in turn matches
15+// runtime/cgo/linux_syscall.c:argset_t.
1216 type argset struct {
17+ _ structs.HostLayout
1318 args *uintptr
1419 retval uintptr
1520 }
@@ -6,10 +6,15 @@
6 6
7 package fakecgo7 package fakecgo
8 8
9-import "unsafe"9+import (
10+ "structs"
11+ "unsafe"
12+)
10 13
11-// argset matches runtime/cgocall.go:argset.14+// argset matches runtime/cgocall.go:argset, which in turn matches
15+// runtime/cgo/linux_syscall.c:argset_t.
12 type argset struct {16 type argset struct {
17+ _ structs.HostLayout
13 args *uintptr18 args *uintptr
14 retval uintptr19 retval uintptr
15 }20 }
M objc/encoding_darwin_test.go +2 -0
@@ -10,11 +10,13 @@ import (
1010 "path/filepath"
1111 "reflect"
1212 "strings"
13+ "structs"
1314 "testing"
1415 "unsafe"
1516 )
1617
1718 type encodeTypeTestStruct struct {
19+ _ structs.HostLayout
1820 A int32
1921 B float64
2022 }
@@ -10,11 +10,13 @@ import (
10 "path/filepath"10 "path/filepath"
11 "reflect"11 "reflect"
12 "strings"12 "strings"
13+ "structs"
13 "testing"14 "testing"
14 "unsafe"15 "unsafe"
15 )16 )
16 17
17 type encodeTypeTestStruct struct {18 type encodeTypeTestStruct struct {
19+ _ structs.HostLayout
18 A int3220 A int32
19 B float6421 B float64
20 }22 }
M objc/objc_block_darwin.go +3 -0
@@ -6,6 +6,7 @@ package objc
66 import (
77 "fmt"
88 "reflect"
9+ "structs"
910 "sync"
1011 "unsafe"
1112
@@ -34,6 +35,7 @@ const (
3435 //
3536 // The layout of this struct matches Block_literal_1 described in https://clang.llvm.org/docs/Block-ABI-Apple.html#high-level
3637 type blockDescriptor struct {
38+ _ structs.HostLayout
3739 _ uintptr
3840 size uintptr
3941 _ uintptr
@@ -47,6 +49,7 @@ type blockDescriptor struct {
4749 //
4850 // The layout of this struct matches __block_literal_1 described in https://clang.llvm.org/docs/Block-ABI-Apple.html#high-level
4951 type blockLayout struct {
52+ _ structs.HostLayout
5053 isa Class
5154 flags uint32
5255 _ uint32
@@ -6,6 +6,7 @@ package objc
6 import (6 import (
7 "fmt"7 "fmt"
8 "reflect"8 "reflect"
9+ "structs"
9 "sync"10 "sync"
10 "unsafe"11 "unsafe"
11 12
@@ -34,6 +35,7 @@ const (
34 //35 //
35 // The layout of this struct matches Block_literal_1 described in https://clang.llvm.org/docs/Block-ABI-Apple.html#high-level36 // The layout of this struct matches Block_literal_1 described in https://clang.llvm.org/docs/Block-ABI-Apple.html#high-level
36 type blockDescriptor struct {37 type blockDescriptor struct {
38+ _ structs.HostLayout
37 _ uintptr39 _ uintptr
38 size uintptr40 size uintptr
39 _ uintptr41 _ uintptr
@@ -47,6 +49,7 @@ type blockDescriptor struct {
47 //49 //
48 // The layout of this struct matches __block_literal_1 described in https://clang.llvm.org/docs/Block-ABI-Apple.html#high-level50 // The layout of this struct matches __block_literal_1 described in https://clang.llvm.org/docs/Block-ABI-Apple.html#high-level
49 type blockLayout struct {51 type blockLayout struct {
52+ _ structs.HostLayout
50 isa Class53 isa Class
51 flags uint3254 flags uint32
52 _ uint3255 _ uint32
M objc/objc_block_darwin_test.go +2 -0
@@ -5,6 +5,7 @@ package objc_test
55
66 import (
77 "fmt"
8+ "structs"
89 "testing"
910
1011 "github.com/ebitengine/purego"
@@ -39,6 +40,7 @@ func ExampleNewBlock() {
3940
4041 func ExampleInvokeBlock() {
4142 type vector struct {
43+ _ structs.HostLayout
4244 X, Y, Z float64
4345 }
4446
@@ -5,6 +5,7 @@ package objc_test
5 5
6 import (6 import (
7 "fmt"7 "fmt"
8+ "structs"
8 "testing"9 "testing"
9 10
10 "github.com/ebitengine/purego"11 "github.com/ebitengine/purego"
@@ -39,6 +40,7 @@ func ExampleNewBlock() {
39 40
40 func ExampleInvokeBlock() {41 func ExampleInvokeBlock() {
41 type vector struct {42 type vector struct {
43+ _ structs.HostLayout
42 X, Y, Z float6444 X, Y, Z float64
43 }45 }
44 46
M objc/objc_runtime_darwin.go +15 -0
@@ -14,6 +14,7 @@ import (
1414 "runtime"
1515 "slices"
1616 stdstrings "strings"
17+ "structs"
1718 "unicode"
1819 "unsafe"
1920
@@ -21,6 +22,8 @@ import (
2122 "github.com/ebitengine/purego/internal/strings"
2223 )
2324
25+var hostLayoutType = reflect.TypeFor[structs.HostLayout]()
26+
2427 // TODO: support try/catch?
2528 // https://stackoverflow.com/questions/7062599/example-of-how-objective-cs-try-catch-implementation-is-executed-at-runtime
2629 var (
@@ -172,6 +175,7 @@ func Send[T any](id ID, sel SEL, args ...any) T {
172175 // as the receiver of a message. It specifies the class definition of the particular superclass that should
173176 // be messaged.
174177 type objc_super struct {
178+ _ structs.HostLayout
175179 receiver ID
176180 superClass Class
177181 }
@@ -470,6 +474,13 @@ func encodeType(typ reflect.Type, insidePtr bool) (string, error) {
470474 encoding.WriteString("=")
471475 for i := 0; i < typ.NumField(); i++ {
472476 f := typ.Field(i)
477+ if f.Type.ConvertibleTo(hostLayoutType) {
478+ // The structs.HostLayout marker is a signal to the Go compiler
479+ // with no counterpart in C, so it is not a member as far as
480+ // @encode is concerned. Other zero-sized fields are: clang
481+ // encodes a zero-length array member as [0c].
482+ continue
483+ }
473484 tmp, err := encodeType(f.Type, false)
474485 if err != nil {
475486 return "", err
@@ -571,7 +582,9 @@ func (i Ivar) Name() string {
571582 }
572583
573584 // MethodDescription holds the name and type definition of a method.
585+// It matches the Objective-C runtime's struct objc_method_description.
574586 type MethodDescription struct {
587+ _ structs.HostLayout
575588 name, types uintptr
576589 }
577590
@@ -586,7 +599,9 @@ func (m MethodDescription) Types() string {
586599 }
587600
588601 // PropertyAttribute contains the null-terminated Name and Value pair of a Properties internal description.
602+// It matches the Objective-C runtime's objc_property_attribute_t.
589603 type PropertyAttribute struct {
604+ _ structs.HostLayout
590605 Name, Value *byte
591606 }
592607
@@ -14,6 +14,7 @@ import (
14 "runtime"14 "runtime"
15 "slices"15 "slices"
16 stdstrings "strings"16 stdstrings "strings"
17+ "structs"
17 "unicode"18 "unicode"
18 "unsafe"19 "unsafe"
19 20
@@ -21,6 +22,8 @@ import (
21 "github.com/ebitengine/purego/internal/strings"22 "github.com/ebitengine/purego/internal/strings"
22 )23 )
23 24
25+var hostLayoutType = reflect.TypeFor[structs.HostLayout]()
26+
24 // TODO: support try/catch?27 // TODO: support try/catch?
25 // https://stackoverflow.com/questions/7062599/example-of-how-objective-cs-try-catch-implementation-is-executed-at-runtime28 // https://stackoverflow.com/questions/7062599/example-of-how-objective-cs-try-catch-implementation-is-executed-at-runtime
26 var (29 var (
@@ -172,6 +175,7 @@ func Send[T any](id ID, sel SEL, args ...any) T {
172 // as the receiver of a message. It specifies the class definition of the particular superclass that should175 // as the receiver of a message. It specifies the class definition of the particular superclass that should
173 // be messaged.176 // be messaged.
174 type objc_super struct {177 type objc_super struct {
178+ _ structs.HostLayout
175 receiver ID179 receiver ID
176 superClass Class180 superClass Class
177 }181 }
@@ -470,6 +474,13 @@ func encodeType(typ reflect.Type, insidePtr bool) (string, error) {
470 encoding.WriteString("=")474 encoding.WriteString("=")
471 for i := 0; i < typ.NumField(); i++ {475 for i := 0; i < typ.NumField(); i++ {
472 f := typ.Field(i)476 f := typ.Field(i)
477+ if f.Type.ConvertibleTo(hostLayoutType) {
478+ // The structs.HostLayout marker is a signal to the Go compiler
479+ // with no counterpart in C, so it is not a member as far as
480+ // @encode is concerned. Other zero-sized fields are: clang
481+ // encodes a zero-length array member as [0c].
482+ continue
483+ }
473 tmp, err := encodeType(f.Type, false)484 tmp, err := encodeType(f.Type, false)
474 if err != nil {485 if err != nil {
475 return "", err486 return "", err
@@ -571,7 +582,9 @@ func (i Ivar) Name() string {
571 }582 }
572 583
573 // MethodDescription holds the name and type definition of a method.584 // MethodDescription holds the name and type definition of a method.
585+// It matches the Objective-C runtime's struct objc_method_description.
574 type MethodDescription struct {586 type MethodDescription struct {
587+ _ structs.HostLayout
575 name, types uintptr588 name, types uintptr
576 }589 }
577 590
@@ -586,7 +599,9 @@ func (m MethodDescription) Types() string {
586 }599 }
587 600
588 // PropertyAttribute contains the null-terminated Name and Value pair of a Properties internal description.601 // PropertyAttribute contains the null-terminated Name and Value pair of a Properties internal description.
602+// It matches the Objective-C runtime's objc_property_attribute_t.
589 type PropertyAttribute struct {603 type PropertyAttribute struct {
604+ _ structs.HostLayout
590 Name, Value *byte605 Name, Value *byte
591 }606 }
592 607
M objc/objc_runtime_darwin_test.go +4 -2
@@ -7,6 +7,7 @@ import (
77 "fmt"
88 "log"
99 "reflect"
10+ "structs"
1011 "testing"
1112
1213 "github.com/ebitengine/purego"
@@ -155,6 +156,7 @@ func TestSend(t *testing.T) {
155156
156157 func ExampleSend() {
157158 type NSRange struct {
159+ _ structs.HostLayout
158160 Location, Range uint
159161 }
160162 class_NSString := objc.GetClass("NSString")
@@ -164,8 +166,8 @@ func ExampleSend() {
164166 subString := objc.ID(class_NSString).Send(sel_stringWithUTF8String, "lo, Wor\x00")
165167
166168 r := objc.Send[NSRange](fullString, objc.RegisterName("rangeOfString:"), subString)
167- fmt.Println(r)
168- // Output: {3 7}
169+ fmt.Println(r.Location, r.Range)
170+ // Output: 3 7
169171 }
170172
171173 func ExampleSendSuper() {
@@ -7,6 +7,7 @@ import (
7 "fmt"7 "fmt"
8 "log"8 "log"
9 "reflect"9 "reflect"
10+ "structs"
10 "testing"11 "testing"
11 12
12 "github.com/ebitengine/purego"13 "github.com/ebitengine/purego"
@@ -155,6 +156,7 @@ func TestSend(t *testing.T) {
155 156
156 func ExampleSend() {157 func ExampleSend() {
157 type NSRange struct {158 type NSRange struct {
159+ _ structs.HostLayout
158 Location, Range uint160 Location, Range uint
159 }161 }
160 class_NSString := objc.GetClass("NSString")162 class_NSString := objc.GetClass("NSString")
@@ -164,8 +166,8 @@ func ExampleSend() {
164 subString := objc.ID(class_NSString).Send(sel_stringWithUTF8String, "lo, Wor\x00")166 subString := objc.ID(class_NSString).Send(sel_stringWithUTF8String, "lo, Wor\x00")
165 167
166 r := objc.Send[NSRange](fullString, objc.RegisterName("rangeOfString:"), subString)168 r := objc.Send[NSRange](fullString, objc.RegisterName("rangeOfString:"), subString)
167- fmt.Println(r)169+ fmt.Println(r.Location, r.Range)
168- // Output: {3 7}170+ // Output: 3 7
169 }171 }
170 172
171 func ExampleSendSuper() {173 func ExampleSendSuper() {
M struct_amd64.go +13 -6
@@ -66,23 +66,24 @@ func getStruct(outType reflect.Type, syscall syscallArgs) (v reflect.Value) {
6666 } else {
6767 // check first 8 bytes if it's floats
6868 hasFirstFloat := false
69- f1 := outType.Field(0).Type
70- if f1.Kind() == reflect.Float64 || f1.Kind() == reflect.Float32 && outType.Field(1).Type.Kind() == reflect.Float32 {
69+ numFields := numABIFields(outType)
70+ f1 := abiField(outType, 0).Type
71+ if f1.Kind() == reflect.Float64 || f1.Kind() == reflect.Float32 && abiField(outType, 1).Type.Kind() == reflect.Float32 {
7172 r1 = syscall.f1
7273 hasFirstFloat = true
7374 }
7475
7576 // find index of the field that starts the second 8 bytes
7677 var i int
77- for i = 0; i < outType.NumField(); i++ {
78- if outType.Field(i).Offset == 8 {
78+ for i = 0; i < numFields; i++ {
79+ if abiField(outType, i).Offset == 8 {
7980 break
8081 }
8182 }
8283
8384 // check last 8 bytes if they are floats
84- f1 = outType.Field(i).Type
85- if f1.Kind() == reflect.Float64 || f1.Kind() == reflect.Float32 && i+1 == outType.NumField() {
85+ f1 = abiField(outType, i).Type
86+ if f1.Kind() == reflect.Float64 || f1.Kind() == reflect.Float32 && i+1 == numFields {
8687 r2 = syscall.f1
8788 } else if hasFirstFloat {
8889 // if the first field was a float then that means the second integer field
@@ -101,6 +102,9 @@ func getStruct(outType reflect.Type, syscall syscallArgs) (v reflect.Value) {
101102 func isAllFloats(ty reflect.Type) bool {
102103 for i := 0; i < ty.NumField(); i++ {
103104 f := ty.Field(i)
105+ if !isABIField(f) {
106+ continue
107+ }
104108 switch f.Type.Kind() {
105109 case reflect.Float64, reflect.Float32:
106110 default:
@@ -217,6 +221,9 @@ func tryPlaceRegister(v reflect.Value, addFloat func(uintptr), addInt func(uintp
217221 }
218222
219223 for i := 0; i < numFields; i++ {
224+ if v.Kind() == reflect.Struct && !isABIField(v.Type().Field(i)) {
225+ continue
226+ }
220227 flushed = false
221228 var f reflect.Value
222229 if v.Kind() == reflect.Struct {
@@ -66,23 +66,24 @@ func getStruct(outType reflect.Type, syscall syscallArgs) (v reflect.Value) {
66 } else {66 } else {
67 // check first 8 bytes if it's floats67 // check first 8 bytes if it's floats
68 hasFirstFloat := false68 hasFirstFloat := false
69- f1 := outType.Field(0).Type69+ numFields := numABIFields(outType)
70- if f1.Kind() == reflect.Float64 || f1.Kind() == reflect.Float32 && outType.Field(1).Type.Kind() == reflect.Float32 {70+ f1 := abiField(outType, 0).Type
71+ if f1.Kind() == reflect.Float64 || f1.Kind() == reflect.Float32 && abiField(outType, 1).Type.Kind() == reflect.Float32 {
71 r1 = syscall.f172 r1 = syscall.f1
72 hasFirstFloat = true73 hasFirstFloat = true
73 }74 }
74 75
75 // find index of the field that starts the second 8 bytes76 // find index of the field that starts the second 8 bytes
76 var i int77 var i int
77- for i = 0; i < outType.NumField(); i++ {78+ for i = 0; i < numFields; i++ {
78- if outType.Field(i).Offset == 8 {79+ if abiField(outType, i).Offset == 8 {
79 break80 break
80 }81 }
81 }82 }
82 83
83 // check last 8 bytes if they are floats84 // check last 8 bytes if they are floats
84- f1 = outType.Field(i).Type85+ f1 = abiField(outType, i).Type
85- if f1.Kind() == reflect.Float64 || f1.Kind() == reflect.Float32 && i+1 == outType.NumField() {86+ if f1.Kind() == reflect.Float64 || f1.Kind() == reflect.Float32 && i+1 == numFields {
86 r2 = syscall.f187 r2 = syscall.f1
87 } else if hasFirstFloat {88 } else if hasFirstFloat {
88 // if the first field was a float then that means the second integer field89 // if the first field was a float then that means the second integer field
@@ -101,6 +102,9 @@ func getStruct(outType reflect.Type, syscall syscallArgs) (v reflect.Value) {
101 func isAllFloats(ty reflect.Type) bool {102 func isAllFloats(ty reflect.Type) bool {
102 for i := 0; i < ty.NumField(); i++ {103 for i := 0; i < ty.NumField(); i++ {
103 f := ty.Field(i)104 f := ty.Field(i)
105+ if !isABIField(f) {
106+ continue
107+ }
104 switch f.Type.Kind() {108 switch f.Type.Kind() {
105 case reflect.Float64, reflect.Float32:109 case reflect.Float64, reflect.Float32:
106 default:110 default:
@@ -217,6 +221,9 @@ func tryPlaceRegister(v reflect.Value, addFloat func(uintptr), addInt func(uintp
217 }221 }
218 222
219 for i := 0; i < numFields; i++ {223 for i := 0; i < numFields; i++ {
224+ if v.Kind() == reflect.Struct && !isABIField(v.Type().Field(i)) {
225+ continue
226+ }
220 flushed = false227 flushed = false
221 var f reflect.Value228 var f reflect.Value
222 if v.Kind() == reflect.Struct {229 if v.Kind() == reflect.Struct {
M struct_arm64.go +23 -18
@@ -85,9 +85,9 @@ func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFl
8585 if hva, hfa, size := isHVA(v.Type()), isHFA(v.Type()), v.Type().Size(); hva || hfa || size <= 16 {
8686 // if this doesn't fit entirely in registers then
8787 // each element goes onto the stack
88- if hfa && *numFloats+v.NumField() > numOfFloatRegisters() {
88+ if hfa && *numFloats+numABIFields(v.Type()) > numOfFloatRegisters() {
8989 *numFloats = numOfFloatRegisters()
90- } else if hva && *numInts+v.NumField() > numOfIntegerRegisters() {
90+ } else if hva && *numInts+numABIFields(v.Type()) > numOfIntegerRegisters() {
9191 *numInts = numOfIntegerRegisters()
9292 }
9393
@@ -120,6 +120,9 @@ func placeRegistersArm64(v reflect.Value, addFloat func(uintptr), addInt func(ui
120120 numFields = v.Type().Len()
121121 }
122122 for k := 0; k < numFields; k++ {
123+ if v.Kind() == reflect.Struct && !isABIField(v.Type().Field(k)) {
124+ continue
125+ }
123126 flushed = false
124127 var f reflect.Value
125128 if v.Kind() == reflect.Struct {
@@ -238,15 +241,16 @@ func placeStack(v reflect.Value, keepAlive []any, addInt func(uintptr)) []any {
238241 func isHFA(t reflect.Type) bool {
239242 // round up struct size to nearest 8 see section B.4
240243 structSize := roundUpTo8(t.Size())
241- if structSize == 0 || t.NumField() > 4 {
244+ numFields := numABIFields(t)
245+ if structSize == 0 || numFields > 4 {
242246 return false
243247 }
244- first := t.Field(0)
248+ first := abiField(t, 0)
245249 switch first.Type.Kind() {
246250 case reflect.Float32, reflect.Float64:
247251 firstKind := first.Type.Kind()
248- for i := 0; i < t.NumField(); i++ {
249- if t.Field(i).Type.Kind() != firstKind {
252+ for i := 0; i < numFields; i++ {
253+ if abiField(t, i).Type.Kind() != firstKind {
250254 return false
251255 }
252256 }
@@ -259,7 +263,7 @@ func isHFA(t reflect.Type) bool {
259263 return false
260264 }
261265 case reflect.Struct:
262- for i := 0; i < first.Type.NumField(); i++ {
266+ for i := 0; i < numABIFields(first.Type); i++ {
263267 if !isHFA(first.Type) {
264268 return false
265269 }
@@ -283,12 +287,13 @@ func isHVA(t reflect.Type) bool {
283287 if structSize == 0 || (structSize != 8 && structSize != 16) {
284288 return false
285289 }
286- first := t.Field(0)
290+ numFields := numABIFields(t)
291+ first := abiField(t, 0)
287292 switch first.Type.Kind() {
288293 case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Int8, reflect.Int16, reflect.Int32:
289294 firstKind := first.Type.Kind()
290- for i := 0; i < t.NumField(); i++ {
291- if t.Field(i).Type.Kind() != firstKind {
295+ for i := 0; i < numFields; i++ {
296+ if abiField(t, i).Type.Kind() != firstKind {
292297 return false
293298 }
294299 }
@@ -388,12 +393,12 @@ func shouldBundleStackArgs(v reflect.Value, numInts, numFloats int) bool {
388393 }
389394
390395 if hfa {
391- need := v.NumField()
396+ need := numABIFields(v.Type())
392397 return numFloats+need > numOfFloatRegisters()
393398 }
394399
395400 if hva {
396- need := v.NumField()
401+ need := numABIFields(v.Type())
397402 return numInts+need > numOfIntegerRegisters()
398403 }
399404
@@ -414,13 +419,13 @@ func structFitsInRegisters(val reflect.Value, tempNumInts, tempNumFloats int) (b
414419
415420 if hfa {
416421 // HFA: check if elements fit in float registers
417- if tempNumFloats+val.NumField() <= numOfFloatRegisters() {
418- return true, tempNumInts, tempNumFloats + val.NumField()
422+ if numFields := numABIFields(val.Type()); tempNumFloats+numFields <= numOfFloatRegisters() {
423+ return true, tempNumInts, tempNumFloats + numFields
419424 }
420425 } else if hva {
421426 // HVA: check if elements fit in int registers
422- if tempNumInts+val.NumField() <= numOfIntegerRegisters() {
423- return true, tempNumInts + val.NumField(), tempNumFloats
427+ if numFields := numABIFields(val.Type()); tempNumInts+numFields <= numOfIntegerRegisters() {
428+ return true, tempNumInts + numFields, tempNumFloats
424429 }
425430 } else if size <= 16 {
426431 // Non-HFA/HVA small structs use int registers for byte-packing
@@ -633,9 +638,9 @@ func readHFAFromRegisters(inType reflect.Type, f *[callbackMaxFrame]uintptr, flo
633638 size := inType.Size()
634639
635640 // Determine the element type
636- root := inType.Field(0).Type
641+ root := abiField(inType, 0).Type
637642 for root.Kind() == reflect.Struct {
638- root = root.Field(0).Type
643+ root = abiField(root, 0).Type
639644 }
640645 isFloat32 := root.Kind() == reflect.Float32
641646
@@ -85,9 +85,9 @@ func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFl
85 if hva, hfa, size := isHVA(v.Type()), isHFA(v.Type()), v.Type().Size(); hva || hfa || size <= 16 {85 if hva, hfa, size := isHVA(v.Type()), isHFA(v.Type()), v.Type().Size(); hva || hfa || size <= 16 {
86 // if this doesn't fit entirely in registers then86 // if this doesn't fit entirely in registers then
87 // each element goes onto the stack87 // each element goes onto the stack
88- if hfa && *numFloats+v.NumField() > numOfFloatRegisters() {88+ if hfa && *numFloats+numABIFields(v.Type()) > numOfFloatRegisters() {
89 *numFloats = numOfFloatRegisters()89 *numFloats = numOfFloatRegisters()
90- } else if hva && *numInts+v.NumField() > numOfIntegerRegisters() {90+ } else if hva && *numInts+numABIFields(v.Type()) > numOfIntegerRegisters() {
91 *numInts = numOfIntegerRegisters()91 *numInts = numOfIntegerRegisters()
92 }92 }
93 93
@@ -120,6 +120,9 @@ func placeRegistersArm64(v reflect.Value, addFloat func(uintptr), addInt func(ui
120 numFields = v.Type().Len()120 numFields = v.Type().Len()
121 }121 }
122 for k := 0; k < numFields; k++ {122 for k := 0; k < numFields; k++ {
123+ if v.Kind() == reflect.Struct && !isABIField(v.Type().Field(k)) {
124+ continue
125+ }
123 flushed = false126 flushed = false
124 var f reflect.Value127 var f reflect.Value
125 if v.Kind() == reflect.Struct {128 if v.Kind() == reflect.Struct {
@@ -238,15 +241,16 @@ func placeStack(v reflect.Value, keepAlive []any, addInt func(uintptr)) []any {
238 func isHFA(t reflect.Type) bool {241 func isHFA(t reflect.Type) bool {
239 // round up struct size to nearest 8 see section B.4242 // round up struct size to nearest 8 see section B.4
240 structSize := roundUpTo8(t.Size())243 structSize := roundUpTo8(t.Size())
241- if structSize == 0 || t.NumField() > 4 {244+ numFields := numABIFields(t)
245+ if structSize == 0 || numFields > 4 {
242 return false246 return false
243 }247 }
244- first := t.Field(0)248+ first := abiField(t, 0)
245 switch first.Type.Kind() {249 switch first.Type.Kind() {
246 case reflect.Float32, reflect.Float64:250 case reflect.Float32, reflect.Float64:
247 firstKind := first.Type.Kind()251 firstKind := first.Type.Kind()
248- for i := 0; i < t.NumField(); i++ {252+ for i := 0; i < numFields; i++ {
249- if t.Field(i).Type.Kind() != firstKind {253+ if abiField(t, i).Type.Kind() != firstKind {
250 return false254 return false
251 }255 }
252 }256 }
@@ -259,7 +263,7 @@ func isHFA(t reflect.Type) bool {
259 return false263 return false
260 }264 }
261 case reflect.Struct:265 case reflect.Struct:
262- for i := 0; i < first.Type.NumField(); i++ {266+ for i := 0; i < numABIFields(first.Type); i++ {
263 if !isHFA(first.Type) {267 if !isHFA(first.Type) {
264 return false268 return false
265 }269 }
@@ -283,12 +287,13 @@ func isHVA(t reflect.Type) bool {
283 if structSize == 0 || (structSize != 8 && structSize != 16) {287 if structSize == 0 || (structSize != 8 && structSize != 16) {
284 return false288 return false
285 }289 }
286- first := t.Field(0)290+ numFields := numABIFields(t)
291+ first := abiField(t, 0)
287 switch first.Type.Kind() {292 switch first.Type.Kind() {
288 case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Int8, reflect.Int16, reflect.Int32:293 case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Int8, reflect.Int16, reflect.Int32:
289 firstKind := first.Type.Kind()294 firstKind := first.Type.Kind()
290- for i := 0; i < t.NumField(); i++ {295+ for i := 0; i < numFields; i++ {
291- if t.Field(i).Type.Kind() != firstKind {296+ if abiField(t, i).Type.Kind() != firstKind {
292 return false297 return false
293 }298 }
294 }299 }
@@ -388,12 +393,12 @@ func shouldBundleStackArgs(v reflect.Value, numInts, numFloats int) bool {
388 }393 }
389 394
390 if hfa {395 if hfa {
391- need := v.NumField()396+ need := numABIFields(v.Type())
392 return numFloats+need > numOfFloatRegisters()397 return numFloats+need > numOfFloatRegisters()
393 }398 }
394 399
395 if hva {400 if hva {
396- need := v.NumField()401+ need := numABIFields(v.Type())
397 return numInts+need > numOfIntegerRegisters()402 return numInts+need > numOfIntegerRegisters()
398 }403 }
399 404
@@ -414,13 +419,13 @@ func structFitsInRegisters(val reflect.Value, tempNumInts, tempNumFloats int) (b
414 419
415 if hfa {420 if hfa {
416 // HFA: check if elements fit in float registers421 // HFA: check if elements fit in float registers
417- if tempNumFloats+val.NumField() <= numOfFloatRegisters() {422+ if numFields := numABIFields(val.Type()); tempNumFloats+numFields <= numOfFloatRegisters() {
418- return true, tempNumInts, tempNumFloats + val.NumField()423+ return true, tempNumInts, tempNumFloats + numFields
419 }424 }
420 } else if hva {425 } else if hva {
421 // HVA: check if elements fit in int registers426 // HVA: check if elements fit in int registers
422- if tempNumInts+val.NumField() <= numOfIntegerRegisters() {427+ if numFields := numABIFields(val.Type()); tempNumInts+numFields <= numOfIntegerRegisters() {
423- return true, tempNumInts + val.NumField(), tempNumFloats428+ return true, tempNumInts + numFields, tempNumFloats
424 }429 }
425 } else if size <= 16 {430 } else if size <= 16 {
426 // Non-HFA/HVA small structs use int registers for byte-packing431 // Non-HFA/HVA small structs use int registers for byte-packing
@@ -633,9 +638,9 @@ func readHFAFromRegisters(inType reflect.Type, f *[callbackMaxFrame]uintptr, flo
633 size := inType.Size()638 size := inType.Size()
634 639
635 // Determine the element type640 // Determine the element type
636- root := inType.Field(0).Type641+ root := abiField(inType, 0).Type
637 for root.Kind() == reflect.Struct {642 for root.Kind() == reflect.Struct {
638- root = root.Field(0).Type643+ root = abiField(root, 0).Type
639 }644 }
640 isFloat32 := root.Kind() == reflect.Float32645 isFloat32 := root.Kind() == reflect.Float32
641 646
M struct_riscv64.go +1 -1
@@ -34,7 +34,7 @@ func getStruct(outType reflect.Type, syscall syscallArgs) reflect.Value {
3434
3535 // Homogeneous float aggregates override integer regs
3636 if isAllFloats, numFields := isAllSameFloat(outType); isAllFloats {
37- if outType.Field(0).Type.Kind() == reflect.Float32 {
37+ if abiField(outType, 0).Type.Kind() == reflect.Float32 {
3838 // float32 values are NaN-boxed in FP regs; use low 32 bits only
3939 f := []uintptr{syscall.f1, syscall.f2, syscall.f3, syscall.f4}
4040 for i := 0; i < numFields; i++ {
@@ -34,7 +34,7 @@ func getStruct(outType reflect.Type, syscall syscallArgs) reflect.Value {
34 34
35 // Homogeneous float aggregates override integer regs35 // Homogeneous float aggregates override integer regs
36 if isAllFloats, numFields := isAllSameFloat(outType); isAllFloats {36 if isAllFloats, numFields := isAllSameFloat(outType); isAllFloats {
37- if outType.Field(0).Type.Kind() == reflect.Float32 {37+ if abiField(outType, 0).Type.Kind() == reflect.Float32 {
38 // float32 values are NaN-boxed in FP regs; use low 32 bits only38 // float32 values are NaN-boxed in FP regs; use low 32 bits only
39 f := []uintptr{syscall.f1, syscall.f2, syscall.f3, syscall.f4}39 f := []uintptr{syscall.f1, syscall.f2, syscall.f3, syscall.f4}
40 for i := 0; i < numFields; i++ {40 for i := 0; i < numFields; i++ {
M struct_s390x.go +1 -1
@@ -34,7 +34,7 @@ func getStruct(outType reflect.Type, syscall syscallArgs) reflect.Value {
3434
3535 // Homogeneous float aggregates override integer regs
3636 if isAllFloats, numFields := isAllSameFloat(outType); isAllFloats {
37- if outType.Field(0).Type.Kind() == reflect.Float32 {
37+ if abiField(outType, 0).Type.Kind() == reflect.Float32 {
3838 // float32 values in FP regs
3939 f := []uintptr{syscall.f1, syscall.f2, syscall.f3, syscall.f4}
4040 for i := 0; i < numFields; i++ {
@@ -34,7 +34,7 @@ func getStruct(outType reflect.Type, syscall syscallArgs) reflect.Value {
34 34
35 // Homogeneous float aggregates override integer regs35 // Homogeneous float aggregates override integer regs
36 if isAllFloats, numFields := isAllSameFloat(outType); isAllFloats {36 if isAllFloats, numFields := isAllSameFloat(outType); isAllFloats {
37- if outType.Field(0).Type.Kind() == reflect.Float32 {37+ if abiField(outType, 0).Type.Kind() == reflect.Float32 {
38 // float32 values in FP regs38 // float32 values in FP regs
39 f := []uintptr{syscall.f1, syscall.f2, syscall.f3, syscall.f4}39 f := []uintptr{syscall.f1, syscall.f2, syscall.f3, syscall.f4}
40 for i := 0; i < numFields; i++ {40 for i := 0; i < numFields; i++ {
M struct_test.go +266 -93
@@ -13,6 +13,7 @@ import (
1313 "reflect"
1414 "runtime"
1515 "slices"
16+ "structs"
1617 "testing"
1718 "unsafe"
1819
@@ -89,7 +90,9 @@ func TestRegisterFunc_structArgs(t *testing.T) {
8990 t.Run(imp.name, func(t *testing.T) {
9091 register := imp.register
9192 {
92- type Empty struct{}
93+ type Empty struct {
94+ _ structs.HostLayout
95+ }
9396 var NoStruct func(Empty) int64
9497 register(&NoStruct, lib, "NoStruct", func(Empty) int64 {
9598 return 0xdeadbeef
@@ -99,7 +102,9 @@ func TestRegisterFunc_structArgs(t *testing.T) {
99102 }
100103 }
101104 {
102- type EmptyEmpty struct{}
105+ type EmptyEmpty struct {
106+ _ structs.HostLayout
107+ }
103108 var EmptyEmptyFn func(EmptyEmpty) int64
104109 register(&EmptyEmptyFn, lib, "EmptyEmpty", func(EmptyEmpty) int64 {
105110 return 0xdeadbeef
@@ -117,6 +122,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
117122 }
118123 {
119124 type GreaterThan16Bytes struct {
125+ _ structs.HostLayout
120126 x, y, z *int64
121127 }
122128 var x, y, z int64 = 0xEF, 0xBE00, 0xDEAD0000
@@ -130,7 +136,9 @@ func TestRegisterFunc_structArgs(t *testing.T) {
130136 }
131137 {
132138 type GreaterThan16BytesStruct struct {
139+ _ structs.HostLayout
133140 a struct {
141+ _ structs.HostLayout
134142 x, y, z *int64
135143 }
136144 }
@@ -139,12 +147,16 @@ func TestRegisterFunc_structArgs(t *testing.T) {
139147 register(&GreaterThan16BytesStructFn, lib, "GreaterThan16BytesStruct", func(g GreaterThan16BytesStruct) int64 {
140148 return *g.a.x + *g.a.y + *g.a.z
141149 })
142- if ret := GreaterThan16BytesStructFn(GreaterThan16BytesStruct{a: struct{ x, y, z *int64 }{x: &x, y: &y, z: &z}}); ret != expectedUnsigned {
150+ if ret := GreaterThan16BytesStructFn(GreaterThan16BytesStruct{a: struct {
151+ _ structs.HostLayout
152+ x, y, z *int64
153+ }{x: &x, y: &y, z: &z}}); ret != expectedUnsigned {
143154 t.Fatalf("GreaterThan16BytesStructFn returned %#x wanted %#x", ret, expectedUnsigned)
144155 }
145156 }
146157 {
147158 type GreaterThan16Bytes struct {
159+ _ structs.HostLayout
148160 x, y, z *int64
149161 }
150162 var x, y, z int64 = 0xEF, 0xBE00, 0xDEAD0000
@@ -168,48 +180,52 @@ func TestRegisterFunc_structArgs(t *testing.T) {
168180 register(&BeforeRegisters, lib, "BeforeRegisters", func(bytes GreaterThan16Bytes, a, b int64) uint64 {
169181 return uint64(*bytes.x + *bytes.y + *bytes.z + a + b)
170182 })
171- if ret := BeforeRegisters(GreaterThan16Bytes{&x, &y, &z}, 0x0F, 0xF0); ret != expectedUnsigned {
183+ if ret := BeforeRegisters(GreaterThan16Bytes{x: &x, y: &y, z: &z}, 0x0F, 0xF0); ret != expectedUnsigned {
172184 t.Fatalf("BeforeRegisters returned %#x wanted %#x", ret, expectedUnsigned)
173185 }
174186 }
175187 {
176188 type IntLessThan16Bytes struct {
189+ _ structs.HostLayout
177190 x, y int64
178191 }
179192 var IntLessThan16BytesFn func(bytes IntLessThan16Bytes) int64
180193 register(&IntLessThan16BytesFn, lib, "IntLessThan16Bytes", func(l IntLessThan16Bytes) int64 {
181194 return l.x + l.y
182195 })
183- if ret := IntLessThan16BytesFn(IntLessThan16Bytes{0xDEAD0000, 0xBEEF}); ret != expectedUnsigned {
196+ if ret := IntLessThan16BytesFn(IntLessThan16Bytes{x: 0xDEAD0000, y: 0xBEEF}); ret != expectedUnsigned {
184197 t.Fatalf("IntLessThan16BytesFn returned %#x wanted %#x", ret, expectedUnsigned)
185198 }
186199 }
187200 {
188201 type FloatLessThan16Bytes struct {
202+ _ structs.HostLayout
189203 x, y float32
190204 }
191205 var FloatLessThan16BytesFn func(FloatLessThan16Bytes) float32
192206 register(&FloatLessThan16BytesFn, lib, "FloatLessThan16Bytes", func(f FloatLessThan16Bytes) float32 {
193207 return f.x + f.y
194208 })
195- if ret := FloatLessThan16BytesFn(FloatLessThan16Bytes{3, 7}); ret != expectedFloat {
209+ if ret := FloatLessThan16BytesFn(FloatLessThan16Bytes{x: 3, y: 7}); ret != expectedFloat {
196210 t.Fatalf("FloatLessThan16Bytes returned %f wanted %f", ret, expectedFloat)
197211 }
198212 }
199213 {
200214 type ThreeSmallFields struct {
215+ _ structs.HostLayout
201216 x, y, z float32
202217 }
203218 var ThreeSmallFieldsFn func(ThreeSmallFields) float32
204219 register(&ThreeSmallFieldsFn, lib, "ThreeSmallFields", func(f ThreeSmallFields) float32 {
205220 return f.x + f.y + f.z
206221 })
207- if ret := ThreeSmallFieldsFn(ThreeSmallFields{1, 2, 7}); ret != expectedFloat {
222+ if ret := ThreeSmallFieldsFn(ThreeSmallFields{x: 1, y: 2, z: 7}); ret != expectedFloat {
208223 t.Fatalf("ThreeSmallFields returned %f wanted %f", ret, expectedFloat)
209224 }
210225 }
211226 {
212227 type FloatAndInt struct {
228+ _ structs.HostLayout
213229 x float32
214230 y int32
215231 }
@@ -217,37 +233,41 @@ func TestRegisterFunc_structArgs(t *testing.T) {
217233 register(&FloatAndIntFn, lib, "FloatAndInt", func(f FloatAndInt) float32 {
218234 return f.x + float32(f.y)
219235 })
220- if ret := FloatAndIntFn(FloatAndInt{3, 7}); ret != expectedFloat {
236+ if ret := FloatAndIntFn(FloatAndInt{x: 3, y: 7}); ret != expectedFloat {
221237 t.Fatalf("FloatAndIntFn returned %f wanted %f", ret, expectedFloat)
222238 }
223239 }
224240 {
225241 type DoubleStruct struct {
242+ _ structs.HostLayout
226243 x float64
227244 }
228245 var DoubleStructFn func(DoubleStruct) float64
229246 register(&DoubleStructFn, lib, "DoubleStruct", func(d DoubleStruct) float64 {
230247 return d.x
231248 })
232- if ret := DoubleStructFn(DoubleStruct{10}); ret != expectedDouble {
249+ if ret := DoubleStructFn(DoubleStruct{x: 10}); ret != expectedDouble {
233250 t.Fatalf("DoubleStruct returned %f wanted %f", ret, expectedDouble)
234251 }
235252 }
236253 {
237254 type TwoDoubleStruct struct {
255+ _ structs.HostLayout
238256 x, y float64
239257 }
240258 var TwoDoubleStructFn func(TwoDoubleStruct) float64
241259 register(&TwoDoubleStructFn, lib, "TwoDoubleStruct", func(d TwoDoubleStruct) float64 {
242260 return d.x + d.y
243261 })
244- if ret := TwoDoubleStructFn(TwoDoubleStruct{3, 7}); ret != expectedDouble {
262+ if ret := TwoDoubleStructFn(TwoDoubleStruct{x: 3, y: 7}); ret != expectedDouble {
245263 t.Fatalf("TwoDoubleStruct returned %f wanted %f", ret, expectedDouble)
246264 }
247265 }
248266 {
249267 type TwoDoubleTwoStruct struct {
268+ _ structs.HostLayout
250269 x struct {
270+ _ structs.HostLayout
251271 x, y float64
252272 }
253273 }
@@ -255,31 +275,36 @@ func TestRegisterFunc_structArgs(t *testing.T) {
255275 register(&TwoDoubleTwoStructFn, lib, "TwoDoubleTwoStruct", func(d TwoDoubleTwoStruct) float64 {
256276 return d.x.x + d.x.y
257277 })
258- if ret := TwoDoubleTwoStructFn(TwoDoubleTwoStruct{x: struct{ x, y float64 }{x: 3, y: 7}}); ret != expectedDouble {
278+ if ret := TwoDoubleTwoStructFn(TwoDoubleTwoStruct{x: struct {
279+ _ structs.HostLayout
280+ x, y float64
281+ }{x: 3, y: 7}}); ret != expectedDouble {
259282 t.Fatalf("TwoDoubleTwoStruct returned %f wanted %f", ret, expectedDouble)
260283 }
261284 }
262285 {
263286 type ThreeDoubleStruct struct {
287+ _ structs.HostLayout
264288 x, y, z float64
265289 }
266290 var ThreeDoubleStructFn func(ThreeDoubleStruct) float64
267291 register(&ThreeDoubleStructFn, lib, "ThreeDoubleStruct", func(d ThreeDoubleStruct) float64 {
268292 return d.x + d.y + d.z
269293 })
270- if ret := ThreeDoubleStructFn(ThreeDoubleStruct{1, 3, 6}); ret != expectedDouble {
294+ if ret := ThreeDoubleStructFn(ThreeDoubleStruct{x: 1, y: 3, z: 6}); ret != expectedDouble {
271295 t.Fatalf("ThreeDoubleStructFn returned %f wanted %f", ret, expectedDouble)
272296 }
273297 }
274298 {
275299 type LargeFloatStruct struct {
300+ _ structs.HostLayout
276301 a, b, c, d, e, f float64
277302 }
278303 var LargeFloatStructFn func(LargeFloatStruct) float64
279304 register(&LargeFloatStructFn, lib, "LargeFloatStruct", func(s LargeFloatStruct) float64 {
280305 return s.a + s.b + s.c + s.d + s.e + s.f
281306 })
282- if ret := LargeFloatStructFn(LargeFloatStruct{1, 2, 3, 4, 5, -5}); ret != expectedDouble {
307+ if ret := LargeFloatStructFn(LargeFloatStruct{a: 1, b: 2, c: 3, d: 4, e: 5, f: -5}); ret != expectedDouble {
283308 t.Fatalf("LargeFloatStructFn returned %f wanted %f", ret, expectedFloat)
284309 }
285310 if runtime.GOARCH != "ppc64le" {
@@ -289,13 +314,14 @@ func TestRegisterFunc_structArgs(t *testing.T) {
289314 register(&LargeFloatStructWithRegs, lib, "LargeFloatStructWithRegs", func(a, b, c float64, s LargeFloatStruct) float64 {
290315 return a + b + c + s.a + s.b + s.c + s.d + s.e + s.f
291316 })
292- if ret := LargeFloatStructWithRegs(1, -1, 0, LargeFloatStruct{1, 2, 3, 4, 5, -5}); ret != expectedDouble {
317+ if ret := LargeFloatStructWithRegs(1, -1, 0, LargeFloatStruct{a: 1, b: 2, c: 3, d: 4, e: 5, f: -5}); ret != expectedDouble {
293318 t.Fatalf("LargeFloatStructWithRegs returned %f wanted %f", ret, expectedFloat)
294319 }
295320 }
296321 }
297322 {
298323 type Rect struct {
324+ _ structs.HostLayout
299325 x, y, w, h float64
300326 }
301327 if runtime.GOARCH != "ppc64le" {
@@ -305,7 +331,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
305331 register(&RectangleWithRegs, lib, "RectangleWithRegs", func(a, b, c, d, e float64, rect Rect) float64 {
306332 return a + b + c + d + e + rect.x + rect.y + rect.w + rect.h
307333 })
308- if ret := RectangleWithRegs(1, 2, 3, 4, -2, Rect{1, 2, 3, -4}); ret != expectedDouble {
334+ if ret := RectangleWithRegs(1, 2, 3, 4, -2, Rect{x: 1, y: 2, w: 3, h: -4}); ret != expectedDouble {
309335 t.Fatalf("RectangleWithRegs returned %f wanted %f", ret, expectedDouble)
310336 }
311337 }
@@ -313,19 +339,20 @@ func TestRegisterFunc_structArgs(t *testing.T) {
313339 register(&RectangleSubtract, lib, "RectangleSubtract", func(rect Rect) float64 {
314340 return (rect.x + rect.y) - (rect.w + rect.h)
315341 })
316- if ret := RectangleSubtract(Rect{15, 5, 3, 7}); ret != expectedDouble {
342+ if ret := RectangleSubtract(Rect{x: 15, y: 5, w: 3, h: 7}); ret != expectedDouble {
317343 t.Fatalf("RectangleSubtract returned %f wanted %f", ret, expectedDouble)
318344 }
319345 var Rectangle func(rect Rect) float64
320346 register(&Rectangle, lib, "Rectangle", func(rect Rect) float64 {
321347 return rect.x + rect.y + rect.w + rect.h
322348 })
323- if ret := Rectangle(Rect{1, 2, 3, 4}); ret != expectedDouble {
349+ if ret := Rectangle(Rect{x: 1, y: 2, w: 3, h: 4}); ret != expectedDouble {
324350 t.Fatalf("Rectangle returned %f wanted %f", ret, expectedFloat)
325351 }
326352 }
327353 {
328354 type FloatArray struct {
355+ _ structs.HostLayout
329356 a [2]float64
330357 }
331358 var FloatArrayFn func(rect FloatArray) float64
@@ -338,6 +365,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
338365 }
339366 {
340367 type UnsignedChar4Bytes struct {
368+ _ structs.HostLayout
341369 a, b, c, d byte
342370 }
343371 var UnsignedChar4BytesFn func(UnsignedChar4Bytes) uint32
@@ -350,16 +378,21 @@ func TestRegisterFunc_structArgs(t *testing.T) {
350378 }
351379 {
352380 type UnsignedChar4BytesStruct struct {
381+ _ structs.HostLayout
353382 x struct {
383+ _ structs.HostLayout
354384 a byte
355385 }
356386 y struct {
387+ _ structs.HostLayout
357388 b byte
358389 }
359390 z struct {
391+ _ structs.HostLayout
360392 c byte
361393 }
362394 w struct {
395+ _ structs.HostLayout
363396 d byte
364397 }
365398 }
@@ -368,16 +401,29 @@ func TestRegisterFunc_structArgs(t *testing.T) {
368401 return uint32(b.x.a)<<24 | uint32(b.y.b)<<16 | uint32(b.z.c)<<8 | uint32(b.w.d)
369402 })
370403 if ret := UnsignedChar4BytesStructFn(UnsignedChar4BytesStruct{
371- x: struct{ a byte }{a: 0xDE},
372- y: struct{ b byte }{b: 0xAD},
373- z: struct{ c byte }{c: 0xBE},
374- w: struct{ d byte }{d: 0xEF},
404+ x: struct {
405+ _ structs.HostLayout
406+ a byte
407+ }{a: 0xDE},
408+ y: struct {
409+ _ structs.HostLayout
410+ b byte
411+ }{b: 0xAD},
412+ z: struct {
413+ _ structs.HostLayout
414+ c byte
415+ }{c: 0xBE},
416+ w: struct {
417+ _ structs.HostLayout
418+ d byte
419+ }{d: 0xEF},
375420 }); ret != expectedUnsigned {
376421 t.Fatalf("UnsignedChar4BytesStructFn returned %#x wanted %#x", ret, expectedUnsigned)
377422 }
378423 }
379424 {
380425 type Short struct {
426+ _ structs.HostLayout
381427 a, b, c, d uint16
382428 }
383429 var ShortFn func(Short) uint64
@@ -390,6 +436,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
390436 }
391437 {
392438 type Int struct {
439+ _ structs.HostLayout
393440 a, b uint32
394441 }
395442 var IntFn func(Int) uint64
@@ -402,6 +449,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
402449 }
403450 {
404451 type Long struct {
452+ _ structs.HostLayout
405453 a uint64
406454 }
407455 var LongFn func(Long) uint64
@@ -414,6 +462,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
414462 }
415463 {
416464 type Char8Bytes struct {
465+ _ structs.HostLayout
417466 a, b, c, d, e, f, g, h int8
418467 }
419468 var Char8BytesFn func(Char8Bytes) int32
@@ -426,6 +475,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
426475 }
427476 {
428477 type Odd struct {
478+ _ structs.HostLayout
429479 a, b, c byte
430480 }
431481 var OddFn func(Odd) int32
@@ -438,6 +488,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
438488 }
439489 {
440490 type Char2Short1 struct {
491+ _ structs.HostLayout
441492 a, b byte
442493 c uint16
443494 }
@@ -451,6 +502,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
451502 }
452503 {
453504 type SignedChar2Short1 struct {
505+ _ structs.HostLayout
454506 a, b int8
455507 c int16
456508 }
@@ -464,6 +516,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
464516 }
465517 {
466518 type Array4UnsignedChars struct {
519+ _ structs.HostLayout
467520 a [4]uint8
468521 }
469522 var Array4UnsignedCharsFn func(chars Array4UnsignedChars) uint32
@@ -476,6 +529,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
476529 }
477530 {
478531 type Array3UnsignedChar struct {
532+ _ structs.HostLayout
479533 a [3]uint8
480534 }
481535 var Array3UnsignedChars func(chars Array3UnsignedChar) uint32
@@ -488,6 +542,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
488542 }
489543 {
490544 type Array2UnsignedShort struct {
545+ _ structs.HostLayout
491546 a [2]uint16
492547 }
493548 var Array2UnsignedShorts func(chars Array2UnsignedShort) uint32
@@ -500,6 +555,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
500555 }
501556 {
502557 type Array4Chars struct {
558+ _ structs.HostLayout
503559 a [4]int8
504560 }
505561 var Array4CharsFn func(chars Array4Chars) int32
@@ -513,6 +569,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
513569 }
514570 {
515571 type Array2Short struct {
572+ _ structs.HostLayout
516573 a [2]int16
517574 }
518575 var Array2Shorts func(chars Array2Short) int32
@@ -525,6 +582,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
525582 }
526583 {
527584 type Array3Short struct {
585+ _ structs.HostLayout
528586 a [3]int16
529587 }
530588 var Array3Shorts func(chars Array3Short) int32
@@ -537,21 +595,23 @@ func TestRegisterFunc_structArgs(t *testing.T) {
537595 }
538596 {
539597 type BoolStruct struct {
598+ _ structs.HostLayout
540599 b bool
541600 }
542601 var BoolStructFn func(BoolStruct) bool
543602 register(&BoolStructFn, lib, "BoolStruct", func(b BoolStruct) bool {
544603 return b.b
545604 })
546- if ret := BoolStructFn(BoolStruct{true}); ret != true {
605+ if ret := BoolStructFn(BoolStruct{b: true}); ret != true {
547606 t.Fatalf("BoolStructFn returned %v wanted %v", ret, true)
548607 }
549- if ret := BoolStructFn(BoolStruct{false}); ret != false {
608+ if ret := BoolStructFn(BoolStruct{b: false}); ret != false {
550609 t.Fatalf("BoolStructFn returned %v wanted %v", ret, false)
551610 }
552611 }
553612 {
554613 type BoolFloat struct {
614+ _ structs.HostLayout
555615 b bool
556616 _ [3]byte // purego won't do padding for you so make sure it aligns properly with C struct
557617 f float32
@@ -571,9 +631,16 @@ func TestRegisterFunc_structArgs(t *testing.T) {
571631 }
572632 }
573633 {
574- type point struct{ x, y float64 }
575- type size struct{ width, height float64 }
634+ type point struct {
635+ _ structs.HostLayout
636+ x, y float64
637+ }
638+ type size struct {
639+ _ structs.HostLayout
640+ width, height float64
641+ }
576642 type Content struct {
643+ _ structs.HostLayout
577644 point point
578645 size size
579646 }
@@ -589,13 +656,14 @@ func TestRegisterFunc_structArgs(t *testing.T) {
589656 })
590657 if ret := InitWithContentRect(new(int),
591658 // These numbers are created so that when added together and then divided by 11 it produces 0xdeadbeef
592- Content{point{x: 41_000_000_000, y: 95_000_000}, size{width: 214_000, height: 149}},
659+ Content{point: point{x: 41_000_000_000, y: 95_000_000}, size: size{width: 214_000, height: 149}},
593660 15, 4, true); ret != expectedUnsigned {
594661 t.Fatalf("InitWithContentRect returned %d wanted %#x", ret, expectedUnsigned)
595662 }
596663 }
597664 {
598665 type GoInt4 struct {
666+ _ structs.HostLayout
599667 A, B, C, D int
600668 }
601669 var GoInt4Fn func(GoInt4) int
@@ -603,12 +671,13 @@ func TestRegisterFunc_structArgs(t *testing.T) {
603671 return g.A + g.B - g.C + g.D
604672 })
605673 const expected = math.MaxInt - 52 - 3 + 4
606- if ret := GoInt4Fn(GoInt4{math.MaxInt, -52, 3, 4}); ret != expected {
674+ if ret := GoInt4Fn(GoInt4{A: math.MaxInt, B: -52, C: 3, D: 4}); ret != expected {
607675 t.Fatalf("GoInt4Fn returned %d wanted %#x", ret, expected)
608676 }
609677 }
610678 {
611679 type GoUint4 struct {
680+ _ structs.HostLayout
612681 A, B, C, D uint
613682 }
614683 var GoUint4Fn func(GoUint4) uint
@@ -616,23 +685,27 @@ func TestRegisterFunc_structArgs(t *testing.T) {
616685 return g.A + g.B + g.C + g.D
617686 })
618687 const expected = 1_000_000 + 53 + 71 + 8
619- if ret := GoUint4Fn(GoUint4{1_000_000, 53, 71, 8}); ret != expected {
688+ if ret := GoUint4Fn(GoUint4{A: 1_000_000, B: 53, C: 71, D: 8}); ret != expected {
620689 t.Fatalf("GoUint4Fn returned %d wanted %#x", ret, expected)
621690 }
622691 }
623692 {
624- type OneLong struct{ a uintptr }
693+ type OneLong struct {
694+ _ structs.HostLayout
695+ a uintptr
696+ }
625697 var TakeGoUintAndReturn func(a OneLong) uint64
626698 register(&TakeGoUintAndReturn, lib, "TakeGoUintAndReturn", func(a OneLong) uint64 {
627699 return uint64(a.a)
628700 })
629701 expected := uint64(7)
630- if ret := TakeGoUintAndReturn(OneLong{7}); ret != expected {
702+ if ret := TakeGoUintAndReturn(OneLong{a: 7}); ret != expected {
631703 t.Fatalf("TakeGoUintAndReturn returned %+v wanted %+v", ret, expected)
632704 }
633705 }
634706 {
635707 type FloatAndBool struct {
708+ _ structs.HostLayout
636709 x float32
637710 y bool
638711 }
@@ -652,13 +725,14 @@ func TestRegisterFunc_structArgs(t *testing.T) {
652725 }
653726 {
654727 type FourInt32s struct {
728+ _ structs.HostLayout
655729 f0, f1, f2, f3 int32
656730 }
657731 var FourInt32sFn func(FourInt32s) int32
658732 register(&FourInt32sFn, lib, "FourInt32s", func(s FourInt32s) int32 {
659733 return s.f0 + s.f1 + s.f2 + s.f3
660734 })
661- result := FourInt32sFn(FourInt32s{100, -127, 4, -100})
735+ result := FourInt32sFn(FourInt32s{f0: 100, f1: -127, f2: 4, f3: -100})
662736 const want = 100 - 127 + 4 - 100
663737 if result != want {
664738 t.Fatalf("FourInt32s returned %d wanted %d", result, want)
@@ -666,6 +740,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
666740 }
667741 {
668742 type PointerWrapper struct {
743+ _ structs.HostLayout
669744 ctx unsafe.Pointer
670745 }
671746 var ExtractPointer func(wrapper PointerWrapper) uintptr
@@ -683,6 +758,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
683758 }
684759 {
685760 type TwoPointers struct {
761+ _ structs.HostLayout
686762 ptr1, ptr2 unsafe.Pointer
687763 }
688764 var AddPointers func(wrapper TwoPointers) uintptr
@@ -694,7 +770,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
694770 ptr1 := unsafe.Pointer(&v1)
695771 ptr2 := unsafe.Pointer(&v2)
696772 expected := uintptr(ptr1) + uintptr(ptr2)
697- result := AddPointers(TwoPointers{ptr1, ptr2})
773+ result := AddPointers(TwoPointers{ptr1: ptr1, ptr2: ptr2})
698774 if result != expected {
699775 t.Fatalf("AddPointers returned %#x wanted %#x", result, expected)
700776 }
@@ -703,48 +779,60 @@ func TestRegisterFunc_structArgs(t *testing.T) {
703779 // Identity struct arg tests
704780 {
705781 // Single int64: one integer register.
706- type OneInt64 struct{ A int64 }
782+ type OneInt64 struct {
783+ _ structs.HostLayout
784+ A int64
785+ }
707786 var fn func(OneInt64) OneInt64
708787 register(&fn, lib, "IdentityOneInt64", func(s OneInt64) OneInt64 {
709788 return s
710789 })
711- expected := OneInt64{0xDEADBEEF}
790+ expected := OneInt64{A: 0xDEADBEEF}
712791 if ret := fn(expected); ret != expected {
713792 t.Fatalf("IdentityOneInt64 returned %+v wanted %+v", ret, expected)
714793 }
715794 }
716795 {
717796 // Two int64 fields: two integer registers.
718- type IntLessThan16Bytes struct{ X, Y int64 }
797+ type IntLessThan16Bytes struct {
798+ _ structs.HostLayout
799+ X, Y int64
800+ }
719801 var fn func(IntLessThan16Bytes) IntLessThan16Bytes
720802 register(&fn, lib, "IdentityIntLessThan16Bytes", func(s IntLessThan16Bytes) IntLessThan16Bytes {
721803 return s
722804 })
723- expected := IntLessThan16Bytes{0xDEADBEEF, -42}
805+ expected := IntLessThan16Bytes{X: 0xDEADBEEF, Y: -42}
724806 if ret := fn(expected); ret != expected {
725807 t.Fatalf("IdentityIntLessThan16Bytes returned %+v wanted %+v", ret, expected)
726808 }
727809 }
728810 {
729811 // Two float64 fields: SSE on amd64, HFA on arm64.
730- type TwoDoubleStruct struct{ X, Y float64 }
812+ type TwoDoubleStruct struct {
813+ _ structs.HostLayout
814+ X, Y float64
815+ }
731816 var fn func(TwoDoubleStruct) TwoDoubleStruct
732817 register(&fn, lib, "IdentityTwoDoubleStruct", func(s TwoDoubleStruct) TwoDoubleStruct {
733818 return s
734819 })
735- expected := TwoDoubleStruct{3.14, -2.71}
820+ expected := TwoDoubleStruct{X: 3.14, Y: -2.71}
736821 if ret := fn(expected); ret != expected {
737822 t.Fatalf("IdentityTwoDoubleStruct returned %+v wanted %+v", ret, expected)
738823 }
739824 }
740825 {
741826 // Four float32 fields: HFA on arm64, SSE on amd64.
742- type FourFloat32 struct{ A, B, C, D float32 }
827+ type FourFloat32 struct {
828+ _ structs.HostLayout
829+ A, B, C, D float32
830+ }
743831 var fn func(FourFloat32) FourFloat32
744832 register(&fn, lib, "IdentityFourFloat32", func(s FourFloat32) FourFloat32 {
745833 return s
746834 })
747- expected := FourFloat32{1.0, 2.0, 3.0, 4.0}
835+ expected := FourFloat32{A: 1.0, B: 2.0, C: 3.0, D: 4.0}
748836 if ret := fn(expected); ret != expected {
749837 t.Fatalf("IdentityFourFloat32 returned %+v wanted %+v", ret, expected)
750838 }
@@ -752,6 +840,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
752840 {
753841 // Mixed float32 + int32: INTEGER class eightbyte on amd64, non-HFA int regs on arm64.
754842 type FloatAndInt struct {
843+ _ structs.HostLayout
755844 X float32
756845 Y int32
757846 }
@@ -759,19 +848,22 @@ func TestRegisterFunc_structArgs(t *testing.T) {
759848 register(&fn, lib, "IdentityFloatAndInt", func(s FloatAndInt) FloatAndInt {
760849 return s
761850 })
762- expected := FloatAndInt{7.5, 42}
851+ expected := FloatAndInt{X: 7.5, Y: 42}
763852 if ret := fn(expected); ret != expected {
764853 t.Fatalf("IdentityFloatAndInt returned %+v wanted %+v", ret, expected)
765854 }
766855 }
767856 {
768857 // Struct > 16 bytes: hidden pointer on amd64, pointer in int register on arm64.
769- type ThreeInt64 struct{ A, B, C int64 }
858+ type ThreeInt64 struct {
859+ _ structs.HostLayout
860+ A, B, C int64
861+ }
770862 var fn func(ThreeInt64) ThreeInt64
771863 register(&fn, lib, "IdentityThreeInt64", func(s ThreeInt64) ThreeInt64 {
772864 return s
773865 })
774- expected := ThreeInt64{1, 2, 3}
866+ expected := ThreeInt64{A: 1, B: 2, C: 3}
775867 if ret := fn(expected); ret != expected {
776868 t.Fatalf("IdentityThreeInt64 returned %+v wanted %+v", ret, expected)
777869 }
@@ -779,6 +871,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
779871 {
780872 // Struct > 16 bytes with pointer fields.
781873 type PtrInt64Ptr struct {
874+ _ structs.HostLayout
782875 A *int64
783876 B int64
784877 C *int64
@@ -789,7 +882,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
789882 register(&fn, lib, "IdentityPtrInt64Ptr", func(s PtrInt64Ptr) PtrInt64Ptr {
790883 return s
791884 })
792- expected := PtrInt64Ptr{a, 200, c}
885+ expected := PtrInt64Ptr{A: a, B: 200, C: c}
793886 ret := fn(expected)
794887 if *ret.A != *expected.A || ret.B != expected.B || *ret.C != *expected.C {
795888 t.Fatalf("IdentityPtrInt64Ptr returned %+v wanted %+v", ret, expected)
@@ -801,24 +894,30 @@ func TestRegisterFunc_structArgs(t *testing.T) {
801894 // Struct arg after some primitive args: register offset correctness.
802895 // ppc64le is skipped: a float argument shadows a GPR, which purego
803896 // does not model for scalars, so the trailing struct is misplaced.
804- type IntLessThan16Bytes struct{ X, Y int64 }
897+ type IntLessThan16Bytes struct {
898+ _ structs.HostLayout
899+ X, Y int64
900+ }
805901 var fn func(int64, float64, IntLessThan16Bytes) IntLessThan16Bytes
806902 register(&fn, lib, "IdentityTwoInt64AfterPrims", func(x int64, y float64, s IntLessThan16Bytes) IntLessThan16Bytes {
807903 return s
808904 })
809- expected := IntLessThan16Bytes{100, 200}
905+ expected := IntLessThan16Bytes{X: 100, Y: 200}
810906 if ret := fn(1, 2.0, expected); ret != expected {
811907 t.Fatalf("IdentityTwoInt64AfterPrims returned %+v wanted %+v", ret, expected)
812908 }
813909 }
814910 {
815911 // Float struct arg after float primitive args: float register offset.
816- type FloatLessThan16Bytes struct{ X, Y float32 }
912+ type FloatLessThan16Bytes struct {
913+ _ structs.HostLayout
914+ X, Y float32
915+ }
817916 var fn func(float64, float64, FloatLessThan16Bytes) FloatLessThan16Bytes
818917 register(&fn, lib, "IdentityTwoFloat32AfterFloats", func(x, y float64, s FloatLessThan16Bytes) FloatLessThan16Bytes {
819918 return s
820919 })
821- expected := FloatLessThan16Bytes{5.0, 6.0}
920+ expected := FloatLessThan16Bytes{X: 5.0, Y: 6.0}
822921 if ret := fn(1.0, 2.0, expected); ret != expected {
823922 t.Fatalf("IdentityTwoFloat32AfterFloats returned %+v wanted %+v", ret, expected)
824923 }
@@ -826,6 +925,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
826925 {
827926 // Mixed struct with pointer: pointer + int32 + float32 + int32.
828927 type Mixed5Args struct {
928+ _ structs.HostLayout
829929 A *int64
830930 B int32
831931 C float32
@@ -837,7 +937,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
837937 register(&fn, lib, "IdentityMixed5Args", func(s Mixed5Args) Mixed5Args {
838938 return s
839939 })
840- expected := Mixed5Args{ptr, 1, 7.2, 9}
940+ expected := Mixed5Args{A: ptr, B: 1, C: 7.2, D: 9}
841941 ret := fn(expected)
842942 if ret.A != expected.A || ret.B != expected.B || ret.C != expected.C || ret.D != expected.D {
843943 t.Fatalf("IdentityMixed5Args returned %+v wanted %+v", ret, expected)
@@ -927,166 +1027,228 @@ func TestRegisterFunc_structReturns(t *testing.T) {
9271027 t.Run(imp.name, func(t *testing.T) {
9281028 register := imp.register
9291029 {
930- type Empty struct{}
1030+ type Empty struct {
1031+ _ structs.HostLayout
1032+ }
9311033 var ReturnEmpty func() Empty
9321034 register(&ReturnEmpty, lib, "ReturnEmpty")
9331035 ret := ReturnEmpty()
9341036 _ = ret
9351037 }
9361038 {
937- type inner struct{ A int16 }
1039+ type inner struct {
1040+ _ structs.HostLayout
1041+ A int16
1042+ }
9381043 type StructInStruct struct {
1044+ _ structs.HostLayout
9391045 A inner
9401046 B inner
9411047 C inner
9421048 }
9431049 var ReturnStructInStruct func(a, b, c int16) StructInStruct
9441050 register(&ReturnStructInStruct, lib, "ReturnStructInStruct")
945- expected := StructInStruct{inner{^int16(0)}, inner{2}, inner{3}}
1051+ expected := StructInStruct{A: inner{A: ^int16(0)}, B: inner{A: 2}, C: inner{A: 3}}
9461052 if ret := ReturnStructInStruct(^int16(0), 2, 3); ret != expected {
9471053 t.Fatalf("StructInStruct returned %+v wanted %+v", ret, expected)
9481054 }
9491055 }
9501056 {
951- type ThreeShorts struct{ A, B, C int16 }
1057+ type ThreeShorts struct {
1058+ _ structs.HostLayout
1059+ A, B, C int16
1060+ }
9521061 var ReturnThreeShorts func(a, b, c int16) ThreeShorts
9531062 register(&ReturnThreeShorts, lib, "ReturnThreeShorts")
954- expected := ThreeShorts{^int16(0), 2, 3}
1063+ expected := ThreeShorts{A: ^int16(0), B: 2, C: 3}
9551064 if ret := ReturnThreeShorts(^int16(0), 2, 3); ret != expected {
9561065 t.Fatalf("ReturnThreeShorts returned %+v wanted %+v", ret, expected)
9571066 }
9581067 }
9591068 {
960- type FourShorts struct{ A, B, C, D int16 }
1069+ type FourShorts struct {
1070+ _ structs.HostLayout
1071+ A, B, C, D int16
1072+ }
9611073 var ReturnFourShorts func(a, b, c, d int16) FourShorts
9621074 register(&ReturnFourShorts, lib, "ReturnFourShorts")
963- expected := FourShorts{^int16(0), 2, 3, 4}
1075+ expected := FourShorts{A: ^int16(0), B: 2, C: 3, D: 4}
9641076 if ret := ReturnFourShorts(^int16(0), 2, 3, 4); ret != expected {
9651077 t.Fatalf("ReturnFourShorts returned %+v wanted %+v", ret, expected)
9661078 }
9671079 }
9681080 {
969- type OneLong struct{ A int64 }
1081+ type OneLong struct {
1082+ _ structs.HostLayout
1083+ A int64
1084+ }
9701085 var ReturnOneLong func(a int64) OneLong
9711086 register(&ReturnOneLong, lib, "ReturnOneLong")
972- expected := OneLong{5}
1087+ expected := OneLong{A: 5}
9731088 if ret := ReturnOneLong(5); ret != expected {
9741089 t.Fatalf("ReturnOneLong returned %+v wanted %+v", ret, expected)
9751090 }
9761091 }
9771092 {
978- type TwoLongs struct{ A, B int64 }
1093+ type TwoLongs struct {
1094+ _ structs.HostLayout
1095+ A, B int64
1096+ }
9791097 var ReturnTwoLongs func(a, b int64) TwoLongs
9801098 register(&ReturnTwoLongs, lib, "ReturnTwoLongs")
981- expected := TwoLongs{1, 2}
1099+ expected := TwoLongs{A: 1, B: 2}
9821100 if ret := ReturnTwoLongs(1, 2); ret != expected {
9831101 t.Fatalf("ReturnTwoLongs returned %+v wanted %+v", ret, expected)
9841102 }
9851103 }
9861104 {
987- type ThreeLongs struct{ A, B, C int64 }
1105+ type ThreeLongs struct {
1106+ _ structs.HostLayout
1107+ A, B, C int64
1108+ }
9881109 var ReturnThreeLongs func(a, b, c int64) ThreeLongs
9891110 register(&ReturnThreeLongs, lib, "ReturnThreeLongs")
990- expected := ThreeLongs{1, 2, 3}
1111+ expected := ThreeLongs{A: 1, B: 2, C: 3}
9911112 if ret := ReturnThreeLongs(1, 2, 3); ret != expected {
9921113 t.Fatalf("ReturnThreeLongs returned %+v wanted %+v", ret, expected)
9931114 }
9941115 }
9951116 {
996- type OneFloat struct{ A float32 }
1117+ type OneFloat struct {
1118+ _ structs.HostLayout
1119+ A float32
1120+ }
9971121 var ReturnOneFloat func(a float32) OneFloat
9981122 register(&ReturnOneFloat, lib, "ReturnOneFloat")
999- expected := OneFloat{1}
1123+ expected := OneFloat{A: 1}
10001124 if ret := ReturnOneFloat(1); ret != expected {
10011125 t.Fatalf("ReturnOneFloat returned %+v wanted %+v", ret, expected)
10021126 }
10031127 }
10041128 {
1005- type TwoFloats struct{ A, B float32 }
1129+ type TwoFloats struct {
1130+ _ structs.HostLayout
1131+ A, B float32
1132+ }
10061133 var ReturnTwoFloats func(a, b float32) TwoFloats
10071134 register(&ReturnTwoFloats, lib, "ReturnTwoFloats")
1008- expected := TwoFloats{5, 2}
1135+ expected := TwoFloats{A: 5, B: 2}
10091136 if ret := ReturnTwoFloats(5, 2); ret != expected {
10101137 t.Fatalf("ReturnTwoFloats returned %+v wanted %+v", ret, expected)
10111138 }
10121139 }
10131140 {
1014- type ThreeFloats struct{ A, B, C float32 }
1141+ type ThreeFloats struct {
1142+ _ structs.HostLayout
1143+ A, B, C float32
1144+ }
10151145 var ReturnThreeFloats func(a, b, c float32) ThreeFloats
10161146 register(&ReturnThreeFloats, lib, "ReturnThreeFloats")
1017- expected := ThreeFloats{1, 2, 3}
1147+ expected := ThreeFloats{A: 1, B: 2, C: 3}
10181148 if ret := ReturnThreeFloats(1, 2, 3); ret != expected {
10191149 t.Fatalf("ReturnThreeFloats returned %+v wanted %+v", ret, expected)
10201150 }
10211151 }
10221152 {
1023- type FourFloats struct{ A, B, C, D float32 }
1153+ type FourFloats struct {
1154+ _ structs.HostLayout
1155+ A, B, C, D float32
1156+ }
10241157 var ReturnFourFloats func(a, b, c, d float32) FourFloats
10251158 register(&ReturnFourFloats, lib, "ReturnFourFloats")
1026- expected := FourFloats{1, 2, 3, 4}
1159+ expected := FourFloats{A: 1, B: 2, C: 3, D: 4}
10271160 if ret := ReturnFourFloats(1, 2, 3, 4); ret != expected {
10281161 t.Fatalf("ReturnFourFloats returned %+v wanted %+v", ret, expected)
10291162 }
10301163 }
10311164 {
1032- type OneDouble struct{ A float64 }
1165+ type OneDouble struct {
1166+ _ structs.HostLayout
1167+ A float64
1168+ }
10331169 var ReturnOneDouble func(a float64) OneDouble
10341170 register(&ReturnOneDouble, lib, "ReturnOneDouble")
1035- expected := OneDouble{1}
1171+ expected := OneDouble{A: 1}
10361172 if ret := ReturnOneDouble(1); ret != expected {
10371173 t.Fatalf("ReturnOneDouble returned %+v wanted %+v", ret, expected)
10381174 }
10391175 }
10401176 {
1041- type TwoDoubles struct{ A, B float64 }
1177+ type TwoDoubles struct {
1178+ _ structs.HostLayout
1179+ A, B float64
1180+ }
10421181 var ReturnTwoDoubles func(a, b float64) TwoDoubles
10431182 register(&ReturnTwoDoubles, lib, "ReturnTwoDoubles")
1044- expected := TwoDoubles{7, 3}
1183+ expected := TwoDoubles{A: 7, B: 3}
10451184 if ret := ReturnTwoDoubles(7, 3); ret != expected {
10461185 t.Fatalf("ReturnTwoDoubles returned %+v wanted %+v", ret, expected)
10471186 }
10481187 }
10491188 {
1050- type ThreeDoubles struct{ A, B, C float64 }
1189+ type ThreeDoubles struct {
1190+ _ structs.HostLayout
1191+ A, B, C float64
1192+ }
10511193 var ReturnThreeDoubles func(a, b, c float64) ThreeDoubles
10521194 register(&ReturnThreeDoubles, lib, "ReturnThreeDoubles")
1053- expected := ThreeDoubles{1, 2, 3}
1195+ expected := ThreeDoubles{A: 1, B: 2, C: 3}
10541196 if ret := ReturnThreeDoubles(1, 2, 3); ret != expected {
10551197 t.Fatalf("ReturnThreeDoubles returned %+v wanted %+v", ret, expected)
10561198 }
10571199 }
10581200 {
1059- type FourDoubles struct{ A, B, C, D float64 }
1201+ type FourDoubles struct {
1202+ _ structs.HostLayout
1203+ A, B, C, D float64
1204+ }
10601205 var ReturnFourDoubles func(a, b, c, d float64) FourDoubles
10611206 register(&ReturnFourDoubles, lib, "ReturnFourDoubles")
1062- expected := FourDoubles{1, 2, 3, 4}
1207+ expected := FourDoubles{A: 1, B: 2, C: 3, D: 4}
10631208 if ret := ReturnFourDoubles(1, 2, 3, 4); ret != expected {
10641209 t.Fatalf("ReturnFourDoubles returned %+v wanted %+v", ret, expected)
10651210 }
10661211 }
10671212 {
10681213 type FourDoublesInternal struct {
1069- F struct{ A, B float64 }
1070- G struct{ C, D float64 }
1214+ _ structs.HostLayout
1215+ F struct {
1216+ _ structs.HostLayout
1217+ A, B float64
1218+ }
1219+ G struct {
1220+ _ structs.HostLayout
1221+ C, D float64
1222+ }
10711223 }
10721224 var ReturnFourDoublesInternal func(a, b, c, d float64) FourDoublesInternal
10731225 register(&ReturnFourDoublesInternal, lib, "ReturnFourDoublesInternal")
1074- expected := FourDoublesInternal{F: struct{ A, B float64 }{A: 1, B: 2}, G: struct{ C, D float64 }{C: 3, D: 4}}
1226+ expected := FourDoublesInternal{F: struct {
1227+ _ structs.HostLayout
1228+ A, B float64
1229+ }{A: 1, B: 2}, G: struct {
1230+ _ structs.HostLayout
1231+ C, D float64
1232+ }{C: 3, D: 4}}
10751233 if ret := ReturnFourDoublesInternal(1, 2, 3, 4); ret != expected {
10761234 t.Fatalf("ReturnFourDoublesInternal returned %+v wanted %+v", ret, expected)
10771235 }
10781236 }
10791237 {
1080- type FiveDoubles struct{ A, B, C, D, E float64 }
1238+ type FiveDoubles struct {
1239+ _ structs.HostLayout
1240+ A, B, C, D, E float64
1241+ }
10811242 var ReturnFiveDoubles func(a, b, c, d, e float64) FiveDoubles
10821243 register(&ReturnFiveDoubles, lib, "ReturnFiveDoubles")
1083- expected := FiveDoubles{1, 2, 3, 4, 5}
1244+ expected := FiveDoubles{A: 1, B: 2, C: 3, D: 4, E: 5}
10841245 if ret := ReturnFiveDoubles(1, 2, 3, 4, 5); ret != expected {
10851246 t.Fatalf("ReturnFiveDoubles returned %+v wanted %+v", ret, expected)
10861247 }
10871248 }
10881249 {
10891250 type OneFloatOneDouble struct {
1251+ _ structs.HostLayout
10901252 A float32
10911253 _ float32
10921254 B float64
@@ -1100,18 +1262,20 @@ func TestRegisterFunc_structReturns(t *testing.T) {
11001262 }
11011263 {
11021264 type OneDoubleOneFloat struct {
1265+ _ structs.HostLayout
11031266 A float64
11041267 B float32
11051268 }
11061269 var ReturnOneDoubleOneFloat func(a float64, b float32) OneDoubleOneFloat
11071270 register(&ReturnOneDoubleOneFloat, lib, "ReturnOneDoubleOneFloat")
1108- expected := OneDoubleOneFloat{1, 2}
1271+ expected := OneDoubleOneFloat{A: 1, B: 2}
11091272 if ret := ReturnOneDoubleOneFloat(1, 2); ret != expected {
11101273 t.Fatalf("ReturnOneDoubleOneFloat returned %+v wanted %+v", ret, expected)
11111274 }
11121275 }
11131276 {
11141277 type Unaligned1 struct {
1278+ _ structs.HostLayout
11151279 A int8
11161280 _ [1]int8
11171281 B int16
@@ -1133,18 +1297,20 @@ func TestRegisterFunc_structReturns(t *testing.T) {
11331297 // ppc64le by modeling the ELFv2 general-purpose register shadowing.
11341298 {
11351299 type Mixed1 struct {
1300+ _ structs.HostLayout
11361301 A float32
11371302 B int32
11381303 }
11391304 var ReturnMixed1 func(a float32, b int32) Mixed1
11401305 register(&ReturnMixed1, lib, "ReturnMixed1")
1141- expected := Mixed1{1, 2}
1306+ expected := Mixed1{A: 1, B: 2}
11421307 if ret := ReturnMixed1(1, 2); ret != expected {
11431308 t.Fatalf("ReturnMixed1 returned %+v wanted %+v", ret, expected)
11441309 }
11451310 }
11461311 {
11471312 type Mixed2 struct {
1313+ _ structs.HostLayout
11481314 A float32
11491315 B int32
11501316 C float32
@@ -1152,39 +1318,42 @@ func TestRegisterFunc_structReturns(t *testing.T) {
11521318 }
11531319 var ReturnMixed2 func(a float32, b int32, c float32, d int32) Mixed2
11541320 register(&ReturnMixed2, lib, "ReturnMixed2")
1155- expected := Mixed2{1, 2, 3, 4}
1321+ expected := Mixed2{A: 1, B: 2, C: 3, D: 4}
11561322 if ret := ReturnMixed2(1, 2, 3, 4); ret != expected {
11571323 t.Fatalf("ReturnMixed2 returned %+v wanted %+v", ret, expected)
11581324 }
11591325 }
11601326 {
11611327 type Mixed3 struct {
1328+ _ structs.HostLayout
11621329 A float32
11631330 B uint32
11641331 C float64
11651332 }
11661333 var ReturnMixed3 func(a float32, b uint32, c float64) Mixed3
11671334 register(&ReturnMixed3, lib, "ReturnMixed3")
1168- expected := Mixed3{1, 2, 3}
1335+ expected := Mixed3{A: 1, B: 2, C: 3}
11691336 if ret := ReturnMixed3(1, 2, 3); ret != expected {
11701337 t.Fatalf("ReturnMixed3 returned %+v wanted %+v", ret, expected)
11711338 }
11721339 }
11731340 {
11741341 type Mixed4 struct {
1342+ _ structs.HostLayout
11751343 A float64
11761344 B uint32
11771345 C float32
11781346 }
11791347 var ReturnMixed4 func(a float64, b uint32, c float32) Mixed4
11801348 register(&ReturnMixed4, lib, "ReturnMixed4")
1181- expected := Mixed4{1, 2, 3}
1349+ expected := Mixed4{A: 1, B: 2, C: 3}
11821350 if ret := ReturnMixed4(1, 2, 3); ret != expected {
11831351 t.Fatalf("ReturnMixed4 returned %+v wanted %+v", ret, expected)
11841352 }
11851353 }
11861354 {
11871355 type Mixed5 struct {
1356+ _ structs.HostLayout
11881357 A *int64
11891358 B int32
11901359 C float32
@@ -1193,7 +1362,7 @@ func TestRegisterFunc_structReturns(t *testing.T) {
11931362 var ReturnMixed5 func(a *int64, b int32, c float32, d int32) Mixed5
11941363 register(&ReturnMixed5, lib, "ReturnMixed5")
11951364 ptr := new(int64)
1196- expected := Mixed5{ptr, 1, 7.2, 9}
1365+ expected := Mixed5{A: ptr, B: 1, C: 7.2, D: 9}
11971366 if ret := ReturnMixed5(ptr, 1, 7.2, 9); ret != expected {
11981367 t.Fatalf("ReturnMixed5 returned %+v wanted %+v", ret, expected)
11991368 }
@@ -1202,6 +1371,7 @@ func TestRegisterFunc_structReturns(t *testing.T) {
12021371 }
12031372 {
12041373 type Mixed5 struct {
1374+ _ structs.HostLayout
12051375 A *int64
12061376 B int32
12071377 C float32
@@ -1213,7 +1383,7 @@ func TestRegisterFunc_structReturns(t *testing.T) {
12131383 // Struct callback args are tested in TestRegisterFunc_structArgs.
12141384 purego.RegisterLibFunc(&IdentityMixed5, lib, "IdentityMixed5")
12151385 ptr := new(int64)
1216- expected := Mixed5{ptr, 1, 7.2, 9}
1386+ expected := Mixed5{A: ptr, B: 1, C: 7.2, D: 9}
12171387 if ret := IdentityMixed5(expected); ret != expected {
12181388 t.Fatalf("IdentityMixed5 returned %+v wanted %+v", ret, expected)
12191389 }
@@ -1221,19 +1391,21 @@ func TestRegisterFunc_structReturns(t *testing.T) {
12211391 }
12221392 {
12231393 type SmallBool struct {
1394+ _ structs.HostLayout
12241395 A bool
12251396 B int32
12261397 C int64
12271398 }
12281399 var ReturnSmallBool func(a bool, b int32, c int64) SmallBool
12291400 register(&ReturnSmallBool, lib, "ReturnSmallBool")
1230- expected := SmallBool{true, 42, 123456789}
1401+ expected := SmallBool{A: true, B: 42, C: 123456789}
12311402 if ret := ReturnSmallBool(true, 42, 123456789); ret != expected {
12321403 t.Fatalf("ReturnSmallBool returned %+v wanted %+v", ret, expected)
12331404 }
12341405 }
12351406 {
12361407 type LargeBool struct {
1408+ _ structs.HostLayout
12371409 A bool
12381410 B int32
12391411 C int64
@@ -1241,20 +1413,21 @@ func TestRegisterFunc_structReturns(t *testing.T) {
12411413 }
12421414 var ReturnLargeBool func(a bool, b int32, c int64, d int64) LargeBool
12431415 register(&ReturnLargeBool, lib, "ReturnLargeBool")
1244- expected := LargeBool{false, -99, 987654321, 111222333444}
1416+ expected := LargeBool{A: false, B: -99, C: 987654321, D: 111222333444}
12451417 if ret := ReturnLargeBool(false, -99, 987654321, 111222333444); ret != expected {
12461418 t.Fatalf("ReturnLargeBool returned %+v wanted %+v", ret, expected)
12471419 }
12481420 }
12491421 {
12501422 type Ptr1 struct {
1423+ _ structs.HostLayout
12511424 a *int64
12521425 b unsafe.Pointer
12531426 }
12541427 var ReturnPtr1 func(a *int64, b unsafe.Pointer) Ptr1
12551428 purego.RegisterLibFunc(&ReturnPtr1, lib, "ReturnPtr1")
12561429 a, b := new(int64), new(struct{})
1257- expected := Ptr1{a, unsafe.Pointer(b)}
1430+ expected := Ptr1{a: a, b: unsafe.Pointer(b)}
12581431 if ret := ReturnPtr1(a, unsafe.Pointer(b)); ret != expected {
12591432 t.Fatalf("ReturnPtr1 returned %+v wanted %+v", ret, expected)
12601433 }
@@ -13,6 +13,7 @@ import (
13 "reflect"13 "reflect"
14 "runtime"14 "runtime"
15 "slices"15 "slices"
16+ "structs"
16 "testing"17 "testing"
17 "unsafe"18 "unsafe"
18 19
@@ -89,7 +90,9 @@ func TestRegisterFunc_structArgs(t *testing.T) {
89 t.Run(imp.name, func(t *testing.T) {90 t.Run(imp.name, func(t *testing.T) {
90 register := imp.register91 register := imp.register
91 {92 {
92- type Empty struct{}93+ type Empty struct {
94+ _ structs.HostLayout
95+ }
93 var NoStruct func(Empty) int6496 var NoStruct func(Empty) int64
94 register(&NoStruct, lib, "NoStruct", func(Empty) int64 {97 register(&NoStruct, lib, "NoStruct", func(Empty) int64 {
95 return 0xdeadbeef98 return 0xdeadbeef
@@ -99,7 +102,9 @@ func TestRegisterFunc_structArgs(t *testing.T) {
99 }102 }
100 }103 }
101 {104 {
102- type EmptyEmpty struct{}105+ type EmptyEmpty struct {
106+ _ structs.HostLayout
107+ }
103 var EmptyEmptyFn func(EmptyEmpty) int64108 var EmptyEmptyFn func(EmptyEmpty) int64
104 register(&EmptyEmptyFn, lib, "EmptyEmpty", func(EmptyEmpty) int64 {109 register(&EmptyEmptyFn, lib, "EmptyEmpty", func(EmptyEmpty) int64 {
105 return 0xdeadbeef110 return 0xdeadbeef
@@ -117,6 +122,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
117 }122 }
118 {123 {
119 type GreaterThan16Bytes struct {124 type GreaterThan16Bytes struct {
125+ _ structs.HostLayout
120 x, y, z *int64126 x, y, z *int64
121 }127 }
122 var x, y, z int64 = 0xEF, 0xBE00, 0xDEAD0000128 var x, y, z int64 = 0xEF, 0xBE00, 0xDEAD0000
@@ -130,7 +136,9 @@ func TestRegisterFunc_structArgs(t *testing.T) {
130 }136 }
131 {137 {
132 type GreaterThan16BytesStruct struct {138 type GreaterThan16BytesStruct struct {
139+ _ structs.HostLayout
133 a struct {140 a struct {
141+ _ structs.HostLayout
134 x, y, z *int64142 x, y, z *int64
135 }143 }
136 }144 }
@@ -139,12 +147,16 @@ func TestRegisterFunc_structArgs(t *testing.T) {
139 register(&GreaterThan16BytesStructFn, lib, "GreaterThan16BytesStruct", func(g GreaterThan16BytesStruct) int64 {147 register(&GreaterThan16BytesStructFn, lib, "GreaterThan16BytesStruct", func(g GreaterThan16BytesStruct) int64 {
140 return *g.a.x + *g.a.y + *g.a.z148 return *g.a.x + *g.a.y + *g.a.z
141 })149 })
142- if ret := GreaterThan16BytesStructFn(GreaterThan16BytesStruct{a: struct{ x, y, z *int64 }{x: &x, y: &y, z: &z}}); ret != expectedUnsigned {150+ if ret := GreaterThan16BytesStructFn(GreaterThan16BytesStruct{a: struct {
151+ _ structs.HostLayout
152+ x, y, z *int64
153+ }{x: &x, y: &y, z: &z}}); ret != expectedUnsigned {
143 t.Fatalf("GreaterThan16BytesStructFn returned %#x wanted %#x", ret, expectedUnsigned)154 t.Fatalf("GreaterThan16BytesStructFn returned %#x wanted %#x", ret, expectedUnsigned)
144 }155 }
145 }156 }
146 {157 {
147 type GreaterThan16Bytes struct {158 type GreaterThan16Bytes struct {
159+ _ structs.HostLayout
148 x, y, z *int64160 x, y, z *int64
149 }161 }
150 var x, y, z int64 = 0xEF, 0xBE00, 0xDEAD0000162 var x, y, z int64 = 0xEF, 0xBE00, 0xDEAD0000
@@ -168,48 +180,52 @@ func TestRegisterFunc_structArgs(t *testing.T) {
168 register(&BeforeRegisters, lib, "BeforeRegisters", func(bytes GreaterThan16Bytes, a, b int64) uint64 {180 register(&BeforeRegisters, lib, "BeforeRegisters", func(bytes GreaterThan16Bytes, a, b int64) uint64 {
169 return uint64(*bytes.x + *bytes.y + *bytes.z + a + b)181 return uint64(*bytes.x + *bytes.y + *bytes.z + a + b)
170 })182 })
171- if ret := BeforeRegisters(GreaterThan16Bytes{&x, &y, &z}, 0x0F, 0xF0); ret != expectedUnsigned {183+ if ret := BeforeRegisters(GreaterThan16Bytes{x: &x, y: &y, z: &z}, 0x0F, 0xF0); ret != expectedUnsigned {
172 t.Fatalf("BeforeRegisters returned %#x wanted %#x", ret, expectedUnsigned)184 t.Fatalf("BeforeRegisters returned %#x wanted %#x", ret, expectedUnsigned)
173 }185 }
174 }186 }
175 {187 {
176 type IntLessThan16Bytes struct {188 type IntLessThan16Bytes struct {
189+ _ structs.HostLayout
177 x, y int64190 x, y int64
178 }191 }
179 var IntLessThan16BytesFn func(bytes IntLessThan16Bytes) int64192 var IntLessThan16BytesFn func(bytes IntLessThan16Bytes) int64
180 register(&IntLessThan16BytesFn, lib, "IntLessThan16Bytes", func(l IntLessThan16Bytes) int64 {193 register(&IntLessThan16BytesFn, lib, "IntLessThan16Bytes", func(l IntLessThan16Bytes) int64 {
181 return l.x + l.y194 return l.x + l.y
182 })195 })
183- if ret := IntLessThan16BytesFn(IntLessThan16Bytes{0xDEAD0000, 0xBEEF}); ret != expectedUnsigned {196+ if ret := IntLessThan16BytesFn(IntLessThan16Bytes{x: 0xDEAD0000, y: 0xBEEF}); ret != expectedUnsigned {
184 t.Fatalf("IntLessThan16BytesFn returned %#x wanted %#x", ret, expectedUnsigned)197 t.Fatalf("IntLessThan16BytesFn returned %#x wanted %#x", ret, expectedUnsigned)
185 }198 }
186 }199 }
187 {200 {
188 type FloatLessThan16Bytes struct {201 type FloatLessThan16Bytes struct {
202+ _ structs.HostLayout
189 x, y float32203 x, y float32
190 }204 }
191 var FloatLessThan16BytesFn func(FloatLessThan16Bytes) float32205 var FloatLessThan16BytesFn func(FloatLessThan16Bytes) float32
192 register(&FloatLessThan16BytesFn, lib, "FloatLessThan16Bytes", func(f FloatLessThan16Bytes) float32 {206 register(&FloatLessThan16BytesFn, lib, "FloatLessThan16Bytes", func(f FloatLessThan16Bytes) float32 {
193 return f.x + f.y207 return f.x + f.y
194 })208 })
195- if ret := FloatLessThan16BytesFn(FloatLessThan16Bytes{3, 7}); ret != expectedFloat {209+ if ret := FloatLessThan16BytesFn(FloatLessThan16Bytes{x: 3, y: 7}); ret != expectedFloat {
196 t.Fatalf("FloatLessThan16Bytes returned %f wanted %f", ret, expectedFloat)210 t.Fatalf("FloatLessThan16Bytes returned %f wanted %f", ret, expectedFloat)
197 }211 }
198 }212 }
199 {213 {
200 type ThreeSmallFields struct {214 type ThreeSmallFields struct {
215+ _ structs.HostLayout
201 x, y, z float32216 x, y, z float32
202 }217 }
203 var ThreeSmallFieldsFn func(ThreeSmallFields) float32218 var ThreeSmallFieldsFn func(ThreeSmallFields) float32
204 register(&ThreeSmallFieldsFn, lib, "ThreeSmallFields", func(f ThreeSmallFields) float32 {219 register(&ThreeSmallFieldsFn, lib, "ThreeSmallFields", func(f ThreeSmallFields) float32 {
205 return f.x + f.y + f.z220 return f.x + f.y + f.z
206 })221 })
207- if ret := ThreeSmallFieldsFn(ThreeSmallFields{1, 2, 7}); ret != expectedFloat {222+ if ret := ThreeSmallFieldsFn(ThreeSmallFields{x: 1, y: 2, z: 7}); ret != expectedFloat {
208 t.Fatalf("ThreeSmallFields returned %f wanted %f", ret, expectedFloat)223 t.Fatalf("ThreeSmallFields returned %f wanted %f", ret, expectedFloat)
209 }224 }
210 }225 }
211 {226 {
212 type FloatAndInt struct {227 type FloatAndInt struct {
228+ _ structs.HostLayout
213 x float32229 x float32
214 y int32230 y int32
215 }231 }
@@ -217,37 +233,41 @@ func TestRegisterFunc_structArgs(t *testing.T) {
217 register(&FloatAndIntFn, lib, "FloatAndInt", func(f FloatAndInt) float32 {233 register(&FloatAndIntFn, lib, "FloatAndInt", func(f FloatAndInt) float32 {
218 return f.x + float32(f.y)234 return f.x + float32(f.y)
219 })235 })
220- if ret := FloatAndIntFn(FloatAndInt{3, 7}); ret != expectedFloat {236+ if ret := FloatAndIntFn(FloatAndInt{x: 3, y: 7}); ret != expectedFloat {
221 t.Fatalf("FloatAndIntFn returned %f wanted %f", ret, expectedFloat)237 t.Fatalf("FloatAndIntFn returned %f wanted %f", ret, expectedFloat)
222 }238 }
223 }239 }
224 {240 {
225 type DoubleStruct struct {241 type DoubleStruct struct {
242+ _ structs.HostLayout
226 x float64243 x float64
227 }244 }
228 var DoubleStructFn func(DoubleStruct) float64245 var DoubleStructFn func(DoubleStruct) float64
229 register(&DoubleStructFn, lib, "DoubleStruct", func(d DoubleStruct) float64 {246 register(&DoubleStructFn, lib, "DoubleStruct", func(d DoubleStruct) float64 {
230 return d.x247 return d.x
231 })248 })
232- if ret := DoubleStructFn(DoubleStruct{10}); ret != expectedDouble {249+ if ret := DoubleStructFn(DoubleStruct{x: 10}); ret != expectedDouble {
233 t.Fatalf("DoubleStruct returned %f wanted %f", ret, expectedDouble)250 t.Fatalf("DoubleStruct returned %f wanted %f", ret, expectedDouble)
234 }251 }
235 }252 }
236 {253 {
237 type TwoDoubleStruct struct {254 type TwoDoubleStruct struct {
255+ _ structs.HostLayout
238 x, y float64256 x, y float64
239 }257 }
240 var TwoDoubleStructFn func(TwoDoubleStruct) float64258 var TwoDoubleStructFn func(TwoDoubleStruct) float64
241 register(&TwoDoubleStructFn, lib, "TwoDoubleStruct", func(d TwoDoubleStruct) float64 {259 register(&TwoDoubleStructFn, lib, "TwoDoubleStruct", func(d TwoDoubleStruct) float64 {
242 return d.x + d.y260 return d.x + d.y
243 })261 })
244- if ret := TwoDoubleStructFn(TwoDoubleStruct{3, 7}); ret != expectedDouble {262+ if ret := TwoDoubleStructFn(TwoDoubleStruct{x: 3, y: 7}); ret != expectedDouble {
245 t.Fatalf("TwoDoubleStruct returned %f wanted %f", ret, expectedDouble)263 t.Fatalf("TwoDoubleStruct returned %f wanted %f", ret, expectedDouble)
246 }264 }
247 }265 }
248 {266 {
249 type TwoDoubleTwoStruct struct {267 type TwoDoubleTwoStruct struct {
268+ _ structs.HostLayout
250 x struct {269 x struct {
270+ _ structs.HostLayout
251 x, y float64271 x, y float64
252 }272 }
253 }273 }
@@ -255,31 +275,36 @@ func TestRegisterFunc_structArgs(t *testing.T) {
255 register(&TwoDoubleTwoStructFn, lib, "TwoDoubleTwoStruct", func(d TwoDoubleTwoStruct) float64 {275 register(&TwoDoubleTwoStructFn, lib, "TwoDoubleTwoStruct", func(d TwoDoubleTwoStruct) float64 {
256 return d.x.x + d.x.y276 return d.x.x + d.x.y
257 })277 })
258- if ret := TwoDoubleTwoStructFn(TwoDoubleTwoStruct{x: struct{ x, y float64 }{x: 3, y: 7}}); ret != expectedDouble {278+ if ret := TwoDoubleTwoStructFn(TwoDoubleTwoStruct{x: struct {
279+ _ structs.HostLayout
280+ x, y float64
281+ }{x: 3, y: 7}}); ret != expectedDouble {
259 t.Fatalf("TwoDoubleTwoStruct returned %f wanted %f", ret, expectedDouble)282 t.Fatalf("TwoDoubleTwoStruct returned %f wanted %f", ret, expectedDouble)
260 }283 }
261 }284 }
262 {285 {
263 type ThreeDoubleStruct struct {286 type ThreeDoubleStruct struct {
287+ _ structs.HostLayout
264 x, y, z float64288 x, y, z float64
265 }289 }
266 var ThreeDoubleStructFn func(ThreeDoubleStruct) float64290 var ThreeDoubleStructFn func(ThreeDoubleStruct) float64
267 register(&ThreeDoubleStructFn, lib, "ThreeDoubleStruct", func(d ThreeDoubleStruct) float64 {291 register(&ThreeDoubleStructFn, lib, "ThreeDoubleStruct", func(d ThreeDoubleStruct) float64 {
268 return d.x + d.y + d.z292 return d.x + d.y + d.z
269 })293 })
270- if ret := ThreeDoubleStructFn(ThreeDoubleStruct{1, 3, 6}); ret != expectedDouble {294+ if ret := ThreeDoubleStructFn(ThreeDoubleStruct{x: 1, y: 3, z: 6}); ret != expectedDouble {
271 t.Fatalf("ThreeDoubleStructFn returned %f wanted %f", ret, expectedDouble)295 t.Fatalf("ThreeDoubleStructFn returned %f wanted %f", ret, expectedDouble)
272 }296 }
273 }297 }
274 {298 {
275 type LargeFloatStruct struct {299 type LargeFloatStruct struct {
300+ _ structs.HostLayout
276 a, b, c, d, e, f float64301 a, b, c, d, e, f float64
277 }302 }
278 var LargeFloatStructFn func(LargeFloatStruct) float64303 var LargeFloatStructFn func(LargeFloatStruct) float64
279 register(&LargeFloatStructFn, lib, "LargeFloatStruct", func(s LargeFloatStruct) float64 {304 register(&LargeFloatStructFn, lib, "LargeFloatStruct", func(s LargeFloatStruct) float64 {
280 return s.a + s.b + s.c + s.d + s.e + s.f305 return s.a + s.b + s.c + s.d + s.e + s.f
281 })306 })
282- if ret := LargeFloatStructFn(LargeFloatStruct{1, 2, 3, 4, 5, -5}); ret != expectedDouble {307+ if ret := LargeFloatStructFn(LargeFloatStruct{a: 1, b: 2, c: 3, d: 4, e: 5, f: -5}); ret != expectedDouble {
283 t.Fatalf("LargeFloatStructFn returned %f wanted %f", ret, expectedFloat)308 t.Fatalf("LargeFloatStructFn returned %f wanted %f", ret, expectedFloat)
284 }309 }
285 if runtime.GOARCH != "ppc64le" {310 if runtime.GOARCH != "ppc64le" {
@@ -289,13 +314,14 @@ func TestRegisterFunc_structArgs(t *testing.T) {
289 register(&LargeFloatStructWithRegs, lib, "LargeFloatStructWithRegs", func(a, b, c float64, s LargeFloatStruct) float64 {314 register(&LargeFloatStructWithRegs, lib, "LargeFloatStructWithRegs", func(a, b, c float64, s LargeFloatStruct) float64 {
290 return a + b + c + s.a + s.b + s.c + s.d + s.e + s.f315 return a + b + c + s.a + s.b + s.c + s.d + s.e + s.f
291 })316 })
292- if ret := LargeFloatStructWithRegs(1, -1, 0, LargeFloatStruct{1, 2, 3, 4, 5, -5}); ret != expectedDouble {317+ if ret := LargeFloatStructWithRegs(1, -1, 0, LargeFloatStruct{a: 1, b: 2, c: 3, d: 4, e: 5, f: -5}); ret != expectedDouble {
293 t.Fatalf("LargeFloatStructWithRegs returned %f wanted %f", ret, expectedFloat)318 t.Fatalf("LargeFloatStructWithRegs returned %f wanted %f", ret, expectedFloat)
294 }319 }
295 }320 }
296 }321 }
297 {322 {
298 type Rect struct {323 type Rect struct {
324+ _ structs.HostLayout
299 x, y, w, h float64325 x, y, w, h float64
300 }326 }
301 if runtime.GOARCH != "ppc64le" {327 if runtime.GOARCH != "ppc64le" {
@@ -305,7 +331,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
305 register(&RectangleWithRegs, lib, "RectangleWithRegs", func(a, b, c, d, e float64, rect Rect) float64 {331 register(&RectangleWithRegs, lib, "RectangleWithRegs", func(a, b, c, d, e float64, rect Rect) float64 {
306 return a + b + c + d + e + rect.x + rect.y + rect.w + rect.h332 return a + b + c + d + e + rect.x + rect.y + rect.w + rect.h
307 })333 })
308- if ret := RectangleWithRegs(1, 2, 3, 4, -2, Rect{1, 2, 3, -4}); ret != expectedDouble {334+ if ret := RectangleWithRegs(1, 2, 3, 4, -2, Rect{x: 1, y: 2, w: 3, h: -4}); ret != expectedDouble {
309 t.Fatalf("RectangleWithRegs returned %f wanted %f", ret, expectedDouble)335 t.Fatalf("RectangleWithRegs returned %f wanted %f", ret, expectedDouble)
310 }336 }
311 }337 }
@@ -313,19 +339,20 @@ func TestRegisterFunc_structArgs(t *testing.T) {
313 register(&RectangleSubtract, lib, "RectangleSubtract", func(rect Rect) float64 {339 register(&RectangleSubtract, lib, "RectangleSubtract", func(rect Rect) float64 {
314 return (rect.x + rect.y) - (rect.w + rect.h)340 return (rect.x + rect.y) - (rect.w + rect.h)
315 })341 })
316- if ret := RectangleSubtract(Rect{15, 5, 3, 7}); ret != expectedDouble {342+ if ret := RectangleSubtract(Rect{x: 15, y: 5, w: 3, h: 7}); ret != expectedDouble {
317 t.Fatalf("RectangleSubtract returned %f wanted %f", ret, expectedDouble)343 t.Fatalf("RectangleSubtract returned %f wanted %f", ret, expectedDouble)
318 }344 }
319 var Rectangle func(rect Rect) float64345 var Rectangle func(rect Rect) float64
320 register(&Rectangle, lib, "Rectangle", func(rect Rect) float64 {346 register(&Rectangle, lib, "Rectangle", func(rect Rect) float64 {
321 return rect.x + rect.y + rect.w + rect.h347 return rect.x + rect.y + rect.w + rect.h
322 })348 })
323- if ret := Rectangle(Rect{1, 2, 3, 4}); ret != expectedDouble {349+ if ret := Rectangle(Rect{x: 1, y: 2, w: 3, h: 4}); ret != expectedDouble {
324 t.Fatalf("Rectangle returned %f wanted %f", ret, expectedFloat)350 t.Fatalf("Rectangle returned %f wanted %f", ret, expectedFloat)
325 }351 }
326 }352 }
327 {353 {
328 type FloatArray struct {354 type FloatArray struct {
355+ _ structs.HostLayout
329 a [2]float64356 a [2]float64
330 }357 }
331 var FloatArrayFn func(rect FloatArray) float64358 var FloatArrayFn func(rect FloatArray) float64
@@ -338,6 +365,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
338 }365 }
339 {366 {
340 type UnsignedChar4Bytes struct {367 type UnsignedChar4Bytes struct {
368+ _ structs.HostLayout
341 a, b, c, d byte369 a, b, c, d byte
342 }370 }
343 var UnsignedChar4BytesFn func(UnsignedChar4Bytes) uint32371 var UnsignedChar4BytesFn func(UnsignedChar4Bytes) uint32
@@ -350,16 +378,21 @@ func TestRegisterFunc_structArgs(t *testing.T) {
350 }378 }
351 {379 {
352 type UnsignedChar4BytesStruct struct {380 type UnsignedChar4BytesStruct struct {
381+ _ structs.HostLayout
353 x struct {382 x struct {
383+ _ structs.HostLayout
354 a byte384 a byte
355 }385 }
356 y struct {386 y struct {
387+ _ structs.HostLayout
357 b byte388 b byte
358 }389 }
359 z struct {390 z struct {
391+ _ structs.HostLayout
360 c byte392 c byte
361 }393 }
362 w struct {394 w struct {
395+ _ structs.HostLayout
363 d byte396 d byte
364 }397 }
365 }398 }
@@ -368,16 +401,29 @@ func TestRegisterFunc_structArgs(t *testing.T) {
368 return uint32(b.x.a)<<24 | uint32(b.y.b)<<16 | uint32(b.z.c)<<8 | uint32(b.w.d)401 return uint32(b.x.a)<<24 | uint32(b.y.b)<<16 | uint32(b.z.c)<<8 | uint32(b.w.d)
369 })402 })
370 if ret := UnsignedChar4BytesStructFn(UnsignedChar4BytesStruct{403 if ret := UnsignedChar4BytesStructFn(UnsignedChar4BytesStruct{
371- x: struct{ a byte }{a: 0xDE},404+ x: struct {
372- y: struct{ b byte }{b: 0xAD},405+ _ structs.HostLayout
373- z: struct{ c byte }{c: 0xBE},406+ a byte
374- w: struct{ d byte }{d: 0xEF},407+ }{a: 0xDE},
408+ y: struct {
409+ _ structs.HostLayout
410+ b byte
411+ }{b: 0xAD},
412+ z: struct {
413+ _ structs.HostLayout
414+ c byte
415+ }{c: 0xBE},
416+ w: struct {
417+ _ structs.HostLayout
418+ d byte
419+ }{d: 0xEF},
375 }); ret != expectedUnsigned {420 }); ret != expectedUnsigned {
376 t.Fatalf("UnsignedChar4BytesStructFn returned %#x wanted %#x", ret, expectedUnsigned)421 t.Fatalf("UnsignedChar4BytesStructFn returned %#x wanted %#x", ret, expectedUnsigned)
377 }422 }
378 }423 }
379 {424 {
380 type Short struct {425 type Short struct {
426+ _ structs.HostLayout
381 a, b, c, d uint16427 a, b, c, d uint16
382 }428 }
383 var ShortFn func(Short) uint64429 var ShortFn func(Short) uint64
@@ -390,6 +436,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
390 }436 }
391 {437 {
392 type Int struct {438 type Int struct {
439+ _ structs.HostLayout
393 a, b uint32440 a, b uint32
394 }441 }
395 var IntFn func(Int) uint64442 var IntFn func(Int) uint64
@@ -402,6 +449,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
402 }449 }
403 {450 {
404 type Long struct {451 type Long struct {
452+ _ structs.HostLayout
405 a uint64453 a uint64
406 }454 }
407 var LongFn func(Long) uint64455 var LongFn func(Long) uint64
@@ -414,6 +462,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
414 }462 }
415 {463 {
416 type Char8Bytes struct {464 type Char8Bytes struct {
465+ _ structs.HostLayout
417 a, b, c, d, e, f, g, h int8466 a, b, c, d, e, f, g, h int8
418 }467 }
419 var Char8BytesFn func(Char8Bytes) int32468 var Char8BytesFn func(Char8Bytes) int32
@@ -426,6 +475,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
426 }475 }
427 {476 {
428 type Odd struct {477 type Odd struct {
478+ _ structs.HostLayout
429 a, b, c byte479 a, b, c byte
430 }480 }
431 var OddFn func(Odd) int32481 var OddFn func(Odd) int32
@@ -438,6 +488,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
438 }488 }
439 {489 {
440 type Char2Short1 struct {490 type Char2Short1 struct {
491+ _ structs.HostLayout
441 a, b byte492 a, b byte
442 c uint16493 c uint16
443 }494 }
@@ -451,6 +502,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
451 }502 }
452 {503 {
453 type SignedChar2Short1 struct {504 type SignedChar2Short1 struct {
505+ _ structs.HostLayout
454 a, b int8506 a, b int8
455 c int16507 c int16
456 }508 }
@@ -464,6 +516,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
464 }516 }
465 {517 {
466 type Array4UnsignedChars struct {518 type Array4UnsignedChars struct {
519+ _ structs.HostLayout
467 a [4]uint8520 a [4]uint8
468 }521 }
469 var Array4UnsignedCharsFn func(chars Array4UnsignedChars) uint32522 var Array4UnsignedCharsFn func(chars Array4UnsignedChars) uint32
@@ -476,6 +529,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
476 }529 }
477 {530 {
478 type Array3UnsignedChar struct {531 type Array3UnsignedChar struct {
532+ _ structs.HostLayout
479 a [3]uint8533 a [3]uint8
480 }534 }
481 var Array3UnsignedChars func(chars Array3UnsignedChar) uint32535 var Array3UnsignedChars func(chars Array3UnsignedChar) uint32
@@ -488,6 +542,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
488 }542 }
489 {543 {
490 type Array2UnsignedShort struct {544 type Array2UnsignedShort struct {
545+ _ structs.HostLayout
491 a [2]uint16546 a [2]uint16
492 }547 }
493 var Array2UnsignedShorts func(chars Array2UnsignedShort) uint32548 var Array2UnsignedShorts func(chars Array2UnsignedShort) uint32
@@ -500,6 +555,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
500 }555 }
501 {556 {
502 type Array4Chars struct {557 type Array4Chars struct {
558+ _ structs.HostLayout
503 a [4]int8559 a [4]int8
504 }560 }
505 var Array4CharsFn func(chars Array4Chars) int32561 var Array4CharsFn func(chars Array4Chars) int32
@@ -513,6 +569,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
513 }569 }
514 {570 {
515 type Array2Short struct {571 type Array2Short struct {
572+ _ structs.HostLayout
516 a [2]int16573 a [2]int16
517 }574 }
518 var Array2Shorts func(chars Array2Short) int32575 var Array2Shorts func(chars Array2Short) int32
@@ -525,6 +582,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
525 }582 }
526 {583 {
527 type Array3Short struct {584 type Array3Short struct {
585+ _ structs.HostLayout
528 a [3]int16586 a [3]int16
529 }587 }
530 var Array3Shorts func(chars Array3Short) int32588 var Array3Shorts func(chars Array3Short) int32
@@ -537,21 +595,23 @@ func TestRegisterFunc_structArgs(t *testing.T) {
537 }595 }
538 {596 {
539 type BoolStruct struct {597 type BoolStruct struct {
598+ _ structs.HostLayout
540 b bool599 b bool
541 }600 }
542 var BoolStructFn func(BoolStruct) bool601 var BoolStructFn func(BoolStruct) bool
543 register(&BoolStructFn, lib, "BoolStruct", func(b BoolStruct) bool {602 register(&BoolStructFn, lib, "BoolStruct", func(b BoolStruct) bool {
544 return b.b603 return b.b
545 })604 })
546- if ret := BoolStructFn(BoolStruct{true}); ret != true {605+ if ret := BoolStructFn(BoolStruct{b: true}); ret != true {
547 t.Fatalf("BoolStructFn returned %v wanted %v", ret, true)606 t.Fatalf("BoolStructFn returned %v wanted %v", ret, true)
548 }607 }
549- if ret := BoolStructFn(BoolStruct{false}); ret != false {608+ if ret := BoolStructFn(BoolStruct{b: false}); ret != false {
550 t.Fatalf("BoolStructFn returned %v wanted %v", ret, false)609 t.Fatalf("BoolStructFn returned %v wanted %v", ret, false)
551 }610 }
552 }611 }
553 {612 {
554 type BoolFloat struct {613 type BoolFloat struct {
614+ _ structs.HostLayout
555 b bool615 b bool
556 _ [3]byte // purego won't do padding for you so make sure it aligns properly with C struct616 _ [3]byte // purego won't do padding for you so make sure it aligns properly with C struct
557 f float32617 f float32
@@ -571,9 +631,16 @@ func TestRegisterFunc_structArgs(t *testing.T) {
571 }631 }
572 }632 }
573 {633 {
574- type point struct{ x, y float64 }634+ type point struct {
575- type size struct{ width, height float64 }635+ _ structs.HostLayout
636+ x, y float64
637+ }
638+ type size struct {
639+ _ structs.HostLayout
640+ width, height float64
641+ }
576 type Content struct {642 type Content struct {
643+ _ structs.HostLayout
577 point point644 point point
578 size size645 size size
579 }646 }
@@ -589,13 +656,14 @@ func TestRegisterFunc_structArgs(t *testing.T) {
589 })656 })
590 if ret := InitWithContentRect(new(int),657 if ret := InitWithContentRect(new(int),
591 // These numbers are created so that when added together and then divided by 11 it produces 0xdeadbeef658 // These numbers are created so that when added together and then divided by 11 it produces 0xdeadbeef
592- Content{point{x: 41_000_000_000, y: 95_000_000}, size{width: 214_000, height: 149}},659+ Content{point: point{x: 41_000_000_000, y: 95_000_000}, size: size{width: 214_000, height: 149}},
593 15, 4, true); ret != expectedUnsigned {660 15, 4, true); ret != expectedUnsigned {
594 t.Fatalf("InitWithContentRect returned %d wanted %#x", ret, expectedUnsigned)661 t.Fatalf("InitWithContentRect returned %d wanted %#x", ret, expectedUnsigned)
595 }662 }
596 }663 }
597 {664 {
598 type GoInt4 struct {665 type GoInt4 struct {
666+ _ structs.HostLayout
599 A, B, C, D int667 A, B, C, D int
600 }668 }
601 var GoInt4Fn func(GoInt4) int669 var GoInt4Fn func(GoInt4) int
@@ -603,12 +671,13 @@ func TestRegisterFunc_structArgs(t *testing.T) {
603 return g.A + g.B - g.C + g.D671 return g.A + g.B - g.C + g.D
604 })672 })
605 const expected = math.MaxInt - 52 - 3 + 4673 const expected = math.MaxInt - 52 - 3 + 4
606- if ret := GoInt4Fn(GoInt4{math.MaxInt, -52, 3, 4}); ret != expected {674+ if ret := GoInt4Fn(GoInt4{A: math.MaxInt, B: -52, C: 3, D: 4}); ret != expected {
607 t.Fatalf("GoInt4Fn returned %d wanted %#x", ret, expected)675 t.Fatalf("GoInt4Fn returned %d wanted %#x", ret, expected)
608 }676 }
609 }677 }
610 {678 {
611 type GoUint4 struct {679 type GoUint4 struct {
680+ _ structs.HostLayout
612 A, B, C, D uint681 A, B, C, D uint
613 }682 }
614 var GoUint4Fn func(GoUint4) uint683 var GoUint4Fn func(GoUint4) uint
@@ -616,23 +685,27 @@ func TestRegisterFunc_structArgs(t *testing.T) {
616 return g.A + g.B + g.C + g.D685 return g.A + g.B + g.C + g.D
617 })686 })
618 const expected = 1_000_000 + 53 + 71 + 8687 const expected = 1_000_000 + 53 + 71 + 8
619- if ret := GoUint4Fn(GoUint4{1_000_000, 53, 71, 8}); ret != expected {688+ if ret := GoUint4Fn(GoUint4{A: 1_000_000, B: 53, C: 71, D: 8}); ret != expected {
620 t.Fatalf("GoUint4Fn returned %d wanted %#x", ret, expected)689 t.Fatalf("GoUint4Fn returned %d wanted %#x", ret, expected)
621 }690 }
622 }691 }
623 {692 {
624- type OneLong struct{ a uintptr }693+ type OneLong struct {
694+ _ structs.HostLayout
695+ a uintptr
696+ }
625 var TakeGoUintAndReturn func(a OneLong) uint64697 var TakeGoUintAndReturn func(a OneLong) uint64
626 register(&TakeGoUintAndReturn, lib, "TakeGoUintAndReturn", func(a OneLong) uint64 {698 register(&TakeGoUintAndReturn, lib, "TakeGoUintAndReturn", func(a OneLong) uint64 {
627 return uint64(a.a)699 return uint64(a.a)
628 })700 })
629 expected := uint64(7)701 expected := uint64(7)
630- if ret := TakeGoUintAndReturn(OneLong{7}); ret != expected {702+ if ret := TakeGoUintAndReturn(OneLong{a: 7}); ret != expected {
631 t.Fatalf("TakeGoUintAndReturn returned %+v wanted %+v", ret, expected)703 t.Fatalf("TakeGoUintAndReturn returned %+v wanted %+v", ret, expected)
632 }704 }
633 }705 }
634 {706 {
635 type FloatAndBool struct {707 type FloatAndBool struct {
708+ _ structs.HostLayout
636 x float32709 x float32
637 y bool710 y bool
638 }711 }
@@ -652,13 +725,14 @@ func TestRegisterFunc_structArgs(t *testing.T) {
652 }725 }
653 {726 {
654 type FourInt32s struct {727 type FourInt32s struct {
728+ _ structs.HostLayout
655 f0, f1, f2, f3 int32729 f0, f1, f2, f3 int32
656 }730 }
657 var FourInt32sFn func(FourInt32s) int32731 var FourInt32sFn func(FourInt32s) int32
658 register(&FourInt32sFn, lib, "FourInt32s", func(s FourInt32s) int32 {732 register(&FourInt32sFn, lib, "FourInt32s", func(s FourInt32s) int32 {
659 return s.f0 + s.f1 + s.f2 + s.f3733 return s.f0 + s.f1 + s.f2 + s.f3
660 })734 })
661- result := FourInt32sFn(FourInt32s{100, -127, 4, -100})735+ result := FourInt32sFn(FourInt32s{f0: 100, f1: -127, f2: 4, f3: -100})
662 const want = 100 - 127 + 4 - 100736 const want = 100 - 127 + 4 - 100
663 if result != want {737 if result != want {
664 t.Fatalf("FourInt32s returned %d wanted %d", result, want)738 t.Fatalf("FourInt32s returned %d wanted %d", result, want)
@@ -666,6 +740,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
666 }740 }
667 {741 {
668 type PointerWrapper struct {742 type PointerWrapper struct {
743+ _ structs.HostLayout
669 ctx unsafe.Pointer744 ctx unsafe.Pointer
670 }745 }
671 var ExtractPointer func(wrapper PointerWrapper) uintptr746 var ExtractPointer func(wrapper PointerWrapper) uintptr
@@ -683,6 +758,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
683 }758 }
684 {759 {
685 type TwoPointers struct {760 type TwoPointers struct {
761+ _ structs.HostLayout
686 ptr1, ptr2 unsafe.Pointer762 ptr1, ptr2 unsafe.Pointer
687 }763 }
688 var AddPointers func(wrapper TwoPointers) uintptr764 var AddPointers func(wrapper TwoPointers) uintptr
@@ -694,7 +770,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
694 ptr1 := unsafe.Pointer(&v1)770 ptr1 := unsafe.Pointer(&v1)
695 ptr2 := unsafe.Pointer(&v2)771 ptr2 := unsafe.Pointer(&v2)
696 expected := uintptr(ptr1) + uintptr(ptr2)772 expected := uintptr(ptr1) + uintptr(ptr2)
697- result := AddPointers(TwoPointers{ptr1, ptr2})773+ result := AddPointers(TwoPointers{ptr1: ptr1, ptr2: ptr2})
698 if result != expected {774 if result != expected {
699 t.Fatalf("AddPointers returned %#x wanted %#x", result, expected)775 t.Fatalf("AddPointers returned %#x wanted %#x", result, expected)
700 }776 }
@@ -703,48 +779,60 @@ func TestRegisterFunc_structArgs(t *testing.T) {
703 // Identity struct arg tests779 // Identity struct arg tests
704 {780 {
705 // Single int64: one integer register.781 // Single int64: one integer register.
706- type OneInt64 struct{ A int64 }782+ type OneInt64 struct {
783+ _ structs.HostLayout
784+ A int64
785+ }
707 var fn func(OneInt64) OneInt64786 var fn func(OneInt64) OneInt64
708 register(&fn, lib, "IdentityOneInt64", func(s OneInt64) OneInt64 {787 register(&fn, lib, "IdentityOneInt64", func(s OneInt64) OneInt64 {
709 return s788 return s
710 })789 })
711- expected := OneInt64{0xDEADBEEF}790+ expected := OneInt64{A: 0xDEADBEEF}
712 if ret := fn(expected); ret != expected {791 if ret := fn(expected); ret != expected {
713 t.Fatalf("IdentityOneInt64 returned %+v wanted %+v", ret, expected)792 t.Fatalf("IdentityOneInt64 returned %+v wanted %+v", ret, expected)
714 }793 }
715 }794 }
716 {795 {
717 // Two int64 fields: two integer registers.796 // Two int64 fields: two integer registers.
718- type IntLessThan16Bytes struct{ X, Y int64 }797+ type IntLessThan16Bytes struct {
798+ _ structs.HostLayout
799+ X, Y int64
800+ }
719 var fn func(IntLessThan16Bytes) IntLessThan16Bytes801 var fn func(IntLessThan16Bytes) IntLessThan16Bytes
720 register(&fn, lib, "IdentityIntLessThan16Bytes", func(s IntLessThan16Bytes) IntLessThan16Bytes {802 register(&fn, lib, "IdentityIntLessThan16Bytes", func(s IntLessThan16Bytes) IntLessThan16Bytes {
721 return s803 return s
722 })804 })
723- expected := IntLessThan16Bytes{0xDEADBEEF, -42}805+ expected := IntLessThan16Bytes{X: 0xDEADBEEF, Y: -42}
724 if ret := fn(expected); ret != expected {806 if ret := fn(expected); ret != expected {
725 t.Fatalf("IdentityIntLessThan16Bytes returned %+v wanted %+v", ret, expected)807 t.Fatalf("IdentityIntLessThan16Bytes returned %+v wanted %+v", ret, expected)
726 }808 }
727 }809 }
728 {810 {
729 // Two float64 fields: SSE on amd64, HFA on arm64.811 // Two float64 fields: SSE on amd64, HFA on arm64.
730- type TwoDoubleStruct struct{ X, Y float64 }812+ type TwoDoubleStruct struct {
813+ _ structs.HostLayout
814+ X, Y float64
815+ }
731 var fn func(TwoDoubleStruct) TwoDoubleStruct816 var fn func(TwoDoubleStruct) TwoDoubleStruct
732 register(&fn, lib, "IdentityTwoDoubleStruct", func(s TwoDoubleStruct) TwoDoubleStruct {817 register(&fn, lib, "IdentityTwoDoubleStruct", func(s TwoDoubleStruct) TwoDoubleStruct {
733 return s818 return s
734 })819 })
735- expected := TwoDoubleStruct{3.14, -2.71}820+ expected := TwoDoubleStruct{X: 3.14, Y: -2.71}
736 if ret := fn(expected); ret != expected {821 if ret := fn(expected); ret != expected {
737 t.Fatalf("IdentityTwoDoubleStruct returned %+v wanted %+v", ret, expected)822 t.Fatalf("IdentityTwoDoubleStruct returned %+v wanted %+v", ret, expected)
738 }823 }
739 }824 }
740 {825 {
741 // Four float32 fields: HFA on arm64, SSE on amd64.826 // Four float32 fields: HFA on arm64, SSE on amd64.
742- type FourFloat32 struct{ A, B, C, D float32 }827+ type FourFloat32 struct {
828+ _ structs.HostLayout
829+ A, B, C, D float32
830+ }
743 var fn func(FourFloat32) FourFloat32831 var fn func(FourFloat32) FourFloat32
744 register(&fn, lib, "IdentityFourFloat32", func(s FourFloat32) FourFloat32 {832 register(&fn, lib, "IdentityFourFloat32", func(s FourFloat32) FourFloat32 {
745 return s833 return s
746 })834 })
747- expected := FourFloat32{1.0, 2.0, 3.0, 4.0}835+ expected := FourFloat32{A: 1.0, B: 2.0, C: 3.0, D: 4.0}
748 if ret := fn(expected); ret != expected {836 if ret := fn(expected); ret != expected {
749 t.Fatalf("IdentityFourFloat32 returned %+v wanted %+v", ret, expected)837 t.Fatalf("IdentityFourFloat32 returned %+v wanted %+v", ret, expected)
750 }838 }
@@ -752,6 +840,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
752 {840 {
753 // Mixed float32 + int32: INTEGER class eightbyte on amd64, non-HFA int regs on arm64.841 // Mixed float32 + int32: INTEGER class eightbyte on amd64, non-HFA int regs on arm64.
754 type FloatAndInt struct {842 type FloatAndInt struct {
843+ _ structs.HostLayout
755 X float32844 X float32
756 Y int32845 Y int32
757 }846 }
@@ -759,19 +848,22 @@ func TestRegisterFunc_structArgs(t *testing.T) {
759 register(&fn, lib, "IdentityFloatAndInt", func(s FloatAndInt) FloatAndInt {848 register(&fn, lib, "IdentityFloatAndInt", func(s FloatAndInt) FloatAndInt {
760 return s849 return s
761 })850 })
762- expected := FloatAndInt{7.5, 42}851+ expected := FloatAndInt{X: 7.5, Y: 42}
763 if ret := fn(expected); ret != expected {852 if ret := fn(expected); ret != expected {
764 t.Fatalf("IdentityFloatAndInt returned %+v wanted %+v", ret, expected)853 t.Fatalf("IdentityFloatAndInt returned %+v wanted %+v", ret, expected)
765 }854 }
766 }855 }
767 {856 {
768 // Struct > 16 bytes: hidden pointer on amd64, pointer in int register on arm64.857 // Struct > 16 bytes: hidden pointer on amd64, pointer in int register on arm64.
769- type ThreeInt64 struct{ A, B, C int64 }858+ type ThreeInt64 struct {
859+ _ structs.HostLayout
860+ A, B, C int64
861+ }
770 var fn func(ThreeInt64) ThreeInt64862 var fn func(ThreeInt64) ThreeInt64
771 register(&fn, lib, "IdentityThreeInt64", func(s ThreeInt64) ThreeInt64 {863 register(&fn, lib, "IdentityThreeInt64", func(s ThreeInt64) ThreeInt64 {
772 return s864 return s
773 })865 })
774- expected := ThreeInt64{1, 2, 3}866+ expected := ThreeInt64{A: 1, B: 2, C: 3}
775 if ret := fn(expected); ret != expected {867 if ret := fn(expected); ret != expected {
776 t.Fatalf("IdentityThreeInt64 returned %+v wanted %+v", ret, expected)868 t.Fatalf("IdentityThreeInt64 returned %+v wanted %+v", ret, expected)
777 }869 }
@@ -779,6 +871,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
779 {871 {
780 // Struct > 16 bytes with pointer fields.872 // Struct > 16 bytes with pointer fields.
781 type PtrInt64Ptr struct {873 type PtrInt64Ptr struct {
874+ _ structs.HostLayout
782 A *int64875 A *int64
783 B int64876 B int64
784 C *int64877 C *int64
@@ -789,7 +882,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
789 register(&fn, lib, "IdentityPtrInt64Ptr", func(s PtrInt64Ptr) PtrInt64Ptr {882 register(&fn, lib, "IdentityPtrInt64Ptr", func(s PtrInt64Ptr) PtrInt64Ptr {
790 return s883 return s
791 })884 })
792- expected := PtrInt64Ptr{a, 200, c}885+ expected := PtrInt64Ptr{A: a, B: 200, C: c}
793 ret := fn(expected)886 ret := fn(expected)
794 if *ret.A != *expected.A || ret.B != expected.B || *ret.C != *expected.C {887 if *ret.A != *expected.A || ret.B != expected.B || *ret.C != *expected.C {
795 t.Fatalf("IdentityPtrInt64Ptr returned %+v wanted %+v", ret, expected)888 t.Fatalf("IdentityPtrInt64Ptr returned %+v wanted %+v", ret, expected)
@@ -801,24 +894,30 @@ func TestRegisterFunc_structArgs(t *testing.T) {
801 // Struct arg after some primitive args: register offset correctness.894 // Struct arg after some primitive args: register offset correctness.
802 // ppc64le is skipped: a float argument shadows a GPR, which purego895 // ppc64le is skipped: a float argument shadows a GPR, which purego
803 // does not model for scalars, so the trailing struct is misplaced.896 // does not model for scalars, so the trailing struct is misplaced.
804- type IntLessThan16Bytes struct{ X, Y int64 }897+ type IntLessThan16Bytes struct {
898+ _ structs.HostLayout
899+ X, Y int64
900+ }
805 var fn func(int64, float64, IntLessThan16Bytes) IntLessThan16Bytes901 var fn func(int64, float64, IntLessThan16Bytes) IntLessThan16Bytes
806 register(&fn, lib, "IdentityTwoInt64AfterPrims", func(x int64, y float64, s IntLessThan16Bytes) IntLessThan16Bytes {902 register(&fn, lib, "IdentityTwoInt64AfterPrims", func(x int64, y float64, s IntLessThan16Bytes) IntLessThan16Bytes {
807 return s903 return s
808 })904 })
809- expected := IntLessThan16Bytes{100, 200}905+ expected := IntLessThan16Bytes{X: 100, Y: 200}
810 if ret := fn(1, 2.0, expected); ret != expected {906 if ret := fn(1, 2.0, expected); ret != expected {
811 t.Fatalf("IdentityTwoInt64AfterPrims returned %+v wanted %+v", ret, expected)907 t.Fatalf("IdentityTwoInt64AfterPrims returned %+v wanted %+v", ret, expected)
812 }908 }
813 }909 }
814 {910 {
815 // Float struct arg after float primitive args: float register offset.911 // Float struct arg after float primitive args: float register offset.
816- type FloatLessThan16Bytes struct{ X, Y float32 }912+ type FloatLessThan16Bytes struct {
913+ _ structs.HostLayout
914+ X, Y float32
915+ }
817 var fn func(float64, float64, FloatLessThan16Bytes) FloatLessThan16Bytes916 var fn func(float64, float64, FloatLessThan16Bytes) FloatLessThan16Bytes
818 register(&fn, lib, "IdentityTwoFloat32AfterFloats", func(x, y float64, s FloatLessThan16Bytes) FloatLessThan16Bytes {917 register(&fn, lib, "IdentityTwoFloat32AfterFloats", func(x, y float64, s FloatLessThan16Bytes) FloatLessThan16Bytes {
819 return s918 return s
820 })919 })
821- expected := FloatLessThan16Bytes{5.0, 6.0}920+ expected := FloatLessThan16Bytes{X: 5.0, Y: 6.0}
822 if ret := fn(1.0, 2.0, expected); ret != expected {921 if ret := fn(1.0, 2.0, expected); ret != expected {
823 t.Fatalf("IdentityTwoFloat32AfterFloats returned %+v wanted %+v", ret, expected)922 t.Fatalf("IdentityTwoFloat32AfterFloats returned %+v wanted %+v", ret, expected)
824 }923 }
@@ -826,6 +925,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
826 {925 {
827 // Mixed struct with pointer: pointer + int32 + float32 + int32.926 // Mixed struct with pointer: pointer + int32 + float32 + int32.
828 type Mixed5Args struct {927 type Mixed5Args struct {
928+ _ structs.HostLayout
829 A *int64929 A *int64
830 B int32930 B int32
831 C float32931 C float32
@@ -837,7 +937,7 @@ func TestRegisterFunc_structArgs(t *testing.T) {
837 register(&fn, lib, "IdentityMixed5Args", func(s Mixed5Args) Mixed5Args {937 register(&fn, lib, "IdentityMixed5Args", func(s Mixed5Args) Mixed5Args {
838 return s938 return s
839 })939 })
840- expected := Mixed5Args{ptr, 1, 7.2, 9}940+ expected := Mixed5Args{A: ptr, B: 1, C: 7.2, D: 9}
841 ret := fn(expected)941 ret := fn(expected)
842 if ret.A != expected.A || ret.B != expected.B || ret.C != expected.C || ret.D != expected.D {942 if ret.A != expected.A || ret.B != expected.B || ret.C != expected.C || ret.D != expected.D {
843 t.Fatalf("IdentityMixed5Args returned %+v wanted %+v", ret, expected)943 t.Fatalf("IdentityMixed5Args returned %+v wanted %+v", ret, expected)
@@ -927,166 +1027,228 @@ func TestRegisterFunc_structReturns(t *testing.T) {
927 t.Run(imp.name, func(t *testing.T) {1027 t.Run(imp.name, func(t *testing.T) {
928 register := imp.register1028 register := imp.register
929 {1029 {
930- type Empty struct{}1030+ type Empty struct {
1031+ _ structs.HostLayout
1032+ }
931 var ReturnEmpty func() Empty1033 var ReturnEmpty func() Empty
932 register(&ReturnEmpty, lib, "ReturnEmpty")1034 register(&ReturnEmpty, lib, "ReturnEmpty")
933 ret := ReturnEmpty()1035 ret := ReturnEmpty()
934 _ = ret1036 _ = ret
935 }1037 }
936 {1038 {
937- type inner struct{ A int16 }1039+ type inner struct {
1040+ _ structs.HostLayout
1041+ A int16
1042+ }
938 type StructInStruct struct {1043 type StructInStruct struct {
1044+ _ structs.HostLayout
939 A inner1045 A inner
940 B inner1046 B inner
941 C inner1047 C inner
942 }1048 }
943 var ReturnStructInStruct func(a, b, c int16) StructInStruct1049 var ReturnStructInStruct func(a, b, c int16) StructInStruct
944 register(&ReturnStructInStruct, lib, "ReturnStructInStruct")1050 register(&ReturnStructInStruct, lib, "ReturnStructInStruct")
945- expected := StructInStruct{inner{^int16(0)}, inner{2}, inner{3}}1051+ expected := StructInStruct{A: inner{A: ^int16(0)}, B: inner{A: 2}, C: inner{A: 3}}
946 if ret := ReturnStructInStruct(^int16(0), 2, 3); ret != expected {1052 if ret := ReturnStructInStruct(^int16(0), 2, 3); ret != expected {
947 t.Fatalf("StructInStruct returned %+v wanted %+v", ret, expected)1053 t.Fatalf("StructInStruct returned %+v wanted %+v", ret, expected)
948 }1054 }
949 }1055 }
950 {1056 {
951- type ThreeShorts struct{ A, B, C int16 }1057+ type ThreeShorts struct {
1058+ _ structs.HostLayout
1059+ A, B, C int16
1060+ }
952 var ReturnThreeShorts func(a, b, c int16) ThreeShorts1061 var ReturnThreeShorts func(a, b, c int16) ThreeShorts
953 register(&ReturnThreeShorts, lib, "ReturnThreeShorts")1062 register(&ReturnThreeShorts, lib, "ReturnThreeShorts")
954- expected := ThreeShorts{^int16(0), 2, 3}1063+ expected := ThreeShorts{A: ^int16(0), B: 2, C: 3}
955 if ret := ReturnThreeShorts(^int16(0), 2, 3); ret != expected {1064 if ret := ReturnThreeShorts(^int16(0), 2, 3); ret != expected {
956 t.Fatalf("ReturnThreeShorts returned %+v wanted %+v", ret, expected)1065 t.Fatalf("ReturnThreeShorts returned %+v wanted %+v", ret, expected)
957 }1066 }
958 }1067 }
959 {1068 {
960- type FourShorts struct{ A, B, C, D int16 }1069+ type FourShorts struct {
1070+ _ structs.HostLayout
1071+ A, B, C, D int16
1072+ }
961 var ReturnFourShorts func(a, b, c, d int16) FourShorts1073 var ReturnFourShorts func(a, b, c, d int16) FourShorts
962 register(&ReturnFourShorts, lib, "ReturnFourShorts")1074 register(&ReturnFourShorts, lib, "ReturnFourShorts")
963- expected := FourShorts{^int16(0), 2, 3, 4}1075+ expected := FourShorts{A: ^int16(0), B: 2, C: 3, D: 4}
964 if ret := ReturnFourShorts(^int16(0), 2, 3, 4); ret != expected {1076 if ret := ReturnFourShorts(^int16(0), 2, 3, 4); ret != expected {
965 t.Fatalf("ReturnFourShorts returned %+v wanted %+v", ret, expected)1077 t.Fatalf("ReturnFourShorts returned %+v wanted %+v", ret, expected)
966 }1078 }
967 }1079 }
968 {1080 {
969- type OneLong struct{ A int64 }1081+ type OneLong struct {
1082+ _ structs.HostLayout
1083+ A int64
1084+ }
970 var ReturnOneLong func(a int64) OneLong1085 var ReturnOneLong func(a int64) OneLong
971 register(&ReturnOneLong, lib, "ReturnOneLong")1086 register(&ReturnOneLong, lib, "ReturnOneLong")
972- expected := OneLong{5}1087+ expected := OneLong{A: 5}
973 if ret := ReturnOneLong(5); ret != expected {1088 if ret := ReturnOneLong(5); ret != expected {
974 t.Fatalf("ReturnOneLong returned %+v wanted %+v", ret, expected)1089 t.Fatalf("ReturnOneLong returned %+v wanted %+v", ret, expected)
975 }1090 }
976 }1091 }
977 {1092 {
978- type TwoLongs struct{ A, B int64 }1093+ type TwoLongs struct {
1094+ _ structs.HostLayout
1095+ A, B int64
1096+ }
979 var ReturnTwoLongs func(a, b int64) TwoLongs1097 var ReturnTwoLongs func(a, b int64) TwoLongs
980 register(&ReturnTwoLongs, lib, "ReturnTwoLongs")1098 register(&ReturnTwoLongs, lib, "ReturnTwoLongs")
981- expected := TwoLongs{1, 2}1099+ expected := TwoLongs{A: 1, B: 2}
982 if ret := ReturnTwoLongs(1, 2); ret != expected {1100 if ret := ReturnTwoLongs(1, 2); ret != expected {
983 t.Fatalf("ReturnTwoLongs returned %+v wanted %+v", ret, expected)1101 t.Fatalf("ReturnTwoLongs returned %+v wanted %+v", ret, expected)
984 }1102 }
985 }1103 }
986 {1104 {
987- type ThreeLongs struct{ A, B, C int64 }1105+ type ThreeLongs struct {
1106+ _ structs.HostLayout
1107+ A, B, C int64
1108+ }
988 var ReturnThreeLongs func(a, b, c int64) ThreeLongs1109 var ReturnThreeLongs func(a, b, c int64) ThreeLongs
989 register(&ReturnThreeLongs, lib, "ReturnThreeLongs")1110 register(&ReturnThreeLongs, lib, "ReturnThreeLongs")
990- expected := ThreeLongs{1, 2, 3}1111+ expected := ThreeLongs{A: 1, B: 2, C: 3}
991 if ret := ReturnThreeLongs(1, 2, 3); ret != expected {1112 if ret := ReturnThreeLongs(1, 2, 3); ret != expected {
992 t.Fatalf("ReturnThreeLongs returned %+v wanted %+v", ret, expected)1113 t.Fatalf("ReturnThreeLongs returned %+v wanted %+v", ret, expected)
993 }1114 }
994 }1115 }
995 {1116 {
996- type OneFloat struct{ A float32 }1117+ type OneFloat struct {
1118+ _ structs.HostLayout
1119+ A float32
1120+ }
997 var ReturnOneFloat func(a float32) OneFloat1121 var ReturnOneFloat func(a float32) OneFloat
998 register(&ReturnOneFloat, lib, "ReturnOneFloat")1122 register(&ReturnOneFloat, lib, "ReturnOneFloat")
999- expected := OneFloat{1}1123+ expected := OneFloat{A: 1}
1000 if ret := ReturnOneFloat(1); ret != expected {1124 if ret := ReturnOneFloat(1); ret != expected {
1001 t.Fatalf("ReturnOneFloat returned %+v wanted %+v", ret, expected)1125 t.Fatalf("ReturnOneFloat returned %+v wanted %+v", ret, expected)
1002 }1126 }
1003 }1127 }
1004 {1128 {
1005- type TwoFloats struct{ A, B float32 }1129+ type TwoFloats struct {
1130+ _ structs.HostLayout
1131+ A, B float32
1132+ }
1006 var ReturnTwoFloats func(a, b float32) TwoFloats1133 var ReturnTwoFloats func(a, b float32) TwoFloats
1007 register(&ReturnTwoFloats, lib, "ReturnTwoFloats")1134 register(&ReturnTwoFloats, lib, "ReturnTwoFloats")
1008- expected := TwoFloats{5, 2}1135+ expected := TwoFloats{A: 5, B: 2}
1009 if ret := ReturnTwoFloats(5, 2); ret != expected {1136 if ret := ReturnTwoFloats(5, 2); ret != expected {
1010 t.Fatalf("ReturnTwoFloats returned %+v wanted %+v", ret, expected)1137 t.Fatalf("ReturnTwoFloats returned %+v wanted %+v", ret, expected)
1011 }1138 }
1012 }1139 }
1013 {1140 {
1014- type ThreeFloats struct{ A, B, C float32 }1141+ type ThreeFloats struct {
1142+ _ structs.HostLayout
1143+ A, B, C float32
1144+ }
1015 var ReturnThreeFloats func(a, b, c float32) ThreeFloats1145 var ReturnThreeFloats func(a, b, c float32) ThreeFloats
1016 register(&ReturnThreeFloats, lib, "ReturnThreeFloats")1146 register(&ReturnThreeFloats, lib, "ReturnThreeFloats")
1017- expected := ThreeFloats{1, 2, 3}1147+ expected := ThreeFloats{A: 1, B: 2, C: 3}
1018 if ret := ReturnThreeFloats(1, 2, 3); ret != expected {1148 if ret := ReturnThreeFloats(1, 2, 3); ret != expected {
1019 t.Fatalf("ReturnThreeFloats returned %+v wanted %+v", ret, expected)1149 t.Fatalf("ReturnThreeFloats returned %+v wanted %+v", ret, expected)
1020 }1150 }
1021 }1151 }
1022 {1152 {
1023- type FourFloats struct{ A, B, C, D float32 }1153+ type FourFloats struct {
1154+ _ structs.HostLayout
1155+ A, B, C, D float32
1156+ }
1024 var ReturnFourFloats func(a, b, c, d float32) FourFloats1157 var ReturnFourFloats func(a, b, c, d float32) FourFloats
1025 register(&ReturnFourFloats, lib, "ReturnFourFloats")1158 register(&ReturnFourFloats, lib, "ReturnFourFloats")
1026- expected := FourFloats{1, 2, 3, 4}1159+ expected := FourFloats{A: 1, B: 2, C: 3, D: 4}
1027 if ret := ReturnFourFloats(1, 2, 3, 4); ret != expected {1160 if ret := ReturnFourFloats(1, 2, 3, 4); ret != expected {
1028 t.Fatalf("ReturnFourFloats returned %+v wanted %+v", ret, expected)1161 t.Fatalf("ReturnFourFloats returned %+v wanted %+v", ret, expected)
1029 }1162 }
1030 }1163 }
1031 {1164 {
1032- type OneDouble struct{ A float64 }1165+ type OneDouble struct {
1166+ _ structs.HostLayout
1167+ A float64
1168+ }
1033 var ReturnOneDouble func(a float64) OneDouble1169 var ReturnOneDouble func(a float64) OneDouble
1034 register(&ReturnOneDouble, lib, "ReturnOneDouble")1170 register(&ReturnOneDouble, lib, "ReturnOneDouble")
1035- expected := OneDouble{1}1171+ expected := OneDouble{A: 1}
1036 if ret := ReturnOneDouble(1); ret != expected {1172 if ret := ReturnOneDouble(1); ret != expected {
1037 t.Fatalf("ReturnOneDouble returned %+v wanted %+v", ret, expected)1173 t.Fatalf("ReturnOneDouble returned %+v wanted %+v", ret, expected)
1038 }1174 }
1039 }1175 }
1040 {1176 {
1041- type TwoDoubles struct{ A, B float64 }1177+ type TwoDoubles struct {
1178+ _ structs.HostLayout
1179+ A, B float64
1180+ }
1042 var ReturnTwoDoubles func(a, b float64) TwoDoubles1181 var ReturnTwoDoubles func(a, b float64) TwoDoubles
1043 register(&ReturnTwoDoubles, lib, "ReturnTwoDoubles")1182 register(&ReturnTwoDoubles, lib, "ReturnTwoDoubles")
1044- expected := TwoDoubles{7, 3}1183+ expected := TwoDoubles{A: 7, B: 3}
1045 if ret := ReturnTwoDoubles(7, 3); ret != expected {1184 if ret := ReturnTwoDoubles(7, 3); ret != expected {
1046 t.Fatalf("ReturnTwoDoubles returned %+v wanted %+v", ret, expected)1185 t.Fatalf("ReturnTwoDoubles returned %+v wanted %+v", ret, expected)
1047 }1186 }
1048 }1187 }
1049 {1188 {
1050- type ThreeDoubles struct{ A, B, C float64 }1189+ type ThreeDoubles struct {
1190+ _ structs.HostLayout
1191+ A, B, C float64
1192+ }
1051 var ReturnThreeDoubles func(a, b, c float64) ThreeDoubles1193 var ReturnThreeDoubles func(a, b, c float64) ThreeDoubles
1052 register(&ReturnThreeDoubles, lib, "ReturnThreeDoubles")1194 register(&ReturnThreeDoubles, lib, "ReturnThreeDoubles")
1053- expected := ThreeDoubles{1, 2, 3}1195+ expected := ThreeDoubles{A: 1, B: 2, C: 3}
1054 if ret := ReturnThreeDoubles(1, 2, 3); ret != expected {1196 if ret := ReturnThreeDoubles(1, 2, 3); ret != expected {
1055 t.Fatalf("ReturnThreeDoubles returned %+v wanted %+v", ret, expected)1197 t.Fatalf("ReturnThreeDoubles returned %+v wanted %+v", ret, expected)
1056 }1198 }
1057 }1199 }
1058 {1200 {
1059- type FourDoubles struct{ A, B, C, D float64 }1201+ type FourDoubles struct {
1202+ _ structs.HostLayout
1203+ A, B, C, D float64
1204+ }
1060 var ReturnFourDoubles func(a, b, c, d float64) FourDoubles1205 var ReturnFourDoubles func(a, b, c, d float64) FourDoubles
1061 register(&ReturnFourDoubles, lib, "ReturnFourDoubles")1206 register(&ReturnFourDoubles, lib, "ReturnFourDoubles")
1062- expected := FourDoubles{1, 2, 3, 4}1207+ expected := FourDoubles{A: 1, B: 2, C: 3, D: 4}
1063 if ret := ReturnFourDoubles(1, 2, 3, 4); ret != expected {1208 if ret := ReturnFourDoubles(1, 2, 3, 4); ret != expected {
1064 t.Fatalf("ReturnFourDoubles returned %+v wanted %+v", ret, expected)1209 t.Fatalf("ReturnFourDoubles returned %+v wanted %+v", ret, expected)
1065 }1210 }
1066 }1211 }
1067 {1212 {
1068 type FourDoublesInternal struct {1213 type FourDoublesInternal struct {
1069- F struct{ A, B float64 }1214+ _ structs.HostLayout
1070- G struct{ C, D float64 }1215+ F struct {
1216+ _ structs.HostLayout
1217+ A, B float64
1218+ }
1219+ G struct {
1220+ _ structs.HostLayout
1221+ C, D float64
1222+ }
1071 }1223 }
1072 var ReturnFourDoublesInternal func(a, b, c, d float64) FourDoublesInternal1224 var ReturnFourDoublesInternal func(a, b, c, d float64) FourDoublesInternal
1073 register(&ReturnFourDoublesInternal, lib, "ReturnFourDoublesInternal")1225 register(&ReturnFourDoublesInternal, lib, "ReturnFourDoublesInternal")
1074- expected := FourDoublesInternal{F: struct{ A, B float64 }{A: 1, B: 2}, G: struct{ C, D float64 }{C: 3, D: 4}}1226+ expected := FourDoublesInternal{F: struct {
1227+ _ structs.HostLayout
1228+ A, B float64
1229+ }{A: 1, B: 2}, G: struct {
1230+ _ structs.HostLayout
1231+ C, D float64
1232+ }{C: 3, D: 4}}
1075 if ret := ReturnFourDoublesInternal(1, 2, 3, 4); ret != expected {1233 if ret := ReturnFourDoublesInternal(1, 2, 3, 4); ret != expected {
1076 t.Fatalf("ReturnFourDoublesInternal returned %+v wanted %+v", ret, expected)1234 t.Fatalf("ReturnFourDoublesInternal returned %+v wanted %+v", ret, expected)
1077 }1235 }
1078 }1236 }
1079 {1237 {
1080- type FiveDoubles struct{ A, B, C, D, E float64 }1238+ type FiveDoubles struct {
1239+ _ structs.HostLayout
1240+ A, B, C, D, E float64
1241+ }
1081 var ReturnFiveDoubles func(a, b, c, d, e float64) FiveDoubles1242 var ReturnFiveDoubles func(a, b, c, d, e float64) FiveDoubles
1082 register(&ReturnFiveDoubles, lib, "ReturnFiveDoubles")1243 register(&ReturnFiveDoubles, lib, "ReturnFiveDoubles")
1083- expected := FiveDoubles{1, 2, 3, 4, 5}1244+ expected := FiveDoubles{A: 1, B: 2, C: 3, D: 4, E: 5}
1084 if ret := ReturnFiveDoubles(1, 2, 3, 4, 5); ret != expected {1245 if ret := ReturnFiveDoubles(1, 2, 3, 4, 5); ret != expected {
1085 t.Fatalf("ReturnFiveDoubles returned %+v wanted %+v", ret, expected)1246 t.Fatalf("ReturnFiveDoubles returned %+v wanted %+v", ret, expected)
1086 }1247 }
1087 }1248 }
1088 {1249 {
1089 type OneFloatOneDouble struct {1250 type OneFloatOneDouble struct {
1251+ _ structs.HostLayout
1090 A float321252 A float32
1091 _ float321253 _ float32
1092 B float641254 B float64
@@ -1100,18 +1262,20 @@ func TestRegisterFunc_structReturns(t *testing.T) {
1100 }1262 }
1101 {1263 {
1102 type OneDoubleOneFloat struct {1264 type OneDoubleOneFloat struct {
1265+ _ structs.HostLayout
1103 A float641266 A float64
1104 B float321267 B float32
1105 }1268 }
1106 var ReturnOneDoubleOneFloat func(a float64, b float32) OneDoubleOneFloat1269 var ReturnOneDoubleOneFloat func(a float64, b float32) OneDoubleOneFloat
1107 register(&ReturnOneDoubleOneFloat, lib, "ReturnOneDoubleOneFloat")1270 register(&ReturnOneDoubleOneFloat, lib, "ReturnOneDoubleOneFloat")
1108- expected := OneDoubleOneFloat{1, 2}1271+ expected := OneDoubleOneFloat{A: 1, B: 2}
1109 if ret := ReturnOneDoubleOneFloat(1, 2); ret != expected {1272 if ret := ReturnOneDoubleOneFloat(1, 2); ret != expected {
1110 t.Fatalf("ReturnOneDoubleOneFloat returned %+v wanted %+v", ret, expected)1273 t.Fatalf("ReturnOneDoubleOneFloat returned %+v wanted %+v", ret, expected)
1111 }1274 }
1112 }1275 }
1113 {1276 {
1114 type Unaligned1 struct {1277 type Unaligned1 struct {
1278+ _ structs.HostLayout
1115 A int81279 A int8
1116 _ [1]int81280 _ [1]int8
1117 B int161281 B int16
@@ -1133,18 +1297,20 @@ func TestRegisterFunc_structReturns(t *testing.T) {
1133 // ppc64le by modeling the ELFv2 general-purpose register shadowing.1297 // ppc64le by modeling the ELFv2 general-purpose register shadowing.
1134 {1298 {
1135 type Mixed1 struct {1299 type Mixed1 struct {
1300+ _ structs.HostLayout
1136 A float321301 A float32
1137 B int321302 B int32
1138 }1303 }
1139 var ReturnMixed1 func(a float32, b int32) Mixed11304 var ReturnMixed1 func(a float32, b int32) Mixed1
1140 register(&ReturnMixed1, lib, "ReturnMixed1")1305 register(&ReturnMixed1, lib, "ReturnMixed1")
1141- expected := Mixed1{1, 2}1306+ expected := Mixed1{A: 1, B: 2}
1142 if ret := ReturnMixed1(1, 2); ret != expected {1307 if ret := ReturnMixed1(1, 2); ret != expected {
1143 t.Fatalf("ReturnMixed1 returned %+v wanted %+v", ret, expected)1308 t.Fatalf("ReturnMixed1 returned %+v wanted %+v", ret, expected)
1144 }1309 }
1145 }1310 }
1146 {1311 {
1147 type Mixed2 struct {1312 type Mixed2 struct {
1313+ _ structs.HostLayout
1148 A float321314 A float32
1149 B int321315 B int32
1150 C float321316 C float32
@@ -1152,39 +1318,42 @@ func TestRegisterFunc_structReturns(t *testing.T) {
1152 }1318 }
1153 var ReturnMixed2 func(a float32, b int32, c float32, d int32) Mixed21319 var ReturnMixed2 func(a float32, b int32, c float32, d int32) Mixed2
1154 register(&ReturnMixed2, lib, "ReturnMixed2")1320 register(&ReturnMixed2, lib, "ReturnMixed2")
1155- expected := Mixed2{1, 2, 3, 4}1321+ expected := Mixed2{A: 1, B: 2, C: 3, D: 4}
1156 if ret := ReturnMixed2(1, 2, 3, 4); ret != expected {1322 if ret := ReturnMixed2(1, 2, 3, 4); ret != expected {
1157 t.Fatalf("ReturnMixed2 returned %+v wanted %+v", ret, expected)1323 t.Fatalf("ReturnMixed2 returned %+v wanted %+v", ret, expected)
1158 }1324 }
1159 }1325 }
1160 {1326 {
1161 type Mixed3 struct {1327 type Mixed3 struct {
1328+ _ structs.HostLayout
1162 A float321329 A float32
1163 B uint321330 B uint32
1164 C float641331 C float64
1165 }1332 }
1166 var ReturnMixed3 func(a float32, b uint32, c float64) Mixed31333 var ReturnMixed3 func(a float32, b uint32, c float64) Mixed3
1167 register(&ReturnMixed3, lib, "ReturnMixed3")1334 register(&ReturnMixed3, lib, "ReturnMixed3")
1168- expected := Mixed3{1, 2, 3}1335+ expected := Mixed3{A: 1, B: 2, C: 3}
1169 if ret := ReturnMixed3(1, 2, 3); ret != expected {1336 if ret := ReturnMixed3(1, 2, 3); ret != expected {
1170 t.Fatalf("ReturnMixed3 returned %+v wanted %+v", ret, expected)1337 t.Fatalf("ReturnMixed3 returned %+v wanted %+v", ret, expected)
1171 }1338 }
1172 }1339 }
1173 {1340 {
1174 type Mixed4 struct {1341 type Mixed4 struct {
1342+ _ structs.HostLayout
1175 A float641343 A float64
1176 B uint321344 B uint32
1177 C float321345 C float32
1178 }1346 }
1179 var ReturnMixed4 func(a float64, b uint32, c float32) Mixed41347 var ReturnMixed4 func(a float64, b uint32, c float32) Mixed4
1180 register(&ReturnMixed4, lib, "ReturnMixed4")1348 register(&ReturnMixed4, lib, "ReturnMixed4")
1181- expected := Mixed4{1, 2, 3}1349+ expected := Mixed4{A: 1, B: 2, C: 3}
1182 if ret := ReturnMixed4(1, 2, 3); ret != expected {1350 if ret := ReturnMixed4(1, 2, 3); ret != expected {
1183 t.Fatalf("ReturnMixed4 returned %+v wanted %+v", ret, expected)1351 t.Fatalf("ReturnMixed4 returned %+v wanted %+v", ret, expected)
1184 }1352 }
1185 }1353 }
1186 {1354 {
1187 type Mixed5 struct {1355 type Mixed5 struct {
1356+ _ structs.HostLayout
1188 A *int641357 A *int64
1189 B int321358 B int32
1190 C float321359 C float32
@@ -1193,7 +1362,7 @@ func TestRegisterFunc_structReturns(t *testing.T) {
1193 var ReturnMixed5 func(a *int64, b int32, c float32, d int32) Mixed51362 var ReturnMixed5 func(a *int64, b int32, c float32, d int32) Mixed5
1194 register(&ReturnMixed5, lib, "ReturnMixed5")1363 register(&ReturnMixed5, lib, "ReturnMixed5")
1195 ptr := new(int64)1364 ptr := new(int64)
1196- expected := Mixed5{ptr, 1, 7.2, 9}1365+ expected := Mixed5{A: ptr, B: 1, C: 7.2, D: 9}
1197 if ret := ReturnMixed5(ptr, 1, 7.2, 9); ret != expected {1366 if ret := ReturnMixed5(ptr, 1, 7.2, 9); ret != expected {
1198 t.Fatalf("ReturnMixed5 returned %+v wanted %+v", ret, expected)1367 t.Fatalf("ReturnMixed5 returned %+v wanted %+v", ret, expected)
1199 }1368 }
@@ -1202,6 +1371,7 @@ func TestRegisterFunc_structReturns(t *testing.T) {
1202 }1371 }
1203 {1372 {
1204 type Mixed5 struct {1373 type Mixed5 struct {
1374+ _ structs.HostLayout
1205 A *int641375 A *int64
1206 B int321376 B int32
1207 C float321377 C float32
@@ -1213,7 +1383,7 @@ func TestRegisterFunc_structReturns(t *testing.T) {
1213 // Struct callback args are tested in TestRegisterFunc_structArgs.1383 // Struct callback args are tested in TestRegisterFunc_structArgs.
1214 purego.RegisterLibFunc(&IdentityMixed5, lib, "IdentityMixed5")1384 purego.RegisterLibFunc(&IdentityMixed5, lib, "IdentityMixed5")
1215 ptr := new(int64)1385 ptr := new(int64)
1216- expected := Mixed5{ptr, 1, 7.2, 9}1386+ expected := Mixed5{A: ptr, B: 1, C: 7.2, D: 9}
1217 if ret := IdentityMixed5(expected); ret != expected {1387 if ret := IdentityMixed5(expected); ret != expected {
1218 t.Fatalf("IdentityMixed5 returned %+v wanted %+v", ret, expected)1388 t.Fatalf("IdentityMixed5 returned %+v wanted %+v", ret, expected)
1219 }1389 }
@@ -1221,19 +1391,21 @@ func TestRegisterFunc_structReturns(t *testing.T) {
1221 }1391 }
1222 {1392 {
1223 type SmallBool struct {1393 type SmallBool struct {
1394+ _ structs.HostLayout
1224 A bool1395 A bool
1225 B int321396 B int32
1226 C int641397 C int64
1227 }1398 }
1228 var ReturnSmallBool func(a bool, b int32, c int64) SmallBool1399 var ReturnSmallBool func(a bool, b int32, c int64) SmallBool
1229 register(&ReturnSmallBool, lib, "ReturnSmallBool")1400 register(&ReturnSmallBool, lib, "ReturnSmallBool")
1230- expected := SmallBool{true, 42, 123456789}1401+ expected := SmallBool{A: true, B: 42, C: 123456789}
1231 if ret := ReturnSmallBool(true, 42, 123456789); ret != expected {1402 if ret := ReturnSmallBool(true, 42, 123456789); ret != expected {
1232 t.Fatalf("ReturnSmallBool returned %+v wanted %+v", ret, expected)1403 t.Fatalf("ReturnSmallBool returned %+v wanted %+v", ret, expected)
1233 }1404 }
1234 }1405 }
1235 {1406 {
1236 type LargeBool struct {1407 type LargeBool struct {
1408+ _ structs.HostLayout
1237 A bool1409 A bool
1238 B int321410 B int32
1239 C int641411 C int64
@@ -1241,20 +1413,21 @@ func TestRegisterFunc_structReturns(t *testing.T) {
1241 }1413 }
1242 var ReturnLargeBool func(a bool, b int32, c int64, d int64) LargeBool1414 var ReturnLargeBool func(a bool, b int32, c int64, d int64) LargeBool
1243 register(&ReturnLargeBool, lib, "ReturnLargeBool")1415 register(&ReturnLargeBool, lib, "ReturnLargeBool")
1244- expected := LargeBool{false, -99, 987654321, 111222333444}1416+ expected := LargeBool{A: false, B: -99, C: 987654321, D: 111222333444}
1245 if ret := ReturnLargeBool(false, -99, 987654321, 111222333444); ret != expected {1417 if ret := ReturnLargeBool(false, -99, 987654321, 111222333444); ret != expected {
1246 t.Fatalf("ReturnLargeBool returned %+v wanted %+v", ret, expected)1418 t.Fatalf("ReturnLargeBool returned %+v wanted %+v", ret, expected)
1247 }1419 }
1248 }1420 }
1249 {1421 {
1250 type Ptr1 struct {1422 type Ptr1 struct {
1423+ _ structs.HostLayout
1251 a *int641424 a *int64
1252 b unsafe.Pointer1425 b unsafe.Pointer
1253 }1426 }
1254 var ReturnPtr1 func(a *int64, b unsafe.Pointer) Ptr11427 var ReturnPtr1 func(a *int64, b unsafe.Pointer) Ptr1
1255 purego.RegisterLibFunc(&ReturnPtr1, lib, "ReturnPtr1")1428 purego.RegisterLibFunc(&ReturnPtr1, lib, "ReturnPtr1")
1256 a, b := new(int64), new(struct{})1429 a, b := new(int64), new(struct{})
1257- expected := Ptr1{a, unsafe.Pointer(b)}1430+ expected := Ptr1{a: a, b: unsafe.Pointer(b)}
1258 if ret := ReturnPtr1(a, unsafe.Pointer(b)); ret != expected {1431 if ret := ReturnPtr1(a, unsafe.Pointer(b)); ret != expected {
1259 t.Fatalf("ReturnPtr1 returned %+v wanted %+v", ret, expected)1432 t.Fatalf("ReturnPtr1 returned %+v wanted %+v", ret, expected)
1260 }1433 }
M syscall.go +6 -0
@@ -7,6 +7,7 @@ package purego
77
88 import (
99 "runtime"
10+ "structs"
1011 "unsafe"
1112 )
1213
@@ -14,7 +15,12 @@ const (
1415 maxArgs = 32
1516 )
1617
18+// syscallArgs is the argument block handed to the syscall15 trampoline. On
19+// platforms that go through internal/cgo it is passed to C as a
20+// struct syscallArgs, so its layout must match the C ABI.
1721 type syscallArgs struct {
22+ _ structs.HostLayout
23+
1824 fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr
1925 a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, a32 uintptr
2026 f1, f2, f3, f4, f5, f6, f7, f8 uintptr
@@ -7,6 +7,7 @@ package purego
7 7
8 import (8 import (
9 "runtime"9 "runtime"
10+ "structs"
10 "unsafe"11 "unsafe"
11 )12 )
12 13
@@ -14,7 +15,12 @@ const (
14 maxArgs = 3215 maxArgs = 32
15 )16 )
16 17
18+// syscallArgs is the argument block handed to the syscall15 trampoline. On
19+// platforms that go through internal/cgo it is passed to C as a
20+// struct syscallArgs, so its layout must match the C ABI.
17 type syscallArgs struct {21 type syscallArgs struct {
22+ _ structs.HostLayout
23+
18 fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr24 fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr
19 a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, a32 uintptr25 a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, a32 uintptr
20 f1, f2, f3, f4, f5, f6, f7, f8 uintptr26 f1, f2, f3, f4, f5, f6, f7, f8 uintptr
M syscall_32bit.go +6 -0
@@ -7,6 +7,7 @@ package purego
77
88 import (
99 "runtime"
10+ "structs"
1011 "unsafe"
1112 )
1213
@@ -14,7 +15,12 @@ const (
1415 maxArgs = 32
1516 )
1617
18+// syscallArgs is the argument block handed to the syscall15 trampoline. On
19+// platforms that go through internal/cgo it is passed to C as a
20+// struct syscallArgs, so its layout must match the C ABI.
1721 type syscallArgs struct {
22+ _ structs.HostLayout
23+
1824 fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr
1925 a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, a32 uintptr
2026 f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16 uintptr
@@ -7,6 +7,7 @@ package purego
7 7
8 import (8 import (
9 "runtime"9 "runtime"
10+ "structs"
10 "unsafe"11 "unsafe"
11 )12 )
12 13
@@ -14,7 +15,12 @@ const (
14 maxArgs = 3215 maxArgs = 32
15 )16 )
16 17
18+// syscallArgs is the argument block handed to the syscall15 trampoline. On
19+// platforms that go through internal/cgo it is passed to C as a
20+// struct syscallArgs, so its layout must match the C ABI.
17 type syscallArgs struct {21 type syscallArgs struct {
22+ _ structs.HostLayout
23+
18 fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr24 fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr
19 a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, a32 uintptr25 a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, a32 uintptr
20 f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16 uintptr26 f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16 uintptr

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 102

↑↓ moveenter openesc close