tinygo icon indicating copy to clipboard operation
tinygo copied to clipboard

how to write this code `pointer := reflect.ValueOf(reflect.TypeOf(false)).Pointer()` in tinygo?

Open hunjixin opened this issue 3 years ago • 12 comments

pointer := reflect.ValueOf(reflect.TypeOf(false)).Pointer()

this code is golang, and in tinygo got panic, how to write it in tinygo?

hunjixin avatar May 20 '22 10:05 hunjixin

Reflection isn't very well supported in tinygo at the moment - there are some parts that are being worked on, but I don't know if I'd ever count of complete support for reflection.

The code you wrote, doesn't look like it need reflection in particular however - as it appears to just be constructing a *bool

skabbes avatar May 20 '22 13:05 skabbes

here is the cast : I converted the go code to wasm to run, but there is a dependency package that has this code

https://github.com/polydawn/refmt/blob/30ac6d18308e584ca6a2e74ba81475559db94c5f/obj/builtins.go#L8

hunjixin avatar May 20 '22 13:05 hunjixin

the author uses this type address as the map key,this maybe slightly faster than the reflect type as the key

hunjixin avatar May 20 '22 14:05 hunjixin

Here is the relevant piece of code, just FYI:

https://github.com/tinygo-org/tinygo/blob/release/src/reflect/value.go#L135-L149

skabbes avatar May 20 '22 14:05 skabbes

https://github.com/tinygo-org/tinygo/blob/release/src/reflect/value.go#L135-L149

yeap, i have dig here, its Uintptr type, maybe can convert this value to unsafe.Pointer and return. its okay?

hunjixin avatar May 20 '22 14:05 hunjixin

The dependency you mentioned uses reflect heavily, so might be hard to get running in tinygo... though I haven't checked. https://github.com/polydawn/refmt

dankegel avatar May 20 '22 14:05 dankegel

@dankegel In fact, it may not be used, but it's in the init, and it fails in the initAll func when just start program....

hunjixin avatar May 20 '22 14:05 hunjixin

So, I tried running polydown/refmt's tests in tinygo, but they failed as follows:

refmt dkegel$ GO111MODULE=off GOPATH="$PWD/.gopath/" tinygo test ./... -v
# github.com/smartystreets/assertions/internal/go-render/render
.gopath/src/github.com/smartystreets/assertions/internal/go-render/render/render.go:318:19: MapOf not declared by package reflect
.gopath/src/github.com/smartystreets/assertions/internal/go-render/render/render.go:418:15: av.InterfaceData undefined (type reflect.Value has no field or method InterfaceData)
.gopath/src/github.com/smartystreets/assertions/internal/go-render/render/render.go:418:35: bv.InterfaceData undefined (type reflect.Value has no field or method InterfaceData)
FAIL

dkegel-fastly avatar May 21 '22 02:05 dkegel-fastly

very said, this is the dependency of the project's dependency, and most of the functions are not used. I just want to make it as easy as possible to get past this init issue, there are too many to rewrites. I'm also not sure if other dependencies have the same issue.

as metion before could i add code in Pointer to resolve Uintptr type like this, i am sure its okay or not

// Pointer returns the underlying pointer of the given value for the following
// types: chan, map, pointer, unsafe.Pointer, slice, func.
func (v Value) Pointer() uintptr {
	switch v.Kind() {
	case Chan, Map, Ptr, UnsafePointer:
		return uintptr(v.pointer())
	case Slice:
		slice := (*sliceHeader)(v.value)
		return uintptr(slice.data)
	case Uintptr:
		return uintptr(v.value)
	case Func:
		panic("unimplemented: (reflect.Value).Pointer()")
	default: // not implemented: Func
		panic(&ValueError{Method: "Pointer"})
	}
}

hunjixin avatar May 21 '22 03:05 hunjixin

Ack there are many issues open about reflection, but I figured I would get specific on this one, as we didn't have the full source. @hunjixin is this what you were trying, and also on https://github.com/tinygo-org/tinygo/issues/2858#issuecomment-1133519485 can you be specific to which file you are patching?

package main

import "reflect"

var pointer = reflect.ValueOf(reflect.TypeOf(false)).Pointer()

func main() {
}

normal

panic: reflect: call of UnsafePointer on zero Value
Abort trap: 6

wasi

panic: reflect: call of UnsafePointer on zero Value
Error: failed to run main module `main.wasm`

Caused by:
    0: failed to invoke command default
    1: wasm trap: wasm `unreachable` instruction executed
       wasm backtrace:
           0:  0x93f - <unknown>!runtime._panic
           1:  0x45c - <unknown>!(reflect.Value).Pointer
           2: 0x25cd - <unknown>!runtime.initAll
           3: 0x255a - <unknown>!runtime.run$1
           4: 0x2498 - <unknown>!runtime.run$1$gowrapper
           5: 0x2616 - <unknown>!tinygo_launch
           6: 0x235c - <unknown>!_start

codefromthecrypt avatar Sep 07 '22 06:09 codefromthecrypt

@hunjixin the code change you have suggested is not correct, because it does not match the API of the reflect package:

