m := make(map[int]int,0)
m := make(map[int]int,0,CONCURRENT)
data interface{}
Where precisely does the Type for the node OMAKE and OMAKEMAP get set,
and is it possible to change the Etype and Type of the node safely without messing everything up?
Would it be possible to modify the normal hmap header and mapType/maptype/MapType to have a field which can be casted to different types to handle the different types of maps?
It probably is possible, but it might be somewhat involved. E.g., you at least also need to update cmd/compile/internal/gc/reflect.go's representation of hmap.
Depending on how different your map needs to be, you could just use a flag bit in hmap's flags field to indicate concurrent vs non-concurrent
It's okay in typecheck to assign a different *Type value to a Nod's Type field though.
t = typ(TCMAP)
C:\Users\theif519\Documents\GitHub\go\src\go\parser\interface.go:12: cannot use make(map[<T>]<T>, int(4), 0) (type map[<T>]<T>) as type map[string]*ast.Object in field valueC:\Users\theif519\Documents\GitHub\go\src\go\parser\interface.go:209: internal compiler error: want MAP, but have map[<T>]<T>
goroutine 1 [running]:runtime/debug.Stack(0x0, 0x0, 0x0) C:/Users/theif519/Documents/GitHub/go/src/runtime/debug/stack.go:24 +0x87bootstrap/compile/internal/gc.Fatalf(0xa381e0, 0x14, 0xc082aee758, 0x2, 0x2) C:/Users/theif519/Documents/GitHub/go/src/cmd/compile/internal/gc/subr.go:165 +0x27dbootstrap/compile/internal/gc.(*Type).wantEtype(0xc082711d60, 0xc08200a718) C:/Users/theif519/Documents/GitHub/go/src/cmd/compile/internal/gc/type.go:717 +0x13bbootstrap/compile/internal/gc.(*Type).MapType(0xc082711d60, 0x6323bf) C:/Users/theif519/Documents/GitHub/go/src/cmd/compile/internal/gc/type.go:187 +0x2dbootstrap/compile/internal/gc.hmap(0xc082711d60, 0x7) C:/Users/theif519/Documents/GitHub/go/src/cmd/compile/internal/gc/reflect.go:174 +0x2cbootstrap/compile/internal/gc.walkexpr(0xc082a72870, 0xc082aef5b0, 0xc082c49300) C:/Users/theif519/Documents/GitHub/go/src/cmd/compile/internal/gc/walk.go:1485 +0xa27abootstrap/compile/internal/gc.walkexpr(0xc082c493b0, 0xc082aef5b0, 0x0) C:/Users/theif519/Documents/GitHub/go/src/cmd/compile/internal/gc/walk.go:735 +0x1e42bootstrap/compile/internal/gc.walkstmt(0xc082c493b0, 0xc082a72360) C:/Users/theif519/Documents/GitHub/go/src/cmd/compile/internal/gc/walk.go:192 +0x2bbbootstrap/compile/internal/gc.walkstmtlist(0xc082c25200, 0x25, 0x40) C:/Users/theif519/Documents/GitHub/go/src/cmd/compile/internal/gc/walk.go:80 +0x5dbootstrap/compile/internal/gc.walk(0xc08280f440) C:/Users/theif519/Documents/GitHub/go/src/cmd/compile/internal/gc/walk.go:65 +0x377bootstrap/compile/internal/gc.compile(0xc08280f440) C:/Users/theif519/Documents/GitHub/go/src/cmd/compile/internal/gc/pgen.go:391 +0x85bbootstrap/compile/internal/gc.funccompile(0xc08280f440) C:/Users/theif519/Documents/GitHub/go/src/cmd/compile/internal/gc/dcl.go:1287 +0x1c1bootstrap/compile/internal/gc.Main() C:/Users/theif519/Documents/GitHub/go/src/cmd/compile/internal/gc/main.go:467 +0x20e3bootstrap/compile/internal/amd64.Main() C:/Users/theif519/Documents/GitHub/go/src/cmd/compile/internal/amd64/galign.go:93 +0x510main.main() C:/Users/theif519/Documents/GitHub/go/src/cmd/compile/main.go:33 +0x39c
go tool dist: FAILED: C:\Users\theif519\Documents\GitHub\go\pkg\tool\windows_amd64\compile -pack -o C:\Users\theif519\AppData\Local\Temp\go-tool-dist-245681255\go\parser\_go_.a -p go/parser C:\Users\theif519\Documents\GitHub\go\src\go\parser\interface.go C:\Users\theif519\Documents\GitHub\go\src\go\parser\parser.go: exit status 2
t = typ(CMAP)
t = substAny(t, n.List.First().Key(), n.List.First().Value())
Even if it was originally written in C, there could have been at least some abstraction designed, or at least over the (nearly 3) years, an interface for the map to implement to allow things like this in the future.
There have never been any plans to extend the map type, though. What
you are doing is an interesting exercise, but I think it's unlikely to
be added to the language. Much more likely to be used would a
concurrent map as a go-gettable package.
It probably is possible, but it might be somewhat involved. E.g., you at least also need to update cmd/compile/internal/gc/reflect.go's representation of hmap.It's more involved than adding a new built-in type to Go?
It's okay in typecheck to assign a different *Type value to a Nod's Type field though.I'd need to know if there are any side-effects to doing so. Just doing...t = typ(TCMAP)
Inside of OMAKE->TMAP gives an issue of pretty much untyped Type.
Could I use substAny on the new type to evaluate it?
And in the mean time, all Go programs that use maps would pay a performance penalty for the additional abstraction layers.
While additional abstractions may have benefited your project, we might also have mispredicted what sort of abstractions would be necessary or appropriate
When you said it was rewritten, was that when it was converted from C to Go, or some other time?
There are other fields you need to populate to construct a new Type value. See the typMap function in type.go.
C:\Users\theif519\Documents\GitHub\go\src\go\parser\interface.go:12: cannot use make(map[string]*ast.Object, int(4), 0) (type map[string]*ast.Object) as type map[string]*ast.Object in field valueC:\Users\theif519\Documents\GitHub\go\src\go\parser\interface.go:209: internal compiler error: want MAP, but have map[string]*ast.Object
goroutine 1 [running]:runtime/debug.Stack(0x0, 0x0, 0x0) C:/Users/theif519/Documents/GitHub/go/src/runtime/debug/stack.go:24 +0x87
bootstrap/compile/internal/gc.Fatalf(0xa38120, 0x14, 0xc082b26758, 0x2, 0x2) C:/Users/theif519/Documents/GitHub/go/src/cmd/compile/internal/gc/subr.go:165 +0x27dbootstrap/compile/internal/gc.(*Type).wantEtype(0xc082825a90, 0xc08200a818) C:/Users/theif519/Documents/GitHub/go/src/cmd/compile/internal/gc/type.go:717 +0x13bbootstrap/compile/internal/gc.(*Type).MapType(0xc082825a90, 0x6323bf) C:/Users/theif519/Documents/GitHub/go/src/cmd/compile/internal/gc/type.go:187 +0x2dbootstrap/compile/internal/gc.hmap(0xc082825a90, 0x7) C:/Users/theif519/Documents/GitHub/go/src/cmd/compile/internal/gc/reflect.go:174 +0x2cbootstrap/compile/internal/gc.walkexpr(0xc08260c240, 0xc082b275b0, 0xc082c4e300) C:/Users/theif519/Documents/GitHub/go/src/cmd/compile/internal/gc/walk.go:1485 +0xa27abootstrap/compile/internal/gc.walkexpr(0xc082c4e3f0, 0xc082b275b0, 0x0) C:/Users/theif519/Documents/GitHub/go/src/cmd/compile/internal/gc/walk.go:735 +0x1e42bootstrap/compile/internal/gc.walkstmt(0xc082c4e3f0, 0xc082611320) C:/Users/theif519/Documents/GitHub/go/src/cmd/compile/internal/gc/walk.go:192 +0x2bbbootstrap/compile/internal/gc.walkstmtlist(0xc082c27200, 0x25, 0x40) C:/Users/theif519/Documents/GitHub/go/src/cmd/compile/internal/gc/walk.go:80 +0x5dbootstrap/compile/internal/gc.walk(0xc082801290) C:/Users/theif519/Documents/GitHub/go/src/cmd/compile/internal/gc/walk.go:65 +0x377bootstrap/compile/internal/gc.compile(0xc082801290) C:/Users/theif519/Documents/GitHub/go/src/cmd/compile/internal/gc/pgen.go:391 +0x85bbootstrap/compile/internal/gc.funccompile(0xc082801290)
C:/Users/theif519/Documents/GitHub/go/src/cmd/compile/internal/gc/dcl.go:1287 +0x1c1bootstrap/compile/internal/gc.Main() C:/Users/theif519/Documents/GitHub/go/src/cmd/compile/internal/gc/main.go:467 +0x20e3bootstrap/compile/internal/amd64.Main() C:/Users/theif519/Documents/GitHub/go/src/cmd/compile/internal/amd64/galign.go:93 +0x510main.main() C:/Users/theif519/Documents/GitHub/go/src/cmd/compile/main.go:33 +0x39c
go tool dist: FAILED: C:\Users\theif519\Documents\GitHub\go\pkg\tool\windows_amd64\compile -pack -o C:\Users\theif519\AppData\Local\Temp\go-tool-dist-719667311\go\parser\_go_.a -p go/parser C:\Users\theif519\Documents\GitHub\go\src\go\parser\interface.go C:\Users\theif519\Documents\GitHub\go\src\go\parser\parser.go: exit status 2go/doc
No, substAny is very specialized. It's purpose is just for rewriting type signatures from builtin/runtime.go, which use the magic "any" type.
It might be easier for you to just add an extra field to MapType.
One complex aspect is that we don't want to lock ourselves into a specific hash function, but a hash function that changes with each release is much harder for other people to use.
I'm sorry you don't consider it maintainable, but it is in fact
maintained. It doesn't seem that bad to me, considering that it is
doing a quite complex job.
// NewScope creates a new scope nested in the outer scope.func NewScope(outer *Scope) *Scope { const n = 4 // initial scope capacity return &Scope{outer, make(map[string]*Object, n)}}
Would this still hold true? I know the chances might be rather slim, but if given a benchmark which proves it to be superior when used concurrently to the original map, would that be enough?
I don't believe any go-gettable would be faster than the runtime map, since it needs to use the runtime map anyway to hash it's values, making it rather pointless, and impossible to make lock-free.
1. You can experiment with making changes to the Go programming language. Some of the details here are subtle/tricky, so I and others have been answering questions about how to implement these changes. You should not mistake this as support/approval though. The sorts of changes you've been experimenting with so far are very unlikely to be accepted, as Ian and Keith have already emphasized.
I certainly don't recommend this for production code, but for experimentation/measurement, you can use cmd/compile's //go:linkname directive to access runtime's hash functions:
1. You can experiment with making changes to the Go programming language. Some of the details here are subtle/tricky, so I and others have been answering questions about how to implement these changes. You should not mistake this as support/approval though. The sorts of changes you've been experimenting with so far are very unlikely to be accepted, as Ian and Keith have already emphasized.2. You can experiment with alternative hashmap implementations to see if any are faster than or have other benefits over the current one. If you find one, that would be very interesting and has a chance of being accepted. However, in this case, it's unnecessary for you to work out all the integration details about how to make it work with the compiler/runtime. It would be sufficient for you to demonstrate that your own map[string]int or map[int32]int alternative type supports the same abstract operations but more efficiently.
I suppose I could use that approach for any runtime function as well, correct? Even even for mbarrier.go?
func Hash(obj interface{}, seed uintptr) uintptr {
t := TypeOf(obj).(*rtype)
return t.alg.hash(unsafe.Pointer(&obj), seed)
}
// Castable mirror of rtype
type typeMirror struct { size uintptr ptrdata uintptr hash uint32 tflag tflag align uint8 fieldalign uint8 kind uint8 alg *typeAlg gcdata *byte str nameOff _ int32}
// Mirror for runtime and reflective typeAlgtype typeAlg struct { hash func(unsafe.Pointer, uintptr) uintptr equal func(unsafe.Pointer, unsafe.Pointer) bool}
TypeOf(someObj).(*typeMirror).alg.hash(someObj, seed)
Actually, now that I write this, I realize how Go got around this issue... it defined a type with the same types and names of fields (rtype and _type) to allow it to be cast. Hence, would it be possible to create my own mirrors of rtype and cast it myself?What I mean is, do something like...
// Castable mirror of rtype
type typeMirror struct {size uintptrptrdata uintptrhash uint32tflag tflagalign uint8fieldalign uint8kind uint8alg *typeAlggcdata *bytestr nameOff_ int32}// Mirror for runtime and reflective typeAlgtype typeAlg struct {hash func(unsafe.Pointer, uintptr) uintptrequal func(unsafe.Pointer, unsafe.Pointer) bool}
And obtain the hash function this way...
TypeOf(someObj).(*typeMirror).alg.hash(someObj, seed)
On Wednesday, June 15, 2016 at 9:38:15 AM UTC-4, Kyle Stanly wrote:I truly appreciate the help you've given me here. Definitely made my life a whole lot easier, however I have one final question (for now)...Is there a specific hash function used to hash literally anything reliably? I see 'memhash' in 'hash64.go' and 'hash32.go', which take a unsafe.Pointer and seems to hash it byte by byte without regard for padding in structs and the like, hence I'm assuming its not safe to use for general-purposes. One of the very main reasons I wanted to add my map to the runtime was not only to have access to the runtime functions (Which apparently can be solved with '//go:linkname') but also because 'maptype' contains valuable information that can be used for efficiency reasons, such as the hashing algorithm used.I'm being optimistic here, but it seems that the hashing algorithm is stored in it's actual type, and obtaining 'TypeOf' SHOULD theoretically allow me to retrieve it's 'Type' (Reflection implementation of Type), which is also castable to '*rtype', but then again not really because it's unexported. I'm assuming that once accessible, I will have access to it's 'alg' field, which will contain the hashing algorithm used to hash it.The issue, of course, being that it's unexported. I'm assuming //go:linkname only works for functions? I suppose it'd be possible create my own function which just takes a 'Type', which obtains it's '*rtype' and return it's 'hash' function it's 'alg' field?I.E, adding an unexported function like such:
func Hash(obj interface{}, seed uintptr) uintptr {
t := TypeOf(obj).(*rtype)
return t.alg.hash(unsafe.Pointer(&obj), seed)
}
But this makes a few assumptions:1) Do all types implement alg's hash and equals functions?
2) Does a function that does this exist already inside of the runtime?
3) When is the hashing algorithm decided? Compile-time or runtime?
4) Is this safe to do? What types are not hashable, and why are they not hashable?
5) Is there a way to directly access an unexported struct via //go:linkname, this way I can have it compatible and work easily with existing versions of Go. I.E, I would normally be unable to access rtype and typeAlg.
On Tuesday, June 14, 2016 at 5:11:54 PM UTC-4, Matthew Dempsky wrote:On Tue, Jun 14, 2016 at 1:42 PM, Kyle Stanly <thei...@gmail.com> wrote:I suppose I could use that approach for any runtime function as well, correct? Even even for mbarrier.go?Correct.Note that to appease "go build", you'll also need to add a dummy empty assembly file (e.g., "empty.s"), otherwise the compiler will give you errors about declaring a function without a body.
--
You received this message because you are subscribed to the Google Groups "golang-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Is there a specific hash function used to hash literally anything reliably?
5) Is there a way to directly access an unexported struct via //go:linkname, this way I can have it compatible and work easily with existing versions of Go. I.E, I would normally be unable to access rtype and typeAlg.