Skip to content

Commit 88f9c8e

Browse files
committed
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.
1 parent 1fd75ff commit 88f9c8e

File tree

5 files changed

+41
-28
lines changed

5 files changed

+41
-28
lines changed

compiler/interface.go

+6-4
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
225225
)
226226
case *types.Map:
227227
typeFieldTypes = append(typeFieldTypes,
228+
types.NewVar(token.NoPos, nil, "extraFlags", types.Typ[types.Uint8]),
228229
types.NewVar(token.NoPos, nil, "numMethods", types.Typ[types.Uint16]),
229230
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
230231
types.NewVar(token.NoPos, nil, "elementType", types.Typ[types.UnsafePointer]),
@@ -273,10 +274,6 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
273274
metabyte |= 1 << 6
274275
}
275276

276-
if hashmapIsBinaryKey(typ) {
277-
metabyte |= 1 << 7
278-
}
279-
280277
switch typ := typ.(type) {
281278
case *types.Basic:
282279
typeFields = []llvm.Value{c.getTypeCode(types.NewPointer(typ))}
@@ -333,7 +330,12 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
333330
c.getTypeCode(types.NewSlice(typ.Elem())), // slicePtr
334331
}
335332
case *types.Map:
333+
var extraFlags uint8
334+
if hashmapIsBinaryKey(typ.Key()) {
335+
extraFlags |= 1 // extraFlagIsBinaryKey
336+
}
336337
typeFields = []llvm.Value{
338+
llvm.ConstInt(c.ctx.Int8Type(), uint64(extraFlags), false),
337339
llvm.ConstInt(c.ctx.Int16Type(), 0, false), // numMethods
338340
c.getTypeCode(types.NewPointer(typ)), // ptrTo
339341
c.getTypeCode(typ.Elem()), // elem

compiler/testdata/gc.ll

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ target triple = "wasm32-unknown-wasi"
2222
@"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 " }
2323
@"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" }
2424
@"reflect/types.type:basic:complex128" = linkonce_odr constant { i8, ptr } { i8 80, ptr @"reflect/types.type:pointer:basic:complex128" }, align 4
25-
@"reflect/types.type:pointer:basic:complex128" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:basic:complex128" }, align 4
25+
@"reflect/types.type:pointer:basic:complex128" = linkonce_odr constant { i8, i16, ptr } { i8 85, i16 0, ptr @"reflect/types.type:basic:complex128" }, align 4
2626

2727
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
2828
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0

compiler/testdata/interface.ll

+5-5
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ target triple = "wasm32-unknown-wasi"
66
%runtime._interface = type { ptr, ptr }
77
%runtime._string = type { ptr, i32 }
88

9-
@"reflect/types.type:basic:int" = linkonce_odr constant { i8, ptr } { i8 -62, ptr @"reflect/types.type:pointer:basic:int" }, align 4
10-
@"reflect/types.type:pointer:basic:int" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:basic:int" }, align 4
11-
@"reflect/types.type:pointer:named:error" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:named:error" }, align 4
9+
@"reflect/types.type:basic:int" = linkonce_odr constant { i8, ptr } { i8 66, ptr @"reflect/types.type:pointer:basic:int" }, align 4
10+
@"reflect/types.type:pointer:basic:int" = linkonce_odr constant { i8, i16, ptr } { i8 85, i16 0, ptr @"reflect/types.type:basic:int" }, align 4
11+
@"reflect/types.type:pointer:named:error" = linkonce_odr constant { i8, i16, ptr } { i8 85, i16 0, ptr @"reflect/types.type:named:error" }, align 4
1212
@"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
1313
@"reflect/types.type.pkgpath.empty" = linkonce_odr unnamed_addr constant [1 x i8] zeroinitializer, align 1
1414
@"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
15-
@"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
16-
@"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
15+
@"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
16+
@"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
1717
@"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
1818
@"reflect/types.typeid:basic:int" = external constant i8
1919

src/reflect/type.go