Pointer returns v's value as a uintptr. It returns uintptr instead of unsafe.Pointer so that code using reflect cannot obtain unsafe.Pointers without importing the unsafe package explicitly. It panics if v's Kind is not Chan, Func, Map, Pointer, Slice, or UnsafePointer.

A uintptr is not a pointer. Therefore, Pointer() shouldn't return it as a pointer.

But it looks like there is a bug here because reflect.ValueOf(reflect.TypeOf(false)).Pointer() does not panic in Go.

aykevl avatar Sep 15 '22 13:09 aykevl

On second thought, it looks like the code is doing something non-portable:

var (
	rtid_bool    = ValueOf(TypeOf(false)).Pointer()
	rtid_string  = ValueOf(TypeOf("")).Pointer()
	rtid_bytes   = ValueOf(TypeOf([]byte{})).Pointer()
	rtid_int     = ValueOf(TypeOf(int(0))).Pointer()
	rtid_int8    = ValueOf(TypeOf(int8(0))).Pointer()
	rtid_int16   = ValueOf(TypeOf(int16(0))).Pointer()
	rtid_int32   = ValueOf(TypeOf(int32(0))).Pointer()
	rtid_int64   = ValueOf(TypeOf(int64(0))).Pointer()
	rtid_uint    = ValueOf(TypeOf(uint(0))).Pointer()
	rtid_uint8   = ValueOf(TypeOf(uint8(0))).Pointer()
	rtid_uint16  = ValueOf(TypeOf(uint16(0))).Pointer()
	rtid_uint32  = ValueOf(TypeOf(uint32(0))).Pointer()
	rtid_uint64  = ValueOf(TypeOf(uint64(0))).Pointer()
	rtid_uintptr = ValueOf(TypeOf(uintptr(0))).Pointer()
	rtid_float32 = ValueOf(TypeOf(float32(0))).Pointer()
	rtid_float64 = ValueOf(TypeOf(float64(0))).Pointer()
)

It looks like they are inspecting the underlying type of reflect.Type. Don't do that. It's an implementation detail. I don't think there is much that TinyGo can do (although #2640 might fix this as an unintended side effect).

aykevl avatar Sep 15 '22 14:09 aykevl

These are now unique, but please don't do this.

~/go/src/github.com/dgryski/bug/m $ cat main.go
package main

import (
	. "reflect"
)

func main() {
	var (
		rtid_bool    = ValueOf(TypeOf(false)).Pointer()
		rtid_string  = ValueOf(TypeOf("")).Pointer()
		rtid_bytes   = ValueOf(TypeOf([]byte{})).Pointer()
		rtid_int     = ValueOf(TypeOf(int(0))).Pointer()
		rtid_int8    = ValueOf(TypeOf(int8(0))).Pointer()
		rtid_int16   = ValueOf(TypeOf(int16(0))).Pointer()
		rtid_int32   = ValueOf(TypeOf(int32(0))).Pointer()
		rtid_int64   = ValueOf(TypeOf(int64(0))).Pointer()
		rtid_uint    = ValueOf(TypeOf(uint(0))).Pointer()
		rtid_uint8   = ValueOf(TypeOf(uint8(0))).Pointer()
		rtid_uint16  = ValueOf(TypeOf(uint16(0))).Pointer()
		rtid_uint32  = ValueOf(TypeOf(uint32(0))).Pointer()
		rtid_uint64  = ValueOf(TypeOf(uint64(0))).Pointer()
		rtid_uintptr = ValueOf(TypeOf(uintptr(0))).Pointer()
		rtid_float32 = ValueOf(TypeOf(float32(0))).Pointer()
		rtid_float64 = ValueOf(TypeOf(float64(0))).Pointer()
	)

	println(rtid_bool)
	println(rtid_string)
	println(rtid_bytes)
	println(rtid_int)
	println(rtid_int8)
	println(rtid_int16)
	println(rtid_int32)
	println(rtid_int64)
	println(rtid_uint)
	println(rtid_uint8)
	println(rtid_uint16)
	println(rtid_uint32)
	println(rtid_uint64)
	println(rtid_uintptr)
	println(rtid_float32)
	println(rtid_float64)
}
~/go/src/github.com/dgryski/bug/m $ tinygo run main.go |sort |uniq -c |sort -n
   1 0x00000001065f0030
   1 0x00000001065f0070
   1 0x00000001065f00b0
   1 0x00000001065f00f8
   1 0x00000001065f0138
   1 0x00000001065f0178
   1 0x00000001065f01b8
   1 0x00000001065f01f8
   1 0x00000001065f0238
   1 0x00000001065f0278
   1 0x00000001065f02b8
   1 0x00000001065f02f8
   1 0x00000001065f0338
   1 0x00000001065f0378
   1 0x00000001065f03b8
   1 0x00000001065f03f8

dgryski avatar Mar 23 '23 05:03 dgryski

good work. I don't want to do this, but it's from someone else's library. i have to fork and replace it before.

hunjixin avatar Mar 24 '23 01:03 hunjixin

This is part of the v0.28 release so now closing this issue. Thanks!

deadprogram avatar Jun 14 '23 09:06 deadprogram