reflect: implement New function
This is very important for some use cases, for example for Vecty.
Этот коммит содержится в:
родитель
57271d7eaa
коммит
e587b1d1b4
8 изменённых файлов: 87 добавлений и 25 удалений
|
@ -23,7 +23,7 @@ import (
|
|||
// Version of the compiler pacakge. Must be incremented each time the compiler
|
||||
// package changes in a way that affects the generated LLVM module.
|
||||
// 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() {
|
||||
llvm.InitializeAllTargets()
|
||||
|
|
|
@ -46,6 +46,7 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
|||
var references llvm.Value
|
||||
var length int64
|
||||
var methodSet llvm.Value
|
||||
var ptrTo llvm.Value
|
||||
switch typ := typ.(type) {
|
||||
case *types.Named:
|
||||
references = c.getTypeCode(typ.Underlying())
|
||||
|
@ -69,22 +70,25 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
|||
if _, ok := typ.Underlying().(*types.Interface); !ok {
|
||||
methodSet = c.getTypeMethodSet(typ)
|
||||
}
|
||||
if !references.IsNil() || length != 0 || !methodSet.IsNil() {
|
||||
// Set the 'references' field of the runtime.typecodeID struct.
|
||||
globalValue := llvm.ConstNull(global.Type().ElementType())
|
||||
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 !methodSet.IsNil() {
|
||||
globalValue = llvm.ConstInsertValue(globalValue, methodSet, []uint32{2})
|
||||
}
|
||||
global.SetInitializer(globalValue)
|
||||
global.SetLinkage(llvm.LinkOnceODRLinkage)
|
||||
if _, ok := typ.Underlying().(*types.Pointer); !ok {
|
||||
ptrTo = c.getTypeCode(types.NewPointer(typ))
|
||||
}
|
||||
globalValue := llvm.ConstNull(global.Type().ElementType())
|
||||
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 !methodSet.IsNil() {
|
||||
globalValue = llvm.ConstInsertValue(globalValue, methodSet, []uint32{2})
|
||||
}
|
||||
if !ptrTo.IsNil() {
|
||||
globalValue = llvm.ConstInsertValue(globalValue, ptrTo, []uint32{3})
|
||||
}
|
||||
global.SetInitializer(globalValue)
|
||||
global.SetLinkage(llvm.LinkOnceODRLinkage)
|
||||
global.SetGlobalConstant(true)
|
||||
}
|
||||
return global
|
||||
|
|
17
compiler/testdata/interface.ll
предоставленный
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 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._interface = type { i32, i8* }
|
||||
%runtime._string = type { i8*, i32 }
|
||||
|
||||
@"reflect/types.type:basic:int" = linkonce_odr constant %runtime.typecodeID zeroinitializer
|
||||
@"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:named:error" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:named:error", 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 }
|
||||
@"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: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, %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, %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, %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, %runtime.typecodeID* @"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" }
|
||||
@"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.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: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:{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: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
|
||||
@"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
|
||||
|
|
|
@ -322,6 +322,9 @@ func TypeOf(i interface{}) Type {
|
|||
}
|
||||
|
||||
func PtrTo(t Type) Type {
|
||||
if t.Kind() == Ptr {
|
||||
panic("reflect: cannot make **T type")
|
||||
}
|
||||
ptrType := t.(rawType)<<5 | 5 // 0b0101 == 5
|
||||
if ptrType>>5 != t {
|
||||
panic("reflect: PtrTo type does not fit")
|
||||
|
|
|
@ -724,8 +724,14 @@ func Zero(typ Type) Value {
|
|||
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 {
|
||||
panic("unimplemented: reflect.New()")
|
||||
return Value{
|
||||
typecode: PtrTo(typ).(rawType),
|
||||
value: alloc(typ.Size()),
|
||||
flags: valueFlagExported,
|
||||
}
|
||||
}
|
||||
|
||||
type funcHeader struct {
|
||||
|
@ -756,6 +762,9 @@ func (e *ValueError) Error() string {
|
|||
// llvm.memcpy.p0i8.p0i8.i32().
|
||||
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
|
||||
// dst has been filled or src has been exhausted.
|
||||
func Copy(dst, src Value) int {
|
||||
|
|
|
@ -112,6 +112,11 @@ type typecodeID struct {
|
|||
length uintptr
|
||||
|
||||
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
|
||||
|
|
15
testdata/reflect.go
предоставленный
15
testdata/reflect.go
предоставленный
|
@ -124,6 +124,21 @@ func main() {
|
|||
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
|
||||
println("\nsizes:")
|
||||
for _, tc := range []struct {
|
||||
|
|
25
testdata/reflect.txt
предоставленный
25
testdata/reflect.txt
предоставленный
|
@ -321,6 +321,31 @@ reflect type: ptr
|
|||
embedded: false
|
||||
reflect type: int addrable=true
|
||||
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:
|
||||
int8 1 8
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче