diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2016-07-22 18:15:38 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2016-07-22 18:15:38 +0000 |
commit | 22b955cca564a9a3a5b8c9d9dd1e295b7943c128 (patch) | |
tree | abdbd898676e1f853fca2d7e031d105d7ebcf676 /libgo/go/reflect | |
parent | 9d04a3af4c6491536badf6bde9707c907e4d196b (diff) | |
download | gcc-22b955cca564a9a3a5b8c9d9dd1e295b7943c128.zip gcc-22b955cca564a9a3a5b8c9d9dd1e295b7943c128.tar.gz gcc-22b955cca564a9a3a5b8c9d9dd1e295b7943c128.tar.bz2 |
libgo: update to go1.7rc3
Reviewed-on: https://go-review.googlesource.com/25150
From-SVN: r238662
Diffstat (limited to 'libgo/go/reflect')
-rw-r--r-- | libgo/go/reflect/all_test.go | 908 | ||||
-rw-r--r-- | libgo/go/reflect/deepequal.go | 2 | ||||
-rw-r--r-- | libgo/go/reflect/example_test.go | 30 | ||||
-rw-r--r-- | libgo/go/reflect/export_test.go | 44 | ||||
-rw-r--r-- | libgo/go/reflect/makefunc.go | 2 | ||||
-rw-r--r-- | libgo/go/reflect/set_test.go | 4 | ||||
-rw-r--r-- | libgo/go/reflect/type.go | 331 | ||||
-rw-r--r-- | libgo/go/reflect/value.go | 67 |
8 files changed, 1244 insertions, 144 deletions
diff --git a/libgo/go/reflect/all_test.go b/libgo/go/reflect/all_test.go index b8e7cd8..7045e44 100644 --- a/libgo/go/reflect/all_test.go +++ b/libgo/go/reflect/all_test.go @@ -21,6 +21,8 @@ import ( "sync" "testing" "time" + "unicode" + "unicode/utf8" "unsafe" ) @@ -44,16 +46,12 @@ type pair struct { s string } -func isDigit(c uint8) bool { return '0' <= c && c <= '9' } - func assert(t *testing.T, s, want string) { if s != want { t.Errorf("have %#q want %#q", s, want) } } -func typestring(i interface{}) string { return TypeOf(i).String() } - var typeTests = []pair{ {struct{ x int }{}, "int"}, {struct{ x int8 }{}, "int8"}, @@ -1891,32 +1889,6 @@ type Tbigp [2]uintptr func (p *Tbigp) M(x int, b byte) (byte, int) { return b, x + int(p[0]) + int(p[1]) } -// Again, with an unexported method. - -type tsmallv byte - -func (v tsmallv) m(x int, b byte) (byte, int) { return b, x + int(v) } - -type tsmallp byte - -func (p *tsmallp) m(x int, b byte) (byte, int) { return b, x + int(*p) } - -type twordv uintptr - -func (v twordv) m(x int, b byte) (byte, int) { return b, x + int(v) } - -type twordp uintptr - -func (p *twordp) m(x int, b byte) (byte, int) { return b, x + int(*p) } - -type tbigv [2]uintptr - -func (v tbigv) m(x int, b byte) (byte, int) { return b, x + int(v[0]) + int(v[1]) } - -type tbigp [2]uintptr - -func (p *tbigp) m(x int, b byte) (byte, int) { return b, x + int(p[0]) + int(p[1]) } - type tinter interface { m(int, byte) (byte, int) } @@ -1960,7 +1932,6 @@ func TestMethod5(t *testing.T) { } var TinterType = TypeOf(new(Tinter)).Elem() - var tinterType = TypeOf(new(tinter)).Elem() CheckI := func(name string, i interface{}, inc int) { v := ValueOf(i) @@ -2002,39 +1973,6 @@ func TestMethod5(t *testing.T) { CheckI("t1", t1, 40) CheckI("&t1", &t1, 40) - methodShouldPanic := func(name string, i interface{}) { - v := ValueOf(i) - m := v.Method(0) - shouldPanic(func() { m.Call([]Value{ValueOf(1000), ValueOf(byte(99))}) }) - shouldPanic(func() { m.Interface() }) - - v = v.Convert(tinterType) - m = v.Method(0) - shouldPanic(func() { m.Call([]Value{ValueOf(1000), ValueOf(byte(99))}) }) - shouldPanic(func() { m.Interface() }) - } - - _sv := tsmallv(1) - methodShouldPanic("_sv", _sv) - methodShouldPanic("&_sv", &_sv) - - _sp := tsmallp(2) - methodShouldPanic("&_sp", &_sp) - - _wv := twordv(3) - methodShouldPanic("_wv", _wv) - methodShouldPanic("&_wv", &_wv) - - _wp := twordp(4) - methodShouldPanic("&_wp", &_wp) - - _bv := tbigv([2]uintptr{5, 6}) - methodShouldPanic("_bv", _bv) - methodShouldPanic("&_bv", &_bv) - - _bp := tbigp([2]uintptr{7, 8}) - methodShouldPanic("&_bp", &_bp) - var tnil Tinter vnil := ValueOf(&tnil).Elem() shouldPanic(func() { vnil.Method(0) }) @@ -2323,6 +2261,8 @@ func TestImportPath(t *testing.T) { {TypeOf((*int64)(nil)), ""}, {TypeOf(map[string]int{}), ""}, {TypeOf((*error)(nil)).Elem(), ""}, + {TypeOf((*Point)(nil)), ""}, + {TypeOf((*Point)(nil)).Elem(), "reflect_test"}, } for _, test := range tests { if path := test.t.PkgPath(); path != test.path { @@ -2331,6 +2271,33 @@ func TestImportPath(t *testing.T) { } } +func TestFieldPkgPath(t *testing.T) { + typ := TypeOf(struct { + Exported string + unexported string + OtherPkgFields + }{}) + for _, test := range []struct { + index []int + pkgPath string + anonymous bool + }{ + {[]int{0}, "", false}, // Exported + {[]int{1}, "reflect_test", false}, // unexported + {[]int{2}, "", true}, // OtherPkgFields + {[]int{2, 0}, "", false}, // OtherExported + {[]int{2, 1}, "reflect", false}, // otherUnexported + } { + f := typ.FieldByIndex(test.index) + if got, want := f.PkgPath, test.pkgPath; got != want { + t.Errorf("Field(%d).PkgPath = %q, want %q", test.index, got, want) + } + if got, want := f.Anonymous, test.anonymous; got != want { + t.Errorf("Field(%d).Anonymous = %v, want %v", test.index, got, want) + } + } +} + func TestVariadicType(t *testing.T) { // Test example from Type documentation. var f func(x int, y ...float64) @@ -2363,14 +2330,14 @@ type outer struct { inner } -func (*inner) m() {} -func (*outer) m() {} +func (*inner) M() {} +func (*outer) M() {} func TestNestedMethods(t *testing.T) { t.Skip("fails on gccgo due to function wrappers") typ := TypeOf((*outer)(nil)) - if typ.NumMethod() != 1 || typ.Method(0).Func.Pointer() != ValueOf((*outer).m).Pointer() { - t.Errorf("Wrong method table for outer: (m=%p)", (*outer).m) + if typ.NumMethod() != 1 || typ.Method(0).Func.Pointer() != ValueOf((*outer).M).Pointer() { + t.Errorf("Wrong method table for outer: (M=%p)", (*outer).M) for i := 0; i < typ.NumMethod(); i++ { m := typ.Method(i) t.Errorf("\t%d: %s %#x\n", i, m.Name, m.Func.Pointer()) @@ -2378,6 +2345,25 @@ func TestNestedMethods(t *testing.T) { } } +type unexp struct{} + +func (*unexp) f() (int32, int8) { return 7, 7 } +func (*unexp) g() (int64, int8) { return 8, 8 } + +type unexpI interface { + f() (int32, int8) +} + +var unexpi unexpI = new(unexp) + +func TestUnexportedMethods(t *testing.T) { + typ := TypeOf(unexpi) + + if got := typ.NumMethod(); got != 0 { + t.Errorf("NumMethod=%d, want 0 satisfied methods", got) + } +} + type InnerInt struct { X int } @@ -2419,6 +2405,17 @@ func TestEmbeddedMethods(t *testing.T) { } } +type FuncDDD func(...interface{}) error + +func (f FuncDDD) M() {} + +func TestNumMethodOnDDD(t *testing.T) { + rv := ValueOf((FuncDDD)(nil)) + if n := rv.NumMethod(); n != 1 { + t.Fatalf("NumMethod()=%d, want 1", n) + } +} + func TestPtrTo(t *testing.T) { var i int @@ -2861,12 +2858,11 @@ func TestUnexported(t *testing.T) { isValid(v.Elem().Field(1)) isValid(v.Elem().FieldByName("x")) isValid(v.Elem().FieldByName("y")) - isValid(v.Type().Method(0).Func) shouldPanic(func() { v.Elem().Field(0).Interface() }) shouldPanic(func() { v.Elem().Field(1).Interface() }) shouldPanic(func() { v.Elem().FieldByName("x").Interface() }) shouldPanic(func() { v.Elem().FieldByName("y").Interface() }) - shouldPanic(func() { v.Type().Method(0).Func.Interface() }) + shouldPanic(func() { v.Type().Method(0) }) } func TestSetPanic(t *testing.T) { @@ -3846,6 +3842,9 @@ func TestSliceOf(t *testing.T) { // check construction and use of type not in binary type T int st := SliceOf(TypeOf(T(1))) + if got, want := st.String(), "[]reflect_test.T"; got != want { + t.Errorf("SliceOf(T(1)).String()=%q, want %q", got, want) + } v := MakeSlice(st, 10, 10) runtime.GC() for i := 0; i < v.Len(); i++ { @@ -3910,6 +3909,591 @@ func TestSliceOfGC(t *testing.T) { } } +func TestStructOf(t *testing.T) { + // check construction and use of type not in binary + fields := []StructField{ + StructField{ + Name: "S", + Tag: "s", + Type: TypeOf(""), + }, + StructField{ + Name: "X", + Tag: "x", + Type: TypeOf(byte(0)), + }, + StructField{ + Name: "Y", + Type: TypeOf(uint64(0)), + }, + StructField{ + Name: "Z", + Type: TypeOf([3]uint16{}), + }, + } + + st := StructOf(fields) + v := New(st).Elem() + runtime.GC() + v.FieldByName("X").Set(ValueOf(byte(2))) + v.FieldByIndex([]int{1}).Set(ValueOf(byte(1))) + runtime.GC() + + s := fmt.Sprint(v.Interface()) + want := `{ 1 0 [0 0 0]}` + if s != want { + t.Errorf("constructed struct = %s, want %s", s, want) + } + const stStr = `struct { S string "s"; X uint8 "x"; Y uint64; Z [3]uint16 }` + if got, want := st.String(), stStr; got != want { + t.Errorf("StructOf(fields).String()=%q, want %q", got, want) + } + + // check the size, alignment and field offsets + stt := TypeOf(struct { + String string + X byte + Y uint64 + Z [3]uint16 + }{}) + if st.Size() != stt.Size() { + t.Errorf("constructed struct size = %v, want %v", st.Size(), stt.Size()) + } + if st.Align() != stt.Align() { + t.Errorf("constructed struct align = %v, want %v", st.Align(), stt.Align()) + } + if st.FieldAlign() != stt.FieldAlign() { + t.Errorf("constructed struct field align = %v, want %v", st.FieldAlign(), stt.FieldAlign()) + } + for i := 0; i < st.NumField(); i++ { + o1 := st.Field(i).Offset + o2 := stt.Field(i).Offset + if o1 != o2 { + t.Errorf("constructed struct field %v offset = %v, want %v", i, o1, o2) + } + } + + // check duplicate names + shouldPanic(func() { + StructOf([]StructField{ + StructField{Name: "string", Type: TypeOf("")}, + StructField{Name: "string", Type: TypeOf("")}, + }) + }) + shouldPanic(func() { + StructOf([]StructField{ + StructField{Type: TypeOf("")}, + StructField{Name: "string", Type: TypeOf("")}, + }) + }) + shouldPanic(func() { + StructOf([]StructField{ + StructField{Type: TypeOf("")}, + StructField{Type: TypeOf("")}, + }) + }) + // check that type already in binary is found + checkSameType(t, Zero(StructOf(fields[2:3])).Interface(), struct{ Y uint64 }{}) +} + +func TestStructOfExportRules(t *testing.T) { + type S1 struct{} + type s2 struct{} + type ΦType struct{} + type φType struct{} + + testPanic := func(i int, mustPanic bool, f func()) { + defer func() { + err := recover() + if err == nil && mustPanic { + t.Errorf("test-%d did not panic", i) + } + if err != nil && !mustPanic { + t.Errorf("test-%d panicked: %v\n", i, err) + } + }() + f() + } + + for i, test := range []struct { + field StructField + mustPanic bool + exported bool + }{ + { + field: StructField{Name: "", Type: TypeOf(S1{})}, + mustPanic: false, + exported: true, + }, + { + field: StructField{Name: "", Type: TypeOf((*S1)(nil))}, + mustPanic: false, + exported: true, + }, + { + field: StructField{Name: "", Type: TypeOf(s2{})}, + mustPanic: false, + exported: false, + }, + { + field: StructField{Name: "", Type: TypeOf((*s2)(nil))}, + mustPanic: false, + exported: false, + }, + { + field: StructField{Name: "", Type: TypeOf(S1{}), PkgPath: "other/pkg"}, + mustPanic: true, + exported: true, + }, + { + field: StructField{Name: "", Type: TypeOf((*S1)(nil)), PkgPath: "other/pkg"}, + mustPanic: true, + exported: true, + }, + { + field: StructField{Name: "", Type: TypeOf(s2{}), PkgPath: "other/pkg"}, + mustPanic: true, + exported: false, + }, + { + field: StructField{Name: "", Type: TypeOf((*s2)(nil)), PkgPath: "other/pkg"}, + mustPanic: true, + exported: false, + }, + { + field: StructField{Name: "S", Type: TypeOf(S1{})}, + mustPanic: false, + exported: true, + }, + { + field: StructField{Name: "S", Type: TypeOf((*S1)(nil))}, + mustPanic: false, + exported: true, + }, + { + field: StructField{Name: "S", Type: TypeOf(s2{})}, + mustPanic: false, + exported: true, + }, + { + field: StructField{Name: "S", Type: TypeOf((*s2)(nil))}, + mustPanic: false, + exported: true, + }, + { + field: StructField{Name: "s", Type: TypeOf(S1{})}, + mustPanic: true, + exported: false, + }, + { + field: StructField{Name: "s", Type: TypeOf((*S1)(nil))}, + mustPanic: true, + exported: false, + }, + { + field: StructField{Name: "s", Type: TypeOf(s2{})}, + mustPanic: true, + exported: false, + }, + { + field: StructField{Name: "s", Type: TypeOf((*s2)(nil))}, + mustPanic: true, + exported: false, + }, + { + field: StructField{Name: "s", Type: TypeOf(S1{}), PkgPath: "other/pkg"}, + mustPanic: true, // TODO(sbinet): creating a name with a package path + exported: false, + }, + { + field: StructField{Name: "s", Type: TypeOf((*S1)(nil)), PkgPath: "other/pkg"}, + mustPanic: true, // TODO(sbinet): creating a name with a package path + exported: false, + }, + { + field: StructField{Name: "s", Type: TypeOf(s2{}), PkgPath: "other/pkg"}, + mustPanic: true, // TODO(sbinet): creating a name with a package path + exported: false, + }, + { + field: StructField{Name: "s", Type: TypeOf((*s2)(nil)), PkgPath: "other/pkg"}, + mustPanic: true, // TODO(sbinet): creating a name with a package path + exported: false, + }, + { + field: StructField{Name: "", Type: TypeOf(ΦType{})}, + mustPanic: false, + exported: true, + }, + { + field: StructField{Name: "", Type: TypeOf(φType{})}, + mustPanic: false, + exported: false, + }, + { + field: StructField{Name: "Φ", Type: TypeOf(0)}, + mustPanic: false, + exported: true, + }, + { + field: StructField{Name: "φ", Type: TypeOf(0)}, + mustPanic: false, + exported: false, + }, + } { + testPanic(i, test.mustPanic, func() { + typ := StructOf([]StructField{test.field}) + if typ == nil { + t.Errorf("test-%d: error creating struct type", i) + return + } + field := typ.Field(0) + n := field.Name + if n == "" { + n = field.Type.Name() + } + exported := isExported(n) + if exported != test.exported { + t.Errorf("test-%d: got exported=%v want exported=%v", i, exported, test.exported) + } + }) + } +} + +// isExported reports whether name is an exported Go symbol +// (that is, whether it begins with an upper-case letter). +// +func isExported(name string) bool { + ch, _ := utf8.DecodeRuneInString(name) + return unicode.IsUpper(ch) +} + +func TestStructOfGC(t *testing.T) { + type T *uintptr + tt := TypeOf(T(nil)) + fields := []StructField{ + {Name: "X", Type: tt}, + {Name: "Y", Type: tt}, + } + st := StructOf(fields) + + const n = 10000 + var x []interface{} + for i := 0; i < n; i++ { + v := New(st).Elem() + for j := 0; j < v.NumField(); j++ { + p := new(uintptr) + *p = uintptr(i*n + j) + v.Field(j).Set(ValueOf(p).Convert(tt)) + } + x = append(x, v.Interface()) + } + runtime.GC() + + for i, xi := range x { + v := ValueOf(xi) + for j := 0; j < v.NumField(); j++ { + k := v.Field(j).Elem().Interface() + if k != uintptr(i*n+j) { + t.Errorf("lost x[%d].%c = %d, want %d", i, "XY"[j], k, i*n+j) + } + } + } +} + +func TestStructOfAlg(t *testing.T) { + st := StructOf([]StructField{{Name: "X", Tag: "x", Type: TypeOf(int(0))}}) + v1 := New(st).Elem() + v2 := New(st).Elem() + if !DeepEqual(v1.Interface(), v1.Interface()) { + t.Errorf("constructed struct %v not equal to itself", v1.Interface()) + } + v1.FieldByName("X").Set(ValueOf(int(1))) + if i1, i2 := v1.Interface(), v2.Interface(); DeepEqual(i1, i2) { + t.Errorf("constructed structs %v and %v should not be equal", i1, i2) + } + + st = StructOf([]StructField{{Name: "X", Tag: "x", Type: TypeOf([]int(nil))}}) + v1 = New(st).Elem() + shouldPanic(func() { _ = v1.Interface() == v1.Interface() }) +} + +func TestStructOfGenericAlg(t *testing.T) { + st1 := StructOf([]StructField{ + {Name: "X", Tag: "x", Type: TypeOf(int64(0))}, + {Name: "Y", Type: TypeOf(string(""))}, + }) + st := StructOf([]StructField{ + {Name: "S0", Type: st1}, + {Name: "S1", Type: st1}, + }) + + for _, table := range []struct { + rt Type + idx []int + }{ + { + rt: st, + idx: []int{0, 1}, + }, + { + rt: st1, + idx: []int{1}, + }, + { + rt: StructOf( + []StructField{ + {Name: "XX", Type: TypeOf([0]int{})}, + {Name: "YY", Type: TypeOf("")}, + }, + ), + idx: []int{1}, + }, + { + rt: StructOf( + []StructField{ + {Name: "XX", Type: TypeOf([0]int{})}, + {Name: "YY", Type: TypeOf("")}, + {Name: "ZZ", Type: TypeOf([2]int{})}, + }, + ), + idx: []int{1}, + }, + { + rt: StructOf( + []StructField{ + {Name: "XX", Type: TypeOf([1]int{})}, + {Name: "YY", Type: TypeOf("")}, + }, + ), + idx: []int{1}, + }, + { + rt: StructOf( + []StructField{ + {Name: "XX", Type: TypeOf([1]int{})}, + {Name: "YY", Type: TypeOf("")}, + {Name: "ZZ", Type: TypeOf([1]int{})}, + }, + ), + idx: []int{1}, + }, + { + rt: StructOf( + []StructField{ + {Name: "XX", Type: TypeOf([2]int{})}, + {Name: "YY", Type: TypeOf("")}, + {Name: "ZZ", Type: TypeOf([2]int{})}, + }, + ), + idx: []int{1}, + }, + { + rt: StructOf( + []StructField{ + {Name: "XX", Type: TypeOf(int64(0))}, + {Name: "YY", Type: TypeOf(byte(0))}, + {Name: "ZZ", Type: TypeOf("")}, + }, + ), + idx: []int{2}, + }, + { + rt: StructOf( + []StructField{ + {Name: "XX", Type: TypeOf(int64(0))}, + {Name: "YY", Type: TypeOf(int64(0))}, + {Name: "ZZ", Type: TypeOf("")}, + {Name: "AA", Type: TypeOf([1]int64{})}, + }, + ), + idx: []int{2}, + }, + } { + v1 := New(table.rt).Elem() + v2 := New(table.rt).Elem() + + if !DeepEqual(v1.Interface(), v1.Interface()) { + t.Errorf("constructed struct %v not equal to itself", v1.Interface()) + } + + v1.FieldByIndex(table.idx).Set(ValueOf("abc")) + v2.FieldByIndex(table.idx).Set(ValueOf("def")) + if i1, i2 := v1.Interface(), v2.Interface(); DeepEqual(i1, i2) { + t.Errorf("constructed structs %v and %v should not be equal", i1, i2) + } + + abc := "abc" + v1.FieldByIndex(table.idx).Set(ValueOf(abc)) + val := "+" + abc + "-" + v2.FieldByIndex(table.idx).Set(ValueOf(val[1:4])) + if i1, i2 := v1.Interface(), v2.Interface(); !DeepEqual(i1, i2) { + t.Errorf("constructed structs %v and %v should be equal", i1, i2) + } + + // Test hash + m := MakeMap(MapOf(table.rt, TypeOf(int(0)))) + m.SetMapIndex(v1, ValueOf(1)) + if i1, i2 := v1.Interface(), v2.Interface(); !m.MapIndex(v2).IsValid() { + t.Errorf("constructed structs %#v and %#v have different hashes", i1, i2) + } + + v2.FieldByIndex(table.idx).Set(ValueOf("abc")) + if i1, i2 := v1.Interface(), v2.Interface(); !DeepEqual(i1, i2) { + t.Errorf("constructed structs %v and %v should be equal", i1, i2) + } + + if i1, i2 := v1.Interface(), v2.Interface(); !m.MapIndex(v2).IsValid() { + t.Errorf("constructed structs %v and %v have different hashes", i1, i2) + } + } +} + +/* +gccgo does not use the same directiface settings as gc. + +func TestStructOfDirectIface(t *testing.T) { + { + type T struct{ X [1]*byte } + i1 := Zero(TypeOf(T{})).Interface() + v1 := ValueOf(&i1).Elem() + p1 := v1.InterfaceData()[1] + + i2 := Zero(StructOf([]StructField{ + { + Name: "X", + Type: ArrayOf(1, TypeOf((*int8)(nil))), + }, + })).Interface() + v2 := ValueOf(&i2).Elem() + p2 := v2.InterfaceData()[1] + + if p1 != 0 { + t.Errorf("got p1=%v. want=%v", p1, nil) + } + + if p2 != 0 { + t.Errorf("got p2=%v. want=%v", p2, nil) + } + } + { + type T struct{ X [0]*byte } + i1 := Zero(TypeOf(T{})).Interface() + v1 := ValueOf(&i1).Elem() + p1 := v1.InterfaceData()[1] + + i2 := Zero(StructOf([]StructField{ + { + Name: "X", + Type: ArrayOf(0, TypeOf((*int8)(nil))), + }, + })).Interface() + v2 := ValueOf(&i2).Elem() + p2 := v2.InterfaceData()[1] + + if p1 == 0 { + t.Errorf("got p1=%v. want=not-%v", p1, nil) + } + + if p2 == 0 { + t.Errorf("got p2=%v. want=not-%v", p2, nil) + } + } +} +*/ + +type StructI int + +func (i StructI) Get() int { return int(i) } + +type StructIPtr int + +func (i *StructIPtr) Get() int { return int(*i) } + +/* +gccgo does not yet support StructOf with methods. + +func TestStructOfWithInterface(t *testing.T) { + const want = 42 + type Iface interface { + Get() int + } + for i, table := range []struct { + typ Type + val Value + impl bool + }{ + { + typ: TypeOf(StructI(want)), + val: ValueOf(StructI(want)), + impl: true, + }, + { + typ: PtrTo(TypeOf(StructI(want))), + val: ValueOf(func() interface{} { + v := StructI(want) + return &v + }()), + impl: true, + }, + { + typ: PtrTo(TypeOf(StructIPtr(want))), + val: ValueOf(func() interface{} { + v := StructIPtr(want) + return &v + }()), + impl: true, + }, + { + typ: TypeOf(StructIPtr(want)), + val: ValueOf(StructIPtr(want)), + impl: false, + }, + // { + // typ: TypeOf((*Iface)(nil)).Elem(), // FIXME(sbinet): fix method.ifn/tfn + // val: ValueOf(StructI(want)), + // impl: true, + // }, + } { + rt := StructOf( + []StructField{ + { + Name: "", + PkgPath: "", + Type: table.typ, + }, + }, + ) + rv := New(rt).Elem() + rv.Field(0).Set(table.val) + + if _, ok := rv.Interface().(Iface); ok != table.impl { + if table.impl { + t.Errorf("test-%d: type=%v fails to implement Iface.\n", i, table.typ) + } else { + t.Errorf("test-%d: type=%v should NOT implement Iface\n", i, table.typ) + } + continue + } + + if !table.impl { + continue + } + + v := rv.Interface().(Iface).Get() + if v != want { + t.Errorf("test-%d: x.Get()=%v. want=%v\n", i, v, want) + } + + fct := rv.MethodByName("Get") + out := fct.Call(nil) + if !DeepEqual(out[0].Interface(), want) { + t.Errorf("test-%d: x.Get()=%v. want=%v\n", i, out[0].Interface(), want) + } + } +} +*/ + func TestChanOf(t *testing.T) { // check construction and use of type not in binary type T string @@ -4116,7 +4700,7 @@ func TestFuncOf(t *testing.T) { if len(args) != 1 { t.Errorf("args == %v, want exactly one arg", args) } else if args[0].Type() != TypeOf(K("")) { - t.Errorf("args[0] is type %v, want %v", args[0].Type, TypeOf(K(""))) + t.Errorf("args[0] is type %v, want %v", args[0].Type(), TypeOf(K(""))) } else if args[0].String() != "gopher" { t.Errorf("args[0] = %q, want %q", args[0].String(), "gopher") } @@ -4128,7 +4712,7 @@ func TestFuncOf(t *testing.T) { if len(outs) != 1 { t.Fatalf("v.Call returned %v, want exactly one result", outs) } else if outs[0].Type() != TypeOf(V(0)) { - t.Fatalf("c.Call[0] is type %v, want %v", outs[0].Type, TypeOf(V(0))) + t.Fatalf("c.Call[0] is type %v, want %v", outs[0].Type(), TypeOf(V(0))) } f := outs[0].Float() if f != 3.14 { @@ -4479,7 +5063,7 @@ func TestFieldByIndexNil(t *testing.T) { // off the stack into the frame will store an *Inner there, and then if a garbage collection // happens to scan that argument frame before it is discarded, it will scan the *Inner // memory as if it were an *Outer. If the two have different memory layouts, the -// collection will intepret the memory incorrectly. +// collection will interpret the memory incorrectly. // // One such possible incorrect interpretation is to treat two arbitrary memory words // (Inner.P1 and Inner.P2 below) as an interface (Outer.R below). Because interpreting @@ -4555,7 +5139,7 @@ func useStack(n int) { type Impl struct{} -func (Impl) f() {} +func (Impl) F() {} func TestValueString(t *testing.T) { rv := ValueOf(Impl{}) @@ -4589,6 +5173,41 @@ func TestLargeGCProg(t *testing.T) { fv.Call([]Value{ValueOf([256]*byte{})}) } +func fieldIndexRecover(t Type, i int) (recovered interface{}) { + defer func() { + recovered = recover() + }() + + t.Field(i) + return +} + +// Issue 15046. +func TestTypeFieldOutOfRangePanic(t *testing.T) { + typ := TypeOf(struct{ X int }{10}) + testIndices := [...]struct { + i int + mustPanic bool + }{ + 0: {-2, true}, + 1: {0, false}, + 2: {1, true}, + 3: {1 << 10, true}, + } + for i, tt := range testIndices { + recoveredErr := fieldIndexRecover(typ, tt.i) + if tt.mustPanic { + if recoveredErr == nil { + t.Errorf("#%d: fieldIndex %d expected to panic", i, tt.i) + } + } else { + if recoveredErr != nil { + t.Errorf("#%d: got err=%v, expected no panic", i, recoveredErr) + } + } + } +} + // Issue 9179. func TestCallGC(t *testing.T) { f := func(a, b, c, d, e string) { @@ -4716,7 +5335,7 @@ func init() { 2 * PtrSize, []byte{1}, []byte{1}, - // Note: this one is tricky, as the receiver is not a pointer. But we + // Note: this one is tricky, as the receiver is not a pointer. But we // pass the receiver by reference to the autogenerated pointer-receiver // version of the function. }) @@ -4768,6 +5387,9 @@ func verifyGCBitsSlice(t *testing.T, typ Type, cap int, bits []byte) { for len(bits) > 2 && bits[len(bits)-1] == 0 { bits = bits[:len(bits)-1] } + if len(bits) == 2 && bits[0] == 0 && bits[1] == 0 { + bits = bits[:0] + } if !bytes.Equal(heapBits, bits) { t.Errorf("heapBits incorrect for make(%v, 0, %v)\nhave %v\nwant %v", typ, cap, heapBits, bits) } @@ -5027,6 +5649,140 @@ func TestChanAlloc(t *testing.T) { t.Errorf("allocs per chan send/recv: want 1 got %f", allocs) } // Note: there is one allocation in reflect.recv which seems to be - // a limitation of escape analysis. If that is ever fixed the + // a limitation of escape analysis. If that is ever fixed the // allocs < 0.5 condition will trigger and this test should be fixed. } + +type TheNameOfThisTypeIsExactly255BytesLongSoWhenTheCompilerPrependsTheReflectTestPackageNameAndExtraStarTheLinkerRuntimeAndReflectPackagesWillHaveToCorrectlyDecodeTheSecondLengthByte0123456789_0123456789_0123456789_0123456789_0123456789_012345678 int + +type nameTest struct { + v interface{} + want string +} + +var nameTests = []nameTest{ + {(*int32)(nil), "int32"}, + {(*D1)(nil), "D1"}, + {(*[]D1)(nil), ""}, + {(*chan D1)(nil), ""}, + {(*func() D1)(nil), ""}, + {(*<-chan D1)(nil), ""}, + {(*chan<- D1)(nil), ""}, + {(*interface{})(nil), ""}, + {(*interface { + F() + })(nil), ""}, + {(*TheNameOfThisTypeIsExactly255BytesLongSoWhenTheCompilerPrependsTheReflectTestPackageNameAndExtraStarTheLinkerRuntimeAndReflectPackagesWillHaveToCorrectlyDecodeTheSecondLengthByte0123456789_0123456789_0123456789_0123456789_0123456789_012345678)(nil), "TheNameOfThisTypeIsExactly255BytesLongSoWhenTheCompilerPrependsTheReflectTestPackageNameAndExtraStarTheLinkerRuntimeAndReflectPackagesWillHaveToCorrectlyDecodeTheSecondLengthByte0123456789_0123456789_0123456789_0123456789_0123456789_012345678"}, +} + +func TestNames(t *testing.T) { + for _, test := range nameTests { + typ := TypeOf(test.v).Elem() + if got := typ.Name(); got != test.want { + t.Errorf("%v Name()=%q, want %q", typ, got, test.want) + } + } +} + +/* +gccgo doesn't really record whether a type is exported. +It's not in the reflect API anyhow. + +func TestExported(t *testing.T) { + type ΦExported struct{} + type φUnexported struct{} + type BigP *big + type P int + type p *P + type P2 p + type p3 p + + type exportTest struct { + v interface{} + want bool + } + exportTests := []exportTest{ + {D1{}, true}, + {(*D1)(nil), true}, + {big{}, false}, + {(*big)(nil), false}, + {(BigP)(nil), true}, + {(*BigP)(nil), true}, + {ΦExported{}, true}, + {φUnexported{}, false}, + {P(0), true}, + {(p)(nil), false}, + {(P2)(nil), true}, + {(p3)(nil), false}, + } + + for i, test := range exportTests { + typ := TypeOf(test.v) + if got := IsExported(typ); got != test.want { + t.Errorf("%d: %s exported=%v, want %v", i, typ.Name(), got, test.want) + } + } +} +*/ + +type embed struct { + EmbedWithUnexpMeth +} + +/* +func TestNameBytesAreAligned(t *testing.T) { + typ := TypeOf(embed{}) + b := FirstMethodNameBytes(typ) + v := uintptr(unsafe.Pointer(b)) + if v%unsafe.Alignof((*byte)(nil)) != 0 { + t.Errorf("reflect.name.bytes pointer is not aligned: %x", v) + } +} +*/ + +func TestTypeStrings(t *testing.T) { + type stringTest struct { + typ Type + want string + } + stringTests := []stringTest{ + {TypeOf(func(int) {}), "func(int)"}, + {FuncOf([]Type{TypeOf(int(0))}, nil, false), "func(int)"}, + {TypeOf(XM{}), "reflect_test.XM"}, + {TypeOf(new(XM)), "*reflect_test.XM"}, + {TypeOf(new(XM).String), "func() string"}, + {TypeOf(new(XM)).Method(0).Type, "func(*reflect_test.XM) string"}, + } + + for i, test := range stringTests { + if got, want := test.typ.String(), test.want; got != want { + t.Errorf("type %d String()=%q, want %q", i, got, want) + } + } +} + +/* +gccgo does not have resolveReflectName. + +func TestOffsetLock(t *testing.T) { + var wg sync.WaitGroup + for i := 0; i < 4; i++ { + i := i + wg.Add(1) + go func() { + for j := 0; j < 50; j++ { + ResolveReflectName(fmt.Sprintf("OffsetLockName:%d:%d", i, j)) + } + wg.Done() + }() + } + wg.Wait() +} +*/ + +func BenchmarkNew(b *testing.B) { + v := TypeOf(XM{}) + for i := 0; i < b.N; i++ { + New(v) + } +} diff --git a/libgo/go/reflect/deepequal.go b/libgo/go/reflect/deepequal.go index 3743e80..9770358 100644 --- a/libgo/go/reflect/deepequal.go +++ b/libgo/go/reflect/deepequal.go @@ -9,7 +9,7 @@ package reflect import "unsafe" // During deepValueEqual, must keep track of checks that are -// in progress. The comparison algorithm assumes that all +// in progress. The comparison algorithm assumes that all // checks in progress are true when it reencounters them. // Visited comparisons are stored in a map indexed by visit. type visit struct { diff --git a/libgo/go/reflect/example_test.go b/libgo/go/reflect/example_test.go index 8ebf976..9e2b9b3 100644 --- a/libgo/go/reflect/example_test.go +++ b/libgo/go/reflect/example_test.go @@ -1,4 +1,4 @@ -// Copyright 2012 The Go Authors. All rights reserved. +// Copyright 2012 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. @@ -67,6 +67,34 @@ func ExampleStructTag() { // blue gopher } +func ExampleStructTag_Lookup() { + type S struct { + F0 string `alias:"field_0"` + F1 string `alias:""` + F2 string + } + + s := S{} + st := reflect.TypeOf(s) + for i := 0; i < st.NumField(); i++ { + field := st.Field(i) + if alias, ok := field.Tag.Lookup("alias"); ok { + if alias == "" { + fmt.Println("(blank)") + } else { + fmt.Println(alias) + } + } else { + fmt.Println("(not specified)") + } + } + + // Output: + // field_0 + // (blank) + // (not specified) +} + func ExampleTypeOf() { // As interface types are only used for static typing, a // common idiom to find the reflection Type for an interface diff --git a/libgo/go/reflect/export_test.go b/libgo/go/reflect/export_test.go index bdbd600..a06e8d0 100644 --- a/libgo/go/reflect/export_test.go +++ b/libgo/go/reflect/export_test.go @@ -1,4 +1,4 @@ -// Copyright 2012 The Go Authors. All rights reserved. +// Copyright 2012 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. @@ -41,3 +41,45 @@ func MapBucketOf(x, y Type) Type { func CachedBucketOf(m Type) Type { return nil } + +type EmbedWithUnexpMeth struct{} + +func (EmbedWithUnexpMeth) f() {} + +type pinUnexpMeth interface { + f() +} + +var pinUnexpMethI = pinUnexpMeth(EmbedWithUnexpMeth{}) + +/* +func FirstMethodNameBytes(t Type) *byte { + _ = pinUnexpMethI + + ut := t.uncommon() + if ut == nil { + panic("type has no methods") + } + m := ut.methods()[0] + mname := t.(*rtype).nameOff(m.name) + if *mname.data(0)&(1<<2) == 0 { + panic("method name does not have pkgPath *string") + } + return mname.bytes +} +*/ + +type OtherPkgFields struct { + OtherExported int + otherUnexported int +} + +func IsExported(t Type) bool { + return t.PkgPath() == "" +} + +/* +func ResolveReflectName(s string) { + resolveReflectName(newName(s, "", "", false)) +} +*/ diff --git a/libgo/go/reflect/makefunc.go b/libgo/go/reflect/makefunc.go index 7ec277b..543a335 100644 --- a/libgo/go/reflect/makefunc.go +++ b/libgo/go/reflect/makefunc.go @@ -1,4 +1,4 @@ -// Copyright 2012 The Go Authors. All rights reserved. +// Copyright 2012 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. diff --git a/libgo/go/reflect/set_test.go b/libgo/go/reflect/set_test.go index 85dc55e..bc35c78 100644 --- a/libgo/go/reflect/set_test.go +++ b/libgo/go/reflect/set_test.go @@ -1,4 +1,4 @@ -// Copyright 2011 The Go Authors. All rights reserved. +// Copyright 2011 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. @@ -194,11 +194,13 @@ var assignableTests = []struct { {new(*int), new(IntPtr), true}, {new(IntPtr), new(*int), true}, {new(IntPtr), new(IntPtr1), false}, + {new(Ch), new(<-chan interface{}), true}, // test runs implementsTests too } type IntPtr *int type IntPtr1 *int +type Ch <-chan interface{} func TestAssignableTo(t *testing.T) { for _, tt := range append(assignableTests, implementsTests...) { diff --git a/libgo/go/reflect/type.go b/libgo/go/reflect/type.go index 88da632..d89f156 100644 --- a/libgo/go/reflect/type.go +++ b/libgo/go/reflect/type.go @@ -3,7 +3,7 @@ // license that can be found in the LICENSE file. // Package reflect implements run-time reflection, allowing a program to -// manipulate objects with arbitrary types. The typical use is to take a value +// manipulate objects with arbitrary types. The typical use is to take a value // with static type interface{} and extract its dynamic type information by // calling TypeOf, which returns a Type. // @@ -24,10 +24,10 @@ import ( // Type is the representation of a Go type. // -// Not all methods apply to all kinds of types. Restrictions, +// Not all methods apply to all kinds of types. Restrictions, // if any, are noted in the documentation for each method. // Use the Kind method to find out the kind of type before -// calling kind-specific methods. Calling a method +// calling kind-specific methods. Calling a method // inappropriate to the kind of type causes a run-time panic. type Type interface { // Methods applicable to all types. @@ -80,7 +80,7 @@ type Type interface { // String returns a string representation of the type. // The string representation may use shortened package names // (e.g., base64 instead of "encoding/base64") and is not - // guaranteed to be unique among types. To test for equality, + // guaranteed to be unique among types. To test for equality, // compare the Types directly. String() string @@ -124,7 +124,7 @@ type Type interface { ChanDir() ChanDir // IsVariadic reports whether a function type's final input parameter - // is a "..." parameter. If so, t.In(t.NumIn() - 1) returns the parameter's + // is a "..." parameter. If so, t.In(t.NumIn() - 1) returns the parameter's // implicit actual type []T. // // For concreteness, if t represents func(x int, y ... float64), then @@ -147,7 +147,7 @@ type Type interface { Field(i int) StructField // FieldByIndex returns the nested field corresponding - // to the index sequence. It is equivalent to calling Field + // to the index sequence. It is equivalent to calling Field // successively for each index i. // It panics if the type's Kind is not Struct. FieldByIndex(index []int) StructField @@ -389,7 +389,7 @@ const ( type Method struct { // Name is the method name. // PkgPath is the package path that qualifies a lower case (unexported) - // method name. It is empty for upper case (exported) method names. + // method name. It is empty for upper case (exported) method names. // The combination of PkgPath and Name uniquely identifies a method // in a method set. // See https://golang.org/ref/spec#Uniqueness_of_identifiers @@ -509,6 +509,21 @@ func (t *uncommonType) Method(i int) (m Method) { if t == nil || i < 0 || i >= len(t.methods) { panic("reflect: Method index out of range") } + found := false + for mi := range t.methods { + if t.methods[mi].pkgPath == nil { + if i == 0 { + i = mi + found = true + break + } + i-- + } + } + if !found { + panic("reflect: Method index out of range") + } + p := &t.methods[i] if p.name != nil { m.Name = *p.name @@ -531,7 +546,13 @@ func (t *uncommonType) NumMethod() int { if t == nil { return 0 } - return len(t.methods) + c := 0 + for i := range t.methods { + if t.methods[i].pkgPath == nil { + c++ + } + } + return c } func (t *uncommonType) MethodByName(name string) (m Method, ok bool) { @@ -541,7 +562,7 @@ func (t *uncommonType) MethodByName(name string) (m Method, ok bool) { var p *method for i := range t.methods { p = &t.methods[i] - if p.name != nil && *p.name == name { + if p.pkgPath == nil && p.name != nil && *p.name == name { return t.Method(i), true } } @@ -758,7 +779,7 @@ type StructField struct { // Name is the field name. Name string // PkgPath is the package path that qualifies a lower case (unexported) - // field name. It is empty for upper case (exported) field names. + // field name. It is empty for upper case (exported) field names. // See https://golang.org/ref/spec#Uniqueness_of_identifiers PkgPath string @@ -782,8 +803,20 @@ type StructTag string // Get returns the value associated with key in the tag string. // If there is no such key in the tag, Get returns the empty string. // If the tag does not have the conventional format, the value -// returned by Get is unspecified. +// returned by Get is unspecified. To determine whether a tag is +// explicitly set to the empty string, use Lookup. func (tag StructTag) Get(key string) string { + v, _ := tag.Lookup(key) + return v +} + +// Lookup returns the value associated with key in the tag string. +// If the key is present in the tag the value (which may be empty) +// is returned. Otherwise the returned value will be the empty string. +// The ok return value reports whether the value was explicitly set in +// the tag string. If the tag does not have the conventional format, +// the value returned by Lookup is unspecified. +func (tag StructTag) Lookup(key string) (value string, ok bool) { // When modifying this code, also update the validateStructTag code // in golang.org/x/tools/cmd/vet/structtag.go. @@ -831,16 +864,16 @@ func (tag StructTag) Get(key string) string { if err != nil { break } - return value + return value, true } } - return "" + return "", false } // Field returns the i'th struct field. func (t *structType) Field(i int) (f StructField) { if i < 0 || i >= len(t.fields) { - return + panic("reflect: Field index out of bounds") } p := &t.fields[i] f.Type = toType(p.typ) @@ -863,12 +896,12 @@ func (t *structType) Field(i int) (f StructField) { f.Offset = p.offset // NOTE(rsc): This is the only allocation in the interface - // presented by a reflect.Type. It would be nice to avoid, + // presented by a reflect.Type. It would be nice to avoid, // at least in the common cases, but we need to make sure // that misbehaving clients of reflect cannot affect other - // uses of reflect. One possibility is CL 5371098, but we + // uses of reflect. One possibility is CL 5371098, but we // postponed that ugliness until there is a demonstrated - // need for the performance. This is issue 2320. + // need for the performance. This is issue 2320. f.Index = []int{i} return } @@ -1082,11 +1115,7 @@ func (t *rtype) ptrTo() *rtype { return p } - // Otherwise, synthesize one. - // This only happens for pointers with no methods. - // We keep the mapping in a map on the side, because - // this operation is rare and a separate map lets us keep - // the type structures in read-only memory. + // Check the cache. ptrMap.RLock() if m := ptrMap.m; m != nil { if p := m[t]; p != nil { @@ -1095,6 +1124,7 @@ func (t *rtype) ptrTo() *rtype { } } ptrMap.RUnlock() + ptrMap.Lock() if ptrMap.m == nil { ptrMap.m = make(map[*rtype]*ptrType) @@ -1762,7 +1792,7 @@ func needKeyUpdate(t *rtype) bool { // Make sure these routines stay in sync with ../../runtime/hashmap.go! // These types exist only for GC, so we only fill out GC relevant info. -// Currently, that's just size and the GC program. We also fill in string +// Currently, that's just size and the GC program. We also fill in string // for possible debugging use. const ( bucketSize uintptr = 8 @@ -1866,7 +1896,7 @@ func bucketOf(ktyp, etyp *rtype) *rtype { } // Take the GC program for "t" and append it to the GC program "gc". -func appendGCProgram(gc []uintptr, t *rtype) []uintptr { +func appendGCProgram(gc []uintptr, t *rtype, offset uintptr) []uintptr { p := t.gc p = unsafe.Pointer(uintptr(p) + unsafe.Sizeof(uintptr(0))) // skip size loop: @@ -1888,7 +1918,11 @@ loop: panic("unknown GC program op for " + *t.string + ": " + strconv.FormatUint(*(*uint64)(p), 10)) } for i := 0; i < argcnt+1; i++ { - gc = append(gc, *(*uintptr)(p)) + v := *(*uintptr)(p) + if i == 1 { + v += offset + } + gc = append(gc, v) p = unsafe.Pointer(uintptr(p) + unsafe.Sizeof(uintptr(0))) } } @@ -1997,8 +2031,247 @@ func SliceOf(t Type) Type { return cachePut(ckey, &slice.rtype) } -// See cmd/compile/internal/gc/reflect.go for derivation of constant. -const maxPtrmaskBytes = 2048 +// The structLookupCache caches StructOf lookups. +// StructOf does not share the common lookupCache since we need to pin +// the memory associated with *structTypeFixedN. +var structLookupCache struct { + sync.RWMutex + m map[uint32][]interface { + common() *rtype + } // keyed by hash calculated in StructOf +} + +// StructOf returns the struct type containing fields. +// The Offset and Index fields are ignored and computed as they would be +// by the compiler. +// +// StructOf currently does not generate wrapper methods for embedded fields. +// This limitation may be lifted in a future version. +func StructOf(fields []StructField) Type { + var ( + hash = uint32(0) + size uintptr + typalign int8 + + fs = make([]structField, len(fields)) + repr = make([]byte, 0, 64) + fset = map[string]struct{}{} // fields' names + + hasPtr = false // records whether at least one struct-field is a pointer + ) + + repr = append(repr, "struct {"...) + for i, field := range fields { + if field.Type == nil { + panic("reflect.StructOf: field " + strconv.Itoa(i) + " has no type") + } + f := runtimeStructField(field) + ft := f.typ + if ft.pointers() { + hasPtr = true + } + + name := "" + // Update string and hash + hash = (hash << 1) + ft.hash + if f.name != nil { + name = *f.name + repr = append(repr, (" " + name)...) + } else { + // Embedded field + repr = append(repr, " ?"...) + if f.typ.Kind() == Ptr { + // Embedded ** and *interface{} are illegal + elem := ft.Elem() + if k := elem.Kind(); k == Ptr || k == Interface { + panic("reflect.StructOf: illegal anonymous field type " + ft.String()) + } + name = elem.String() + } else { + name = ft.String() + } + // TODO(sbinet) check for syntactically impossible type names? + + switch f.typ.Kind() { + case Interface: + ift := (*interfaceType)(unsafe.Pointer(ft)) + if len(ift.methods) > 0 { + panic("reflect.StructOf: embedded field with methods not supported") + } + case Ptr: + ptr := (*ptrType)(unsafe.Pointer(ft)) + if unt := ptr.uncommon(); unt != nil { + if len(unt.methods) > 0 { + panic("reflect.StructOf: embedded field with methods not supported") + } + } + if unt := ptr.elem.uncommon(); unt != nil { + if len(unt.methods) > 0 { + panic("reflect.StructOf: embedded field with methods not supported") + } + } + default: + if unt := ft.uncommon(); unt != nil { + if len(unt.methods) > 0 { + panic("reflect.StructOf: embedded field with methods not supported") + } + } + } + } + if _, dup := fset[name]; dup { + panic("reflect.StructOf: duplicate field " + name) + } + fset[name] = struct{}{} + + repr = append(repr, (" " + ft.String())...) + if f.tag != nil { + repr = append(repr, (" " + strconv.Quote(*f.tag))...) + } + if i < len(fields)-1 { + repr = append(repr, ';') + } + + f.offset = align(size, uintptr(ft.fieldAlign)) + if int8(ft.fieldAlign) > typalign { + typalign = int8(ft.fieldAlign) + } + size = f.offset + ft.size + + fs[i] = f + } + + if len(fs) > 0 { + repr = append(repr, ' ') + } + repr = append(repr, '}') + hash <<= 2 + str := string(repr) + + // Round the size up to be a multiple of the alignment. + size = align(size, uintptr(typalign)) + + // Make the struct type. + var istruct interface{} = struct{}{} + prototype := *(**structType)(unsafe.Pointer(&istruct)) + typ := new(structType) + *typ = *prototype + typ.fields = fs + + // Look in cache + structLookupCache.RLock() + for _, st := range structLookupCache.m[hash] { + t := st.common() + if haveIdenticalUnderlyingType(&typ.rtype, t) { + structLookupCache.RUnlock() + return t + } + } + structLookupCache.RUnlock() + + // not in cache, lock and retry + structLookupCache.Lock() + defer structLookupCache.Unlock() + if structLookupCache.m == nil { + structLookupCache.m = make(map[uint32][]interface { + common() *rtype + }) + } + for _, st := range structLookupCache.m[hash] { + t := st.common() + if haveIdenticalUnderlyingType(&typ.rtype, t) { + return t + } + } + + typ.string = &str + typ.hash = hash + typ.size = size + typ.align = typalign + typ.fieldAlign = uint8(typalign) + if !hasPtr { + typ.kind |= kindNoPointers + gc := [...]uintptr{size, _GC_END} + typ.gc = unsafe.Pointer(&gc[0]) + } else { + typ.kind &^= kindNoPointers + gc := []uintptr{size} + for _, ft := range fs { + gc = appendGCProgram(gc, ft.typ, ft.offset) + } + gc = append(gc, _GC_END) + typ.gc = unsafe.Pointer(&gc[0]) + } + + typ.hashfn = func(p unsafe.Pointer, size uintptr) uintptr { + ret := uintptr(0) + for i, ft := range typ.fields { + if i > 0 { + ret *= 33 + } + o := unsafe.Pointer(uintptr(p) + ft.offset) + ret += ft.typ.hashfn(o, ft.typ.size) + } + return ret + } + + typ.equalfn = func(p, q unsafe.Pointer, size uintptr) bool { + for _, ft := range typ.fields { + pi := unsafe.Pointer(uintptr(p) + ft.offset) + qi := unsafe.Pointer(uintptr(q) + ft.offset) + if !ft.typ.equalfn(pi, qi, ft.typ.size) { + return false + } + } + return true + } + + typ.kind &^= kindDirectIface + typ.uncommonType = nil + typ.ptrToThis = nil + + structLookupCache.m[hash] = append(structLookupCache.m[hash], typ) + return &typ.rtype +} + +func runtimeStructField(field StructField) structField { + var name *string + if field.Name == "" { + t := field.Type.(*rtype) + if t.Kind() == Ptr { + t = t.Elem().(*rtype) + } + } else if field.PkgPath == "" { + s := field.Name + name = &s + b0 := s[0] + if ('a' <= b0 && b0 <= 'z') || b0 == '_' { + panic("reflect.StructOf: field \"" + field.Name + "\" is unexported but has no PkgPath") + } + } + + var pkgPath *string + if field.PkgPath != "" { + s := field.PkgPath + pkgPath = &s + // This could work with gccgo but we panic to be + // compatible with gc. + panic("reflect: creating a name with a package path is not supported") + } + + var tag *string + if field.Tag != "" { + s := string(field.Tag) + tag = &s + } + + return structField{ + name: name, + pkgPath: pkgPath, + typ: field.Type.common(), + tag: tag, + offset: 0, + } +} // ArrayOf returns the array type with the given count and element type. // For example, if t represents int, ArrayOf(5, t) represents [5]int. @@ -2037,6 +2310,7 @@ func ArrayOf(count int, elem Type) Type { array.hash = typ.hash + 1 + 13 array.elem = typ + array.ptrToThis = nil max := ^uintptr(0) / typ.size if uintptr(count) > max { panic("reflect.ArrayOf: array size would exceed virtual address space") @@ -2048,7 +2322,6 @@ func ArrayOf(count int, elem Type) Type { array.align = typ.align array.fieldAlign = typ.fieldAlign array.uncommonType = nil - array.ptrToThis = nil array.len = uintptr(count) array.slice = slice.(*rtype) @@ -2067,7 +2340,7 @@ func ArrayOf(count int, elem Type) Type { default: gc := []uintptr{array.size, _GC_ARRAY_START, 0, uintptr(count), typ.size} - gc = appendGCProgram(gc, typ) + gc = appendGCProgram(gc, typ, 0) gc = append(gc, _GC_ARRAY_NEXT, _GC_END) array.gc = unsafe.Pointer(&gc[0]) } diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go index 75944a6..1d18876 100644 --- a/libgo/go/reflect/value.go +++ b/libgo/go/reflect/value.go @@ -11,14 +11,13 @@ import ( ) const ptrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const -const cannotSet = "cannot set value obtained from unexported struct field" // Value is the reflection interface to a Go value. // -// Not all methods apply to all kinds of values. Restrictions, +// Not all methods apply to all kinds of values. Restrictions, // if any, are noted in the documentation for each method. // Use the Kind method to find out the kind of value before -// calling kind-specific methods. Calling a method +// calling kind-specific methods. Calling a method // inappropriate to the kind of type causes a run time panic. // // The zero Value represents no value. @@ -57,7 +56,7 @@ type Value struct { flag // A method value represents a curried method invocation - // like r.Read for some receiver r. The typ+val+flag bits describe + // like r.Read for some receiver r. The typ+val+flag bits describe // the receiver r, but the flag's Kind bits say Func (methods are // functions), and the top bits of the flag give the method number // in r's type's method table. @@ -116,14 +115,14 @@ func packEface(v Value) interface{} { } e.word = ptr case v.flag&flagIndir != 0: - // Value is indirect, but interface is direct. We need + // Value is indirect, but interface is direct. We need // to load the data at v.ptr into the interface data word. e.word = *(*unsafe.Pointer)(v.ptr) default: // Value is direct, and so is the interface. e.word = v.ptr } - // Now, fill in the type portion. We're very careful here not + // Now, fill in the type portion. We're very careful here not // to have any operation between the e.word and e.typ assignments // that would let the garbage collector observe the partially-built // interface value. @@ -147,7 +146,7 @@ func unpackEface(i interface{}) Value { } // A ValueError occurs when a Value method is invoked on -// a Value that does not support it. Such cases are documented +// a Value that does not support it. Such cases are documented // in the description of each method. type ValueError struct { Method string @@ -269,7 +268,7 @@ func (v Value) runes() []rune { } // CanAddr reports whether the value's address can be obtained with Addr. -// Such values are called addressable. A value is addressable if it is +// Such values are called addressable. A value is addressable if it is // an element of a slice, an element of an addressable array, // a field of an addressable struct, or the result of dereferencing a pointer. // If CanAddr returns false, calling Addr will panic. @@ -500,7 +499,7 @@ func methodReceiver(op string, v Value, methodIndex int) (rcvrtype, t *rtype, fn return } -// v is a method receiver. Store at p the word which is used to +// v is a method receiver. Store at p the word which is used to // encode that receiver at the start of the argument list. // Reflect uses the "interface" calling convention for // methods, which always uses one word to record the receiver. @@ -541,7 +540,7 @@ func (v Value) Cap() int { case Array: return v.typ.Len() case Chan: - return int(chancap(v.pointer())) + return chancap(v.pointer()) case Slice: // Slice is always bigger than a word; assume flagIndir. return (*sliceHeader)(v.ptr).Cap @@ -760,7 +759,7 @@ func (v Value) Int() int64 { case Int32: return int64(*(*int32)(p)) case Int64: - return int64(*(*int64)(p)) + return *(*int64)(p) } panic(&ValueError{"reflect.Value.Int", v.kind()}) } @@ -909,9 +908,9 @@ func (v Value) MapIndex(key Value) Value { // Do not require key to be exported, so that DeepEqual // and other programs can use all the keys returned by - // MapKeys as arguments to MapIndex. If either the map + // MapKeys as arguments to MapIndex. If either the map // or the key is unexported, though, the result will be - // considered unexported. This is consistent with the + // considered unexported. This is consistent with the // behavior for structs, which allow read but not write // of unexported fields. key = key.assignTo("reflect.Value.MapIndex", tt.key, nil) @@ -963,7 +962,7 @@ func (v Value) MapKeys() []Value { key := mapiterkey(it) if key == nil { // Someone deleted an entry from the map since we - // called maplen above. It's a data race, but nothing + // called maplen above. It's a data race, but nothing // we can do about it. break } @@ -1110,7 +1109,7 @@ func (v Value) OverflowUint(x uint64) bool { // result is zero if and only if v is a nil func Value. // // If v's Kind is Slice, the returned pointer is to the first -// element of the slice. If the slice is nil the returned value +// element of the slice. If the slice is nil the returned value // is 0. If the slice is empty but non-nil the return value is non-zero. func (v Value) Pointer() uintptr { // TODO: deprecate @@ -1311,7 +1310,7 @@ func (v Value) SetCap(n int) { v.mustBeAssignable() v.mustBe(Slice) s := (*sliceHeader)(v.ptr) - if n < int(s.Len) || n > int(s.Cap) { + if n < s.Len || n > s.Cap { panic("reflect: slice capacity out of range in SetCap") } s.Cap = n @@ -1413,7 +1412,7 @@ func (v Value) Slice(i, j int) Value { case Slice: typ = (*sliceType)(unsafe.Pointer(v.typ)) s := (*sliceHeader)(v.ptr) - base = unsafe.Pointer(s.Data) + base = s.Data cap = s.Cap case String: @@ -1585,7 +1584,7 @@ func (v Value) Uint() uint64 { case Uint32: return uint64(*(*uint32)(p)) case Uint64: - return uint64(*(*uint64)(p)) + return *(*uint64)(p) case Uintptr: return uint64(*(*uintptr)(p)) } @@ -1751,13 +1750,13 @@ func Copy(dst, src Value) int { // A runtimeSelect is a single case passed to rselect. // This must match ../runtime/select.go:/runtimeSelect type runtimeSelect struct { - dir uintptr // 0, SendDir, or RecvDir + dir SelectDir // SelectSend, SelectRecv or SelectDefault typ *rtype // channel type ch unsafe.Pointer // channel val unsafe.Pointer // ptr to data (SendDir) or ptr to receive buffer (RecvDir) } -// rselect runs a select. It returns the index of the chosen case. +// rselect runs a select. It returns the index of the chosen case. // If the case was a receive, val is filled in with the received value. // The conventional OK bool indicates whether the receive corresponds // to a sent value. @@ -1814,7 +1813,7 @@ func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) { haveDefault := false for i, c := range cases { rc := &runcases[i] - rc.dir = uintptr(c.Dir) + rc.dir = c.Dir switch c.Dir { default: panic("reflect.Select: invalid Dir") @@ -1877,7 +1876,7 @@ func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) { } chosen, recvOK = rselect(runcases) - if runcases[chosen].dir == uintptr(SelectRecv) { + if runcases[chosen].dir == SelectRecv { tt := (*chanType)(unsafe.Pointer(runcases[chosen].typ)) t := tt.elem p := runcases[chosen].val @@ -1954,14 +1953,14 @@ func Indirect(v Value) Value { } // ValueOf returns a new Value initialized to the concrete value -// stored in the interface i. ValueOf(nil) returns the zero Value. +// stored in the interface i. ValueOf(nil) returns the zero Value. func ValueOf(i interface{}) Value { if i == nil { return Value{} } // TODO: Maybe allow contents of a Value to live on the stack. - // For now we make the contents always escape to the heap. It + // For now we make the contents always escape to the heap. It // makes life easier in a few places (see chanrecv/mapassign // comment below). escapes(i) @@ -1987,7 +1986,7 @@ func Zero(typ Type) Value { } // New returns a Value representing a pointer to a new zero value -// for the specified type. That is, the returned Value's Type is PtrTo(typ). +// for the specified type. That is, the returned Value's Type is PtrTo(typ). func New(typ Type) Value { if typ == nil { panic("reflect: New(nil)") @@ -2142,13 +2141,13 @@ func makeInt(f flag, bits uint64, t Type) Value { ptr := unsafe_New(typ) switch typ.size { case 1: - *(*uint8)(unsafe.Pointer(ptr)) = uint8(bits) + *(*uint8)(ptr) = uint8(bits) case 2: - *(*uint16)(unsafe.Pointer(ptr)) = uint16(bits) + *(*uint16)(ptr) = uint16(bits) case 4: - *(*uint32)(unsafe.Pointer(ptr)) = uint32(bits) + *(*uint32)(ptr) = uint32(bits) case 8: - *(*uint64)(unsafe.Pointer(ptr)) = bits + *(*uint64)(ptr) = bits } return Value{typ, ptr, f | flagIndir | flag(typ.Kind())} } @@ -2160,9 +2159,9 @@ func makeFloat(f flag, v float64, t Type) Value { ptr := unsafe_New(typ) switch typ.size { case 4: - *(*float32)(unsafe.Pointer(ptr)) = float32(v) + *(*float32)(ptr) = float32(v) case 8: - *(*float64)(unsafe.Pointer(ptr)) = v + *(*float64)(ptr) = v } return Value{typ, ptr, f | flagIndir | flag(typ.Kind())} } @@ -2174,9 +2173,9 @@ func makeComplex(f flag, v complex128, t Type) Value { ptr := unsafe_New(typ) switch typ.size { case 8: - *(*complex64)(unsafe.Pointer(ptr)) = complex64(v) + *(*complex64)(ptr) = complex64(v) case 16: - *(*complex128)(unsafe.Pointer(ptr)) = v + *(*complex128)(ptr) = v } return Value{typ, ptr, f | flagIndir | flag(typ.Kind())} } @@ -2320,7 +2319,7 @@ func chanclose(ch unsafe.Pointer) func chanlen(ch unsafe.Pointer) int // Note: some of the noescape annotations below are technically a lie, -// but safe in the context of this package. Functions like chansend +// but safe in the context of this package. Functions like chansend // and mapassign don't escape the referent, but may escape anything // the referent points to (they do shallow copies of the referent). // It is safe in this package because the referent may only point |