Browse Source

reflect: move binary flag into map type

The map type had a byte of padding ready for such a flag (on all systems
except AVR). I want to use the now-free flag bit in the meta byte in a
followup PR, this just lays the groundwork.
reflect-map-keyflag
Ayke van Laethem 3 months ago
parent
commit
73dc9963ed
No known key found for this signature in database GPG Key ID: E97FF5335DFDFDED
  1. 10
      compiler/interface.go
  2. 2
      compiler/testdata/gc.ll
  3. 10
      compiler/testdata/interface.ll
  4. 17
      src/reflect/type.go
  5. 19
      src/reflect/value.go

10
compiler/interface.go

@ -225,6 +225,7 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
)
case *types.Map:
typeFieldTypes = append(typeFieldTypes,
types.NewVar(token.NoPos, nil, "extraFlags", types.Typ[types.Uint8]),
types.NewVar(token.NoPos, nil, "numMethods", types.Typ[types.Uint16]),
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
types.NewVar(token.NoPos, nil, "elementType", types.Typ[types.UnsafePointer]),
@ -273,10 +274,6 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
metabyte |= 1 << 6
}
if hashmapIsBinaryKey(typ) {
metabyte |= 1 << 7
}
switch typ := typ.(type) {
case *types.Basic:
typeFields = []llvm.Value{c.getTypeCode(types.NewPointer(typ))}
@ -333,7 +330,12 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
c.getTypeCode(types.NewSlice(typ.Elem())), // slicePtr
}
case *types.Map:
var extraFlags uint8
if hashmapIsBinaryKey(typ.Key()) {
extraFlags |= 1 // extraFlagIsBinaryKey
}
typeFields = []llvm.Value{
llvm.ConstInt(c.ctx.Int8Type(), uint64(extraFlags), false),
llvm.ConstInt(c.ctx.Int16Type(), 0, false), // numMethods
c.getTypeCode(types.NewPointer(typ)), // ptrTo
c.getTypeCode(typ.Elem()), // elem

2
compiler/testdata/gc.ll

@ -22,7 +22,7 @@ target triple = "wasm32-unknown-wasi"
@"runtime/gc.layout:62-2000000000000001" = linkonce_odr unnamed_addr constant { i32, [8 x i8] } { i32 62, [8 x i8] c"\01\00\00\00\00\00\00 " }
@"runtime/gc.layout:62-0001" = linkonce_odr unnamed_addr constant { i32, [8 x i8] } { i32 62, [8 x i8] c"\01\00\00\00\00\00\00\00" }
@"reflect/types.type:basic:complex128" = linkonce_odr constant { i8, ptr } { i8 80, ptr @"reflect/types.type:pointer:basic:complex128" }, align 4
@"reflect/types.type:pointer:basic:complex128" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:basic:complex128" }, align 4
@"reflect/types.type:pointer:basic:complex128" = linkonce_odr constant { i8, i16, ptr } { i8 85, i16 0, ptr @"reflect/types.type:basic:complex128" }, align 4
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0

10
compiler/testdata/interface.ll

@ -6,14 +6,14 @@ target triple = "wasm32-unknown-wasi"
%runtime._interface = type { ptr, ptr }
%runtime._string = type { ptr, i32 }
@"reflect/types.type:basic:int" = linkonce_odr constant { i8, ptr } { i8 -62, ptr @"reflect/types.type:pointer:basic:int" }, align 4
@"reflect/types.type:pointer:basic:int" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:basic:int" }, align 4
@"reflect/types.type:pointer:named:error" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:named:error" }, align 4
@"reflect/types.type:basic:int" = linkonce_odr constant { i8, ptr } { i8 66, ptr @"reflect/types.type:pointer:basic:int" }, align 4
@"reflect/types.type:pointer:basic:int" = linkonce_odr constant { i8, i16, ptr } { i8 85, i16 0, ptr @"reflect/types.type:basic:int" }, align 4
@"reflect/types.type:pointer:named:error" = linkonce_odr constant { i8, i16, ptr } { i8 85, i16 0, ptr @"reflect/types.type:named:error" }, align 4
@"reflect/types.type:named:error" = linkonce_odr constant { i8, i16, ptr, ptr, ptr, [7 x i8] } { i8 116, i16 1, ptr @"reflect/types.type:pointer:named:error", ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}", ptr @"reflect/types.type.pkgpath.empty", [7 x i8] c".error\00" }, align 4
@"reflect/types.type.pkgpath.empty" = linkonce_odr unnamed_addr constant [1 x i8] zeroinitializer, align 1
@"reflect/types.type:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr } { i8 84, ptr @"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" }, align 4
@"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}" }, align 4
@"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:interface:{String:func:{}{basic:string}}" }, align 4
@"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, i16, ptr } { i8 85, i16 0, ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}" }, align 4
@"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, i16, ptr } { i8 85, i16 0, ptr @"reflect/types.type:interface:{String:func:{}{basic:string}}" }, align 4
@"reflect/types.type:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr } { i8 84, ptr @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" }, align 4
@"reflect/types.typeid:basic:int" = external constant i8

17
src/reflect/type.go

