From fe27b674cdacd1ad78a2412013844f13eb1b3b15 Mon Sep 17 00:00:00 2001 From: Randy Reddig Date: Tue, 14 May 2024 05:04:54 -0700 Subject: [PATCH] reflect: use int in StringHeader and SliceHeader on non-AVR platforms (#4156) --- src/reflect/intw.go | 8 ++++++++ src/reflect/intw_avr.go | 8 ++++++++ src/reflect/intw_test.go | 30 ++++++++++++++++++++++++++++++ src/reflect/value.go | 16 +++++++++++++--- tests/runtime_wasi/malloc_test.go | 2 +- 5 files changed, 60 insertions(+), 4 deletions(-) create mode 100644 src/reflect/intw.go create mode 100644 src/reflect/intw_avr.go create mode 100644 src/reflect/intw_test.go diff --git a/src/reflect/intw.go b/src/reflect/intw.go new file mode 100644 index 0000000000..20fbd4341e --- /dev/null +++ b/src/reflect/intw.go @@ -0,0 +1,8 @@ +//go:build !avr + +package reflect + +// intw is an integer type, used in places where an int is typically required, +// except architectures where the size of an int != word size. +// See https://github.com/tinygo-org/tinygo/issues/1284. +type intw = int diff --git a/src/reflect/intw_avr.go b/src/reflect/intw_avr.go new file mode 100644 index 0000000000..8f294eeee2 --- /dev/null +++ b/src/reflect/intw_avr.go @@ -0,0 +1,8 @@ +//go:build avr + +package reflect + +// intw is an integer type, used in places where an int is typically required, +// except architectures where the size of an int != word size. +// See https://github.com/tinygo-org/tinygo/issues/1284. +type intw = uintptr diff --git a/src/reflect/intw_test.go b/src/reflect/intw_test.go new file mode 100644 index 0000000000..1014a9ae4e --- /dev/null +++ b/src/reflect/intw_test.go @@ -0,0 +1,30 @@ +//go:build !avr + +package reflect_test + +import ( + "reflect" + "testing" + "unsafe" +) + +// Verify that SliceHeader is the same size as a slice. +var _ [unsafe.Sizeof([]byte{})]byte = [unsafe.Sizeof(reflect.SliceHeader{})]byte{} + +// TestSliceHeaderIntegerSize verifies that SliceHeader.Len and Cap are type int on non-AVR platforms. +// See https://github.com/tinygo-org/tinygo/issues/1284. +func TestSliceHeaderIntegerSize(t *testing.T) { + var h reflect.SliceHeader + h.Len = int(0) + h.Cap = int(0) +} + +// Verify that StringHeader is the same size as a string. +var _ [unsafe.Sizeof("hello")]byte = [unsafe.Sizeof(reflect.StringHeader{})]byte{} + +// TestStringHeaderIntegerSize verifies that StringHeader.Len and Cap are type int on non-AVR platforms. +// See https://github.com/tinygo-org/tinygo/issues/1284. +func TestStringHeaderIntegerSize(t *testing.T) { + var h reflect.StringHeader + h.Len = int(0) +} diff --git a/src/reflect/value.go b/src/reflect/value.go index 6e882ed17b..c8439ccef2 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -1578,8 +1578,8 @@ type funcHeader struct { type SliceHeader struct { Data uintptr - Len uintptr - Cap uintptr + Len intw + Cap intw } // Slice header that matches the underlying structure. Used for when we switch @@ -1592,7 +1592,7 @@ type sliceHeader struct { type StringHeader struct { Data uintptr - Len uintptr + Len intw } // Like sliceHeader, this type is used internally to make sure pointer and @@ -1602,6 +1602,16 @@ type stringHeader struct { len uintptr } +// Verify SliceHeader and StringHeader sizes. +// See https://github.com/tinygo-org/tinygo/pull/4156 +// and https://github.com/tinygo-org/tinygo/issues/1284. +var ( + _ [unsafe.Sizeof([]byte{})]byte = [unsafe.Sizeof(SliceHeader{})]byte{} + _ [unsafe.Sizeof([]byte{})]byte = [unsafe.Sizeof(sliceHeader{})]byte{} + _ [unsafe.Sizeof("")]byte = [unsafe.Sizeof(StringHeader{})]byte{} + _ [unsafe.Sizeof("")]byte = [unsafe.Sizeof(stringHeader{})]byte{} +) + type ValueError struct { Method string Kind Kind diff --git a/tests/runtime_wasi/malloc_test.go b/tests/runtime_wasi/malloc_test.go index e5bbb4ebb3..465e662a45 100644 --- a/tests/runtime_wasi/malloc_test.go +++ b/tests/runtime_wasi/malloc_test.go @@ -67,7 +67,7 @@ func checkFilledBuffer(t *testing.T, ptr uintptr, content string) { t.Helper() buf := *(*string)(unsafe.Pointer(&reflect.StringHeader{ Data: ptr, - Len: uintptr(len(content)), + Len: len(content), })) if buf != content { t.Errorf("expected %q, got %q", content, buf)