From 265e73ee14ebfedc027871cd153f0b90c6665070 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Fri, 17 Oct 2008 18:06:29 -0700 Subject: [PATCH] beginnings of reflection values. R=rsc DELTA=421 (357 added, 17 deleted, 47 changed) OCL=17388 CL=17401 --- usr/r/reflect/Makefile | 11 ++- usr/r/reflect/cast_amd64.s | 133 +++++++++++++++++++++++++++++++++++++ usr/r/reflect/gencast.sh | 36 ++++++++++ usr/r/reflect/main.go | 102 +++++++++++++++++++--------- usr/r/reflect/tostring.go | 77 ++++++++++++++++----- usr/r/reflect/type.go | 114 ++++++++++++++++++++++++++----- 6 files changed, 408 insertions(+), 65 deletions(-) create mode 100644 usr/r/reflect/cast_amd64.s create mode 100755 usr/r/reflect/gencast.sh diff --git a/usr/r/reflect/Makefile b/usr/r/reflect/Makefile index ffd1f14bcc..1d999f4e0a 100644 --- a/usr/r/reflect/Makefile +++ b/usr/r/reflect/Makefile @@ -3,7 +3,7 @@ # license that can be found in the LICENSE file. # DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m reflect tostring.go type.go +# gobuild -m reflect tostring.go type.go value.go cast_amd64.s O=6 GC=$(O)g CC=$(O)c -w @@ -32,16 +32,23 @@ clean: O1=\ type.$O\ + cast_amd64.$O\ O2=\ + value.$O\ + +O3=\ tostring.$O\ -$(PKG): a1 a2 +$(PKG): a1 a2 a3 a1: $(O1) $(AR) grc $(PKG) $(O1) a2: $(O2) $(AR) grc $(PKG) $(O2) +a3: $(O3) + $(AR) grc $(PKG) $(O3) $(O1): nuke $(O2): a1 +$(O3): a2 diff --git a/usr/r/reflect/cast_amd64.s b/usr/r/reflect/cast_amd64.s new file mode 100644 index 0000000000..1de31dd041 --- /dev/null +++ b/usr/r/reflect/cast_amd64.s @@ -0,0 +1,133 @@ +// Conversion operators - really just casts +// *** Created by gencast.sh - Do Not Edit *** + +TEXT reflect·AddrToPtrAddr(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·PtrAddrToAddr(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·AddrToPtrInt8(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·PtrInt8ToAddr(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·AddrToPtrInt16(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·PtrInt16ToAddr(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·AddrToPtrInt32(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·PtrInt32ToAddr(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·AddrToPtrInt64(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·PtrInt64ToAddr(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·AddrToPtrUint8(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·PtrUint8ToAddr(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·AddrToPtrUint16(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·PtrUint16ToAddr(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·AddrToPtrUint32(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·PtrUint32ToAddr(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·AddrToPtrUint64(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·PtrUint64ToAddr(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·AddrToPtrFloat32(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·PtrFloat32ToAddr(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·AddrToPtrFloat64(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·PtrFloat64ToAddr(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·AddrToPtrFloat80(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·PtrFloat80ToAddr(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·AddrToPtrString(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·PtrStringToAddr(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + diff --git a/usr/r/reflect/gencast.sh b/usr/r/reflect/gencast.sh new file mode 100755 index 0000000000..e3871a5316 --- /dev/null +++ b/usr/r/reflect/gencast.sh @@ -0,0 +1,36 @@ +#!/bin/bash +# Copyright 2009 The Go Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +awk ' +BEGIN { + print("// Conversion operators - really just casts") + print("// *** Created by gencast.sh - Do Not Edit ***\n")} +{ + print("TEXT reflect·AddrToPtr" $0 "(SB),7,$-8") + print("\tMOVQ 8(SP), AX") + print("\tMOVQ AX, 16(SP)") + print("\tRET") + print("") + print("TEXT reflect·Ptr" $0 "ToAddr(SB),7,$-8") + print("\tMOVQ 8(SP), AX") + print("\tMOVQ AX, 16(SP)") + print("\tRET") + print("") +} +' > cast_$GOARCH.s << '!' +Addr +Int8 +Int16 +Int32 +Int64 +Uint8 +Uint16 +Uint32 +Uint64 +Float32 +Float64 +Float80 +String +! diff --git a/usr/r/reflect/main.go b/usr/r/reflect/main.go index 0348cef9fe..1967ed7c39 100644 --- a/usr/r/reflect/main.go +++ b/usr/r/reflect/main.go @@ -8,37 +8,79 @@ import ( "reflect" ) +func typedump(s string) { + t := reflect.ParseTypeString(s); + print(reflect.TypeToString(t),"; size = ", t.Size(), "\n"); +} + +func valuedump(s string) { + t := reflect.ParseTypeString(s); + v := reflect.NewInitValue(t); + switch v.Kind() { + case reflect.Int8Kind: + v.(reflect.Int8Value).Put(8); + case reflect.Int16Kind: + v.(reflect.Int16Value).Put(16); + case reflect.Int32Kind: + v.(reflect.Int32Value).Put(32); + case reflect.Int64Kind: + v.(reflect.Int64Value).Put(64); + case reflect.Uint8Kind: + v.(reflect.Uint8Value).Put(8); + case reflect.Uint16Kind: + v.(reflect.Uint16Value).Put(16); + case reflect.Uint32Kind: + v.(reflect.Uint32Value).Put(32); + case reflect.Uint64Kind: + v.(reflect.Uint64Value).Put(64); + case reflect.Float32Kind: + v.(reflect.Float32Value).Put(320.0); + case reflect.Float64Kind: + v.(reflect.Float32Value).Put(640.0); + case reflect.StringKind: + v.(reflect.StringValue).Put("stringy cheese"); + } + print(s, " value = ", reflect.ValueToString(v), "\n"); +} + func main() { var s string; var t reflect.Type; - - t = reflect.ParseTypeString("int8"); - s = reflect.ToString(t); print(s, "\n"); - - t = reflect.ParseTypeString("**int8"); - s = reflect.ToString(t); print(s, "\n"); - - t = reflect.ParseTypeString("**P.integer"); - s = reflect.ToString(t); print(s, "\n"); - - t = reflect.ParseTypeString("[32]int32"); - s = reflect.ToString(t); print(s, "\n"); - - t = reflect.ParseTypeString("[]int8"); - s = reflect.ToString(t); print(s, "\n"); - - t = reflect.ParseTypeString("map[string]int32"); - s = reflect.ToString(t); print(s, "\n"); - - t = reflect.ParseTypeString("*chan<-string"); - s = reflect.ToString(t); print(s, "\n"); - - t = reflect.ParseTypeString("struct {c *chan *int32; d float32}"); - s = reflect.ToString(t); print(s, "\n"); - - t = reflect.ParseTypeString("*(a int8, b int32)"); - s = reflect.ToString(t); print(s, "\n"); - - t = reflect.ParseTypeString("struct {c *(? *chan *P.integer, ? *int8)}"); - s = reflect.ToString(t); print(s, "\n"); + + typedump("int8"); + typedump("int16"); + typedump("int32"); + typedump("int64"); + typedump("uint8"); + typedump("uint16"); + typedump("uint32"); + typedump("uint64"); + typedump("float32"); + typedump("float64"); + typedump("float80"); + typedump("int8"); + typedump("**int8"); + typedump("**P.integer"); + typedump("[32]int32"); + typedump("[]int8"); + typedump("*map[string]int32"); + typedump("*chan<-string"); + typedump("struct {c *chan *int32; d float32}"); + typedump("*(a int8, b int32)"); + typedump("struct {c *(? *chan *P.integer, ? *int8)}"); + typedump("struct {a int8; b int32}"); + typedump("struct {a int8; b int8; b int32}"); + typedump("struct {a int8; b int8; c int8; b int32}"); + typedump("struct {a int8; b int8; c int8; d int8; b int32}"); + typedump("struct {a int8; b int8; c int8; d int8; e int8; b int32}"); + + valuedump("int8"); + valuedump("int16"); + valuedump("int32"); + valuedump("int64"); + valuedump("uint8"); + valuedump("uint16"); + valuedump("uint32"); + valuedump("uint64"); + valuedump("string"); } diff --git a/usr/r/reflect/tostring.go b/usr/r/reflect/tostring.go index 09b6945a2a..0449a6e9e0 100644 --- a/usr/r/reflect/tostring.go +++ b/usr/r/reflect/tostring.go @@ -12,14 +12,15 @@ import ( "strings"; ) -export func ToString(typ Type) string +export func TypeToString(typ Type) string +export func ValueToString(val Value) string -func FieldsToString(t Type, sep string) string { +func TypeFieldsToString(t Type, sep string) string { s := t.(StructType); var str string; for i := 0; i < s.Len(); i++ { str1, t := s.Field(i); - str1 += " " + ToString(t); + str1 += " " + TypeToString(t); if i < s.Len() - 1 { str1 += sep + " "; } @@ -28,7 +29,7 @@ func FieldsToString(t Type, sep string) string { return str; } -func ToString(typ Type) string { +func TypeToString(typ Type) string { var str string; switch(typ.Kind()) { case MissingKind: @@ -59,7 +60,7 @@ func ToString(typ Type) string { return "string"; case PtrKind: p := typ.(PtrType); - return "*" + ToString(p.Sub()); + return "*" + TypeToString(p.Sub()); case ArrayKind: a := typ.(ArrayType); if a.Len() < 0 { @@ -67,11 +68,11 @@ func ToString(typ Type) string { } else { str = "[" + strings.itoa(a.Len()) + "]" } - return str + ToString(a.Elem()); + return str + TypeToString(a.Elem()); case MapKind: m := typ.(MapType); - str = "map[" + ToString(m.Key()) + "]"; - return str + ToString(m.Elem()); + str = "map[" + TypeToString(m.Key()) + "]"; + return str + TypeToString(m.Elem()); case ChanKind: c := typ.(ChanType); switch c.Dir() { @@ -82,23 +83,67 @@ func ToString(typ Type) string { case BothDir: str = "chan"; default: - panicln("reflect.ToString: unknown chan direction"); + panicln("reflect.TypeToString: unknown chan direction"); } - return str + ToString(c.Elem()); + return str + TypeToString(c.Elem()); case StructKind: - return "struct{" + FieldsToString(typ, ";") + "}"; + return "struct{" + TypeFieldsToString(typ, ";") + "}"; case InterfaceKind: - return "interface{" + FieldsToString(typ, ";") + "}"; + return "interface{" + TypeFieldsToString(typ, ";") + "}"; case FuncKind: f := typ.(FuncType); str = "func"; - str += "(" + FieldsToString(f.In(), ",") + ")"; + str += "(" + TypeFieldsToString(f.In(), ",") + ")"; if f.Out() != nil { - str += "(" + FieldsToString(f.Out(), ",") + ")"; + str += "(" + TypeFieldsToString(f.Out(), ",") + ")"; } return str; default: - panicln("reflect.ToString: can't print type ", typ.Kind()); + panicln("reflect.TypeToString: can't print type ", typ.Kind()); } - return "reflect.ToString: can't happen"; + return "reflect.TypeToString: can't happen"; +} + +// TODO: want an unsigned one too +func integer(v int64) string { + return strings.itol(v); +} + +func ValueToString(val Value) string { + var str string; + typ := val.Type(); + switch(val.Kind()) { + case MissingKind: + return "missing"; + case Int8Kind: + return integer(int64(val.(Int8Value).Get())); + case Int16Kind: + return integer(int64(val.(Int16Value).Get())); + case Int32Kind: + return integer(int64(val.(Int32Value).Get())); + case Int64Kind: + return integer(int64(val.(Int64Value).Get())); + case Uint8Kind: + return integer(int64(val.(Uint8Value).Get())); + case Uint16Kind: + return integer(int64(val.(Uint16Value).Get())); + case Uint32Kind: + return integer(int64(val.(Uint32Value).Get())); + case Uint64Kind: + return integer(int64(val.(Uint64Value).Get())); + case Float32Kind: + return "float32"; + case Float64Kind: + return "float64"; + case Float80Kind: + return "float80"; + case StringKind: + return val.(StringValue).Get(); + case PtrKind: + p := typ.(PtrType); + return ValueToString(p.Sub()); + default: + panicln("reflect.ValueToString: can't print type ", val.Kind()); + } + return "reflect.ValueToString: can't happen"; } diff --git a/usr/r/reflect/type.go b/usr/r/reflect/type.go index 965a3177b3..9ed6c75e9e 100644 --- a/usr/r/reflect/type.go +++ b/usr/r/reflect/type.go @@ -36,45 +36,58 @@ export const ( Uint8Kind; ) +var ptrsize int +var interfacesize int + var MissingString = "missing" // syntactic name for undefined type names -type Type interface { +export type Type interface { Kind() int; + Size() int; } +// -- Basic + type BasicType struct{ - kind int + kind int; + size int; } func (t *BasicType) Kind() int { return t.kind } -func NewBasicType(k int) Type { +func (t *BasicType) Size() int { + return t.size +} + +func NewBasicType(k, size int) Type { t := new(BasicType); t.kind = k; + t.size = size; return t; } -// Basic types +// Prebuilt basic types export var ( - Missing = NewBasicType(MissingKind); - Int8 = NewBasicType(Int8Kind); - Int16 = NewBasicType(Int16Kind); - Int32 = NewBasicType(Int32Kind); - Int64 = NewBasicType(Int64Kind); - Uint8 = NewBasicType(Uint8Kind); - Uint16 = NewBasicType(Uint16Kind); - Uint32 = NewBasicType(Uint32Kind); - Uint64 = NewBasicType(Uint64Kind); - Float32 = NewBasicType(Float32Kind); - Float64 = NewBasicType(Float64Kind); - Float80 = NewBasicType(Float80Kind); - String = NewBasicType(StringKind); + Missing = NewBasicType(MissingKind, 1); + Int8 = NewBasicType(Int8Kind, 1); + Int16 = NewBasicType(Int16Kind, 2); + Int32 = NewBasicType(Int32Kind, 4); + Int64 = NewBasicType(Int64Kind, 8); + Uint8 = NewBasicType(Uint8Kind, 1); + Uint16 = NewBasicType(Uint16Kind, 2); + Uint32 = NewBasicType(Uint32Kind, 4); + Uint64 = NewBasicType(Uint64Kind, 8); + Float32 = NewBasicType(Float32Kind, 4); + Float64 = NewBasicType(Float64Kind, 8); + Float80 = NewBasicType(Float80Kind, 10); // TODO: strange size? + String = NewBasicType(StringKind, 8); // implemented as a pointer ) // Stub types allow us to defer evaluating type names until needed. // If the name is empty, the type must be non-nil. + type StubType struct { name string; typ Type; @@ -99,6 +112,8 @@ func NewNamedStubType(n string) *StubType { return s; } +// -- Pointer + export type PtrType interface { Sub() Type } @@ -111,6 +126,10 @@ func (t *PtrTypeStruct) Kind() int { return PtrKind } +func (t *PtrTypeStruct) Size() int { + return ptrsize +} + func (t *PtrTypeStruct) Sub() Type { return t.sub.Get() } @@ -121,6 +140,8 @@ func NewPtrTypeStruct(sub *StubType) *PtrTypeStruct { return t; } +// -- Array + export type ArrayType interface { Len() int; Elem() Type; @@ -135,6 +156,13 @@ func (t *ArrayTypeStruct) Kind() int { return ArrayKind } +func (t *ArrayTypeStruct) Size() int { + if t.len < 0 { + return ptrsize // open arrays are pointers to structures + } + return t.len * t.elem.Get().Size(); +} + func (t *ArrayTypeStruct) Len() int { // -1 is open array? TODO return t.len @@ -151,6 +179,8 @@ func NewArrayTypeStruct(len int, elem *StubType) *ArrayTypeStruct { return t; } +// -- Map + export type MapType interface { Key() Type; Elem() Type; @@ -165,6 +195,11 @@ func (t *MapTypeStruct) Kind() int { return MapKind } +func (t *MapTypeStruct) Size() int { + panic("reflect.type: map.Size(): cannot happen"); + return 0 +} + func (t *MapTypeStruct) Key() Type { return t.key.Get() } @@ -180,6 +215,8 @@ func NewMapTypeStruct(key, elem *StubType) *MapTypeStruct { return t; } +// -- Chan + export type ChanType interface { Dir() int; Elem() Type; @@ -199,6 +236,11 @@ type ChanTypeStruct struct { func (t *ChanTypeStruct) Kind() int { return ChanKind } + +func (t *ChanTypeStruct) Size() int { + panic("reflect.type: chan.Size(): cannot happen"); + return 0 +} func (t *ChanTypeStruct) Dir() int { // -1 is open array? TODO @@ -216,6 +258,8 @@ func NewChanTypeStruct(dir int, elem *StubType) *ChanTypeStruct { return t; } +// -- Struct + export type StructType interface { Field(int) (name string, typ Type); Len() int; @@ -224,6 +268,7 @@ export type StructType interface { type Field struct { name string; typ *StubType; + size int; } type StructTypeStruct struct { @@ -234,6 +279,25 @@ func (t *StructTypeStruct) Kind() int { return StructKind } +// TODO: not portable; depends on 6g +func (t *StructTypeStruct) Size() int { + size := 0; + for i := 0; i < len(t.field); i++ { + elemsize := t.field[i].typ.Get().Size(); + // pad until at (elemsize mod 8) boundary + align := elemsize - 1; + if align > 7 { // BUG: we know structs are at 8-aligned + align = 7 + } + if align > 0 { + size = (size + align) & ^align; + } + size += elemsize; + } + size = (size + 7) & ^7; + return size; +} + func (t *StructTypeStruct) Field(i int) (name string, typ Type) { return t.field[i].name, t.field[i].typ.Get() } @@ -248,6 +312,8 @@ func NewStructTypeStruct(field *[]Field) *StructTypeStruct { return t; } +// -- Interface + export type InterfaceType interface { Field(int) (name string, typ Type); Len() int; @@ -275,6 +341,12 @@ func (t *InterfaceTypeStruct) Kind() int { return InterfaceKind } +func (t *InterfaceTypeStruct) Size() int { + return interfacesize +} + +// -- Func + export type FuncType interface { In() StructType; Out() StructType; @@ -289,6 +361,11 @@ func (t *FuncTypeStruct) Kind() int { return FuncKind } +func (t *FuncTypeStruct) Size() int { + panic("reflect.type: func.Size(): cannot happen"); + return 0 +} + func (t *FuncTypeStruct) In() StructType { return t.in } @@ -330,6 +407,9 @@ func Unlock() { } func init() { + ptrsize = 8; // TODO: compute this + interfacesize = 2*ptrsize; // TODO: compute this + lockchan = new(chan bool, 1); // unlocked at creation - buffer is empty Lock(); // not necessary because of init ordering but be safe.