diff --git a/compiler/interface.go b/compiler/interface.go index fc698c7a9..eb83465a7 100644 --- a/compiler/interface.go +++ b/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 diff --git a/compiler/testdata/gc.ll b/compiler/testdata/gc.ll index 82260fbf4..f5a5a756a 100644 --- a/compiler/testdata/gc.ll +++ b/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 diff --git a/compiler/testdata/interface.ll b/compiler/testdata/interface.ll index 801f370d5..8e100a4e8 100644 --- a/compiler/testdata/interface.ll +++ b/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 diff --git a/src/reflect/type.go b/src/reflect/type.go index 1356f67cd..90a32989a 100644 --- a/src/reflect/type.go +++ b/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 @@ -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. @@ -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 { @@ -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 { diff --git a/src/reflect/value.go b/src/reflect/value.go index 07553fbc5..f037472e0 100644 --- a/src/reflect/value.go +++ b/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