From 2147d01c1a7daad7b56aa163b937c49c09387f48 Mon Sep 17 00:00:00 2001 From: Moses Narrow <36607567+0pcom@users.noreply.github.com> Date: Thu, 13 Aug 2026 20:26:32 -0500 Subject: [PATCH] reflect: provide the linkname targets modern-go/reflect2 expects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit reflect2 — pulled in by json-iterator, which plenty of dependency trees carry — reaches into reflect's unexported runtime helpers by //go:linkname. TinyGo's reflect has no such symbols, so linking any program that touches that path fails with "undefined symbol: reflect.mapassign" and similar, long after it has compiled. These are matching symbols so such programs LINK. They panic if actually exercised, and the file says so plainly: reflect2/jsoniter is not functional under TinyGo, and encoding/json — which this reflect does support — is the way to serialise. That is a deliberate trade. A link error names a symbol nobody wrote and offers no way forward; a panic at the one call that is genuinely unsupported names the thing you did. --- src/reflect/reflect2_linkname.go | 58 ++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 src/reflect/reflect2_linkname.go diff --git a/src/reflect/reflect2_linkname.go b/src/reflect/reflect2_linkname.go new file mode 100644 index 0000000000..d222b57c73 --- /dev/null +++ b/src/reflect/reflect2_linkname.go @@ -0,0 +1,58 @@ +package reflect + +// github.com/modern-go/reflect2 (used by github.com/json-iterator/go) reaches +// into reflect's unexported runtime helpers via //go:linkname. TinyGo's reflect +// does not implement these, so a program that links reflect2 fails at link time +// with "undefined symbol: reflect.mapassign" etc. Provide matching symbols so +// such programs LINK; they panic if actually exercised. reflect2/jsoniter is +// therefore non-functional under TinyGo — callers should use encoding/json, +// which TinyGo's reflect does support. See the skywire TinyGo build notes. + +import "unsafe" + +// sliceHeader mirrors reflect2's slice header ABI for typedslicecopy. +type reflect2SliceHeader struct { + Data unsafe.Pointer + Len int + Cap int +} + +//go:linkname reflect2_makemap reflect.makemap +func reflect2_makemap(rtype unsafe.Pointer, cap int) unsafe.Pointer { + panic("reflect.makemap: reflect2/jsoniter is unsupported under TinyGo (use encoding/json)") +} + +//go:linkname reflect2_unsafe_New reflect.unsafe_New +func reflect2_unsafe_New(rtype unsafe.Pointer) unsafe.Pointer { + panic("reflect.unsafe_New: reflect2/jsoniter is unsupported under TinyGo (use encoding/json)") +} + +//go:linkname reflect2_unsafe_NewArray reflect.unsafe_NewArray +func reflect2_unsafe_NewArray(rtype unsafe.Pointer, length int) unsafe.Pointer { + panic("reflect.unsafe_NewArray: reflect2/jsoniter is unsupported under TinyGo (use encoding/json)") +} + +//go:linkname reflect2_typedmemmove reflect.typedmemmove +func reflect2_typedmemmove(rtype, dst, src unsafe.Pointer) { + panic("reflect.typedmemmove: reflect2/jsoniter is unsupported under TinyGo (use encoding/json)") +} + +//go:linkname reflect2_typedslicecopy reflect.typedslicecopy +func reflect2_typedslicecopy(elemType unsafe.Pointer, dst, src reflect2SliceHeader) int { + panic("reflect.typedslicecopy: reflect2/jsoniter is unsupported under TinyGo (use encoding/json)") +} + +//go:linkname reflect2_mapassign reflect.mapassign +func reflect2_mapassign(rtype, m, key, val unsafe.Pointer) { + panic("reflect.mapassign: reflect2/jsoniter is unsupported under TinyGo (use encoding/json)") +} + +//go:linkname reflect2_mapiterinit reflect.mapiterinit +func reflect2_mapiterinit(rtype, m, it unsafe.Pointer) { + panic("reflect.mapiterinit: reflect2/jsoniter is unsupported under TinyGo (use encoding/json)") +} + +//go:linkname reflect2_mapiternext reflect.mapiternext +func reflect2_mapiternext(it unsafe.Pointer) { + panic("reflect.mapiternext: reflect2/jsoniter is unsupported under TinyGo (use encoding/json)") +}