reflect: implement New function

This is very important for some use cases, for example for Vecty.
Этот коммит содержится в:
Ayke van Laethem 2021-04-11 13:50:44 +02:00 коммит произвёл Ron Evans
родитель 57271d7eaa
коммит e587b1d1b4
8 изменённых файлов: 87 добавлений и 25 удалений

Просмотреть файл

@ -23,7 +23,7 @@ import (
// Version of the compiler pacakge. Must be incremented each time the compiler // Version of the compiler pacakge. Must be incremented each time the compiler
// package changes in a way that affects the generated LLVM module. // package changes in a way that affects the generated LLVM module.
// This version is independent of the TinyGo version number. // This version is independent of the TinyGo version number.
const Version = 8 // last change: don't use runtime.typecodeID in func lowering const Version = 9 // last change: implement reflect.New()
func init() { func init() {
llvm.InitializeAllTargets() llvm.InitializeAllTargets()

Просмотреть файл

@ -46,6 +46,7 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
var references llvm.Value var references llvm.Value
var length int64 var length int64
var methodSet llvm.Value var methodSet llvm.Value
var ptrTo llvm.Value
switch typ := typ.(type) { switch typ := typ.(type) {
case *types.Named: case *types.Named:
references = c.getTypeCode(typ.Underlying()) references = c.getTypeCode(typ.Underlying())
@ -69,8 +70,9 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
if _, ok := typ.Underlying().(*types.Interface); !ok { if _, ok := typ.Underlying().(*types.Interface); !ok {
methodSet = c.getTypeMethodSet(typ) methodSet = c.getTypeMethodSet(typ)
} }
if !references.IsNil() || length != 0 || !methodSet.IsNil() { if _, ok := typ.Underlying().(*types.Pointer); !ok {
// Set the 'references' field of the runtime.typecodeID struct. ptrTo = c.getTypeCode(types.NewPointer(typ))
}
globalValue := llvm.ConstNull(global.Type().ElementType()) globalValue := llvm.ConstNull(global.Type().ElementType())
if !references.IsNil() { if !references.IsNil() {
globalValue = llvm.ConstInsertValue(globalValue, references, []uint32{0}) globalValue = llvm.ConstInsertValue(globalValue, references, []uint32{0})
@ -82,9 +84,11 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
if !methodSet.IsNil() { if !methodSet.IsNil() {
globalValue = llvm.ConstInsertValue(globalValue, methodSet, []uint32{2}) globalValue = llvm.ConstInsertValue(globalValue, methodSet, []uint32{2})
} }
if !ptrTo.IsNil() {
globalValue = llvm.ConstInsertValue(globalValue, ptrTo, []uint32{3})
}
global.SetInitializer(globalValue) global.SetInitializer(globalValue)
global.SetLinkage(llvm.LinkOnceODRLinkage) global.SetLinkage(llvm.LinkOnceODRLinkage)
}
global.SetGlobalConstant(true) global.SetGlobalConstant(true)
} }
return global return global

17
compiler/testdata/interface.ll предоставленный
Просмотреть файл

@ -3,20 +3,21 @@ source_filename = "interface.go"
target datalayout = "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-f64:32:64-f80:32-n8:16:32-S128" target datalayout = "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-f64:32:64-f80:32-n8:16:32-S128"
target triple = "i686--linux" target triple = "i686--linux"
%runtime.typecodeID = type { %runtime.typecodeID*, i32, %runtime.interfaceMethodInfo* } %runtime.typecodeID = type { %runtime.typecodeID*, i32, %runtime.interfaceMethodInfo*, %runtime.typecodeID* }
%runtime.interfaceMethodInfo = type { i8*, i32 } %runtime.interfaceMethodInfo = type { i8*, i32 }
%runtime._interface = type { i32, i8* } %runtime._interface = type { i32, i8* }
%runtime._string = type { i8*, i32 } %runtime._string = type { i8*, i32 }
@"reflect/types.type:basic:int" = linkonce_odr constant %runtime.typecodeID zeroinitializer @"reflect/types.type:basic:int" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* null, i32 0, %runtime.interfaceMethodInfo* null, %runtime.typecodeID* @"reflect/types.type:pointer:basic:int" }
@"reflect/types.type:pointer:basic:int" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:basic:int", i32 0, %runtime.interfaceMethodInfo* null } @"reflect/types.type:pointer:basic:int" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:basic:int", i32 0, %runtime.interfaceMethodInfo* null, %runtime.typecodeID* null }
@"reflect/types.type:pointer:named:error" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:named:error", i32 0, %runtime.interfaceMethodInfo* null } @"reflect/types.type:pointer:named:error" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:named:error", i32 0, %runtime.interfaceMethodInfo* null, %runtime.typecodeID* null }
@"reflect/types.type:named:error" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:interface:{Error:func:{}{basic:string}}", i32 0, %runtime.interfaceMethodInfo* null } @"reflect/types.type:named:error" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:interface:{Error:func:{}{basic:string}}", i32 0, %runtime.interfaceMethodInfo* null, %runtime.typecodeID* @"reflect/types.type:pointer:named:error" }
@"reflect/types.type:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* bitcast ([1 x i8*]* @"reflect/types.interface:interface{Error() string}$interface" to %runtime.typecodeID*), i32 0, %runtime.interfaceMethodInfo* null } @"reflect/types.type:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* bitcast ([1 x i8*]* @"reflect/types.interface:interface{Error() string}$interface" to %runtime.typecodeID*), i32 0, %runtime.interfaceMethodInfo* null, %runtime.typecodeID* @"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" }
@"func Error() string" = external constant i8 @"func Error() string" = external constant i8
@"reflect/types.interface:interface{Error() string}$interface" = linkonce_odr constant [1 x i8*] [i8* @"func Error() string"] @"reflect/types.interface:interface{Error() string}$interface" = linkonce_odr constant [1 x i8*] [i8* @"func Error() string"]
@"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:interface:{String:func:{}{basic:string}}", i32 0, %runtime.interfaceMethodInfo* null } @"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:interface:{Error:func:{}{basic:string}}", i32 0, %runtime.interfaceMethodInfo* null, %runtime.typecodeID* null }
@"reflect/types.type:interface:{String:func:{}{basic:string}}" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* bitcast ([1 x i8*]* @"reflect/types.interface:interface{String() string}$interface" to %runtime.typecodeID*), i32 0, %runtime.interfaceMethodInfo* null } @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:interface:{String:func:{}{basic:string}}", i32 0, %runtime.interfaceMethodInfo* null, %runtime.typecodeID* null }
@"reflect/types.type:interface:{String:func:{}{basic:string}}" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* bitcast ([1 x i8*]* @"reflect/types.interface:interface{String() string}$interface" to %runtime.typecodeID*), i32 0, %runtime.interfaceMethodInfo* null, %runtime.typecodeID* @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" }
@"func String() string" = external constant i8 @"func String() string" = external constant i8
@"reflect/types.interface:interface{String() string}$interface" = linkonce_odr constant [1 x i8*] [i8* @"func String() string"] @"reflect/types.interface:interface{String() string}$interface" = linkonce_odr constant [1 x i8*] [i8* @"func String() string"]
@"reflect/types.typeid:basic:int" = external constant i8 @"reflect/types.typeid:basic:int" = external constant i8

