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
|
// 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,22 +70,25 @@ 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())
|
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
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)
|
global.SetGlobalConstant(true)
|
||||||
}
|
}
|
||||||
return global
|
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 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
предоставленный
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
предоставленный
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
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче