Skip to content

Commit

Permalink
reflect: move binary flag into map type
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
aykevl committed Jul 28, 2024
1 parent 1fd75ff commit 73dc996
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 29 deletions.
10 changes: 6 additions & 4 deletions compiler/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -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]),
Expand Down Expand Up @@ -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))}
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion compiler/testdata/gc.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 5 additions & 5 deletions compiler/testdata/interface.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
31 changes: 19 additions & 12 deletions src/reflect/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -396,10 +397,14 @@ type Type interface {

// Constants for the 'meta' byte.
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
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
)

// 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.
Expand Down Expand Up @@ -433,10 +438,11 @@ type arrayType struct {

type mapType struct {
rawType
numMethod uint16
ptrTo *rawType
elem *rawType
key *rawType
extraFlags uint8
numMethod uint16
ptrTo *rawType
elem *rawType
key *rawType
}

type namedType struct {
Expand Down Expand Up @@ -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 {
Expand Down
19 changes: 12 additions & 7 deletions src/reflect/value.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 73dc996

Please sign in to comment.