Просмотреть файл

@ -322,6 +322,9 @@ func TypeOf(i interface{}) Type {
} }
func PtrTo(t Type) Type { func PtrTo(t Type) Type {
if t.Kind() == Ptr {
panic("reflect: cannot make **T type")
}
ptrType := t.(rawType)<<5 | 5 // 0b0101 == 5 ptrType := t.(rawType)<<5 | 5 // 0b0101 == 5
if ptrType>>5 != t { if ptrType>>5 != t {
panic("reflect: PtrTo type does not fit") panic("reflect: PtrTo type does not fit")

Просмотреть файл

@ -724,8 +724,14 @@ func Zero(typ Type) Value {
panic("unimplemented: reflect.Zero()") panic("unimplemented: reflect.Zero()")
} }
// New is the reflect equivalent of the new(T) keyword, returning a pointer to a
// new value of the given type.
func New(typ Type) Value { func New(typ Type) Value {
panic("unimplemented: reflect.New()") return Value{
typecode: PtrTo(typ).(rawType),
value: alloc(typ.Size()),
flags: valueFlagExported,
}
} }
type funcHeader struct { type funcHeader struct {
@ -756,6 +762,9 @@ func (e *ValueError) Error() string {
// llvm.memcpy.p0i8.p0i8.i32(). // llvm.memcpy.p0i8.p0i8.i32().
func memcpy(dst, src unsafe.Pointer, size uintptr) func memcpy(dst, src unsafe.Pointer, size uintptr)
//go:linkname alloc runtime.alloc
func alloc(size uintptr) unsafe.Pointer
// Copy copies the contents of src into dst until either // Copy copies the contents of src into dst until either
// dst has been filled or src has been exhausted. // dst has been filled or src has been exhausted.
func Copy(dst, src Value) int { func Copy(dst, src Value) int {

Просмотреть файл

@ -112,6 +112,11 @@ type typecodeID struct {
length uintptr length uintptr
methodSet *interfaceMethodInfo // nil or a GEP of an array methodSet *interfaceMethodInfo // nil or a GEP of an array
// The type that's a pointer to this type, nil if it is already a pointer.
// Keeping the type struct alive here is important so that values from
// reflect.New (which uses reflect.PtrTo) can be used in type asserts etc.
ptrTo *typecodeID
} }
// structField is used by the compiler to pass information to the interface // structField is used by the compiler to pass information to the interface

15
testdata/reflect.go предоставленный
Просмотреть файл

@ -124,6 +124,21 @@ func main() {
showValue(reflect.ValueOf(v), "") showValue(reflect.ValueOf(v), "")
} }
// Test reflect.New().
newInt8 := reflect.New(reflect.TypeOf(int8(0)))
newInt8.Elem().SetInt(5)
newInt16 := reflect.New(reflect.TypeOf(int16(0)))
newInt16.Elem().SetInt(-800)
newInt32 := reflect.New(reflect.TypeOf(int32(0)))
newInt32.Elem().SetInt(1e8)
newInt64 := reflect.New(reflect.TypeOf(int64(0)))
newInt64.Elem().SetInt(-1e12)
newComplex128 := reflect.New(reflect.TypeOf(0 + 0i))
newComplex128.Elem().SetComplex(-8 - 20e5i)
for _, val := range []reflect.Value{newInt8, newInt16, newInt32, newInt64, newComplex128} {
showValue(val, "")
}
// test sizes // test sizes
println("\nsizes:") println("\nsizes:")
for _, tc := range []struct { for _, tc := range []struct {

25
testdata/reflect.txt предоставленный
Просмотреть файл

@ -321,6 +321,31 @@ reflect type: ptr
embedded: false embedded: false
reflect type: int addrable=true reflect type: int addrable=true
int: 42 int: 42
reflect type: ptr
pointer: true int8
nil: false
reflect type: int8 settable=true addrable=true
int: 5
reflect type: ptr
pointer: true int16
nil: false
reflect type: int16 settable=true addrable=true
int: -800
reflect type: ptr
pointer: true int32
nil: false
reflect type: int32 settable=true addrable=true
int: 100000000
reflect type: ptr
pointer: true int64
nil: false
reflect type: int64 settable=true addrable=true
int: -1000000000000
reflect type: ptr
pointer: true complex128
nil: false
reflect type: complex128 settable=true addrable=true
complex: (-8.000000e+000-2.000000e+006i)
sizes: sizes:
int8 1 8 int8 1 8