diff --git a/compiler/interface.go b/compiler/interface.go index d6ed420d..cbebec82 100644 --- a/compiler/interface.go +++ b/compiler/interface.go @@ -134,6 +134,7 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value { typeFieldTypes = append(typeFieldTypes, types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]), types.NewVar(token.NoPos, nil, "underlying", types.Typ[types.UnsafePointer]), + types.NewVar(token.NoPos, nil, "numMethods", types.Typ[types.Uint16]), types.NewVar(token.NoPos, nil, "pkgpath", types.Typ[types.UnsafePointer]), types.NewVar(token.NoPos, nil, "name", types.NewArray(types.Typ[types.Int8], 1+int64(len(typ.Obj().Name())))), ) @@ -145,6 +146,7 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value { case *types.Pointer: typeFieldTypes = append(typeFieldTypes, types.NewVar(token.NoPos, nil, "elementType", types.Typ[types.UnsafePointer]), + types.NewVar(token.NoPos, nil, "numMethods", types.Typ[types.Uint16]), ) case *types.Array: typeFieldTypes = append(typeFieldTypes, @@ -161,6 +163,7 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value { case *types.Struct: typeFieldTypes = append(typeFieldTypes, types.NewVar(token.NoPos, nil, "numFields", types.Typ[types.Uint16]), + 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, "pkgpath", types.Typ[types.UnsafePointer]), types.NewVar(token.NoPos, nil, "fields", types.NewArray(c.getRuntimeType("structField"), int64(typ.NumFields()))), @@ -201,8 +204,9 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value { } pkgPathPtr := c.pkgPathPtr(pkgpath) typeFields = []llvm.Value{ - c.getTypeCode(types.NewPointer(typ)), // ptrTo - c.getTypeCode(typ.Underlying()), // underlying + c.getTypeCode(types.NewPointer(typ)), // ptrTo + c.getTypeCode(typ.Underlying()), // underlying + llvm.ConstInt(c.ctx.Int16Type(), uint64(ms.Len()), false), // numMethods pkgPathPtr, // pkgpath pointer c.ctx.ConstString(name+"\x00", false), // name } @@ -218,7 +222,10 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value { c.getTypeCode(typ.Elem()), // elementType } case *types.Pointer: - typeFields = []llvm.Value{c.getTypeCode(typ.Elem())} + typeFields = []llvm.Value{ + c.getTypeCode(typ.Elem()), + llvm.ConstInt(c.ctx.Int16Type(), uint64(ms.Len()), false), // numMethods + } case *types.Array: typeFields = []llvm.Value{ c.getTypeCode(types.NewPointer(typ)), // ptrTo @@ -242,6 +249,7 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value { typeFields = []llvm.Value{ llvm.ConstInt(c.ctx.Int16Type(), uint64(typ.NumFields()), false), // numFields + llvm.ConstInt(c.ctx.Int16Type(), uint64(ms.Len()), false), // numMethods c.getTypeCode(types.NewPointer(typ)), // ptrTo pkgPathPtr, } diff --git a/compiler/testdata/gc.ll b/compiler/testdata/gc.ll index b833958a..492f9d57 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 16, ptr @"reflect/types.type:pointer:basic:complex128" }, align 4 -@"reflect/types.type:pointer:basic:complex128" = linkonce_odr constant { i8, ptr } { i8 21, ptr @"reflect/types.type:basic:complex128" }, align 4 +@"reflect/types.type:pointer:basic:complex128" = linkonce_odr constant { i8, ptr, i16 } { i8 21, ptr @"reflect/types.type:basic:complex128", i16 0 }, align 4 declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0 diff --git a/compiler/testdata/interface.ll b/compiler/testdata/interface.ll index cb04c11c..a619b62f 100644 --- a/compiler/testdata/interface.ll +++ b/compiler/testdata/interface.ll @@ -7,13 +7,13 @@ target triple = "wasm32-unknown-wasi" %runtime._string = type { ptr, i32 } @"reflect/types.type:basic:int" = linkonce_odr constant { i8, ptr } { i8 2, ptr @"reflect/types.type:pointer:basic:int" }, align 4 -@"reflect/types.type:pointer:basic:int" = linkonce_odr constant { i8, ptr } { i8 21, ptr @"reflect/types.type:basic:int" }, align 4 -@"reflect/types.type:pointer:named:error" = linkonce_odr constant { i8, ptr } { i8 21, ptr @"reflect/types.type:named:error" }, align 4 -@"reflect/types.type:named:error" = linkonce_odr constant { i8, ptr, ptr, ptr, [6 x i8] } { i8 52, ptr @"reflect/types.type:pointer:named:error", ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}", ptr @"reflect/types.type.pkgpath.empty", [6 x i8] c"error\00" }, align 4 +@"reflect/types.type:pointer:basic:int" = linkonce_odr constant { i8, ptr, i16 } { i8 21, ptr @"reflect/types.type:basic:int", i16 0 }, align 4 +@"reflect/types.type:pointer:named:error" = linkonce_odr constant { i8, ptr, i16 } { i8 21, ptr @"reflect/types.type:named:error", i16 0 }, align 4 +@"reflect/types.type:named:error" = linkonce_odr constant { i8, ptr, ptr, i16, ptr, [6 x i8] } { i8 52, ptr @"reflect/types.type:pointer:named:error", ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}", i16 1, ptr @"reflect/types.type.pkgpath.empty", [6 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 20, 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, ptr } { i8 21, ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}" }, align 4 -@"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr } { i8 21, ptr @"reflect/types.type:interface:{String:func:{}{basic:string}}" }, align 4 +@"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr, i16 } { i8 21, ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}", i16 0 }, align 4 +@"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr, i16 } { i8 21, ptr @"reflect/types.type:interface:{String:func:{}{basic:string}}", i16 0 }, align 4 @"reflect/types.type:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr } { i8 20, 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 134711a7..54a5e349 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -25,6 +25,7 @@ // - pointer types (see ptrType, this doesn't include chan, map, etc): // meta uint8 // elementType *typeStruct +// nmethods uint16 // - array types (see arrayType) // meta uint8 // ptrTo *typeStruct @@ -38,6 +39,7 @@ // - struct types (see structType): // meta uint8 // numField uint16 +// nmethods uint16 // ptrTo *typeStruct // pkgpath *byte // fields [...]structField // the remaining fields are all of type structField @@ -51,6 +53,7 @@ // meta uint8 // ptrTo *typeStruct // elem *typeStruct // underlying type +// nmethods uint16 // number of methods // pkg *byte // pkgpath // name [1]byte // actual name; length nlem // @@ -409,7 +412,8 @@ type elemType struct { type ptrType struct { rawType - elem *rawType + elem *rawType + numMethod uint16 } type arrayType struct { @@ -428,10 +432,11 @@ type mapType struct { type namedType struct { rawType - ptrTo *rawType - elem *rawType - pkg *byte - name [1]byte + ptrTo *rawType + elem *rawType + numMethod uint16 + pkg *byte + name [1]byte } // Type for struct types. The numField value is intentionally put before ptrTo @@ -443,10 +448,11 @@ type namedType struct { // checker. type structType struct { rawType - numField uint16 - ptrTo *rawType - pkgpath *byte - fields [1]structField // the remaining fields are all of type structField + numField uint16 + numMethod uint16 + ptrTo *rawType + pkgpath *byte + fields [1]structField // the remaining fields are all of type structField } type structField struct { @@ -992,7 +998,20 @@ func (t *rawType) NumOut() int { } func (t *rawType) NumMethod() int { - panic("unimplemented: (reflect.Type).NumMethod()") + + if t.isNamed() { + return int((*namedType)(unsafe.Pointer(t)).numMethod) + } + + switch t.Kind() { + case Pointer: + return int((*ptrType)(unsafe.Pointer(t)).numMethod) + case Struct: + return int((*structType)(unsafe.Pointer(t)).numMethod) + } + + // Other types have no methods attached. Note we don't panic here. + return 0 } // Read and return a null terminated string starting from data.