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 Unverified
B5690EEEBB952194The 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 | |||
| 5 | 5 | ||
| 6 | 6 | import ( | |
| 7 | 7 | "runtime" | |
| 8 | + | "structs" | |
| 8 | 9 | ||
| 9 | 10 | "github.com/ebitengine/purego" | |
| 10 | 11 | "github.com/ebitengine/purego/objc" | |
| @@ -17,14 +18,17 @@ const ( | |||
| 17 | 18 | ) | |
| 18 | 19 | ||
| 19 | 20 | type NSPoint struct { | |
| 21 | + | _ structs.HostLayout | |
| 20 | 22 | X, Y float64 | |
| 21 | 23 | } | |
| 22 | 24 | ||
| 23 | 25 | type NSSize struct { | |
| 26 | + | _ structs.HostLayout | |
| 24 | 27 | Width, Height float64 | |
| 25 | 28 | } | |
| 26 | 29 | ||
| 27 | 30 | type NSRect struct { | |
| 31 | + | _ structs.HostLayout | |
| 28 | 32 | Origin NSPoint | |
| 29 | 33 | Size NSSize | |
| 30 | 34 | } | |
| @@ -56,5 +60,5 @@ func main() { | |||
| 56 | 60 | } | |
| 57 | 61 | ||
| 58 | 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 | } | |
| @@ -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 float64 | 22 | X, Y float64 | ||
| 21 | } | 23 | } | ||
| 22 | 24 | ||||
| 23 | type NSSize struct { | 25 | type NSSize struct { | ||
| 26 | + | _ structs.HostLayout | |||
| 24 | Width, Height float64 | 27 | Width, Height float64 | ||
| 25 | } | 28 | } | ||
| 26 | 29 | ||||
| 27 | type NSRect struct { | 30 | type NSRect struct { | ||
| 31 | + | _ structs.HostLayout | |||
| 28 | Origin NSPoint | 32 | Origin NSPoint | ||
| 29 | Size NSSize | 33 | 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 | |||
| 5 | 5 | ||
| 6 | 6 | import ( | |
| 7 | 7 | "runtime" | |
| 8 | + | "structs" | |
| 8 | 9 | "syscall" | |
| 9 | 10 | "unsafe" | |
| 10 | 11 | ||
| @@ -30,6 +31,7 @@ type ( | |||
| 30 | 31 | ) | |
| 31 | 32 | ||
| 32 | 33 | type WNDCLASSEX struct { | |
| 34 | + | _ structs.HostLayout | |
| 33 | 35 | Size uint32 | |
| 34 | 36 | Style uint32 | |
| 35 | 37 | WndProc uintptr | |
| @@ -45,14 +47,17 @@ type WNDCLASSEX struct { | |||
| 45 | 47 | } | |
| 46 | 48 | ||
| 47 | 49 | type RECT struct { | |
| 50 | + | _ structs.HostLayout | |
| 48 | 51 | Left, Top, Right, Bottom int32 | |
| 49 | 52 | } | |
| 50 | 53 | ||
| 51 | 54 | type POINT struct { | |
| 55 | + | _ structs.HostLayout | |
| 52 | 56 | X, Y int32 | |
| 53 | 57 | } | |
| 54 | 58 | ||
| 55 | 59 | type MSG struct { | |
| 60 | + | _ structs.HostLayout | |
| 56 | 61 | Hwnd HWND | |
| 57 | 62 | Message uint32 | |
| 58 | 63 | 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 uint32 | 35 | Size uint32 | ||
| 34 | Style uint32 | 36 | Style uint32 | ||
| 35 | WndProc uintptr | 37 | 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 int32 | 51 | Left, Top, Right, Bottom int32 | ||
| 49 | } | 52 | } | ||
| 50 | 53 | ||||
| 51 | type POINT struct { | 54 | type POINT struct { | ||
| 55 | + | _ structs.HostLayout | |||
| 52 | X, Y int32 | 56 | X, Y int32 | ||
| 53 | } | 57 | } | ||
| 54 | 58 | ||||
| 55 | type MSG struct { | 59 | type MSG struct { | ||
| 60 | + | _ structs.HostLayout | |||
| 56 | Hwnd HWND | 61 | Hwnd HWND | ||
| 57 | Message uint32 | 62 | Message uint32 | ||
| 58 | WParam uintptr | 63 | WParam uintptr | ||
M func.go +50 -2
| @@ -10,6 +10,7 @@ import ( | |||
| 10 | 10 | "math" | |
| 11 | 11 | "reflect" | |
| 12 | 12 | "runtime" | |
| 13 | + | "structs" | |
| 13 | 14 | "sync" | |
| 14 | 15 | "unsafe" | |
| 15 | 16 | ||
| @@ -555,17 +556,61 @@ func addValue(v reflect.Value, keepAlive []any, addInt func(x uintptr), addFloat | |||
| 555 | 556 | // If you change this make sure to update it in objc_runtime_darwin.go | |
| 556 | 557 | 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 | 594 | func isAllSameFloat(ty reflect.Type) (allFloats bool, numFields int) { | |
| 559 | 595 | allFloats = true | |
| 560 | - | root := ty.Field(0).Type | |
| 596 | + | if numABIFields(ty) == 0 { | |
| 597 | + | return false, 0 | |
| 598 | + | } | |
| 599 | + | root := abiField(ty, 0).Type | |
| 561 | 600 | 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 | |
| 563 | 605 | } | |
| 564 | 606 | first := root.Kind() | |
| 565 | 607 | if first != reflect.Float32 && first != reflect.Float64 { | |
| 566 | 608 | allFloats = false | |
| 567 | 609 | } | |
| 568 | 610 | for i := 0; i < ty.NumField(); i++ { | |
| 611 | + | if !isABIField(ty.Field(i)) { | |
| 612 | + | continue | |
| 613 | + | } | |
| 569 | 614 | f := ty.Field(i).Type | |
| 570 | 615 | if f.Kind() == reflect.Struct { | |
| 571 | 616 | var structNumFields int | |
| @@ -583,6 +628,9 @@ func isAllSameFloat(ty reflect.Type) (allFloats bool, numFields int) { | |||
| 583 | 628 | ||
| 584 | 629 | func checkStructFieldsSupported(ty reflect.Type) { | |
| 585 | 630 | for i := 0; i < ty.NumField(); i++ { | |
| 631 | + | if !isABIField(ty.Field(i)) { | |
| 632 | + | continue | |
| 633 | + | } | |
| 586 | 634 | f := ty.Field(i).Type | |
| 587 | 635 | if f.Kind() == reflect.Array { | |
| 588 | 636 | 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.go | 556 | // If you change this make sure to update it in objc_runtime_darwin.go | ||
| 556 | const maxRegAllocStructSize = 16 | 557 | 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 = true | 595 | allFloats = true | ||
| 560 | - | root := ty.Field(0).Type | 596 | + | 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).Type | 601 | + | 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 = false | 608 | 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).Type | 614 | f := ty.Field(i).Type | ||
| 570 | if f.Kind() == reflect.Struct { | 615 | if f.Kind() == reflect.Struct { | ||
| 571 | var structNumFields int | 616 | 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).Type | 634 | 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 ( | |||
| 15 | 15 | "runtime" | |
| 16 | 16 | "strconv" | |
| 17 | 17 | "strings" | |
| 18 | + | "structs" | |
| 18 | 19 | "sync" | |
| 19 | 20 | "testing" | |
| 20 | 21 | "unsafe" | |
| @@ -393,11 +394,20 @@ func TestABI_ArgumentPassing(t *testing.T) { | |||
| 393 | 394 | }, | |
| 394 | 395 | { | |
| 395 | 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 | - | 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", | |
| 398 | 402 | call: func(f any) string { | |
| 399 | 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 | 411 | return string(buf[:bytes.IndexByte(buf, 0)]) | |
| 402 | 412 | }, | |
| 403 | 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 | 416 | name: "8int_mixed_struct", | |
| 407 | 417 | fn: new(func(*byte, uintptr, int32, int32, int32, int32, int32, int32, int32, int32, struct { | |
| 418 | + | _ structs.HostLayout | |
| 408 | 419 | a int32 | |
| 409 | 420 | b float32 | |
| 410 | 421 | })), | |
| @@ -412,12 +423,14 @@ func TestABI_ArgumentPassing(t *testing.T) { | |||
| 412 | 423 | call: func(f any) string { | |
| 413 | 424 | buf := make([]byte, 256) | |
| 414 | 425 | (*f.(*func(*byte, uintptr, int32, int32, int32, int32, int32, int32, int32, int32, struct { | |
| 426 | + | _ structs.HostLayout | |
| 415 | 427 | a int32 | |
| 416 | 428 | b float32 | |
| 417 | 429 | })))(&buf[0], 256, 1, 2, 3, 4, 5, 6, 7, 8, struct { | |
| 430 | + | _ structs.HostLayout | |
| 418 | 431 | a int32 | |
| 419 | 432 | b float32 | |
| 420 | - | }{9, 10.0}) | |
| 433 | + | }{a: 9, b: 10.0}) | |
| 421 | 434 | return string(buf[:bytes.IndexByte(buf, 0)]) | |
| 422 | 435 | }, | |
| 423 | 436 | 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 int32 | 419 | a int32 | ||
| 409 | b float32 | 420 | 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 int32 | 427 | a int32 | ||
| 416 | b float32 | 428 | 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 int32 | 431 | a int32 | ||
| 419 | b float32 | 432 | 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 @@ | |||
| 5 | 5 | ||
| 6 | 6 | package fakecgo | |
| 7 | 7 | ||
| 8 | + | import "structs" | |
| 9 | + | ||
| 8 | 10 | type ( | |
| 9 | 11 | size_t uintptr | |
| 10 | 12 | // Sources: | |
| @@ -28,11 +30,13 @@ const ( | |||
| 28 | 30 | ) | |
| 29 | 31 | ||
| 30 | 32 | type G struct { | |
| 33 | + | _ structs.HostLayout | |
| 31 | 34 | stacklo uintptr | |
| 32 | 35 | stackhi uintptr | |
| 33 | 36 | } | |
| 34 | 37 | ||
| 35 | 38 | type ThreadStart struct { | |
| 39 | + | _ structs.HostLayout | |
| 36 | 40 | g *G | |
| 37 | 41 | tls *uintptr | |
| 38 | 42 | fn uintptr | |
| @@ -5,6 +5,8 @@ | |||||
| 5 | 5 | ||||
| 6 | package fakecgo | 6 | package fakecgo | ||
| 7 | 7 | ||||
| 8 | + | import "structs" | |||
| 9 | + | ||||
| 8 | type ( | 10 | type ( | ||
| 9 | size_t uintptr | 11 | 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 uintptr | 34 | stacklo uintptr | ||
| 32 | stackhi uintptr | 35 | stackhi uintptr | ||
| 33 | } | 36 | } | ||
| 34 | 37 | ||||
| 35 | type ThreadStart struct { | 38 | type ThreadStart struct { | ||
| 39 | + | _ structs.HostLayout | |||
| 36 | g *G | 40 | g *G | ||
| 37 | tls *uintptr | 41 | tls *uintptr | ||
| 38 | fn uintptr | 42 | fn uintptr | ||
M internal/fakecgo/libcgo_darwin.go +4 -0
| @@ -5,12 +5,16 @@ | |||
| 5 | 5 | ||
| 6 | 6 | package fakecgo | |
| 7 | 7 | ||
| 8 | + | import "structs" | |
| 9 | + | ||
| 8 | 10 | type ( | |
| 9 | 11 | pthread_mutex_t struct { | |
| 12 | + | _ structs.HostLayout | |
| 10 | 13 | sig int64 | |
| 11 | 14 | opaque [56]byte | |
| 12 | 15 | } | |
| 13 | 16 | pthread_cond_t struct { | |
| 17 | + | _ structs.HostLayout | |
| 14 | 18 | sig int64 | |
| 15 | 19 | opaque [40]byte | |
| 16 | 20 | } | |
| @@ -5,12 +5,16 @@ | |||||
| 5 | 5 | ||||
| 6 | package fakecgo | 6 | 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 int64 | 13 | sig int64 | ||
| 11 | opaque [56]byte | 14 | opaque [56]byte | ||
| 12 | } | 15 | } | ||
| 13 | pthread_cond_t struct { | 16 | pthread_cond_t struct { | ||
| 17 | + | _ structs.HostLayout | |||
| 14 | sig int64 | 18 | sig int64 | ||
| 15 | opaque [40]byte | 19 | opaque [40]byte | ||
| 16 | } | 20 | } | ||
M internal/fakecgo/libcgo_netbsd.go +3 -0
| @@ -5,6 +5,8 @@ | |||
| 5 | 5 | ||
| 6 | 6 | package fakecgo | |
| 7 | 7 | ||
| 8 | + | import "structs" | |
| 9 | + | ||
| 8 | 10 | type ( | |
| 9 | 11 | pthread_cond_t uintptr | |
| 10 | 12 | pthread_mutex_t uintptr | |
| @@ -17,6 +19,7 @@ var ( | |||
| 17 | 19 | ||
| 18 | 20 | // Source: https://github.com/NetBSD/src/blob/613e27c65223fd2283b6ed679da1197e12f50e27/sys/sys/signal.h#L225 | |
| 19 | 21 | type stack_t struct { | |
| 22 | + | _ structs.HostLayout | |
| 20 | 23 | ss_sp uintptr | |
| 21 | 24 | ss_size uintptr | |
| 22 | 25 | ss_flags int32 | |
| @@ -5,6 +5,8 @@ | |||||
| 5 | 5 | ||||
| 6 | package fakecgo | 6 | package fakecgo | ||
| 7 | 7 | ||||
| 8 | + | import "structs" | |||
| 9 | + | ||||
| 8 | type ( | 10 | type ( | ||
| 9 | pthread_cond_t uintptr | 11 | pthread_cond_t uintptr | ||
| 10 | pthread_mutex_t uintptr | 12 | pthread_mutex_t uintptr | ||
| @@ -17,6 +19,7 @@ var ( | |||||
| 17 | 19 | ||||
| 18 | // Source: https://github.com/NetBSD/src/blob/613e27c65223fd2283b6ed679da1197e12f50e27/sys/sys/signal.h#L225 | 20 | // 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 uintptr | 23 | ss_sp uintptr | ||
| 21 | ss_size uintptr | 24 | ss_size uintptr | ||
| 22 | ss_flags int32 | 25 | ss_flags int32 | ||
M internal/fakecgo/linux.go +7 -2
| @@ -6,10 +6,15 @@ | |||
| 6 | 6 | ||
| 7 | 7 | 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 | 16 | type argset struct { | |
| 17 | + | _ structs.HostLayout | |
| 13 | 18 | args *uintptr | |
| 14 | 19 | retval uintptr | |
| 15 | 20 | } | |
| @@ -6,10 +6,15 @@ | |||||
| 6 | 6 | ||||
| 7 | package fakecgo | 7 | 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 *uintptr | 18 | args *uintptr | ||
| 14 | retval uintptr | 19 | retval uintptr | ||
| 15 | } | 20 | } | ||
M objc/encoding_darwin_test.go +2 -0
| @@ -10,11 +10,13 @@ import ( | |||
| 10 | 10 | "path/filepath" | |
| 11 | 11 | "reflect" | |
| 12 | 12 | "strings" | |
| 13 | + | "structs" | |
| 13 | 14 | "testing" | |
| 14 | 15 | "unsafe" | |
| 15 | 16 | ) | |
| 16 | 17 | ||
| 17 | 18 | type encodeTypeTestStruct struct { | |
| 19 | + | _ structs.HostLayout | |
| 18 | 20 | A int32 | |
| 19 | 21 | B float64 | |
| 20 | 22 | } | |
| @@ -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 int32 | 20 | A int32 | ||
| 19 | B float64 | 21 | B float64 | ||
| 20 | } | 22 | } | ||
M objc/objc_block_darwin.go +3 -0
| @@ -6,6 +6,7 @@ package objc | |||
| 6 | 6 | import ( | |
| 7 | 7 | "fmt" | |
| 8 | 8 | "reflect" | |
| 9 | + | "structs" | |
| 9 | 10 | "sync" | |
| 10 | 11 | "unsafe" | |
| 11 | 12 | ||
| @@ -34,6 +35,7 @@ const ( | |||
| 34 | 35 | // | |
| 35 | 36 | // The layout of this struct matches Block_literal_1 described in https://clang.llvm.org/docs/Block-ABI-Apple.html#high-level | |
| 36 | 37 | type blockDescriptor struct { | |
| 38 | + | _ structs.HostLayout | |
| 37 | 39 | _ uintptr | |
| 38 | 40 | size uintptr | |
| 39 | 41 | _ uintptr | |
| @@ -47,6 +49,7 @@ type blockDescriptor struct { | |||
| 47 | 49 | // | |
| 48 | 50 | // The layout of this struct matches __block_literal_1 described in https://clang.llvm.org/docs/Block-ABI-Apple.html#high-level | |
| 49 | 51 | type blockLayout struct { | |
| 52 | + | _ structs.HostLayout | |
| 50 | 53 | isa Class | |
| 51 | 54 | flags uint32 | |
| 52 | 55 | _ 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-level | 36 | // 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 | _ uintptr | 39 | _ uintptr | ||
| 38 | size uintptr | 40 | size uintptr | ||
| 39 | _ uintptr | 41 | _ 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-level | 50 | // 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 Class | 53 | isa Class | ||
| 51 | flags uint32 | 54 | flags uint32 | ||
| 52 | _ uint32 | 55 | _ uint32 | ||
M objc/objc_block_darwin_test.go +2 -0
| @@ -5,6 +5,7 @@ package objc_test | |||
| 5 | 5 | ||
| 6 | 6 | import ( | |
| 7 | 7 | "fmt" | |
| 8 | + | "structs" | |
| 8 | 9 | "testing" | |
| 9 | 10 | ||
| 10 | 11 | "github.com/ebitengine/purego" | |
| @@ -39,6 +40,7 @@ func ExampleNewBlock() { | |||
| 39 | 40 | ||
| 40 | 41 | func ExampleInvokeBlock() { | |
| 41 | 42 | type vector struct { | |
| 43 | + | _ structs.HostLayout | |
| 42 | 44 | X, Y, Z float64 | |
| 43 | 45 | } | |
| 44 | 46 | ||
| @@ -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 float64 | 44 | X, Y, Z float64 | ||
| 43 | } | 45 | } | ||
| 44 | 46 | ||||
M objc/objc_runtime_darwin.go +15 -0
| @@ -14,6 +14,7 @@ import ( | |||
| 14 | 14 | "runtime" | |
| 15 | 15 | "slices" | |
| 16 | 16 | stdstrings "strings" | |
| 17 | + | "structs" | |
| 17 | 18 | "unicode" | |
| 18 | 19 | "unsafe" | |
| 19 | 20 | ||
| @@ -21,6 +22,8 @@ import ( | |||
| 21 | 22 | "github.com/ebitengine/purego/internal/strings" | |
| 22 | 23 | ) | |
| 23 | 24 | ||
| 25 | + | var hostLayoutType = reflect.TypeFor[structs.HostLayout]() | |
| 26 | + | ||
| 24 | 27 | // TODO: support try/catch? | |
| 25 | 28 | // https://stackoverflow.com/questions/7062599/example-of-how-objective-cs-try-catch-implementation-is-executed-at-runtime | |
| 26 | 29 | var ( | |
| @@ -172,6 +175,7 @@ func Send[T any](id ID, sel SEL, args ...any) T { | |||
| 172 | 175 | // as the receiver of a message. It specifies the class definition of the particular superclass that should | |
| 173 | 176 | // be messaged. | |
| 174 | 177 | type objc_super struct { | |
| 178 | + | _ structs.HostLayout | |
| 175 | 179 | receiver ID | |
| 176 | 180 | superClass Class | |
| 177 | 181 | } | |
| @@ -470,6 +474,13 @@ func encodeType(typ reflect.Type, insidePtr bool) (string, error) { | |||
| 470 | 474 | encoding.WriteString("=") | |
| 471 | 475 | for i := 0; i < typ.NumField(); i++ { | |
| 472 | 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 | 484 | tmp, err := encodeType(f.Type, false) | |
| 474 | 485 | if err != nil { | |
| 475 | 486 | return "", err | |
| @@ -571,7 +582,9 @@ func (i Ivar) Name() string { | |||
| 571 | 582 | } | |
| 572 | 583 | ||
| 573 | 584 | // MethodDescription holds the name and type definition of a method. | |
| 585 | + | // It matches the Objective-C runtime's struct objc_method_description. | |
| 574 | 586 | type MethodDescription struct { | |
| 587 | + | _ structs.HostLayout | |
| 575 | 588 | name, types uintptr | |
| 576 | 589 | } | |
| 577 | 590 | ||
| @@ -586,7 +599,9 @@ func (m MethodDescription) Types() string { | |||
| 586 | 599 | } | |
| 587 | 600 | ||
| 588 | 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 | 603 | type PropertyAttribute struct { | |
| 604 | + | _ structs.HostLayout | |
| 590 | 605 | Name, Value *byte | |
| 591 | 606 | } | |
| 592 | 607 | ||
| @@ -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-runtime | 28 | // 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 should | 175 | // 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 ID | 179 | receiver ID | ||
| 176 | superClass Class | 180 | 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 "", err | 486 | 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 uintptr | 588 | 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 *byte | 605 | Name, Value *byte | ||
| 591 | } | 606 | } | ||
| 592 | 607 | ||||
M objc/objc_runtime_darwin_test.go +4 -2
| @@ -7,6 +7,7 @@ import ( | |||
| 7 | 7 | "fmt" | |
| 8 | 8 | "log" | |
| 9 | 9 | "reflect" | |
| 10 | + | "structs" | |
| 10 | 11 | "testing" | |
| 11 | 12 | ||
| 12 | 13 | "github.com/ebitengine/purego" | |
| @@ -155,6 +156,7 @@ func TestSend(t *testing.T) { | |||
| 155 | 156 | ||
| 156 | 157 | func ExampleSend() { | |
| 157 | 158 | type NSRange struct { | |
| 159 | + | _ structs.HostLayout | |
| 158 | 160 | Location, Range uint | |
| 159 | 161 | } | |
| 160 | 162 | class_NSString := objc.GetClass("NSString") | |
| @@ -164,8 +166,8 @@ func ExampleSend() { | |||
| 164 | 166 | subString := objc.ID(class_NSString).Send(sel_stringWithUTF8String, "lo, Wor\x00") | |
| 165 | 167 | ||
| 166 | 168 | 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 | |
| 169 | 171 | } | |
| 170 | 172 | ||
| 171 | 173 | 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 uint | 160 | 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) { | |||
| 66 | 66 | } else { | |
| 67 | 67 | // check first 8 bytes if it's floats | |
| 68 | 68 | 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 { | |
| 71 | 72 | r1 = syscall.f1 | |
| 72 | 73 | hasFirstFloat = true | |
| 73 | 74 | } | |
| 74 | 75 | ||
| 75 | 76 | // find index of the field that starts the second 8 bytes | |
| 76 | 77 | 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 { | |
| 79 | 80 | break | |
| 80 | 81 | } | |
| 81 | 82 | } | |
| 82 | 83 | ||
| 83 | 84 | // 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 { | |
| 86 | 87 | r2 = syscall.f1 | |
| 87 | 88 | } else if hasFirstFloat { | |
| 88 | 89 | // 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 | 102 | func isAllFloats(ty reflect.Type) bool { | |
| 102 | 103 | for i := 0; i < ty.NumField(); i++ { | |
| 103 | 104 | f := ty.Field(i) | |
| 105 | + | if !isABIField(f) { | |
| 106 | + | continue | |
| 107 | + | } | |
| 104 | 108 | switch f.Type.Kind() { | |
| 105 | 109 | case reflect.Float64, reflect.Float32: | |
| 106 | 110 | default: | |
| @@ -217,6 +221,9 @@ func tryPlaceRegister(v reflect.Value, addFloat func(uintptr), addInt func(uintp | |||
| 217 | 221 | } | |
| 218 | 222 | ||
| 219 | 223 | for i := 0; i < numFields; i++ { | |
| 224 | + | if v.Kind() == reflect.Struct && !isABIField(v.Type().Field(i)) { | |
| 225 | + | continue | |
| 226 | + | } | |
| 220 | 227 | flushed = false | |
| 221 | 228 | var f reflect.Value | |
| 222 | 229 | 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 floats | 67 | // check first 8 bytes if it's floats | ||
| 68 | hasFirstFloat := false | 68 | hasFirstFloat := false | ||
| 69 | - | f1 := outType.Field(0).Type | 69 | + | 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.f1 | 72 | r1 = syscall.f1 | ||
| 72 | hasFirstFloat = true | 73 | hasFirstFloat = true | ||
| 73 | } | 74 | } | ||
| 74 | 75 | ||||
| 75 | // find index of the field that starts the second 8 bytes | 76 | // find index of the field that starts the second 8 bytes | ||
| 76 | var i int | 77 | 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 | break | 80 | break | ||
| 80 | } | 81 | } | ||
| 81 | } | 82 | } | ||
| 82 | 83 | ||||
| 83 | // check last 8 bytes if they are floats | 84 | // check last 8 bytes if they are floats | ||
| 84 | - | f1 = outType.Field(i).Type | 85 | + | 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.f1 | 87 | 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 field | 89 | // 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 = false | 227 | flushed = false | ||
| 221 | var f reflect.Value | 228 | 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 | |||
| 85 | 85 | if hva, hfa, size := isHVA(v.Type()), isHFA(v.Type()), v.Type().Size(); hva || hfa || size <= 16 { | |
| 86 | 86 | // if this doesn't fit entirely in registers then | |
| 87 | 87 | // each element goes onto the stack | |
| 88 | - | if hfa && *numFloats+v.NumField() > numOfFloatRegisters() { | |
| 88 | + | if hfa && *numFloats+numABIFields(v.Type()) > numOfFloatRegisters() { | |
| 89 | 89 | *numFloats = numOfFloatRegisters() | |
| 90 | - | } else if hva && *numInts+v.NumField() > numOfIntegerRegisters() { | |
| 90 | + | } else if hva && *numInts+numABIFields(v.Type()) > numOfIntegerRegisters() { | |
| 91 | 91 | *numInts = numOfIntegerRegisters() | |
| 92 | 92 | } | |
| 93 | 93 | ||
| @@ -120,6 +120,9 @@ func placeRegistersArm64(v reflect.Value, addFloat func(uintptr), addInt func(ui | |||
| 120 | 120 | numFields = v.Type().Len() | |
| 121 | 121 | } | |
| 122 | 122 | for k := 0; k < numFields; k++ { | |
| 123 | + | if v.Kind() == reflect.Struct && !isABIField(v.Type().Field(k)) { | |
| 124 | + | continue | |
| 125 | + | } | |
| 123 | 126 | flushed = false | |
| 124 | 127 | var f reflect.Value | |
| 125 | 128 | if v.Kind() == reflect.Struct { | |
| @@ -238,15 +241,16 @@ func placeStack(v reflect.Value, keepAlive []any, addInt func(uintptr)) []any { | |||
| 238 | 241 | func isHFA(t reflect.Type) bool { | |
| 239 | 242 | // round up struct size to nearest 8 see section B.4 | |
| 240 | 243 | structSize := roundUpTo8(t.Size()) | |
| 241 | - | if structSize == 0 || t.NumField() > 4 { | |
| 244 | + | numFields := numABIFields(t) | |
| 245 | + | if structSize == 0 || numFields > 4 { | |
| 242 | 246 | return false | |
| 243 | 247 | } | |
| 244 | - | first := t.Field(0) | |
| 248 | + | first := abiField(t, 0) | |
| 245 | 249 | switch first.Type.Kind() { | |
| 246 | 250 | case reflect.Float32, reflect.Float64: | |
| 247 | 251 | 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 { | |
| 250 | 254 | return false | |
| 251 | 255 | } | |
| 252 | 256 | } | |
| @@ -259,7 +263,7 @@ func isHFA(t reflect.Type) bool { | |||
| 259 | 263 | return false | |
| 260 | 264 | } | |
| 261 | 265 | case reflect.Struct: | |
| 262 | - | for i := 0; i < first.Type.NumField(); i++ { | |
| 266 | + | for i := 0; i < numABIFields(first.Type); i++ { | |
| 263 | 267 | if !isHFA(first.Type) { | |
| 264 | 268 | return false | |
| 265 | 269 | } | |
| @@ -283,12 +287,13 @@ func isHVA(t reflect.Type) bool { | |||
| 283 | 287 | if structSize == 0 || (structSize != 8 && structSize != 16) { | |
| 284 | 288 | return false | |
| 285 | 289 | } | |
| 286 | - | first := t.Field(0) | |
| 290 | + | numFields := numABIFields(t) | |
| 291 | + | first := abiField(t, 0) | |
| 287 | 292 | switch first.Type.Kind() { | |
| 288 | 293 | case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Int8, reflect.Int16, reflect.Int32: | |
| 289 | 294 | 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 { | |
| 292 | 297 | return false | |
| 293 | 298 | } | |
| 294 | 299 | } | |
| @@ -388,12 +393,12 @@ func shouldBundleStackArgs(v reflect.Value, numInts, numFloats int) bool { | |||
| 388 | 393 | } | |
| 389 | 394 | ||
| 390 | 395 | if hfa { | |
| 391 | - | need := v.NumField() | |
| 396 | + | need := numABIFields(v.Type()) | |
| 392 | 397 | return numFloats+need > numOfFloatRegisters() | |
| 393 | 398 | } | |
| 394 | 399 | ||
| 395 | 400 | if hva { | |
| 396 | - | need := v.NumField() | |
| 401 | + | need := numABIFields(v.Type()) | |
| 397 | 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 | 420 | if hfa { | |
| 416 | 421 | // 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 | |
| 419 | 424 | } | |
| 420 | 425 | } else if hva { | |
| 421 | 426 | // 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 | |
| 424 | 429 | } | |
| 425 | 430 | } else if size <= 16 { | |
| 426 | 431 | // 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 | 638 | size := inType.Size() | |
| 634 | 639 | ||
| 635 | 640 | // Determine the element type | |
| 636 | - | root := inType.Field(0).Type | |
| 641 | + | root := abiField(inType, 0).Type | |
| 637 | 642 | for root.Kind() == reflect.Struct { | |
| 638 | - | root = root.Field(0).Type | |
| 643 | + | root = abiField(root, 0).Type | |
| 639 | 644 | } | |
| 640 | 645 | isFloat32 := root.Kind() == reflect.Float32 | |
| 641 | 646 | ||
| @@ -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 then | 86 | // if this doesn't fit entirely in registers then | ||
| 87 | // each element goes onto the stack | 87 | // 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 = false | 126 | flushed = false | ||
| 124 | var f reflect.Value | 127 | 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.4 | 242 | // 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 false | 246 | 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 false | 254 | return false | ||
| 251 | } | 255 | } | ||
| 252 | } | 256 | } | ||
| @@ -259,7 +263,7 @@ func isHFA(t reflect.Type) bool { | |||||
| 259 | return false | 263 | 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 false | 268 | 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 false | 288 | 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 false | 297 | 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 registers | 421 | // 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 registers | 426 | // 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(), tempNumFloats | 428 | + | 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-packing | 431 | // 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 type | 640 | // Determine the element type | ||
| 636 | - | root := inType.Field(0).Type | 641 | + | root := abiField(inType, 0).Type |
| 637 | for root.Kind() == reflect.Struct { | 642 | for root.Kind() == reflect.Struct { | ||
| 638 | - | root = root.Field(0).Type | 643 | + | root = abiField(root, 0).Type |
| 639 | } | 644 | } | ||
| 640 | isFloat32 := root.Kind() == reflect.Float32 | 645 | 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 { | |||
| 34 | 34 | ||
| 35 | 35 | // Homogeneous float aggregates override integer regs | |
| 36 | 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 | 38 | // float32 values are NaN-boxed in FP regs; use low 32 bits only | |
| 39 | 39 | f := []uintptr{syscall.f1, syscall.f2, syscall.f3, syscall.f4} | |
| 40 | 40 | 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 regs | 35 | // 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 only | 38 | // 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 { | |||
| 34 | 34 | ||
| 35 | 35 | // Homogeneous float aggregates override integer regs | |
| 36 | 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 | 38 | // float32 values in FP regs | |
| 39 | 39 | f := []uintptr{syscall.f1, syscall.f2, syscall.f3, syscall.f4} | |
| 40 | 40 | 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 regs | 35 | // 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 regs | 38 | // 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 ( | |||
| 13 | 13 | "reflect" | |
| 14 | 14 | "runtime" | |
| 15 | 15 | "slices" | |
| 16 | + | "structs" | |
| 16 | 17 | "testing" | |
| 17 | 18 | "unsafe" | |
| 18 | 19 | ||
| @@ -89,7 +90,9 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||
| 89 | 90 | t.Run(imp.name, func(t *testing.T) { | |
| 90 | 91 | register := imp.register | |
| 91 | 92 | { | |
| 92 | - | type Empty struct{} | |
| 93 | + | type Empty struct { | |
| 94 | + | _ structs.HostLayout | |
| 95 | + | } | |
| 93 | 96 | var NoStruct func(Empty) int64 | |
| 94 | 97 | register(&NoStruct, lib, "NoStruct", func(Empty) int64 { | |
| 95 | 98 | 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 | 108 | var EmptyEmptyFn func(EmptyEmpty) int64 | |
| 104 | 109 | register(&EmptyEmptyFn, lib, "EmptyEmpty", func(EmptyEmpty) int64 { | |
| 105 | 110 | return 0xdeadbeef | |
| @@ -117,6 +122,7 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||
| 117 | 122 | } | |
| 118 | 123 | { | |
| 119 | 124 | type GreaterThan16Bytes struct { | |
| 125 | + | _ structs.HostLayout | |
| 120 | 126 | x, y, z *int64 | |
| 121 | 127 | } | |
| 122 | 128 | var x, y, z int64 = 0xEF, 0xBE00, 0xDEAD0000 | |
| @@ -130,7 +136,9 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||
| 130 | 136 | } | |
| 131 | 137 | { | |
| 132 | 138 | type GreaterThan16BytesStruct struct { | |
| 139 | + | _ structs.HostLayout | |
| 133 | 140 | a struct { | |
| 141 | + | _ structs.HostLayout | |
| 134 | 142 | x, y, z *int64 | |
| 135 | 143 | } | |
| 136 | 144 | } | |
| @@ -139,12 +147,16 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||
| 139 | 147 | register(&GreaterThan16BytesStructFn, lib, "GreaterThan16BytesStruct", func(g GreaterThan16BytesStruct) int64 { | |
| 140 | 148 | 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 | 154 | t.Fatalf("GreaterThan16BytesStructFn returned %#x wanted %#x", ret, expectedUnsigned) | |
| 144 | 155 | } | |
| 145 | 156 | } | |
| 146 | 157 | { | |
| 147 | 158 | type GreaterThan16Bytes struct { | |
| 159 | + | _ structs.HostLayout | |
| 148 | 160 | x, y, z *int64 | |
| 149 | 161 | } | |
| 150 | 162 | var x, y, z int64 = 0xEF, 0xBE00, 0xDEAD0000 | |
| @@ -168,48 +180,52 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||
| 168 | 180 | register(&BeforeRegisters, lib, "BeforeRegisters", func(bytes GreaterThan16Bytes, a, b int64) uint64 { | |
| 169 | 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 | 184 | t.Fatalf("BeforeRegisters returned %#x wanted %#x", ret, expectedUnsigned) | |
| 173 | 185 | } | |
| 174 | 186 | } | |
| 175 | 187 | { | |
| 176 | 188 | type IntLessThan16Bytes struct { | |
| 189 | + | _ structs.HostLayout | |
| 177 | 190 | x, y int64 | |
| 178 | 191 | } | |
| 179 | 192 | var IntLessThan16BytesFn func(bytes IntLessThan16Bytes) int64 | |
| 180 | 193 | register(&IntLessThan16BytesFn, lib, "IntLessThan16Bytes", func(l IntLessThan16Bytes) int64 { | |
| 181 | 194 | 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 | 197 | t.Fatalf("IntLessThan16BytesFn returned %#x wanted %#x", ret, expectedUnsigned) | |
| 185 | 198 | } | |
| 186 | 199 | } | |
| 187 | 200 | { | |
| 188 | 201 | type FloatLessThan16Bytes struct { | |
| 202 | + | _ structs.HostLayout | |
| 189 | 203 | x, y float32 | |
| 190 | 204 | } | |
| 191 | 205 | var FloatLessThan16BytesFn func(FloatLessThan16Bytes) float32 | |
| 192 | 206 | register(&FloatLessThan16BytesFn, lib, "FloatLessThan16Bytes", func(f FloatLessThan16Bytes) float32 { | |
| 193 | 207 | 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 | 210 | t.Fatalf("FloatLessThan16Bytes returned %f wanted %f", ret, expectedFloat) | |
| 197 | 211 | } | |
| 198 | 212 | } | |
| 199 | 213 | { | |
| 200 | 214 | type ThreeSmallFields struct { | |
| 215 | + | _ structs.HostLayout | |
| 201 | 216 | x, y, z float32 | |
| 202 | 217 | } | |
| 203 | 218 | var ThreeSmallFieldsFn func(ThreeSmallFields) float32 | |
| 204 | 219 | register(&ThreeSmallFieldsFn, lib, "ThreeSmallFields", func(f ThreeSmallFields) float32 { | |
| 205 | 220 | 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 | 223 | t.Fatalf("ThreeSmallFields returned %f wanted %f", ret, expectedFloat) | |
| 209 | 224 | } | |
| 210 | 225 | } | |
| 211 | 226 | { | |
| 212 | 227 | type FloatAndInt struct { | |
| 228 | + | _ structs.HostLayout | |
| 213 | 229 | x float32 | |
| 214 | 230 | y int32 | |
| 215 | 231 | } | |
| @@ -217,37 +233,41 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||
| 217 | 233 | register(&FloatAndIntFn, lib, "FloatAndInt", func(f FloatAndInt) float32 { | |
| 218 | 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 | 237 | t.Fatalf("FloatAndIntFn returned %f wanted %f", ret, expectedFloat) | |
| 222 | 238 | } | |
| 223 | 239 | } | |
| 224 | 240 | { | |
| 225 | 241 | type DoubleStruct struct { | |
| 242 | + | _ structs.HostLayout | |
| 226 | 243 | x float64 | |
| 227 | 244 | } | |
| 228 | 245 | var DoubleStructFn func(DoubleStruct) float64 | |
| 229 | 246 | register(&DoubleStructFn, lib, "DoubleStruct", func(d DoubleStruct) float64 { | |
| 230 | 247 | return d.x | |
| 231 | 248 | }) | |
| 232 | - | if ret := DoubleStructFn(DoubleStruct{10}); ret != expectedDouble { | |
| 249 | + | if ret := DoubleStructFn(DoubleStruct{x: 10}); ret != expectedDouble { | |
| 233 | 250 | t.Fatalf("DoubleStruct returned %f wanted %f", ret, expectedDouble) | |
| 234 | 251 | } | |
| 235 | 252 | } | |
| 236 | 253 | { | |
| 237 | 254 | type TwoDoubleStruct struct { | |
| 255 | + | _ structs.HostLayout | |
| 238 | 256 | x, y float64 | |
| 239 | 257 | } | |
| 240 | 258 | var TwoDoubleStructFn func(TwoDoubleStruct) float64 | |
| 241 | 259 | register(&TwoDoubleStructFn, lib, "TwoDoubleStruct", func(d TwoDoubleStruct) float64 { | |
| 242 | 260 | 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 | 263 | t.Fatalf("TwoDoubleStruct returned %f wanted %f", ret, expectedDouble) | |
| 246 | 264 | } | |
| 247 | 265 | } | |
| 248 | 266 | { | |
| 249 | 267 | type TwoDoubleTwoStruct struct { | |
| 268 | + | _ structs.HostLayout | |
| 250 | 269 | x struct { | |
| 270 | + | _ structs.HostLayout | |
| 251 | 271 | x, y float64 | |
| 252 | 272 | } | |
| 253 | 273 | } | |
| @@ -255,31 +275,36 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||
| 255 | 275 | register(&TwoDoubleTwoStructFn, lib, "TwoDoubleTwoStruct", func(d TwoDoubleTwoStruct) float64 { | |
| 256 | 276 | 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 | 282 | t.Fatalf("TwoDoubleTwoStruct returned %f wanted %f", ret, expectedDouble) | |
| 260 | 283 | } | |
| 261 | 284 | } | |
| 262 | 285 | { | |
| 263 | 286 | type ThreeDoubleStruct struct { | |
| 287 | + | _ structs.HostLayout | |
| 264 | 288 | x, y, z float64 | |
| 265 | 289 | } | |
| 266 | 290 | var ThreeDoubleStructFn func(ThreeDoubleStruct) float64 | |
| 267 | 291 | register(&ThreeDoubleStructFn, lib, "ThreeDoubleStruct", func(d ThreeDoubleStruct) float64 { | |
| 268 | 292 | 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 | 295 | t.Fatalf("ThreeDoubleStructFn returned %f wanted %f", ret, expectedDouble) | |
| 272 | 296 | } | |
| 273 | 297 | } | |
| 274 | 298 | { | |
| 275 | 299 | type LargeFloatStruct struct { | |
| 300 | + | _ structs.HostLayout | |
| 276 | 301 | a, b, c, d, e, f float64 | |
| 277 | 302 | } | |
| 278 | 303 | var LargeFloatStructFn func(LargeFloatStruct) float64 | |
| 279 | 304 | register(&LargeFloatStructFn, lib, "LargeFloatStruct", func(s LargeFloatStruct) float64 { | |
| 280 | 305 | 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 | 308 | t.Fatalf("LargeFloatStructFn returned %f wanted %f", ret, expectedFloat) | |
| 284 | 309 | } | |
| 285 | 310 | if runtime.GOARCH != "ppc64le" { | |
| @@ -289,13 +314,14 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||
| 289 | 314 | register(&LargeFloatStructWithRegs, lib, "LargeFloatStructWithRegs", func(a, b, c float64, s LargeFloatStruct) float64 { | |
| 290 | 315 | 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 | 318 | t.Fatalf("LargeFloatStructWithRegs returned %f wanted %f", ret, expectedFloat) | |
| 294 | 319 | } | |
| 295 | 320 | } | |
| 296 | 321 | } | |
| 297 | 322 | { | |
| 298 | 323 | type Rect struct { | |
| 324 | + | _ structs.HostLayout | |
| 299 | 325 | x, y, w, h float64 | |
| 300 | 326 | } | |
| 301 | 327 | if runtime.GOARCH != "ppc64le" { | |
| @@ -305,7 +331,7 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||
| 305 | 331 | register(&RectangleWithRegs, lib, "RectangleWithRegs", func(a, b, c, d, e float64, rect Rect) float64 { | |
| 306 | 332 | 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 | 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 | 339 | register(&RectangleSubtract, lib, "RectangleSubtract", func(rect Rect) float64 { | |
| 314 | 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 | 343 | t.Fatalf("RectangleSubtract returned %f wanted %f", ret, expectedDouble) | |
| 318 | 344 | } | |
| 319 | 345 | var Rectangle func(rect Rect) float64 | |
| 320 | 346 | register(&Rectangle, lib, "Rectangle", func(rect Rect) float64 { | |
| 321 | 347 | 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 | 350 | t.Fatalf("Rectangle returned %f wanted %f", ret, expectedFloat) | |
| 325 | 351 | } | |
| 326 | 352 | } | |
| 327 | 353 | { | |
| 328 | 354 | type FloatArray struct { | |
| 355 | + | _ structs.HostLayout | |
| 329 | 356 | a [2]float64 | |
| 330 | 357 | } | |
| 331 | 358 | var FloatArrayFn func(rect FloatArray) float64 | |
| @@ -338,6 +365,7 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||
| 338 | 365 | } | |
| 339 | 366 | { | |
| 340 | 367 | type UnsignedChar4Bytes struct { | |
| 368 | + | _ structs.HostLayout | |
| 341 | 369 | a, b, c, d byte | |
| 342 | 370 | } | |
| 343 | 371 | var UnsignedChar4BytesFn func(UnsignedChar4Bytes) uint32 | |
| @@ -350,16 +378,21 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||
| 350 | 378 | } | |
| 351 | 379 | { | |
| 352 | 380 | type UnsignedChar4BytesStruct struct { | |
| 381 | + | _ structs.HostLayout | |
| 353 | 382 | x struct { | |
| 383 | + | _ structs.HostLayout | |
| 354 | 384 | a byte | |
| 355 | 385 | } | |
| 356 | 386 | y struct { | |
| 387 | + | _ structs.HostLayout | |
| 357 | 388 | b byte | |
| 358 | 389 | } | |
| 359 | 390 | z struct { | |
| 391 | + | _ structs.HostLayout | |
| 360 | 392 | c byte | |
| 361 | 393 | } | |
| 362 | 394 | w struct { | |
| 395 | + | _ structs.HostLayout | |
| 363 | 396 | d byte | |
| 364 | 397 | } | |
| 365 | 398 | } | |
| @@ -368,16 +401,29 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||
| 368 | 401 | return uint32(b.x.a)<<24 | uint32(b.y.b)<<16 | uint32(b.z.c)<<8 | uint32(b.w.d) | |
| 369 | 402 | }) | |
| 370 | 403 | 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}, | |
| 375 | 420 | }); ret != expectedUnsigned { | |
| 376 | 421 | t.Fatalf("UnsignedChar4BytesStructFn returned %#x wanted %#x", ret, expectedUnsigned) | |
| 377 | 422 | } | |
| 378 | 423 | } | |
| 379 | 424 | { | |
| 380 | 425 | type Short struct { | |
| 426 | + | _ structs.HostLayout | |
| 381 | 427 | a, b, c, d uint16 | |
| 382 | 428 | } | |
| 383 | 429 | var ShortFn func(Short) uint64 | |
| @@ -390,6 +436,7 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||
| 390 | 436 | } | |
| 391 | 437 | { | |
| 392 | 438 | type Int struct { | |
| 439 | + | _ structs.HostLayout | |
| 393 | 440 | a, b uint32 | |
| 394 | 441 | } | |
| 395 | 442 | var IntFn func(Int) uint64 | |
| @@ -402,6 +449,7 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||
| 402 | 449 | } | |
| 403 | 450 | { | |
| 404 | 451 | type Long struct { | |
| 452 | + | _ structs.HostLayout | |
| 405 | 453 | a uint64 | |
| 406 | 454 | } | |
| 407 | 455 | var LongFn func(Long) uint64 | |
| @@ -414,6 +462,7 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||
| 414 | 462 | } | |
| 415 | 463 | { | |
| 416 | 464 | type Char8Bytes struct { | |
| 465 | + | _ structs.HostLayout | |
| 417 | 466 | a, b, c, d, e, f, g, h int8 | |
| 418 | 467 | } | |
| 419 | 468 | var Char8BytesFn func(Char8Bytes) int32 | |
| @@ -426,6 +475,7 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||
| 426 | 475 | } | |
| 427 | 476 | { | |
| 428 | 477 | type Odd struct { | |
| 478 | + | _ structs.HostLayout | |
| 429 | 479 | a, b, c byte | |
| 430 | 480 | } | |
| 431 | 481 | var OddFn func(Odd) int32 | |
| @@ -438,6 +488,7 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||
| 438 | 488 | } | |
| 439 | 489 | { | |
| 440 | 490 | type Char2Short1 struct { | |
| 491 | + | _ structs.HostLayout | |
| 441 | 492 | a, b byte | |
| 442 | 493 | c uint16 | |
| 443 | 494 | } | |
| @@ -451,6 +502,7 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||
| 451 | 502 | } | |
| 452 | 503 | { | |
| 453 | 504 | type SignedChar2Short1 struct { | |
| 505 | + | _ structs.HostLayout | |
| 454 | 506 | a, b int8 | |
| 455 | 507 | c int16 | |
| 456 | 508 | } | |
| @@ -464,6 +516,7 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||
| 464 | 516 | } | |
| 465 | 517 | { | |
| 466 | 518 | type Array4UnsignedChars struct { | |
| 519 | + | _ structs.HostLayout | |
| 467 | 520 | a [4]uint8 | |
| 468 | 521 | } | |
| 469 | 522 | var Array4UnsignedCharsFn func(chars Array4UnsignedChars) uint32 | |
| @@ -476,6 +529,7 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||
| 476 | 529 | } | |
| 477 | 530 | { | |
| 478 | 531 | type Array3UnsignedChar struct { | |
| 532 | + | _ structs.HostLayout | |
| 479 | 533 | a [3]uint8 | |
| 480 | 534 | } | |
| 481 | 535 | var Array3UnsignedChars func(chars Array3UnsignedChar) uint32 | |
| @@ -488,6 +542,7 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||
| 488 | 542 | } | |
| 489 | 543 | { | |
| 490 | 544 | type Array2UnsignedShort struct { | |
| 545 | + | _ structs.HostLayout | |
| 491 | 546 | a [2]uint16 | |
| 492 | 547 | } | |
| 493 | 548 | var Array2UnsignedShorts func(chars Array2UnsignedShort) uint32 | |
| @@ -500,6 +555,7 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||
| 500 | 555 | } | |
| 501 | 556 | { | |
| 502 | 557 | type Array4Chars struct { | |
| 558 | + | _ structs.HostLayout | |
| 503 | 559 | a [4]int8 | |
| 504 | 560 | } | |
| 505 | 561 | var Array4CharsFn func(chars Array4Chars) int32 | |
| @@ -513,6 +569,7 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||
| 513 | 569 | } | |
| 514 | 570 | { | |
| 515 | 571 | type Array2Short struct { | |
| 572 | + | _ structs.HostLayout | |
| 516 | 573 | a [2]int16 | |
| 517 | 574 | } | |
| 518 | 575 | var Array2Shorts func(chars Array2Short) int32 | |
| @@ -525,6 +582,7 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||
| 525 | 582 | } | |
| 526 | 583 | { | |
| 527 | 584 | type Array3Short struct { | |
| 585 | + | _ structs.HostLayout | |
| 528 | 586 | a [3]int16 | |
| 529 | 587 | } | |
| 530 | 588 | var Array3Shorts func(chars Array3Short) int32 | |
| @@ -537,21 +595,23 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||
| 537 | 595 | } | |
| 538 | 596 | { | |
| 539 | 597 | type BoolStruct struct { | |
| 598 | + | _ structs.HostLayout | |
| 540 | 599 | b bool | |
| 541 | 600 | } | |
| 542 | 601 | var BoolStructFn func(BoolStruct) bool | |
| 543 | 602 | register(&BoolStructFn, lib, "BoolStruct", func(b BoolStruct) bool { | |
| 544 | 603 | return b.b | |
| 545 | 604 | }) | |
| 546 | - | if ret := BoolStructFn(BoolStruct{true}); ret != true { | |
| 605 | + | if ret := BoolStructFn(BoolStruct{b: true}); ret != true { | |
| 547 | 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 | 609 | t.Fatalf("BoolStructFn returned %v wanted %v", ret, false) | |
| 551 | 610 | } | |
| 552 | 611 | } | |
| 553 | 612 | { | |
| 554 | 613 | type BoolFloat struct { | |
| 614 | + | _ structs.HostLayout | |
| 555 | 615 | b bool | |
| 556 | 616 | _ [3]byte // purego won't do padding for you so make sure it aligns properly with C struct | |
| 557 | 617 | 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 } | |
| 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 | + | } | |
| 576 | 642 | type Content struct { | |
| 643 | + | _ structs.HostLayout | |
| 577 | 644 | point point | |
| 578 | 645 | size size | |
| 579 | 646 | } | |
| @@ -589,13 +656,14 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||
| 589 | 656 | }) | |
| 590 | 657 | if ret := InitWithContentRect(new(int), | |
| 591 | 658 | // 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 | 660 | 15, 4, true); ret != expectedUnsigned { | |
| 594 | 661 | t.Fatalf("InitWithContentRect returned %d wanted %#x", ret, expectedUnsigned) | |
| 595 | 662 | } | |
| 596 | 663 | } | |
| 597 | 664 | { | |
| 598 | 665 | type GoInt4 struct { | |
| 666 | + | _ structs.HostLayout | |
| 599 | 667 | A, B, C, D int | |
| 600 | 668 | } | |
| 601 | 669 | var GoInt4Fn func(GoInt4) int | |
| @@ -603,12 +671,13 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||
| 603 | 671 | return g.A + g.B - g.C + g.D | |
| 604 | 672 | }) | |
| 605 | 673 | 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 | 675 | t.Fatalf("GoInt4Fn returned %d wanted %#x", ret, expected) | |
| 608 | 676 | } | |
| 609 | 677 | } | |
| 610 | 678 | { | |
| 611 | 679 | type GoUint4 struct { | |
| 680 | + | _ structs.HostLayout | |
| 612 | 681 | A, B, C, D uint | |
| 613 | 682 | } | |
| 614 | 683 | var GoUint4Fn func(GoUint4) uint | |
| @@ -616,23 +685,27 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||
| 616 | 685 | return g.A + g.B + g.C + g.D | |
| 617 | 686 | }) | |
| 618 | 687 | 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 | 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 | 697 | var TakeGoUintAndReturn func(a OneLong) uint64 | |
| 626 | 698 | register(&TakeGoUintAndReturn, lib, "TakeGoUintAndReturn", func(a OneLong) uint64 { | |
| 627 | 699 | return uint64(a.a) | |
| 628 | 700 | }) | |
| 629 | 701 | expected := uint64(7) | |
| 630 | - | if ret := TakeGoUintAndReturn(OneLong{7}); ret != expected { | |
| 702 | + | if ret := TakeGoUintAndReturn(OneLong{a: 7}); ret != expected { | |
| 631 | 703 | t.Fatalf("TakeGoUintAndReturn returned %+v wanted %+v", ret, expected) | |
| 632 | 704 | } | |
| 633 | 705 | } | |
| 634 | 706 | { | |
| 635 | 707 | type FloatAndBool struct { | |
| 708 | + | _ structs.HostLayout | |
| 636 | 709 | x float32 | |
| 637 | 710 | y bool | |
| 638 | 711 | } | |
| @@ -652,13 +725,14 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||
| 652 | 725 | } | |
| 653 | 726 | { | |
| 654 | 727 | type FourInt32s struct { | |
| 728 | + | _ structs.HostLayout | |
| 655 | 729 | f0, f1, f2, f3 int32 | |
| 656 | 730 | } | |
| 657 | 731 | var FourInt32sFn func(FourInt32s) int32 | |
| 658 | 732 | register(&FourInt32sFn, lib, "FourInt32s", func(s FourInt32s) int32 { | |
| 659 | 733 | 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 | 736 | const want = 100 - 127 + 4 - 100 | |
| 663 | 737 | if result != want { | |
| 664 | 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 | 742 | type PointerWrapper struct { | |
| 743 | + | _ structs.HostLayout | |
| 669 | 744 | ctx unsafe.Pointer | |
| 670 | 745 | } | |
| 671 | 746 | var ExtractPointer func(wrapper PointerWrapper) uintptr | |
| @@ -683,6 +758,7 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||
| 683 | 758 | } | |
| 684 | 759 | { | |
| 685 | 760 | type TwoPointers struct { | |
| 761 | + | _ structs.HostLayout | |
| 686 | 762 | ptr1, ptr2 unsafe.Pointer | |
| 687 | 763 | } | |
| 688 | 764 | var AddPointers func(wrapper TwoPointers) uintptr | |
| @@ -694,7 +770,7 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||
| 694 | 770 | ptr1 := unsafe.Pointer(&v1) | |
| 695 | 771 | ptr2 := unsafe.Pointer(&v2) | |
| 696 | 772 | expected := uintptr(ptr1) + uintptr(ptr2) | |
| 697 | - | result := AddPointers(TwoPointers{ptr1, ptr2}) | |
| 773 | + | result := AddPointers(TwoPointers{ptr1: ptr1, ptr2: ptr2}) | |
| 698 | 774 | if result != expected { | |
| 699 | 775 | t.Fatalf("AddPointers returned %#x wanted %#x", result, expected) | |
| 700 | 776 | } | |
| @@ -703,48 +779,60 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||
| 703 | 779 | // Identity struct arg tests | |
| 704 | 780 | { | |
| 705 | 781 | // Single int64: one integer register. | |
| 706 | - | type OneInt64 struct{ A int64 } | |
| 782 | + | type OneInt64 struct { | |
| 783 | + | _ structs.HostLayout | |
| 784 | + | A int64 | |
| 785 | + | } | |
| 707 | 786 | var fn func(OneInt64) OneInt64 | |
| 708 | 787 | register(&fn, lib, "IdentityOneInt64", func(s OneInt64) OneInt64 { | |
| 709 | 788 | return s | |
| 710 | 789 | }) | |
| 711 | - | expected := OneInt64{0xDEADBEEF} | |
| 790 | + | expected := OneInt64{A: 0xDEADBEEF} | |
| 712 | 791 | if ret := fn(expected); ret != expected { | |
| 713 | 792 | t.Fatalf("IdentityOneInt64 returned %+v wanted %+v", ret, expected) | |
| 714 | 793 | } | |
| 715 | 794 | } | |
| 716 | 795 | { | |
| 717 | 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 | 801 | var fn func(IntLessThan16Bytes) IntLessThan16Bytes | |
| 720 | 802 | register(&fn, lib, "IdentityIntLessThan16Bytes", func(s IntLessThan16Bytes) IntLessThan16Bytes { | |
| 721 | 803 | return s | |
| 722 | 804 | }) | |
| 723 | - | expected := IntLessThan16Bytes{0xDEADBEEF, -42} | |
| 805 | + | expected := IntLessThan16Bytes{X: 0xDEADBEEF, Y: -42} | |
| 724 | 806 | if ret := fn(expected); ret != expected { | |
| 725 | 807 | t.Fatalf("IdentityIntLessThan16Bytes returned %+v wanted %+v", ret, expected) | |
| 726 | 808 | } | |
| 727 | 809 | } | |
| 728 | 810 | { | |
| 729 | 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 | 816 | var fn func(TwoDoubleStruct) TwoDoubleStruct | |
| 732 | 817 | register(&fn, lib, "IdentityTwoDoubleStruct", func(s TwoDoubleStruct) TwoDoubleStruct { | |
| 733 | 818 | return s | |
| 734 | 819 | }) | |
| 735 | - | expected := TwoDoubleStruct{3.14, -2.71} | |
| 820 | + | expected := TwoDoubleStruct{X: 3.14, Y: -2.71} | |
| 736 | 821 | if ret := fn(expected); ret != expected { | |
| 737 | 822 | t.Fatalf("IdentityTwoDoubleStruct returned %+v wanted %+v", ret, expected) | |
| 738 | 823 | } | |
| 739 | 824 | } | |
| 740 | 825 | { | |
| 741 | 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 | 831 | var fn func(FourFloat32) FourFloat32 | |
| 744 | 832 | register(&fn, lib, "IdentityFourFloat32", func(s FourFloat32) FourFloat32 { | |
| 745 | 833 | 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 | 836 | if ret := fn(expected); ret != expected { | |
| 749 | 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 | 841 | // Mixed float32 + int32: INTEGER class eightbyte on amd64, non-HFA int regs on arm64. | |
| 754 | 842 | type FloatAndInt struct { | |
| 843 | + | _ structs.HostLayout | |
| 755 | 844 | X float32 | |
| 756 | 845 | Y int32 | |
| 757 | 846 | } | |
| @@ -759,19 +848,22 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||
| 759 | 848 | register(&fn, lib, "IdentityFloatAndInt", func(s FloatAndInt) FloatAndInt { | |
| 760 | 849 | return s | |
| 761 | 850 | }) | |
| 762 | - | expected := FloatAndInt{7.5, 42} | |
| 851 | + | expected := FloatAndInt{X: 7.5, Y: 42} | |
| 763 | 852 | if ret := fn(expected); ret != expected { | |
| 764 | 853 | t.Fatalf("IdentityFloatAndInt returned %+v wanted %+v", ret, expected) | |
| 765 | 854 | } | |
| 766 | 855 | } | |
| 767 | 856 | { | |
| 768 | 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 | 862 | var fn func(ThreeInt64) ThreeInt64 | |
| 771 | 863 | register(&fn, lib, "IdentityThreeInt64", func(s ThreeInt64) ThreeInt64 { | |
| 772 | 864 | return s | |
| 773 | 865 | }) | |
| 774 | - | expected := ThreeInt64{1, 2, 3} | |
| 866 | + | expected := ThreeInt64{A: 1, B: 2, C: 3} | |
| 775 | 867 | if ret := fn(expected); ret != expected { | |
| 776 | 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 | 872 | // Struct > 16 bytes with pointer fields. | |
| 781 | 873 | type PtrInt64Ptr struct { | |
| 874 | + | _ structs.HostLayout | |
| 782 | 875 | A *int64 | |
| 783 | 876 | B int64 | |
| 784 | 877 | C *int64 | |
| @@ -789,7 +882,7 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||
| 789 | 882 | register(&fn, lib, "IdentityPtrInt64Ptr", func(s PtrInt64Ptr) PtrInt64Ptr { | |
| 790 | 883 | return s | |
| 791 | 884 | }) | |
| 792 | - | expected := PtrInt64Ptr{a, 200, c} | |
| 885 | + | expected := PtrInt64Ptr{A: a, B: 200, C: c} | |
| 793 | 886 | ret := fn(expected) | |
| 794 | 887 | if *ret.A != *expected.A || ret.B != expected.B || *ret.C != *expected.C { | |
| 795 | 888 | t.Fatalf("IdentityPtrInt64Ptr returned %+v wanted %+v", ret, expected) | |
| @@ -801,24 +894,30 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||
| 801 | 894 | // Struct arg after some primitive args: register offset correctness. | |
| 802 | 895 | // ppc64le is skipped: a float argument shadows a GPR, which purego | |
| 803 | 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 | 901 | var fn func(int64, float64, IntLessThan16Bytes) IntLessThan16Bytes | |
| 806 | 902 | register(&fn, lib, "IdentityTwoInt64AfterPrims", func(x int64, y float64, s IntLessThan16Bytes) IntLessThan16Bytes { | |
| 807 | 903 | return s | |
| 808 | 904 | }) | |
| 809 | - | expected := IntLessThan16Bytes{100, 200} | |
| 905 | + | expected := IntLessThan16Bytes{X: 100, Y: 200} | |
| 810 | 906 | if ret := fn(1, 2.0, expected); ret != expected { | |
| 811 | 907 | t.Fatalf("IdentityTwoInt64AfterPrims returned %+v wanted %+v", ret, expected) | |
| 812 | 908 | } | |
| 813 | 909 | } | |
| 814 | 910 | { | |
| 815 | 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 | 916 | var fn func(float64, float64, FloatLessThan16Bytes) FloatLessThan16Bytes | |
| 818 | 917 | register(&fn, lib, "IdentityTwoFloat32AfterFloats", func(x, y float64, s FloatLessThan16Bytes) FloatLessThan16Bytes { | |
| 819 | 918 | return s | |
| 820 | 919 | }) | |
| 821 | - | expected := FloatLessThan16Bytes{5.0, 6.0} | |
| 920 | + | expected := FloatLessThan16Bytes{X: 5.0, Y: 6.0} | |
| 822 | 921 | if ret := fn(1.0, 2.0, expected); ret != expected { | |
| 823 | 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 | 926 | // Mixed struct with pointer: pointer + int32 + float32 + int32. | |
| 828 | 927 | type Mixed5Args struct { | |
| 928 | + | _ structs.HostLayout | |
| 829 | 929 | A *int64 | |
| 830 | 930 | B int32 | |
| 831 | 931 | C float32 | |
| @@ -837,7 +937,7 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||
| 837 | 937 | register(&fn, lib, "IdentityMixed5Args", func(s Mixed5Args) Mixed5Args { | |
| 838 | 938 | 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 | 941 | ret := fn(expected) | |
| 842 | 942 | if ret.A != expected.A || ret.B != expected.B || ret.C != expected.C || ret.D != expected.D { | |
| 843 | 943 | t.Fatalf("IdentityMixed5Args returned %+v wanted %+v", ret, expected) | |
| @@ -927,166 +1027,228 @@ func TestRegisterFunc_structReturns(t *testing.T) { | |||
| 927 | 1027 | t.Run(imp.name, func(t *testing.T) { | |
| 928 | 1028 | register := imp.register | |
| 929 | 1029 | { | |
| 930 | - | type Empty struct{} | |
| 1030 | + | type Empty struct { | |
| 1031 | + | _ structs.HostLayout | |
| 1032 | + | } | |
| 931 | 1033 | var ReturnEmpty func() Empty | |
| 932 | 1034 | register(&ReturnEmpty, lib, "ReturnEmpty") | |
| 933 | 1035 | ret := ReturnEmpty() | |
| 934 | 1036 | _ = ret | |
| 935 | 1037 | } | |
| 936 | 1038 | { | |
| 937 | - | type inner struct{ A int16 } | |
| 1039 | + | type inner struct { | |
| 1040 | + | _ structs.HostLayout | |
| 1041 | + | A int16 | |
| 1042 | + | } | |
| 938 | 1043 | type StructInStruct struct { | |
| 1044 | + | _ structs.HostLayout | |
| 939 | 1045 | A inner | |
| 940 | 1046 | B inner | |
| 941 | 1047 | C inner | |
| 942 | 1048 | } | |
| 943 | 1049 | var ReturnStructInStruct func(a, b, c int16) StructInStruct | |
| 944 | 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 | 1052 | if ret := ReturnStructInStruct(^int16(0), 2, 3); ret != expected { | |
| 947 | 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 | 1061 | var ReturnThreeShorts func(a, b, c int16) ThreeShorts | |
| 953 | 1062 | register(&ReturnThreeShorts, lib, "ReturnThreeShorts") | |
| 954 | - | expected := ThreeShorts{^int16(0), 2, 3} | |
| 1063 | + | expected := ThreeShorts{A: ^int16(0), B: 2, C: 3} | |
| 955 | 1064 | if ret := ReturnThreeShorts(^int16(0), 2, 3); ret != expected { | |
| 956 | 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 | 1073 | var ReturnFourShorts func(a, b, c, d int16) FourShorts | |
| 962 | 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 | 1076 | if ret := ReturnFourShorts(^int16(0), 2, 3, 4); ret != expected { | |
| 965 | 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 | 1085 | var ReturnOneLong func(a int64) OneLong | |
| 971 | 1086 | register(&ReturnOneLong, lib, "ReturnOneLong") | |
| 972 | - | expected := OneLong{5} | |
| 1087 | + | expected := OneLong{A: 5} | |
| 973 | 1088 | if ret := ReturnOneLong(5); ret != expected { | |
| 974 | 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 | 1097 | var ReturnTwoLongs func(a, b int64) TwoLongs | |
| 980 | 1098 | register(&ReturnTwoLongs, lib, "ReturnTwoLongs") | |
| 981 | - | expected := TwoLongs{1, 2} | |
| 1099 | + | expected := TwoLongs{A: 1, B: 2} | |
| 982 | 1100 | if ret := ReturnTwoLongs(1, 2); ret != expected { | |
| 983 | 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 | 1109 | var ReturnThreeLongs func(a, b, c int64) ThreeLongs | |
| 989 | 1110 | register(&ReturnThreeLongs, lib, "ReturnThreeLongs") | |
| 990 | - | expected := ThreeLongs{1, 2, 3} | |
| 1111 | + | expected := ThreeLongs{A: 1, B: 2, C: 3} | |
| 991 | 1112 | if ret := ReturnThreeLongs(1, 2, 3); ret != expected { | |
| 992 | 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 | 1121 | var ReturnOneFloat func(a float32) OneFloat | |
| 998 | 1122 | register(&ReturnOneFloat, lib, "ReturnOneFloat") | |
| 999 | - | expected := OneFloat{1} | |
| 1123 | + | expected := OneFloat{A: 1} | |
| 1000 | 1124 | if ret := ReturnOneFloat(1); ret != expected { | |
| 1001 | 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 | 1133 | var ReturnTwoFloats func(a, b float32) TwoFloats | |
| 1007 | 1134 | register(&ReturnTwoFloats, lib, "ReturnTwoFloats") | |
| 1008 | - | expected := TwoFloats{5, 2} | |
| 1135 | + | expected := TwoFloats{A: 5, B: 2} | |
| 1009 | 1136 | if ret := ReturnTwoFloats(5, 2); ret != expected { | |
| 1010 | 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 | 1145 | var ReturnThreeFloats func(a, b, c float32) ThreeFloats | |
| 1016 | 1146 | register(&ReturnThreeFloats, lib, "ReturnThreeFloats") | |
| 1017 | - | expected := ThreeFloats{1, 2, 3} | |
| 1147 | + | expected := ThreeFloats{A: 1, B: 2, C: 3} | |
| 1018 | 1148 | if ret := ReturnThreeFloats(1, 2, 3); ret != expected { | |
| 1019 | 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 | 1157 | var ReturnFourFloats func(a, b, c, d float32) FourFloats | |
| 1025 | 1158 | register(&ReturnFourFloats, lib, "ReturnFourFloats") | |
| 1026 | - | expected := FourFloats{1, 2, 3, 4} | |
| 1159 | + | expected := FourFloats{A: 1, B: 2, C: 3, D: 4} | |
| 1027 | 1160 | if ret := ReturnFourFloats(1, 2, 3, 4); ret != expected { | |
| 1028 | 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 | 1169 | var ReturnOneDouble func(a float64) OneDouble | |
| 1034 | 1170 | register(&ReturnOneDouble, lib, "ReturnOneDouble") | |
| 1035 | - | expected := OneDouble{1} | |
| 1171 | + | expected := OneDouble{A: 1} | |
| 1036 | 1172 | if ret := ReturnOneDouble(1); ret != expected { | |
| 1037 | 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 | 1181 | var ReturnTwoDoubles func(a, b float64) TwoDoubles | |
| 1043 | 1182 | register(&ReturnTwoDoubles, lib, "ReturnTwoDoubles") | |
| 1044 | - | expected := TwoDoubles{7, 3} | |
| 1183 | + | expected := TwoDoubles{A: 7, B: 3} | |
| 1045 | 1184 | if ret := ReturnTwoDoubles(7, 3); ret != expected { | |
| 1046 | 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 | 1193 | var ReturnThreeDoubles func(a, b, c float64) ThreeDoubles | |
| 1052 | 1194 | register(&ReturnThreeDoubles, lib, "ReturnThreeDoubles") | |
| 1053 | - | expected := ThreeDoubles{1, 2, 3} | |
| 1195 | + | expected := ThreeDoubles{A: 1, B: 2, C: 3} | |
| 1054 | 1196 | if ret := ReturnThreeDoubles(1, 2, 3); ret != expected { | |
| 1055 | 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 | 1205 | var ReturnFourDoubles func(a, b, c, d float64) FourDoubles | |
| 1061 | 1206 | register(&ReturnFourDoubles, lib, "ReturnFourDoubles") | |
| 1062 | - | expected := FourDoubles{1, 2, 3, 4} | |
| 1207 | + | expected := FourDoubles{A: 1, B: 2, C: 3, D: 4} | |
| 1063 | 1208 | if ret := ReturnFourDoubles(1, 2, 3, 4); ret != expected { | |
| 1064 | 1209 | t.Fatalf("ReturnFourDoubles returned %+v wanted %+v", ret, expected) | |
| 1065 | 1210 | } | |
| 1066 | 1211 | } | |
| 1067 | 1212 | { | |
| 1068 | 1213 | 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 | + | } | |
| 1071 | 1223 | } | |
| 1072 | 1224 | var ReturnFourDoublesInternal func(a, b, c, d float64) FourDoublesInternal | |
| 1073 | 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 | 1233 | if ret := ReturnFourDoublesInternal(1, 2, 3, 4); ret != expected { | |
| 1076 | 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 | 1242 | var ReturnFiveDoubles func(a, b, c, d, e float64) FiveDoubles | |
| 1082 | 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 | 1245 | if ret := ReturnFiveDoubles(1, 2, 3, 4, 5); ret != expected { | |
| 1085 | 1246 | t.Fatalf("ReturnFiveDoubles returned %+v wanted %+v", ret, expected) | |
| 1086 | 1247 | } | |
| 1087 | 1248 | } | |
| 1088 | 1249 | { | |
| 1089 | 1250 | type OneFloatOneDouble struct { | |
| 1251 | + | _ structs.HostLayout | |
| 1090 | 1252 | A float32 | |
| 1091 | 1253 | _ float32 | |
| 1092 | 1254 | B float64 | |
| @@ -1100,18 +1262,20 @@ func TestRegisterFunc_structReturns(t *testing.T) { | |||
| 1100 | 1262 | } | |
| 1101 | 1263 | { | |
| 1102 | 1264 | type OneDoubleOneFloat struct { | |
| 1265 | + | _ structs.HostLayout | |
| 1103 | 1266 | A float64 | |
| 1104 | 1267 | B float32 | |
| 1105 | 1268 | } | |
| 1106 | 1269 | var ReturnOneDoubleOneFloat func(a float64, b float32) OneDoubleOneFloat | |
| 1107 | 1270 | register(&ReturnOneDoubleOneFloat, lib, "ReturnOneDoubleOneFloat") | |
| 1108 | - | expected := OneDoubleOneFloat{1, 2} | |
| 1271 | + | expected := OneDoubleOneFloat{A: 1, B: 2} | |
| 1109 | 1272 | if ret := ReturnOneDoubleOneFloat(1, 2); ret != expected { | |
| 1110 | 1273 | t.Fatalf("ReturnOneDoubleOneFloat returned %+v wanted %+v", ret, expected) | |
| 1111 | 1274 | } | |
| 1112 | 1275 | } | |
| 1113 | 1276 | { | |
| 1114 | 1277 | type Unaligned1 struct { | |
| 1278 | + | _ structs.HostLayout | |
| 1115 | 1279 | A int8 | |
| 1116 | 1280 | _ [1]int8 | |
| 1117 | 1281 | B int16 | |
| @@ -1133,18 +1297,20 @@ func TestRegisterFunc_structReturns(t *testing.T) { | |||
| 1133 | 1297 | // ppc64le by modeling the ELFv2 general-purpose register shadowing. | |
| 1134 | 1298 | { | |
| 1135 | 1299 | type Mixed1 struct { | |
| 1300 | + | _ structs.HostLayout | |
| 1136 | 1301 | A float32 | |
| 1137 | 1302 | B int32 | |
| 1138 | 1303 | } | |
| 1139 | 1304 | var ReturnMixed1 func(a float32, b int32) Mixed1 | |
| 1140 | 1305 | register(&ReturnMixed1, lib, "ReturnMixed1") | |
| 1141 | - | expected := Mixed1{1, 2} | |
| 1306 | + | expected := Mixed1{A: 1, B: 2} | |
| 1142 | 1307 | if ret := ReturnMixed1(1, 2); ret != expected { | |
| 1143 | 1308 | t.Fatalf("ReturnMixed1 returned %+v wanted %+v", ret, expected) | |
| 1144 | 1309 | } | |
| 1145 | 1310 | } | |
| 1146 | 1311 | { | |
| 1147 | 1312 | type Mixed2 struct { | |
| 1313 | + | _ structs.HostLayout | |
| 1148 | 1314 | A float32 | |
| 1149 | 1315 | B int32 | |
| 1150 | 1316 | C float32 | |
| @@ -1152,39 +1318,42 @@ func TestRegisterFunc_structReturns(t *testing.T) { | |||
| 1152 | 1318 | } | |
| 1153 | 1319 | var ReturnMixed2 func(a float32, b int32, c float32, d int32) Mixed2 | |
| 1154 | 1320 | register(&ReturnMixed2, lib, "ReturnMixed2") | |
| 1155 | - | expected := Mixed2{1, 2, 3, 4} | |
| 1321 | + | expected := Mixed2{A: 1, B: 2, C: 3, D: 4} | |
| 1156 | 1322 | if ret := ReturnMixed2(1, 2, 3, 4); ret != expected { | |
| 1157 | 1323 | t.Fatalf("ReturnMixed2 returned %+v wanted %+v", ret, expected) | |
| 1158 | 1324 | } | |
| 1159 | 1325 | } | |
| 1160 | 1326 | { | |
| 1161 | 1327 | type Mixed3 struct { | |
| 1328 | + | _ structs.HostLayout | |
| 1162 | 1329 | A float32 | |
| 1163 | 1330 | B uint32 | |
| 1164 | 1331 | C float64 | |
| 1165 | 1332 | } | |
| 1166 | 1333 | var ReturnMixed3 func(a float32, b uint32, c float64) Mixed3 | |
| 1167 | 1334 | register(&ReturnMixed3, lib, "ReturnMixed3") | |
| 1168 | - | expected := Mixed3{1, 2, 3} | |
| 1335 | + | expected := Mixed3{A: 1, B: 2, C: 3} | |
| 1169 | 1336 | if ret := ReturnMixed3(1, 2, 3); ret != expected { | |
| 1170 | 1337 | t.Fatalf("ReturnMixed3 returned %+v wanted %+v", ret, expected) | |
| 1171 | 1338 | } | |
| 1172 | 1339 | } | |
| 1173 | 1340 | { | |
| 1174 | 1341 | type Mixed4 struct { | |
| 1342 | + | _ structs.HostLayout | |
| 1175 | 1343 | A float64 | |
| 1176 | 1344 | B uint32 | |
| 1177 | 1345 | C float32 | |
| 1178 | 1346 | } | |
| 1179 | 1347 | var ReturnMixed4 func(a float64, b uint32, c float32) Mixed4 | |
| 1180 | 1348 | register(&ReturnMixed4, lib, "ReturnMixed4") | |
| 1181 | - | expected := Mixed4{1, 2, 3} | |
| 1349 | + | expected := Mixed4{A: 1, B: 2, C: 3} | |
| 1182 | 1350 | if ret := ReturnMixed4(1, 2, 3); ret != expected { | |
| 1183 | 1351 | t.Fatalf("ReturnMixed4 returned %+v wanted %+v", ret, expected) | |
| 1184 | 1352 | } | |
| 1185 | 1353 | } | |
| 1186 | 1354 | { | |
| 1187 | 1355 | type Mixed5 struct { | |
| 1356 | + | _ structs.HostLayout | |
| 1188 | 1357 | A *int64 | |
| 1189 | 1358 | B int32 | |
| 1190 | 1359 | C float32 | |
| @@ -1193,7 +1362,7 @@ func TestRegisterFunc_structReturns(t *testing.T) { | |||
| 1193 | 1362 | var ReturnMixed5 func(a *int64, b int32, c float32, d int32) Mixed5 | |
| 1194 | 1363 | register(&ReturnMixed5, lib, "ReturnMixed5") | |
| 1195 | 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 | 1366 | if ret := ReturnMixed5(ptr, 1, 7.2, 9); ret != expected { | |
| 1198 | 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 | 1373 | type Mixed5 struct { | |
| 1374 | + | _ structs.HostLayout | |
| 1205 | 1375 | A *int64 | |
| 1206 | 1376 | B int32 | |
| 1207 | 1377 | C float32 | |
| @@ -1213,7 +1383,7 @@ func TestRegisterFunc_structReturns(t *testing.T) { | |||
| 1213 | 1383 | // Struct callback args are tested in TestRegisterFunc_structArgs. | |
| 1214 | 1384 | purego.RegisterLibFunc(&IdentityMixed5, lib, "IdentityMixed5") | |
| 1215 | 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 | 1387 | if ret := IdentityMixed5(expected); ret != expected { | |
| 1218 | 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 | 1393 | type SmallBool struct { | |
| 1394 | + | _ structs.HostLayout | |
| 1224 | 1395 | A bool | |
| 1225 | 1396 | B int32 | |
| 1226 | 1397 | C int64 | |
| 1227 | 1398 | } | |
| 1228 | 1399 | var ReturnSmallBool func(a bool, b int32, c int64) SmallBool | |
| 1229 | 1400 | register(&ReturnSmallBool, lib, "ReturnSmallBool") | |
| 1230 | - | expected := SmallBool{true, 42, 123456789} | |
| 1401 | + | expected := SmallBool{A: true, B: 42, C: 123456789} | |
| 1231 | 1402 | if ret := ReturnSmallBool(true, 42, 123456789); ret != expected { | |
| 1232 | 1403 | t.Fatalf("ReturnSmallBool returned %+v wanted %+v", ret, expected) | |
| 1233 | 1404 | } | |
| 1234 | 1405 | } | |
| 1235 | 1406 | { | |
| 1236 | 1407 | type LargeBool struct { | |
| 1408 | + | _ structs.HostLayout | |
| 1237 | 1409 | A bool | |
| 1238 | 1410 | B int32 | |
| 1239 | 1411 | C int64 | |
| @@ -1241,20 +1413,21 @@ func TestRegisterFunc_structReturns(t *testing.T) { | |||
| 1241 | 1413 | } | |
| 1242 | 1414 | var ReturnLargeBool func(a bool, b int32, c int64, d int64) LargeBool | |
| 1243 | 1415 | register(&ReturnLargeBool, lib, "ReturnLargeBool") | |
| 1244 | - | expected := LargeBool{false, -99, 987654321, 111222333444} | |
| 1416 | + | expected := LargeBool{A: false, B: -99, C: 987654321, D: 111222333444} | |
| 1245 | 1417 | if ret := ReturnLargeBool(false, -99, 987654321, 111222333444); ret != expected { | |
| 1246 | 1418 | t.Fatalf("ReturnLargeBool returned %+v wanted %+v", ret, expected) | |
| 1247 | 1419 | } | |
| 1248 | 1420 | } | |
| 1249 | 1421 | { | |
| 1250 | 1422 | type Ptr1 struct { | |
| 1423 | + | _ structs.HostLayout | |
| 1251 | 1424 | a *int64 | |
| 1252 | 1425 | b unsafe.Pointer | |
| 1253 | 1426 | } | |
| 1254 | 1427 | var ReturnPtr1 func(a *int64, b unsafe.Pointer) Ptr1 | |
| 1255 | 1428 | purego.RegisterLibFunc(&ReturnPtr1, lib, "ReturnPtr1") | |
| 1256 | 1429 | a, b := new(int64), new(struct{}) | |
| 1257 | - | expected := Ptr1{a, unsafe.Pointer(b)} | |
| 1430 | + | expected := Ptr1{a: a, b: unsafe.Pointer(b)} | |
| 1258 | 1431 | if ret := ReturnPtr1(a, unsafe.Pointer(b)); ret != expected { | |
| 1259 | 1432 | t.Fatalf("ReturnPtr1 returned %+v wanted %+v", ret, expected) | |
| 1260 | 1433 | } | |
| @@ -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.register | 91 | register := imp.register | ||
| 91 | { | 92 | { | ||
| 92 | - | type Empty struct{} | 93 | + | type Empty struct { |
| 94 | + | _ structs.HostLayout | |||
| 95 | + | } | |||
| 93 | var NoStruct func(Empty) int64 | 96 | var NoStruct func(Empty) int64 | ||
| 94 | register(&NoStruct, lib, "NoStruct", func(Empty) int64 { | 97 | register(&NoStruct, lib, "NoStruct", func(Empty) int64 { | ||
| 95 | return 0xdeadbeef | 98 | 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) int64 | 108 | var EmptyEmptyFn func(EmptyEmpty) int64 | ||
| 104 | register(&EmptyEmptyFn, lib, "EmptyEmpty", func(EmptyEmpty) int64 { | 109 | register(&EmptyEmptyFn, lib, "EmptyEmpty", func(EmptyEmpty) int64 { | ||
| 105 | return 0xdeadbeef | 110 | 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 *int64 | 126 | x, y, z *int64 | ||
| 121 | } | 127 | } | ||
| 122 | var x, y, z int64 = 0xEF, 0xBE00, 0xDEAD0000 | 128 | 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 *int64 | 142 | 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.z | 148 | 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 *int64 | 160 | x, y, z *int64 | ||
| 149 | } | 161 | } | ||
| 150 | var x, y, z int64 = 0xEF, 0xBE00, 0xDEAD0000 | 162 | 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 int64 | 190 | x, y int64 | ||
| 178 | } | 191 | } | ||
| 179 | var IntLessThan16BytesFn func(bytes IntLessThan16Bytes) int64 | 192 | 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.y | 194 | 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 float32 | 203 | x, y float32 | ||
| 190 | } | 204 | } | ||
| 191 | var FloatLessThan16BytesFn func(FloatLessThan16Bytes) float32 | 205 | 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.y | 207 | 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 float32 | 216 | x, y, z float32 | ||
| 202 | } | 217 | } | ||
| 203 | var ThreeSmallFieldsFn func(ThreeSmallFields) float32 | 218 | 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.z | 220 | 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 float32 | 229 | x float32 | ||
| 214 | y int32 | 230 | 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 float64 | 243 | x float64 | ||
| 227 | } | 244 | } | ||
| 228 | var DoubleStructFn func(DoubleStruct) float64 | 245 | 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.x | 247 | 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 float64 | 256 | x, y float64 | ||
| 239 | } | 257 | } | ||
| 240 | var TwoDoubleStructFn func(TwoDoubleStruct) float64 | 258 | 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.y | 260 | 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 float64 | 271 | 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.y | 276 | 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 float64 | 288 | x, y, z float64 | ||
| 265 | } | 289 | } | ||
| 266 | var ThreeDoubleStructFn func(ThreeDoubleStruct) float64 | 290 | 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.z | 292 | 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 float64 | 301 | a, b, c, d, e, f float64 | ||
| 277 | } | 302 | } | ||
| 278 | var LargeFloatStructFn func(LargeFloatStruct) float64 | 303 | 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.f | 305 | 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.f | 315 | 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 float64 | 325 | 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.h | 332 | 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) float64 | 345 | 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.h | 347 | 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]float64 | 356 | a [2]float64 | ||
| 330 | } | 357 | } | ||
| 331 | var FloatArrayFn func(rect FloatArray) float64 | 358 | 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 byte | 369 | a, b, c, d byte | ||
| 342 | } | 370 | } | ||
| 343 | var UnsignedChar4BytesFn func(UnsignedChar4Bytes) uint32 | 371 | 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 byte | 384 | a byte | ||
| 355 | } | 385 | } | ||
| 356 | y struct { | 386 | y struct { | ||
| 387 | + | _ structs.HostLayout | |||
| 357 | b byte | 388 | b byte | ||
| 358 | } | 389 | } | ||
| 359 | z struct { | 390 | z struct { | ||
| 391 | + | _ structs.HostLayout | |||
| 360 | c byte | 392 | c byte | ||
| 361 | } | 393 | } | ||
| 362 | w struct { | 394 | w struct { | ||
| 395 | + | _ structs.HostLayout | |||
| 363 | d byte | 396 | 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 uint16 | 427 | a, b, c, d uint16 | ||
| 382 | } | 428 | } | ||
| 383 | var ShortFn func(Short) uint64 | 429 | 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 uint32 | 440 | a, b uint32 | ||
| 394 | } | 441 | } | ||
| 395 | var IntFn func(Int) uint64 | 442 | 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 uint64 | 453 | a uint64 | ||
| 406 | } | 454 | } | ||
| 407 | var LongFn func(Long) uint64 | 455 | 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 int8 | 466 | a, b, c, d, e, f, g, h int8 | ||
| 418 | } | 467 | } | ||
| 419 | var Char8BytesFn func(Char8Bytes) int32 | 468 | 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 byte | 479 | a, b, c byte | ||
| 430 | } | 480 | } | ||
| 431 | var OddFn func(Odd) int32 | 481 | 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 byte | 492 | a, b byte | ||
| 442 | c uint16 | 493 | 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 int8 | 506 | a, b int8 | ||
| 455 | c int16 | 507 | 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]uint8 | 520 | a [4]uint8 | ||
| 468 | } | 521 | } | ||
| 469 | var Array4UnsignedCharsFn func(chars Array4UnsignedChars) uint32 | 522 | 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]uint8 | 533 | a [3]uint8 | ||
| 480 | } | 534 | } | ||
| 481 | var Array3UnsignedChars func(chars Array3UnsignedChar) uint32 | 535 | 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]uint16 | 546 | a [2]uint16 | ||
| 492 | } | 547 | } | ||
| 493 | var Array2UnsignedShorts func(chars Array2UnsignedShort) uint32 | 548 | 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]int8 | 559 | a [4]int8 | ||
| 504 | } | 560 | } | ||
| 505 | var Array4CharsFn func(chars Array4Chars) int32 | 561 | 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]int16 | 573 | a [2]int16 | ||
| 517 | } | 574 | } | ||
| 518 | var Array2Shorts func(chars Array2Short) int32 | 575 | 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]int16 | 586 | a [3]int16 | ||
| 529 | } | 587 | } | ||
| 530 | var Array3Shorts func(chars Array3Short) int32 | 588 | 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 bool | 599 | b bool | ||
| 541 | } | 600 | } | ||
| 542 | var BoolStructFn func(BoolStruct) bool | 601 | 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.b | 603 | 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 bool | 615 | b bool | ||
| 556 | _ [3]byte // purego won't do padding for you so make sure it aligns properly with C struct | 616 | _ [3]byte // purego won't do padding for you so make sure it aligns properly with C struct | ||
| 557 | f float32 | 617 | 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 point | 644 | point point | ||
| 578 | size size | 645 | 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 0xdeadbeef | 658 | // 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 int | 667 | A, B, C, D int | ||
| 600 | } | 668 | } | ||
| 601 | var GoInt4Fn func(GoInt4) int | 669 | var GoInt4Fn func(GoInt4) int | ||
| @@ -603,12 +671,13 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||||
| 603 | return g.A + g.B - g.C + g.D | 671 | return g.A + g.B - g.C + g.D | ||
| 604 | }) | 672 | }) | ||
| 605 | const expected = math.MaxInt - 52 - 3 + 4 | 673 | 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 uint | 681 | A, B, C, D uint | ||
| 613 | } | 682 | } | ||
| 614 | var GoUint4Fn func(GoUint4) uint | 683 | var GoUint4Fn func(GoUint4) uint | ||
| @@ -616,23 +685,27 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||||
| 616 | return g.A + g.B + g.C + g.D | 685 | return g.A + g.B + g.C + g.D | ||
| 617 | }) | 686 | }) | ||
| 618 | const expected = 1_000_000 + 53 + 71 + 8 | 687 | 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) uint64 | 697 | 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 float32 | 709 | x float32 | ||
| 637 | y bool | 710 | 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 int32 | 729 | f0, f1, f2, f3 int32 | ||
| 656 | } | 730 | } | ||
| 657 | var FourInt32sFn func(FourInt32s) int32 | 731 | 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.f3 | 733 | 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 - 100 | 736 | 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.Pointer | 744 | ctx unsafe.Pointer | ||
| 670 | } | 745 | } | ||
| 671 | var ExtractPointer func(wrapper PointerWrapper) uintptr | 746 | 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.Pointer | 762 | ptr1, ptr2 unsafe.Pointer | ||
| 687 | } | 763 | } | ||
| 688 | var AddPointers func(wrapper TwoPointers) uintptr | 764 | 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 tests | 779 | // 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) OneInt64 | 786 | 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 s | 788 | 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) IntLessThan16Bytes | 801 | 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 s | 803 | 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) TwoDoubleStruct | 816 | 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 s | 818 | 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) FourFloat32 | 831 | 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 s | 833 | 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 float32 | 844 | X float32 | ||
| 756 | Y int32 | 845 | 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 s | 849 | 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) ThreeInt64 | 862 | 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 s | 864 | 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 *int64 | 875 | A *int64 | ||
| 783 | B int64 | 876 | B int64 | ||
| 784 | C *int64 | 877 | 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 s | 883 | 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 purego | 895 | // 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) IntLessThan16Bytes | 901 | 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 s | 903 | 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) FloatLessThan16Bytes | 916 | 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 s | 918 | 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 *int64 | 929 | A *int64 | ||
| 830 | B int32 | 930 | B int32 | ||
| 831 | C float32 | 931 | 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 s | 938 | 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.register | 1028 | register := imp.register | ||
| 929 | { | 1029 | { | ||
| 930 | - | type Empty struct{} | 1030 | + | type Empty struct { |
| 1031 | + | _ structs.HostLayout | |||
| 1032 | + | } | |||
| 931 | var ReturnEmpty func() Empty | 1033 | var ReturnEmpty func() Empty | ||
| 932 | register(&ReturnEmpty, lib, "ReturnEmpty") | 1034 | register(&ReturnEmpty, lib, "ReturnEmpty") | ||
| 933 | ret := ReturnEmpty() | 1035 | ret := ReturnEmpty() | ||
| 934 | _ = ret | 1036 | _ = 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 inner | 1045 | A inner | ||
| 940 | B inner | 1046 | B inner | ||
| 941 | C inner | 1047 | C inner | ||
| 942 | } | 1048 | } | ||
| 943 | var ReturnStructInStruct func(a, b, c int16) StructInStruct | 1049 | 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) ThreeShorts | 1061 | 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) FourShorts | 1073 | 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) OneLong | 1085 | 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) TwoLongs | 1097 | 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) ThreeLongs | 1109 | 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) OneFloat | 1121 | 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) TwoFloats | 1133 | 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) ThreeFloats | 1145 | 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) FourFloats | 1157 | 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) OneDouble | 1169 | 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) TwoDoubles | 1181 | 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) ThreeDoubles | 1193 | 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) FourDoubles | 1205 | 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) FourDoublesInternal | 1224 | 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) FiveDoubles | 1242 | 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 float32 | 1252 | A float32 | ||
| 1091 | _ float32 | 1253 | _ float32 | ||
| 1092 | B float64 | 1254 | 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 float64 | 1266 | A float64 | ||
| 1104 | B float32 | 1267 | B float32 | ||
| 1105 | } | 1268 | } | ||
| 1106 | var ReturnOneDoubleOneFloat func(a float64, b float32) OneDoubleOneFloat | 1269 | 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 int8 | 1279 | A int8 | ||
| 1116 | _ [1]int8 | 1280 | _ [1]int8 | ||
| 1117 | B int16 | 1281 | 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 float32 | 1301 | A float32 | ||
| 1137 | B int32 | 1302 | B int32 | ||
| 1138 | } | 1303 | } | ||
| 1139 | var ReturnMixed1 func(a float32, b int32) Mixed1 | 1304 | 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 float32 | 1314 | A float32 | ||
| 1149 | B int32 | 1315 | B int32 | ||
| 1150 | C float32 | 1316 | 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) Mixed2 | 1319 | 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 float32 | 1329 | A float32 | ||
| 1163 | B uint32 | 1330 | B uint32 | ||
| 1164 | C float64 | 1331 | C float64 | ||
| 1165 | } | 1332 | } | ||
| 1166 | var ReturnMixed3 func(a float32, b uint32, c float64) Mixed3 | 1333 | 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 float64 | 1343 | A float64 | ||
| 1176 | B uint32 | 1344 | B uint32 | ||
| 1177 | C float32 | 1345 | C float32 | ||
| 1178 | } | 1346 | } | ||
| 1179 | var ReturnMixed4 func(a float64, b uint32, c float32) Mixed4 | 1347 | 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 *int64 | 1357 | A *int64 | ||
| 1189 | B int32 | 1358 | B int32 | ||
| 1190 | C float32 | 1359 | C float32 | ||
| @@ -1193,7 +1362,7 @@ func TestRegisterFunc_structReturns(t *testing.T) { | |||||
| 1193 | var ReturnMixed5 func(a *int64, b int32, c float32, d int32) Mixed5 | 1362 | 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 *int64 | 1375 | A *int64 | ||
| 1206 | B int32 | 1376 | B int32 | ||
| 1207 | C float32 | 1377 | 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 bool | 1395 | A bool | ||
| 1225 | B int32 | 1396 | B int32 | ||
| 1226 | C int64 | 1397 | C int64 | ||
| 1227 | } | 1398 | } | ||
| 1228 | var ReturnSmallBool func(a bool, b int32, c int64) SmallBool | 1399 | 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 bool | 1409 | A bool | ||
| 1238 | B int32 | 1410 | B int32 | ||
| 1239 | C int64 | 1411 | 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) LargeBool | 1414 | 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 *int64 | 1424 | a *int64 | ||
| 1252 | b unsafe.Pointer | 1425 | b unsafe.Pointer | ||
| 1253 | } | 1426 | } | ||
| 1254 | var ReturnPtr1 func(a *int64, b unsafe.Pointer) Ptr1 | 1427 | 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 | |||
| 7 | 7 | ||
| 8 | 8 | import ( | |
| 9 | 9 | "runtime" | |
| 10 | + | "structs" | |
| 10 | 11 | "unsafe" | |
| 11 | 12 | ) | |
| 12 | 13 | ||
| @@ -14,7 +15,12 @@ const ( | |||
| 14 | 15 | 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 | 21 | type syscallArgs struct { | |
| 22 | + | _ structs.HostLayout | |
| 23 | + | ||
| 18 | 24 | fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr | |
| 19 | 25 | a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, a32 uintptr | |
| 20 | 26 | 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 = 32 | 15 | 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 uintptr | 24 | 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 uintptr | 25 | 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 uintptr | 26 | f1, f2, f3, f4, f5, f6, f7, f8 uintptr | ||
M syscall_32bit.go +6 -0
| @@ -7,6 +7,7 @@ package purego | |||
| 7 | 7 | ||
| 8 | 8 | import ( | |
| 9 | 9 | "runtime" | |
| 10 | + | "structs" | |
| 10 | 11 | "unsafe" | |
| 11 | 12 | ) | |
| 12 | 13 | ||
| @@ -14,7 +15,12 @@ const ( | |||
| 14 | 15 | 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 | 21 | type syscallArgs struct { | |
| 22 | + | _ structs.HostLayout | |
| 23 | + | ||
| 18 | 24 | fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr | |
| 19 | 25 | a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, a32 uintptr | |
| 20 | 26 | 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 = 32 | 15 | 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 uintptr | 24 | 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 uintptr | 25 | 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 uintptr | 26 | f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16 uintptr | ||