diff --git a/compiler/interface.go b/compiler/interface.go index 030c67571b..f77cfab939 100644 --- a/compiler/interface.go +++ b/compiler/interface.go @@ -72,14 +72,34 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value { structGlobal := c.makeStructTypeFields(typ) references = llvm.ConstBitCast(structGlobal, global.Type()) } - if !references.IsNil() { + methodSet := types.NewMethodSet(typ) + numMethods := 0 + _, isInterface := typ.Underlying().(*types.Interface) + for i := 0; i < methodSet.Len(); i++ { + // NumMethod (unintentionally) includes unexported methods for + // interface types but excludes unexported methods for other types. + // This makes sure we're bug-compatible with the Go reflect package. + // For a discussion, see: + // https://github.com/golang/go/issues/22075 (original bug) + // https://github.com/golang/go/issues/42123 (revert of bugfix) + if methodSet.At(i).Obj().Exported() || isInterface { + numMethods++ + } + } + if !references.IsNil() || numMethods != 0 || isInterface { // Set the 'references' field of the runtime.typecodeID struct. globalValue := llvm.ConstNull(global.Type().ElementType()) - globalValue = llvm.ConstInsertValue(globalValue, references, []uint32{0}) + if !references.IsNil() { + globalValue = llvm.ConstInsertValue(globalValue, references, []uint32{0}) + } if length != 0 { lengthValue := llvm.ConstInt(c.uintptrType, uint64(length), false) globalValue = llvm.ConstInsertValue(globalValue, lengthValue, []uint32{1}) } + if numMethods != 0 { + numMethodsValue := llvm.ConstInt(c.uintptrType, uint64(numMethods), false) + globalValue = llvm.ConstInsertValue(globalValue, numMethodsValue, []uint32{2}) + } global.SetInitializer(globalValue) global.SetLinkage(llvm.PrivateLinkage) } @@ -187,7 +207,7 @@ func getTypeCodeName(t types.Type) string { case *types.Interface: methods := make([]string, t.NumMethods()) for i := 0; i < t.NumMethods(); i++ { - methods[i] = getTypeCodeName(t.Method(i).Type()) + methods[i] = t.Method(i).Name() + ":" + getTypeCodeName(t.Method(i).Type()) } return "interface:" + "{" + strings.Join(methods, ",") + "}" case *types.Map: diff --git a/src/reflect/sidetables.go b/src/reflect/sidetables.go index f53b53bd5d..db29eaabac 100644 --- a/src/reflect/sidetables.go +++ b/src/reflect/sidetables.go @@ -4,12 +4,22 @@ import ( "unsafe" ) +// This stores the number of methods (for Type.NumMethod()) for each named basic +// type. It is indexed by the named type number. +//go:extern reflect.namedBasicNumMethodSidetable +var namedBasicNumMethodSidetable byte + // This stores a varint for each named type. Named types are identified by their // name instead of by their type. The named types stored in this struct are -// non-basic types: pointer, struct, and channel. +// non-basic types: pointer, struct, channel, and interface. //go:extern reflect.namedNonBasicTypesSidetable var namedNonBasicTypesSidetable uintptr +// This stores the number of methods (for Type.NumMethods()) for each named +// non-basic type. It is indexed by the named type number. +//go:extern reflect.namedNonBasicNumMethodSidetable +var namedNonBasicNumMethodSidetable byte + //go:extern reflect.structTypesSidetable var structTypesSidetable byte @@ -19,6 +29,9 @@ var structNamesSidetable byte //go:extern reflect.arrayTypesSidetable var arrayTypesSidetable byte +//go:extern reflect.interfaceTypesSidetable +var interfaceTypesSidetable byte + // readStringSidetable reads a string from the given table (like // structNamesSidetable) and returns this string. No heap allocation is // necessary because it makes the string point directly to the raw bytes of the diff --git a/src/reflect/type.go b/src/reflect/type.go index 237a5a6a9e..843abb4ebd 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -146,6 +146,20 @@ func (t Type) Kind() Kind { } } +// isBasic returns true if (and only if) this is a basic type. +func (t Type) isBasic() bool { + return t%2 == 0 +} + +// isNamed returns true if (and only if) this is a named type. +func (t Type) isNamed() bool { + if t.isBasic() { + return t>>6 != 0 + } else { + return (t>>4)%2 != 0 + } +} + // Elem returns the element type for channel, slice and array types, the // pointed-to value for pointer types, and the key type for map types. func (t Type) Elem() Type { @@ -170,7 +184,7 @@ func (t Type) Elem() Type { func (t Type) stripPrefix() Type { // Look at the 'n' bit in the type code (see the top of this file) to see // whether this is a named type. - if (t>>4)%2 != 0 { + if t.isNamed() { // This is a named type. The data is stored in a sidetable. namedTypeNum := t >> 5 n := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&namedNonBasicTypesSidetable)) + uintptr(namedTypeNum)*unsafe.Sizeof(uintptr(0)))) @@ -188,7 +202,11 @@ func (t Type) Field(i int) StructField { } structIdentifier := t.stripPrefix() - numField, p := readVarint(unsafe.Pointer(uintptr(unsafe.Pointer(&structTypesSidetable)) + uintptr(structIdentifier))) + // Skip past the NumMethod field. + _, p := readVarint(unsafe.Pointer(uintptr(unsafe.Pointer(&structTypesSidetable)) + uintptr(structIdentifier))) + + // Read the NumField field. + numField, p := readVarint(p) if uint(i) >= uint(numField) { panic("reflect: field index out of range") } @@ -287,7 +305,10 @@ func (t Type) NumField() int { panic(&TypeError{"NumField"}) } structIdentifier := t.stripPrefix() - n, _ := readVarint(unsafe.Pointer(uintptr(unsafe.Pointer(&structTypesSidetable)) + uintptr(structIdentifier))) + // Skip past the NumMethod field. + _, p := readVarint(unsafe.Pointer(uintptr(unsafe.Pointer(&structTypesSidetable)) + uintptr(structIdentifier))) + // Read the NumField field. + n, _ := readVarint(p) return int(n) } @@ -405,10 +426,23 @@ func (t Type) AssignableTo(u Type) bool { } func (t Type) Implements(u Type) bool { - if t.Kind() != Interface { + if u.Kind() != Interface { panic("reflect: non-interface type passed to Type.Implements") } - return u.AssignableTo(t) + if u.NumMethod() == 0 { + // Empty interface (not even unexported methods, see NumNethod + // implementation comments), therefore implements any type. + return true + } + // Type u has (possibly unexported) methods. + if t.Kind() == Interface && t.NumMethod() == 0 { + // Type t has no methods (not even unexported methods since it is an + // interface), while u has. Therefore, t cannot implement u. + return false + } + // Now we'd have to compare individual methods. + // This has not yet been implemented. + panic("unimplemented: (reflect.Type).Implements()") } // Comparable returns whether values of this type can be compared to each other. @@ -454,7 +488,36 @@ func (t Type) ConvertibleTo(u Type) bool { } func (t Type) NumMethod() int { - panic("unimplemented: (reflect.Type).NumMethod()") + if t.isBasic() { + if !t.isNamed() { + // Not a named type, so can't have methods. + return 0 + } + // Named type methods are stored in a sidetable. + namedTypeNum := t >> 6 + return int(*(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&namedBasicNumMethodSidetable)) + uintptr(namedTypeNum) - 1))) + } else { + if !t.isNamed() { + // Most non-named types cannot have methods. However, structs can + // because they can embed named values. + switch t.Kind() { + case Struct: + structIdentifier := t.stripPrefix() + numMethod, _ := readVarint(unsafe.Pointer(uintptr(unsafe.Pointer(&structTypesSidetable)) + uintptr(structIdentifier))) + return int(numMethod) + case Interface: + interfaceIdentifier := t.stripPrefix() + numMethod, _ := readVarint(unsafe.Pointer(uintptr(unsafe.Pointer(&interfaceTypesSidetable)) + uintptr(interfaceIdentifier))) + return int(numMethod) + default: + // This type cannot have methods. + return 0 + } + } + // Named non-basic type, so read the number of methods from a sidetable. + namedTypeNum := t >> 5 + return int(*(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&namedNonBasicNumMethodSidetable)) + uintptr(namedTypeNum)))) + } } func (t Type) Name() string { diff --git a/src/reflect/value.go b/src/reflect/value.go index 087ddfa15b..1e5eaaf2c0 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -532,6 +532,10 @@ func maskAndShift(value, offset, size uintptr) uintptr { return (uintptr(value) >> (offset * 8)) & mask } +func (v Value) NumMethod() int { + return v.Type().NumMethod() +} + func (v Value) MapKeys() []Value { panic("unimplemented: (reflect.Value).MapKeys()") } diff --git a/src/runtime/interface.go b/src/runtime/interface.go index 870ba6ab10..4c76c55fed 100644 --- a/src/runtime/interface.go +++ b/src/runtime/interface.go @@ -107,6 +107,9 @@ type typecodeID struct { // The array length, for array types. length uintptr + + // Number of methods on this type. Usually 0 for non-named types. + numMethods uintptr } // structField is used by the compiler to pass information to the interface diff --git a/testdata/reflect.go b/testdata/reflect.go index c4df84601b..05eda3a653 100644 --- a/testdata/reflect.go +++ b/testdata/reflect.go @@ -26,8 +26,18 @@ type ( next *linkedList `description:"chain"` foo int } + myitf interface { + Foo() + bar() + baz() + } ) +// To test Type.NumMethod. +func (n myint) foo() {} +func (n myint) bar() {} +func (n myint) Baz() {} + func main() { println("matching types") println(reflect.TypeOf(int(3)) == reflect.TypeOf(int(5))) @@ -111,6 +121,16 @@ func main() { &linkedList{ foo: 42, }, + // interfaces + struct { + a interface{} + b interface { + Foo() + bar() + } + c myitf + d *myitf + }{}, } { showValue(reflect.ValueOf(v), "") } @@ -284,6 +304,9 @@ func showValue(rv reflect.Value, indent string) { if !rt.Comparable() { print(" comparable=false") } + if rt.NumMethod() != 0 { + print(" methods=", rt.NumMethod()) + } println() switch rt.Kind() { case reflect.Bool: @@ -339,7 +362,9 @@ func showValue(rv reflect.Value, indent string) { for i := 0; i < rv.NumField(); i++ { field := rt.Field(i) println(indent+" field:", i, field.Name) - println(indent+" tag:", field.Tag) + if field.Tag != "" { + println(indent+" tag:", field.Tag) + } println(indent+" embedded:", field.Anonymous) showValue(rv.Field(i), indent+" ") } diff --git a/testdata/reflect.txt b/testdata/reflect.txt index eeaa9c6f80..ade899a4c9 100644 --- a/testdata/reflect.txt +++ b/testdata/reflect.txt @@ -51,7 +51,7 @@ reflect type: complex64 complex: (+1.200000e+000+3.000000e-001i) reflect type: complex128 complex: (+1.300000e+000+4.000000e-001i) -reflect type: int +reflect type: int methods=1 int: 32 reflect type: string string: foo 3 @@ -77,7 +77,7 @@ reflect type: ptr reflect type: ptr pointer: true interface nil: false - reflect type: interface settable=true + reflect type: interface settable=true methods=1 interface nil: true reflect type: ptr @@ -230,28 +230,24 @@ reflect type: map comparable=false nil: false reflect type: struct struct: 0 -reflect type: struct +reflect type: struct methods=1 struct: 1 field: 0 error - tag: embedded: true - reflect type: interface + reflect type: interface methods=1 interface nil: true reflect type: struct struct: 3 field: 0 a - tag: embedded: false reflect type: uint8 uint: 42 field: 1 b - tag: embedded: false reflect type: int16 int: 321 field: 2 c - tag: embedded: false reflect type: int8 int: 123 @@ -263,27 +259,22 @@ reflect type: struct comparable=false reflect type: int int: 5 field: 1 some - tag: embedded: false reflect type: struct struct: 2 field: 0 X - tag: embedded: false reflect type: int16 int: -5 field: 1 Y - tag: embedded: false reflect type: int16 int: 3 field: 2 zero - tag: embedded: false reflect type: struct struct: 0 field: 3 buf - tag: embedded: false reflect type: slice comparable=false slice: uint8 2 2 @@ -296,7 +287,6 @@ reflect type: struct comparable=false reflect type: uint8 uint: 111 field: 4 Buf - tag: embedded: false reflect type: slice comparable=false slice: uint8 1 1 @@ -317,10 +307,31 @@ reflect type: ptr pointer: false struct nil: true field: 1 foo - tag: embedded: false reflect type: int int: 42 +reflect type: struct + struct: 4 + field: 0 a + embedded: false + reflect type: interface + interface + nil: true + field: 1 b + embedded: false + reflect type: interface methods=2 + interface + nil: true + field: 2 c + embedded: false + reflect type: interface methods=3 + interface + nil: true + field: 3 d + embedded: false + reflect type: ptr + pointer: false interface + nil: true sizes: int8 1 8 diff --git a/transform/reflect.go b/transform/reflect.go index fcab9a068f..6c44a68384 100644 --- a/transform/reflect.go +++ b/transform/reflect.go @@ -97,12 +97,17 @@ type typeCodeAssignmentState struct { // Map of struct types to their type code. structTypes map[string]int structTypesSidetable []byte - needsStructNamesSidetable bool + needsStructTypesSidetable bool // Map of struct names and tags to their name string. structNames map[string]int structNamesSidetable []byte - needsStructTypesSidetable bool + needsStructNamesSidetable bool + + // Map of interface types to their type code. + interfaceTypes map[string]int + interfaceTypesSidetable []byte + needsInterfaceTypesSidetable bool // This byte array is stored in reflect.namedNonBasicTypesSidetable and is // used at runtime to get details about a named non-basic type. @@ -120,6 +125,11 @@ type typeCodeAssignmentState struct { // all. If it is false, namedNonBasicTypesSidetable will contain simple // monotonically increasing numbers. needsNamedNonBasicTypesSidetable bool + + // These two slices contain the number of methods on named types, and are + // stored in the output binary with similar names. + namedBasicNumMethodSidetable []byte + namedNonBasicNumMethodSidetable []byte } // assignTypeCodes is used to assign a type code to each type in the program @@ -138,10 +148,12 @@ func assignTypeCodes(mod llvm.Module, typeSlice typeInfoSlice) { arrayTypes: make(map[string]int), structTypes: make(map[string]int), structNames: make(map[string]int), - needsNamedNonBasicTypesSidetable: len(getUses(mod.NamedGlobal("reflect.namedNonBasicTypesSidetable"))) != 0, + interfaceTypes: make(map[string]int), + needsNamedNonBasicTypesSidetable: len(getUses(mod.NamedGlobal("reflect.namedNonBasicTypesSidetable"))) != 0 || len(getUses(mod.NamedGlobal("reflect.namedNonBasicNumMethodSidetable"))) != 0, needsStructTypesSidetable: len(getUses(mod.NamedGlobal("reflect.structTypesSidetable"))) != 0, needsStructNamesSidetable: len(getUses(mod.NamedGlobal("reflect.structNamesSidetable"))) != 0, needsArrayTypesSidetable: len(getUses(mod.NamedGlobal("reflect.arrayTypesSidetable"))) != 0, + needsInterfaceTypesSidetable: len(getUses(mod.NamedGlobal("reflect.interfaceTypesSidetable"))) != 0, } for _, t := range typeSlice { num := state.getTypeCodeNum(t.typecode) @@ -157,7 +169,21 @@ func assignTypeCodes(mod llvm.Module, typeSlice typeInfoSlice) { // Only create this sidetable when it is necessary. if state.needsNamedNonBasicTypesSidetable { - global := replaceGlobalIntWithArray(mod, "reflect.namedNonBasicTypesSidetable", state.namedNonBasicTypesSidetable) + if len(getUses(mod.NamedGlobal("reflect.namedNonBasicTypesSidetable"))) != 0 { + global := replaceGlobalIntWithArray(mod, "reflect.namedNonBasicTypesSidetable", state.namedNonBasicTypesSidetable) + global.SetLinkage(llvm.InternalLinkage) + global.SetUnnamedAddr(true) + global.SetGlobalConstant(true) + } + if len(getUses(mod.NamedGlobal("reflect.namedNonBasicNumMethodSidetable"))) != 0 { + global := replaceGlobalIntWithArray(mod, "reflect.namedNonBasicNumMethodSidetable", state.namedNonBasicNumMethodSidetable) + global.SetLinkage(llvm.InternalLinkage) + global.SetUnnamedAddr(true) + global.SetGlobalConstant(true) + } + } + if len(getUses(mod.NamedGlobal("reflect.namedBasicNumMethodSidetable"))) != 0 { + global := replaceGlobalIntWithArray(mod, "reflect.namedBasicNumMethodSidetable", state.namedBasicNumMethodSidetable) global.SetLinkage(llvm.InternalLinkage) global.SetUnnamedAddr(true) global.SetGlobalConstant(true) @@ -180,6 +206,12 @@ func assignTypeCodes(mod llvm.Module, typeSlice typeInfoSlice) { global.SetUnnamedAddr(true) global.SetGlobalConstant(true) } + if state.needsInterfaceTypesSidetable { + global := replaceGlobalIntWithArray(mod, "reflect.interfaceTypesSidetable", state.interfaceTypesSidetable) + global.SetLinkage(llvm.InternalLinkage) + global.SetUnnamedAddr(true) + global.SetGlobalConstant(true) + } } // getTypeCodeNum returns the typecode for a given type as expected by the @@ -189,9 +221,12 @@ func (state *typeCodeAssignmentState) getTypeCodeNum(typecode llvm.Value) *big.I // Note: see src/reflect/type.go for bit allocations. class, value := getClassAndValueFromTypeCode(typecode) name := "" + var namedNumMethods uint64 // number of methods for a named type if class == "named" { name = value - typecode = llvm.ConstExtractValue(typecode.Initializer(), []uint32{0}) + initializer := typecode.Initializer() + typecode = llvm.ConstExtractValue(initializer, []uint32{0}) + namedNumMethods = llvm.ConstExtractValue(initializer, []uint32{2}).ZExtValue() class, value = getClassAndValueFromTypeCode(typecode) } if class == "basic" { @@ -205,7 +240,7 @@ func (state *typeCodeAssignmentState) getTypeCodeNum(typecode llvm.Value) *big.I } if name != "" { // This type is named, set the upper bits to the name ID. - num |= int64(state.getBasicNamedTypeNum(name)) << 5 + num |= int64(state.getBasicNamedTypeNum(name, namedNumMethods)) << 5 } return big.NewInt(num << 1) } else { @@ -248,6 +283,14 @@ func (state *typeCodeAssignmentState) getTypeCodeNum(typecode llvm.Value) *big.I index := len(state.namedNonBasicTypesSidetable) state.namedNonBasicTypesSidetable = append(state.namedNonBasicTypesSidetable, 0) state.namedNonBasicTypes[name] = index + // Also store the number of methods. + if index != len(state.namedNonBasicNumMethodSidetable) { + panic("unexpected side table length") + } + if uint64(byte(namedNumMethods)) != namedNumMethods { + panic("too many methods for type " + name) + } + state.namedNonBasicNumMethodSidetable = append(state.namedNonBasicNumMethodSidetable, byte(namedNumMethods)) // Get the typecode of the underlying type (which could be the // element type in the case of pointers, for example). num = state.getNonBasicTypeCode(class, typecode) @@ -285,6 +328,10 @@ func (state *typeCodeAssignmentState) getNonBasicTypeCode(class string, typecode // More complicated type kind. The upper bits contain the index to the // struct type in the struct types sidetable. return big.NewInt(int64(state.getStructTypeNum(typecode))) + case "interface": + // Interfaces can be stored in a reflect.Value as a result of extracting + // a field from a struct, for example. + return big.NewInt(int64(state.getInterfaceTypeNum(typecode))) default: // Type has not yet been implemented, so fall back by using a unique // number. @@ -316,12 +363,19 @@ func getClassAndValueFromTypeCode(typecode llvm.Value) (class, value string) { // getBasicNamedTypeNum returns an appropriate (unique) number for the given // named type. If the name already has a number that number is returned, else a // new number is returned. The number is always non-zero. -func (state *typeCodeAssignmentState) getBasicNamedTypeNum(name string) int { +func (state *typeCodeAssignmentState) getBasicNamedTypeNum(name string, numMethods uint64) int { if num, ok := state.namedBasicTypes[name]; ok { return num } num := len(state.namedBasicTypes) + 1 state.namedBasicTypes[name] = num + if uint64(byte(numMethods)) != numMethods { + panic("too many methods for type " + name) + } + if len(state.namedBasicNumMethodSidetable) != num-1 { + panic("unexpected side table length") + } + state.namedBasicNumMethodSidetable = append(state.namedBasicNumMethodSidetable, byte(numMethods)) return num } @@ -381,15 +435,21 @@ func (state *typeCodeAssignmentState) getStructTypeNum(typecode llvm.Value) int } // Get the fields this struct type contains. - // The struct number will be the start index of - structTypeGlobal := llvm.ConstExtractValue(typecode.Initializer(), []uint32{0}).Operand(0).Initializer() + // The struct number will be the start index into + // reflect.structTypesSidetable. + typecodeID := typecode.Initializer() + structTypeGlobal := llvm.ConstExtractValue(typecodeID, []uint32{0}).Operand(0).Initializer() numFields := structTypeGlobal.Type().ArrayLength() + numMethods := llvm.ConstExtractValue(typecodeID, []uint32{2}).ZExtValue() - // The first data that is stored in the struct sidetable is the number of - // fields this struct contains. This is usually just a single byte because - // most structs don't contain that many fields, but make it a varint just - // to be sure. - buf := makeVarint(uint64(numFields)) + // The first element that is stored in the struct sidetable is the number + // of methods this struct has. It is used by Type.NumMethod(). + buf := makeVarint(numMethods) + // The second element that is stored in the struct sidetable is the number + // of fields this struct contains. This is usually just a single byte + // because most structs don't contain that many fields, but make it a varint + // just to be sure. + buf = append(buf, makeVarint(uint64(numFields))...) // Iterate over every field in the struct. // Every field is stored sequentially in the struct sidetable. Fields can @@ -478,6 +538,43 @@ func (state *typeCodeAssignmentState) getStructNameNumber(nameBytes []byte) int return n } +// getInterfaceTypeNum returns the interface type number, which is an index into +// reflect.interfaceTypesSidetable or an unique number for every interface if +// this sidetable is not needed in the to-be-compiled program. +func (state *typeCodeAssignmentState) getInterfaceTypeNum(typecode llvm.Value) int { + name := typecode.Name() + if num, ok := state.interfaceTypes[name]; ok { + // This interface already has an assigned type code. + return num + } + + if !state.needsInterfaceTypesSidetable { + // We don't need interface sidetables, so we can just assign + // monotonically increasing numbers to each interface type. + num := len(state.interfaceTypes) + state.interfaceTypes[name] = num + return num + } + + typecodeID := typecode.Initializer() + numMethods := llvm.ConstExtractValue(typecodeID, []uint32{2}).ZExtValue() + + // The first (and only, so far) element that is stored in the interface + // sidetable is the number of methods this interface has. It is used by + // Type.NumMethod(). + buf := makeVarint(numMethods) + + // In the future, we'll want to include data on the methods this interface + // supports, so that Implements() can be fully implemented. + + // The interface number will be the start index into + // reflect.interfaceTypesSidetable. + num := len(state.interfaceTypesSidetable) + state.interfaceTypes[name] = num + state.interfaceTypesSidetable = append(state.interfaceTypesSidetable, buf...) + return num +} + // makeVarint is a small helper function that returns the bytes of the number in // varint encoding. func makeVarint(n uint64) []byte { diff --git a/transform/testdata/func-lowering.ll b/transform/testdata/func-lowering.ll index c00264d91f..e34a77b2cb 100644 --- a/transform/testdata/func-lowering.ll +++ b/transform/testdata/func-lowering.ll @@ -1,7 +1,7 @@ target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" target triple = "wasm32-unknown-unknown-wasm" -%runtime.typecodeID = type { %runtime.typecodeID*, i32 } +%runtime.typecodeID = type { %runtime.typecodeID*, i32, i32 } %runtime.funcValueWithSignature = type { i32, %runtime.typecodeID* } @"reflect/types.type:func:{basic:uint8}{}" = external constant %runtime.typecodeID diff --git a/transform/testdata/func-lowering.out.ll b/transform/testdata/func-lowering.out.ll index deba41b0d4..e0ffa73c82 100644 --- a/transform/testdata/func-lowering.out.ll +++ b/transform/testdata/func-lowering.out.ll @@ -1,7 +1,7 @@ target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" target triple = "wasm32-unknown-unknown-wasm" -%runtime.typecodeID = type { %runtime.typecodeID*, i32 } +%runtime.typecodeID = type { %runtime.typecodeID*, i32, i32 } %runtime.funcValueWithSignature = type { i32, %runtime.typecodeID* } @"reflect/types.type:func:{basic:uint8}{}" = external constant %runtime.typecodeID diff --git a/transform/testdata/interface.ll b/transform/testdata/interface.ll index 1e2ce61b6e..764426eb87 100644 --- a/transform/testdata/interface.ll +++ b/transform/testdata/interface.ll @@ -1,7 +1,7 @@ target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" target triple = "armv7m-none-eabi" -%runtime.typecodeID = type { %runtime.typecodeID*, i32 } +%runtime.typecodeID = type { %runtime.typecodeID*, i32, i32 } %runtime.typeInInterface = type { %runtime.typecodeID*, %runtime.interfaceMethodInfo* } %runtime.interfaceMethodInfo = type { i8*, i32 } @@ -14,7 +14,7 @@ target triple = "armv7m-none-eabi" @"func Double() int" = external constant i8 @"Doubler$interface" = private constant [1 x i8*] [i8* @"func Double() int"] @"Number$methodset" = private constant [1 x %runtime.interfaceMethodInfo] [%runtime.interfaceMethodInfo { i8* @"func Double() int", i32 ptrtoint (i32 (i8*, i8*)* @"(Number).Double$invoke" to i32) }] -@"reflect/types.type:named:Number" = private constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:basic:int", i32 0 } +@"reflect/types.type:named:Number" = private constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:basic:int", i32 0, i32 1 } @"typeInInterface:reflect/types.type:named:Number" = private constant %runtime.typeInInterface { %runtime.typecodeID* @"reflect/types.type:named:Number", %runtime.interfaceMethodInfo* getelementptr inbounds ([1 x %runtime.interfaceMethodInfo], [1 x %runtime.interfaceMethodInfo]* @"Number$methodset", i32 0, i32 0) } declare i1 @runtime.interfaceImplements(i32, i8**) diff --git a/transform/testdata/interface.out.ll b/transform/testdata/interface.out.ll index 4bb9ec1bbc..ddb1913837 100644 --- a/transform/testdata/interface.out.ll +++ b/transform/testdata/interface.out.ll @@ -1,7 +1,7 @@ target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" target triple = "armv7m-none-eabi" -%runtime.typecodeID = type { %runtime.typecodeID*, i32 } +%runtime.typecodeID = type { %runtime.typecodeID*, i32, i32 } @"reflect/types.type:basic:uint8" = external constant %runtime.typecodeID @"reflect/types.type:basic:int" = external constant %runtime.typecodeID @@ -9,7 +9,7 @@ target triple = "armv7m-none-eabi" @"Unmatched$interface" = private constant [1 x i8*] [i8* @"func NeverImplementedMethod()"] @"func Double() int" = external constant i8 @"Doubler$interface" = private constant [1 x i8*] [i8* @"func Double() int"] -@"reflect/types.type:named:Number" = private constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:basic:int", i32 0 } +@"reflect/types.type:named:Number" = private constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:basic:int", i32 0, i32 1 } declare i1 @runtime.interfaceImplements(i32, i8**)