+17-11
Original file line numberDiff line numberDiff line change
@@ -396,10 +396,14 @@ type Type interface {
396396

397397
// Constants for the 'meta' byte.
398398
const (
399-
kindMask = 31 // mask to apply to the meta byte to get the Kind value
400-
flagNamed = 32 // flag that is set if this is a named type
401-
flagComparable = 64 // flag that is set if this type is comparable
402-
flagIsBinary = 128 // flag that is set if this type uses the hashmap binary algorithm
399+
kindMask = 31 // mask to apply to the meta byte to get the Kind value
400+
flagNamed = 32 // flag that is set if this is a named type
401+
flagComparable = 64 // flag that is set if this type is comparable
402+
)
403+
404+
// Constants for the 'extraFlags' byte in the map type.
405+
const (
406+
extraFlagIsBinaryKey = 1 // flag that is set if this type uses the hashmap binary algorithm
403407
)
404408

405409
// The base type struct. All type structs start with this.
@@ -433,10 +437,11 @@ type arrayType struct {
433437

434438
type mapType struct {
435439
rawType
436-
numMethod uint16
437-
ptrTo *rawType
438-
elem *rawType
439-
key *rawType
440+
extraFlags uint8
441+
numMethod uint16
442+
ptrTo *rawType
443+
elem *rawType
444+
key *rawType
440445
}
441446

442447
type namedType struct {
@@ -980,9 +985,10 @@ func (t *rawType) Comparable() bool {
980985
return (t.meta & flagComparable) == flagComparable
981986
}
982987

983-
// isBinary returns if the hashmapAlgorithmBinary functions can be used on this type
984-
func (t *rawType) isBinary() bool {
985-
return (t.meta & flagIsBinary) == flagIsBinary
988+
// isBinaryKey returns if the hashmapAlgorithmBinary functions can be used on
989+
// the key type of this map.
990+
func (t *mapType) isBinaryKey() bool {
991+
return t.extraFlags&extraFlagIsBinaryKey != 0
986992
}
987993

988994
func (t *rawType) ChanDir() ChanDir {

src/reflect/value.go

+12-7
Original file line numberDiff line numberDiff line change
@@ -947,9 +947,10 @@ func (v Value) MapKeys() []Value {
947947
k := New(v.typecode.Key())
948948
e := New(v.typecode.Elem())
949949

950+
typecode := (*mapType)(unsafe.Pointer((v.typecode.underlying())))
950951
keyType := v.typecode.key()
951952
keyTypeIsEmptyInterface := keyType.Kind() == Interface && keyType.NumMethod() == 0
952-
shouldUnpackInterface := !keyTypeIsEmptyInterface && keyType.Kind() != String && !keyType.isBinary()
953+
shouldUnpackInterface := !keyTypeIsEmptyInterface && keyType.Kind() != String && !typecode.isBinaryKey()
953954

954955
for hashmapNext(v.pointer(), it, k.value, e.value) {
955956
if shouldUnpackInterface {
@@ -979,6 +980,7 @@ func (v Value) MapIndex(key Value) Value {
979980
panic(&ValueError{Method: "MapIndex", Kind: v.Kind()})
980981
}
981982

983+
typecode := (*mapType)(unsafe.Pointer(v.typecode.underlying()))
982984
vkey := v.typecode.key()
983985

984986
// compare key type with actual key type of map
@@ -997,7 +999,7 @@ func (v Value) MapIndex(key Value) Value {
997999
return Value{}
9981000
}
9991001
return elem.Elem()
1000-
} else if vkey.isBinary() {
1002+
} else if typecode.isBinaryKey() {
10011003
var keyptr unsafe.Pointer
10021004
if key.isIndirect() || key.typecode.Size() > unsafe.Sizeof(uintptr(0)) {
10031005
keyptr = key.value
@@ -1028,10 +1030,11 @@ func (v Value) MapRange() *MapIter {
10281030
panic(&ValueError{Method: "MapRange", Kind: v.Kind()})
10291031
}
10301032

1033+
typecode := (*mapType)(unsafe.Pointer(v.typecode.underlying()))
10311034
keyType := v.typecode.key()
10321035

10331036
keyTypeIsEmptyInterface := keyType.Kind() == Interface && keyType.NumMethod() == 0
1034-
shouldUnpackInterface := !keyTypeIsEmptyInterface && keyType.Kind() != String && !keyType.isBinary()
1037+
shouldUnpackInterface := !keyTypeIsEmptyInterface && keyType.Kind() != String && !typecode.isBinaryKey()
10351038

10361039
return &MapIter{
10371040
m: v,
@@ -1824,6 +1827,7 @@ func (v Value) SetMapIndex(key, elem Value) {
18241827
}
18251828

18261829
vkey := v.typecode.key()
1830+
typecode := (*mapType)(unsafe.Pointer(v.typecode.underlying()))
18271831

18281832
// compare key type with actual key type of map
18291833
if !key.typecode.AssignableTo(vkey) {
@@ -1859,7 +1863,7 @@ func (v Value) SetMapIndex(key, elem Value) {
18591863
hashmapStringSet(v.pointer(), *(*string)(key.value), elemptr)
18601864
}
18611865

1862-
} else if key.typecode.isBinary() {
1866+
} else if typecode.isBinaryKey() {
18631867
var keyptr unsafe.Pointer
18641868
if key.isIndirect() || key.typecode.Size() > unsafe.Sizeof(uintptr(0)) {
18651869
keyptr = key.value
@@ -1965,14 +1969,15 @@ func MakeMapWithSize(typ Type, n int) Value {
19651969
panic("reflect.MakeMapWithSize: negative size hint")
19661970
}
19671971

1968-
key := typ.Key().(*rawType)
1969-
val := typ.Elem().(*rawType)
1972+
typecode := (*mapType)(unsafe.Pointer(typ.(*rawType).underlying()))
1973+
key := typecode.rawType.key()
1974+
val := typecode.rawType.elem()
19701975

19711976
var alg uint8
19721977

19731978
if key.Kind() == String {
19741979
alg = hashmapAlgorithmString
1975-
} else if key.isBinary() {
1980+
} else if typecode.isBinaryKey() {
19761981
alg = hashmapAlgorithmBinary
19771982
} else {
19781983
alg = hashmapAlgorithmInterface

0 commit comments

Comments
 (0)