@ -30,8 +30,9 @@
// elem *typeStruct // element type of the array
// arrayLen uintptr // length of the array (this is part of the type)
// slicePtr *typeStruct // pointer to []T type
// - map types (this is still missing the key and element types)
// - map types
// meta uint8
// extraMeta uint8
// nmethods uint16 (0)
// ptrTo *typeStruct
// elem *typeStruct
@ -399,7 +400,11 @@ const (
kindMask = 31 // mask to apply to the meta byte to get the Kind value
flagNamed = 32 // flag that is set if this is a named type
flagComparable = 64 // flag that is set if this type is comparable
flagIsBinary = 128 // flag that is set if this type uses the hashmap binary algorithm
)
// Constants for the 'extraFlags' byte in the map type.
const (
extraFlagIsBinaryKey = 1 // flag that is set if this type uses the hashmap binary algorithm
)
// The base type struct. All type structs start with this.
@ -433,6 +438,7 @@ type arrayType struct {
type mapType struct {
rawType
extraFlags uint8
numMethod uint16
ptrTo *rawType
elem *rawType
@ -980,9 +986,10 @@ func (t *rawType) Comparable() bool {
return (t.meta & flagComparable) == flagComparable
}
// isBinary returns if the hashmapAlgorithmBinary functions can be used on this type
func (t *rawType) isBinary() bool {
return (t.meta & flagIsBinary) == flagIsBinary
// isBinaryKey returns if the hashmapAlgorithmBinary functions can be used on
// the key type of this map.
func (t *mapType) isBinaryKey() bool {
return t.extraFlags&extraFlagIsBinaryKey != 0
}
func (t *rawType) ChanDir() ChanDir {

19
src/reflect/value.go

@ -947,9 +947,10 @@ func (v Value) MapKeys() []Value {
k := New(v.typecode.Key())
e := New(v.typecode.Elem())
typecode := (*mapType)(unsafe.Pointer((v.typecode.underlying())))
keyType := v.typecode.key()
keyTypeIsEmptyInterface := keyType.Kind() == Interface && keyType.NumMethod() == 0
shouldUnpackInterface := !keyTypeIsEmptyInterface && keyType.Kind() != String && !keyType.isBinary()
shouldUnpackInterface := !keyTypeIsEmptyInterface && keyType.Kind() != String && !typecode.isBinaryKey()
for hashmapNext(v.pointer(), it, k.value, e.value) {
if shouldUnpackInterface {
@ -979,6 +980,7 @@ func (v Value) MapIndex(key Value) Value {
panic(&ValueError{Method: "MapIndex", Kind: v.Kind()})
}
typecode := (*mapType)(unsafe.Pointer(v.typecode.underlying()))
vkey := v.typecode.key()
// compare key type with actual key type of map
@ -997,7 +999,7 @@ func (v Value) MapIndex(key Value) Value {
return Value{}
}
return elem.Elem()
} else if vkey.isBinary() {
} else if typecode.isBinaryKey() {
var keyptr unsafe.Pointer
if key.isIndirect() || key.typecode.Size() > unsafe.Sizeof(uintptr(0)) {
keyptr = key.value
@ -1028,10 +1030,11 @@ func (v Value) MapRange() *MapIter {
panic(&ValueError{Method: "MapRange", Kind: v.Kind()})
}
typecode := (*mapType)(unsafe.Pointer(v.typecode.underlying()))
keyType := v.typecode.key()
keyTypeIsEmptyInterface := keyType.Kind() == Interface && keyType.NumMethod() == 0
shouldUnpackInterface := !keyTypeIsEmptyInterface && keyType.Kind() != String && !keyType.isBinary()
shouldUnpackInterface := !keyTypeIsEmptyInterface && keyType.Kind() != String && !typecode.isBinaryKey()
return &MapIter{
m: v,
@ -1824,6 +1827,7 @@ func (v Value) SetMapIndex(key, elem Value) {
}
vkey := v.typecode.key()
typecode := (*mapType)(unsafe.Pointer(v.typecode.underlying()))
// compare key type with actual key type of map
if !key.typecode.AssignableTo(vkey) {
@ -1859,7 +1863,7 @@ func (v Value) SetMapIndex(key, elem Value) {
hashmapStringSet(v.pointer(), *(*string)(key.value), elemptr)
}
} else if key.typecode.isBinary() {
} else if typecode.isBinaryKey() {
var keyptr unsafe.Pointer
if key.isIndirect() || key.typecode.Size() > unsafe.Sizeof(uintptr(0)) {
keyptr = key.value
@ -1965,14 +1969,15 @@ func MakeMapWithSize(typ Type, n int) Value {
panic("reflect.MakeMapWithSize: negative size hint")
}
key := typ.Key().(*rawType)
val := typ.Elem().(*rawType)
typecode := (*mapType)(unsafe.Pointer(typ.(*rawType).underlying()))
key := typecode.rawType.key()
val := typecode.rawType.elem()
var alg uint8
if key.Kind() == String {
alg = hashmapAlgorithmString
} else if key.isBinary() {
} else if typecode.isBinaryKey() {
alg = hashmapAlgorithmBinary
} else {
alg = hashmapAlgorithmInterface

Loading…
Cancel
Save