From patchwork Wed Nov 21 07:04:08 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ian Lance Taylor X-Patchwork-Id: 200589 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 26DFC2C0085 for ; Wed, 21 Nov 2012 18:04:38 +1100 (EST) Comment: DKIM? See http://www.dkim.org DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gcc.gnu.org; s=default; x=1354086279; h=Comment: DomainKey-Signature:Received:Received:Received:Received:Received: Received:From:To:Subject:Date:Message-ID:User-Agent:MIME-Version: Content-Type:Mailing-List:Precedence:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:Sender:Delivered-To; bh=nAAyurM jYD8B7LMEOVOrxwekbVw=; b=h2bE4OoepogErvtVlj+J54/ojIm17qsZJLcKTsH oolfdGY37X9e1ijbmgyV5kw1IwEnf0ntnvkzKuG4YRiA5Hpyh1UbtpA3Rd1oKZdP 9K17IqcG97FQX4tDFl+OR+AP/EzCH+C8zE4mcRVxiyCWWGk01cH56HiYIqZOAUq5 yqoY= Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=gcc.gnu.org; h=Received:Received:X-SWARE-Spam-Status:X-Spam-Check-By:Received:Received:X-Google-DKIM-Signature:Received:Received:From:To:Subject:Date:Message-ID:User-Agent:MIME-Version:Content-Type:X-Gm-Message-State:X-IsSubscribed:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=gI7dEAvN3QuWbjDoj8M1JztvBDFEChe/40WtS1MdSnAW3UeNayc1E7sqw+A+ka z83ooKtBxvuLV6RaDz0wY2K6One3l0S64kY93hs64aW7NQc55omxt9DlkFfV148R dFOI7cwLpdO7aZjMW+LXaeI7yiEG4SmmcSmCkOZzbKu1Y=; Received: (qmail 32558 invoked by alias); 21 Nov 2012 07:04:32 -0000 Received: (qmail 32319 invoked by uid 22791); 21 Nov 2012 07:04:31 -0000 X-SWARE-Spam-Status: No, hits=-3.0 required=5.0 tests=AWL, BAYES_50, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, KHOP_RCVD_TRUST, RCVD_IN_DNSWL_LOW, RCVD_IN_HOSTKARMA_YE, RP_MATCHES_RCVD, TW_CC, TW_FN, TW_HF, TW_OV, T_TVD_MIME_NO_HEADERS X-Spam-Check-By: sourceware.org Received: from mail-pa0-f47.google.com (HELO mail-pa0-f47.google.com) (209.85.220.47) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 21 Nov 2012 07:04:14 +0000 Received: by mail-pa0-f47.google.com with SMTP id fa11so4500063pad.20 for ; Tue, 20 Nov 2012 23:04:13 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=from:to:subject:date:message-id:user-agent:mime-version :content-type:x-gm-message-state; bh=9ZOMfSVP0gCNGdvZRRllAQPZT5N02Y9p5uHWFyAK0so=; b=OjdmbOOJHjdSNfl0Jiy2quf3ugjvGUKgy1dWRObdpFgNdw6StQY+HkrEeecd5uJbHj HHIBWOFULJHK6NGQYoHZB1K5J8zc+pcjuxAUFV7xS1Q0GAqPpuxd3kR4Y1jZE8ITbhDh +DPcZ3DiHs57Vl6ScPhfPR4XAk0R/i2+FLoHMKicogftjVen72AnzUvlIMTcalc/I87d b6tGFFFoJcex5Kb71vyNfjgzMc1miDlXYUW0Hr2q2nV+uZsHUdqveSouLr6sqOGAZM3M 8M5s1XQFsbiaBsXHvT+t4m/84/x1BSc2rWNyEWCKVbSkiXREOfVGqANIoMHhwd6f9qaS 8UcA== Received: by 10.69.1.9 with SMTP id bc9mr56561821pbd.61.1353481453807; Tue, 20 Nov 2012 23:04:13 -0800 (PST) Received: from coign.google.com (adsl-71-133-8-30.dsl.pltn13.pacbell.net. [71.133.8.30]) by mx.google.com with ESMTPS id pu4sm9428965pbb.72.2012.11.20.23.04.09 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 20 Nov 2012 23:04:12 -0800 (PST) From: Ian Lance Taylor To: gcc-patches@gcc.gnu.org, gofrontend-dev@googlegroups.com Subject: libgo patch committed: Update to current version of library Date: Tue, 20 Nov 2012 23:04:08 -0800 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.1 (gnu/linux) MIME-Version: 1.0 X-Gm-Message-State: ALoCoQnx9DZb152Lt6bAgoOiOzkcGHDHm+Ak2SwWpdHHReH31tGq7fowAmaRVLHKGBFQ/j+hr6JrhRfNrxYR85twU9JKNlNZ7OeG2HRB0uPndyIxr1MoOrpeyM8M0jllb2jlT1m8Ig/jgrrXRoMOhzgp/R4Y+C5AifvD4b3kPcydU43ZQVY+IE5c30xozqMIGU/W8REYYV1M X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org I have updated libgo to the current version of the master library. As usual the patch is too large to include in this mail message. I have only included the changes to areas that are specific to gccgo. The rest of the patch may be seen in the repository, or, of course, in the master sources. Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu. Committed to mainline. Ian diff -r 69102534501a libgo/MERGE --- a/libgo/MERGE Mon Nov 19 08:26:48 2012 -0800 +++ b/libgo/MERGE Tue Nov 20 22:23:37 2012 -0800 @@ -1,4 +1,4 @@ -291d9f1baf75 +a070de932857 The first line of this file holds the Mercurial revision number of the last merge done from the master library sources. diff -r 69102534501a libgo/Makefile.am --- a/libgo/Makefile.am Mon Nov 19 08:26:48 2012 -0800 +++ b/libgo/Makefile.am Tue Nov 20 22:23:37 2012 -0800 @@ -773,7 +773,6 @@ go/net/lookup_unix.go \ go/net/mac.go \ go/net/net.go \ - go/net/net_posix.go \ go/net/parse.go \ go/net/pipe.go \ go/net/port.go \ @@ -1117,6 +1116,7 @@ go/crypto/x509/pkcs8.go \ go/crypto/x509/root.go \ go/crypto/x509/root_unix.go \ + go/crypto/x509/sec1.go \ go/crypto/x509/verify.go \ go/crypto/x509/x509.go @@ -1245,10 +1245,17 @@ go/exp/terminal/terminal.go \ go/exp/terminal/util.go go_exp_types_files = \ + go/exp/types/builtins.go \ go/exp/types/check.go \ go/exp/types/const.go \ + go/exp/types/conversions.go \ + go/exp/types/errors.go \ go/exp/types/exportdata.go \ + go/exp/types/expr.go \ go/exp/types/gcimporter.go \ + go/exp/types/operand.go \ + go/exp/types/predicates.go \ + go/exp/types/stmt.go \ go/exp/types/types.go \ go/exp/types/universe.go go_exp_utf8string_files = \ @@ -1329,6 +1336,7 @@ go/image/jpeg/huffman.go \ go/image/jpeg/idct.go \ go/image/jpeg/reader.go \ + go/image/jpeg/scan.go \ go/image/jpeg/writer.go go_image_png_files = \ diff -r 69102534501a libgo/go/reflect/all_test.go --- a/libgo/go/reflect/all_test.go Mon Nov 19 08:26:48 2012 -0800 +++ b/libgo/go/reflect/all_test.go Tue Nov 20 22:23:37 2012 -0800 @@ -1332,7 +1332,7 @@ // selectWatch and the selectWatcher are a watchdog mechanism for running Select. // If the selectWatcher notices that the select has been blocked for >1 second, it prints -// an error describing the select and panics the entire test binary. +// an error describing the select and panics the entire test binary. var selectWatch struct { sync.Mutex once sync.Once @@ -1700,6 +1700,20 @@ S8 } +// The X in S15.S11.S1 and S16.S11.S1 annihilate. +type S14 struct { + S15 + S16 +} + +type S15 struct { + S11 +} + +type S16 struct { + S11 +} + var fieldTests = []FTest{ {struct{}{}, "", nil, 0}, {struct{}{}, "Foo", nil, 0}, @@ -1725,6 +1739,7 @@ {S5{}, "Y", []int{2, 0, 1}, 0}, {S10{}, "X", nil, 0}, {S10{}, "Y", []int{2, 0, 0, 1}, 0}, + {S14{}, "X", nil, 0}, } func TestFieldByIndex(t *testing.T) { @@ -2046,6 +2061,24 @@ } } +func TestIndex(t *testing.T) { + xs := []byte{1, 2, 3, 4, 5, 6, 7, 8} + v := ValueOf(xs).Index(3).Interface().(byte) + if v != xs[3] { + t.Errorf("xs.Index(3) = %v; expected %v", v, xs[3]) + } + xa := [8]byte{10, 20, 30, 40, 50, 60, 70, 80} + v = ValueOf(xa).Index(2).Interface().(byte) + if v != xa[2] { + t.Errorf("xa.Index(2) = %v; expected %v", v, xa[2]) + } + s := "0123456789" + v = ValueOf(s).Index(3).Interface().(byte) + if v != s[3] { + t.Errorf("s.Index(3) = %v; expected %v", v, s[3]) + } +} + func TestSlice(t *testing.T) { xs := []int{1, 2, 3, 4, 5, 6, 7, 8} v := ValueOf(xs).Slice(3, 5).Interface().([]int) @@ -2058,7 +2091,6 @@ if !DeepEqual(v[0:5], xs[3:]) { t.Errorf("xs.Slice(3, 5)[0:5] = %v", v[0:5]) } - xa := [8]int{10, 20, 30, 40, 50, 60, 70, 80} v = ValueOf(&xa).Elem().Slice(2, 5).Interface().([]int) if len(v) != 3 { @@ -2070,6 +2102,11 @@ if !DeepEqual(v[0:6], xa[2:]) { t.Errorf("xs.Slice(2, 5)[0:6] = %v", v[0:6]) } + s := "0123456789" + vs := ValueOf(s).Slice(3, 5).Interface().(string) + if vs != s[3:5] { + t.Errorf("s.Slice(3, 5) = %q; expected %q", vs, s[3:5]) + } } func TestVariadic(t *testing.T) { @@ -2652,6 +2689,127 @@ } } +func TestOverflow(t *testing.T) { + if ovf := V(float64(0)).OverflowFloat(1e300); ovf { + t.Errorf("%v wrongly overflows float64", 1e300) + } + + maxFloat32 := float64((1<<24 - 1) << (127 - 23)) + if ovf := V(float32(0)).OverflowFloat(maxFloat32); ovf { + t.Errorf("%v wrongly overflows float32", maxFloat32) + } + ovfFloat32 := float64((1<<24-1)<<(127-23) + 1<<(127-52)) + if ovf := V(float32(0)).OverflowFloat(ovfFloat32); !ovf { + t.Errorf("%v should overflow float32", ovfFloat32) + } + if ovf := V(float32(0)).OverflowFloat(-ovfFloat32); !ovf { + t.Errorf("%v should overflow float32", -ovfFloat32) + } + + maxInt32 := int64(0x7fffffff) + if ovf := V(int32(0)).OverflowInt(maxInt32); ovf { + t.Errorf("%v wrongly overflows int32", maxInt32) + } + if ovf := V(int32(0)).OverflowInt(-1 << 31); ovf { + t.Errorf("%v wrongly overflows int32", -int64(1)<<31) + } + ovfInt32 := int64(1 << 31) + if ovf := V(int32(0)).OverflowInt(ovfInt32); !ovf { + t.Errorf("%v should overflow int32", ovfInt32) + } + + maxUint32 := uint64(0xffffffff) + if ovf := V(uint32(0)).OverflowUint(maxUint32); ovf { + t.Errorf("%v wrongly overflows uint32", maxUint32) + } + ovfUint32 := uint64(1 << 32) + if ovf := V(uint32(0)).OverflowUint(ovfUint32); !ovf { + t.Errorf("%v should overflow uint32", ovfUint32) + } +} + +func checkSameType(t *testing.T, x, y interface{}) { + if TypeOf(x) != TypeOf(y) { + t.Errorf("did not find preexisting type for %s (vs %s)", TypeOf(x), TypeOf(y)) + } +} + +func TestArrayOf(t *testing.T) { + // check construction and use of type not in binary + type T int + at := ArrayOf(10, TypeOf(T(1))) + v := New(at).Elem() + for i := 0; i < v.Len(); i++ { + v.Index(i).Set(ValueOf(T(i))) + } + s := fmt.Sprint(v.Interface()) + want := "[0 1 2 3 4 5 6 7 8 9]" + if s != want { + t.Errorf("constructed array = %s, want %s", s, want) + } + + // check that type already in binary is found + checkSameType(t, Zero(ArrayOf(5, TypeOf(T(1)))).Interface(), [5]T{}) +} + +func TestSliceOf(t *testing.T) { + // check construction and use of type not in binary + type T int + st := SliceOf(TypeOf(T(1))) + v := MakeSlice(st, 10, 10) + for i := 0; i < v.Len(); i++ { + v.Index(i).Set(ValueOf(T(i))) + } + s := fmt.Sprint(v.Interface()) + want := "[0 1 2 3 4 5 6 7 8 9]" + if s != want { + t.Errorf("constructed slice = %s, want %s", s, want) + } + + // check that type already in binary is found + type T1 int + checkSameType(t, Zero(SliceOf(TypeOf(T1(1)))).Interface(), []T1{}) +} + +func TestChanOf(t *testing.T) { + // check construction and use of type not in binary + type T string + ct := ChanOf(BothDir, TypeOf(T(""))) + v := MakeChan(ct, 2) + v.Send(ValueOf(T("hello"))) + v.Send(ValueOf(T("world"))) + + sv1, _ := v.Recv() + sv2, _ := v.Recv() + s1 := sv1.String() + s2 := sv2.String() + if s1 != "hello" || s2 != "world" { + t.Errorf("constructed chan: have %q, %q, want %q, %q", s1, s2, "hello", "world") + } + + // check that type already in binary is found + type T1 int + checkSameType(t, Zero(ChanOf(BothDir, TypeOf(T1(1)))).Interface(), (chan T1)(nil)) +} + +func TestMapOf(t *testing.T) { + // check construction and use of type not in binary + type K string + type V float64 + + v := MakeMap(MapOf(TypeOf(K("")), TypeOf(V(0)))) + v.SetMapIndex(ValueOf(K("a")), ValueOf(V(1))) + + s := fmt.Sprint(v.Interface()) + want := "map[a:1]" + if s != want { + t.Errorf("constructed map = %s, want %s", s, want) + } + + // check that type already in binary is found + checkSameType(t, Zero(MapOf(TypeOf(V(0)), TypeOf(K("")))).Interface(), map[V]K(nil)) +} + type B1 struct { X int Y int diff -r 69102534501a libgo/go/reflect/deepequal.go --- a/libgo/go/reflect/deepequal.go Mon Nov 19 08:26:48 2012 -0800 +++ b/libgo/go/reflect/deepequal.go Tue Nov 20 22:23:37 2012 -0800 @@ -122,9 +122,11 @@ panic("Not reached") } -// DeepEqual tests for deep equality. It uses normal == equality where possible -// but will scan members of arrays, slices, maps, and fields of structs. It correctly -// handles recursive types. Functions are equal only if they are both nil. +// DeepEqual tests for deep equality. It uses normal == equality where +// possible but will scan elements of arrays, slices, maps, and fields of +// structs. In maps, keys are compared with == but elements use deep +// equality. DeepEqual correctly handles recursive types. Functions are equal +// only if they are both nil. // An empty slice is not equal to a nil slice. func DeepEqual(a1, a2 interface{}) bool { if a1 == nil || a2 == nil { diff -r 69102534501a libgo/go/reflect/export_test.go --- a/libgo/go/reflect/export_test.go Mon Nov 19 08:26:48 2012 -0800 +++ b/libgo/go/reflect/export_test.go Tue Nov 20 22:23:37 2012 -0800 @@ -14,3 +14,5 @@ func IsRO(v Value) bool { return v.flag&flagRO != 0 } + +var ArrayOf = arrayOf diff -r 69102534501a libgo/go/reflect/set_test.go --- a/libgo/go/reflect/set_test.go Mon Nov 19 08:26:48 2012 -0800 +++ b/libgo/go/reflect/set_test.go Tue Nov 20 22:23:37 2012 -0800 @@ -85,7 +85,7 @@ } } { - // convert channel direction + // convert channel direction m := make(map[<-chan int]chan int) mv := ValueOf(m) c1 := make(chan int) diff -r 69102534501a libgo/go/reflect/type.go --- a/libgo/go/reflect/type.go Mon Nov 19 08:26:48 2012 -0800 +++ b/libgo/go/reflect/type.go Tue Nov 20 22:23:37 2012 -0800 @@ -187,8 +187,7 @@ // It panics if i is not in the range [0, NumOut()). Out(i int) Type - runtimeType() *runtimeType - common() *commonType + common() *rtype uncommon() *uncommonType } @@ -232,13 +231,11 @@ UnsafePointer ) -type runtimeType commonType - -// commonType is the common implementation of most values. +// rtype is the common implementation of most values. // It is embedded in other, public struct types, but always // with a unique tag like `reflect:"array"` or `reflect:"ptr"` // so that code cannot convert from, say, *arrayType to *ptrType. -type commonType struct { +type rtype struct { kind uint8 // enumeration for C align int8 // alignment of variable with this type fieldAlign uint8 // alignment of struct field with this type @@ -249,17 +246,17 @@ hashfn func(unsafe.Pointer, uintptr) // hash function equalfn func(unsafe.Pointer, unsafe.Pointer, uintptr) // equality function - string *string // string form; unnecessary but undeniably useful - *uncommonType // (relatively) uncommon fields - ptrToThis *runtimeType // pointer to this type, if used in binary or has methods + string *string // string form; unnecessary but undeniably useful + *uncommonType // (relatively) uncommon fields + ptrToThis *rtype // type for pointer to this type, if used in binary or has methods } // Method on non-interface type type method struct { name *string // name of method pkgPath *string // nil for exported Names; otherwise import path - mtyp *runtimeType // method type (without receiver) - typ *runtimeType // .(*FuncType) underneath (with receiver) + mtyp *rtype // method type (without receiver) + typ *rtype // .(*FuncType) underneath (with receiver) tfn unsafe.Pointer // fn used for normal method call } @@ -284,72 +281,72 @@ // arrayType represents a fixed array type. type arrayType struct { - commonType `reflect:"array"` - elem *runtimeType // array element type - slice *runtimeType // slice type - len uintptr + rtype `reflect:"array"` + elem *rtype // array element type + slice *rtype // slice type + len uintptr } // chanType represents a channel type. type chanType struct { - commonType `reflect:"chan"` - elem *runtimeType // channel element type - dir uintptr // channel direction (ChanDir) + rtype `reflect:"chan"` + elem *rtype // channel element type + dir uintptr // channel direction (ChanDir) } // funcType represents a function type. type funcType struct { - commonType `reflect:"func"` - dotdotdot bool // last input parameter is ... - in []*runtimeType // input parameter types - out []*runtimeType // output parameter types + rtype `reflect:"func"` + dotdotdot bool // last input parameter is ... + in []*rtype // input parameter types + out []*rtype // output parameter types } // imethod represents a method on an interface type type imethod struct { - name *string // name of method - pkgPath *string // nil for exported Names; otherwise import path - typ *runtimeType // .(*FuncType) underneath + name *string // name of method + pkgPath *string // nil for exported Names; otherwise import path + typ *rtype // .(*FuncType) underneath } // interfaceType represents an interface type. type interfaceType struct { - commonType `reflect:"interface"` - methods []imethod // sorted by hash + rtype `reflect:"interface"` + methods []imethod // sorted by hash } // mapType represents a map type. type mapType struct { - commonType `reflect:"map"` - key *runtimeType // map key type - elem *runtimeType // map element (value) type + rtype `reflect:"map"` + key *rtype // map key type + elem *rtype // map element (value) type } // ptrType represents a pointer type. type ptrType struct { - commonType `reflect:"ptr"` - elem *runtimeType // pointer element (pointed at) type + rtype `reflect:"ptr"` + elem *rtype // pointer element (pointed at) type } // sliceType represents a slice type. type sliceType struct { - commonType `reflect:"slice"` - elem *runtimeType // slice element type + rtype `reflect:"slice"` + elem *rtype // slice element type } // Struct field type structField struct { - name *string // nil for embedded fields - pkgPath *string // nil for exported Names; otherwise import path - typ *runtimeType // type of field - tag *string // nil if no tag - offset uintptr // byte offset of field within struct + name *string // nil for embedded fields + pkgPath *string // nil for exported Names; otherwise import path + typ *rtype // type of field + tag *string // nil if no tag + offset uintptr // byte offset of field within struct } // structType represents a struct type. type structType struct { - commonType `reflect:"struct"` - fields []structField // sorted by offset + rtype `reflect:"struct"` + fields []structField // sorted by offset } /* @@ -432,16 +429,9 @@ return *t.name } -func (t *commonType) toType() Type { - if t == nil { - return nil - } - return canonicalize(t) -} +func (t *rtype) rawString() string { return *t.string } -func (t *commonType) rawString() string { return *t.string } - -func (t *commonType) String() string { +func (t *rtype) String() string { // For gccgo, strip out quoted strings. s := *t.string var q bool @@ -458,9 +448,9 @@ return string(r[:j]) } -func (t *commonType) Size() uintptr { return t.size } +func (t *rtype) Size() uintptr { return t.size } -func (t *commonType) Bits() int { +func (t *rtype) Bits() int { if t == nil { panic("reflect: Bits of nil Type") } @@ -471,13 +461,13 @@ return int(t.size) * 8 } -func (t *commonType) Align() int { return int(t.align) } +func (t *rtype) Align() int { return int(t.align) } -func (t *commonType) FieldAlign() int { return int(t.fieldAlign) } +func (t *rtype) FieldAlign() int { return int(t.fieldAlign) } -func (t *commonType) Kind() Kind { return Kind(t.kind & kindMask) } +func (t *rtype) Kind() Kind { return Kind(t.kind & kindMask) } -func (t *commonType) common() *commonType { return t } +func (t *rtype) common() *rtype { return t } func (t *uncommonType) Method(i int) (m Method) { if t == nil || i < 0 || i >= len(t.methods) { @@ -492,8 +482,8 @@ m.PkgPath = *p.pkgPath fl |= flagRO } - mt := toCommonType(p.typ) - m.Type = mt.toType() + mt := p.typ + m.Type = toType(mt) x := new(unsafe.Pointer) *x = p.tfn m.Func = Value{mt, unsafe.Pointer(x), fl | flagIndir} @@ -524,8 +514,8 @@ // TODO(rsc): 6g supplies these, but they are not // as efficient as they could be: they have commonType -// as the receiver instead of *commonType. -func (t *commonType) NumMethod() int { +// as the receiver instead of *rtype. +func (t *rtype) NumMethod() int { if t.Kind() == Interface { tt := (*interfaceType)(unsafe.Pointer(t)) return tt.NumMethod() @@ -533,7 +523,7 @@ return t.uncommonType.NumMethod() } -func (t *commonType) Method(i int) (m Method) { +func (t *rtype) Method(i int) (m Method) { if t.Kind() == Interface { tt := (*interfaceType)(unsafe.Pointer(t)) return tt.Method(i) @@ -541,7 +531,7 @@ return t.uncommonType.Method(i) } -func (t *commonType) MethodByName(name string) (m Method, ok bool) { +func (t *rtype) MethodByName(name string) (m Method, ok bool) { if t.Kind() == Interface { tt := (*interfaceType)(unsafe.Pointer(t)) return tt.MethodByName(name) @@ -549,15 +539,15 @@ return t.uncommonType.MethodByName(name) } -func (t *commonType) PkgPath() string { +func (t *rtype) PkgPath() string { return t.uncommonType.PkgPath() } -func (t *commonType) Name() string { +func (t *rtype) Name() string { return t.uncommonType.Name() } -func (t *commonType) ChanDir() ChanDir { +func (t *rtype) ChanDir() ChanDir { if t.Kind() != Chan { panic("reflect: ChanDir of non-chan type") } @@ -565,7 +555,7 @@ return ChanDir(tt.dir) } -func (t *commonType) IsVariadic() bool { +func (t *rtype) IsVariadic() bool { if t.Kind() != Func { panic("reflect: IsVariadic of non-func type") } @@ -573,7 +563,7 @@ return tt.dotdotdot } -func (t *commonType) Elem() Type { +func (t *rtype) Elem() Type { switch t.Kind() { case Array: tt := (*arrayType)(unsafe.Pointer(t)) @@ -594,7 +584,7 @@ panic("reflect: Elem of invalid type") } -func (t *commonType) Field(i int) StructField { +func (t *rtype) Field(i int) StructField { if t.Kind() != Struct { panic("reflect: Field of non-struct type") } @@ -602,7 +592,7 @@ return tt.Field(i) } -func (t *commonType) FieldByIndex(index []int) StructField { +func (t *rtype) FieldByIndex(index []int) StructField { if t.Kind() != Struct { panic("reflect: FieldByIndex of non-struct type") } @@ -610,7 +600,7 @@ return tt.FieldByIndex(index) } -func (t *commonType) FieldByName(name string) (StructField, bool) { +func (t *rtype) FieldByName(name string) (StructField, bool) { if t.Kind() != Struct { panic("reflect: FieldByName of non-struct type") } @@ -618,7 +608,7 @@ return tt.FieldByName(name) } -func (t *commonType) FieldByNameFunc(match func(string) bool) (StructField, bool) { +func (t *rtype) FieldByNameFunc(match func(string) bool) (StructField, bool) { if t.Kind() != Struct { panic("reflect: FieldByNameFunc of non-struct type") } @@ -626,7 +616,7 @@ return tt.FieldByNameFunc(match) } -func (t *commonType) In(i int) Type { +func (t *rtype) In(i int) Type { if t.Kind() != Func { panic("reflect: In of non-func type") } @@ -634,7 +624,7 @@ return toType(tt.in[i]) } -func (t *commonType) Key() Type { +func (t *rtype) Key() Type { if t.Kind() != Map { panic("reflect: Key of non-map type") } @@ -642,7 +632,7 @@ return toType(tt.key) } -func (t *commonType) Len() int { +func (t *rtype) Len() int { if t.Kind() != Array { panic("reflect: Len of non-array type") } @@ -650,7 +640,7 @@ return int(tt.len) } -func (t *commonType) NumField() int { +func (t *rtype) NumField() int { if t.Kind() != Struct { panic("reflect: NumField of non-struct type") } @@ -658,7 +648,7 @@ return len(tt.fields) } -func (t *commonType) NumIn() int { +func (t *rtype) NumIn() int { if t.Kind() != Func { panic("reflect: NumIn of non-func type") } @@ -666,7 +656,7 @@ return len(tt.in) } -func (t *commonType) NumOut() int { +func (t *rtype) NumOut() int { if t.Kind() != Func { panic("reflect: NumOut of non-func type") } @@ -674,7 +664,7 @@ return len(tt.out) } -func (t *commonType) Out(i int) Type { +func (t *rtype) Out(i int) Type { if t.Kind() != Func { panic("reflect: Out of non-func type") } @@ -844,7 +834,7 @@ // FieldByIndex returns the nested field corresponding to index. func (t *structType) FieldByIndex(index []int) (f StructField) { - f.Type = Type(t.toType()) + f.Type = toType(&t.rtype) for i, x := range index { if i > 0 { ft := f.Type @@ -915,13 +905,13 @@ f := &t.fields[i] // Find name and type for field f. var fname string - var ntyp *commonType + var ntyp *rtype if f.name != nil { fname = *f.name } else { // Anonymous field of type T or *T. // Name taken from type. - ntyp = toCommonType(f.typ) + ntyp = f.typ if ntyp.Kind() == Ptr { ntyp = ntyp.Elem().common() } @@ -945,19 +935,23 @@ // Queue embedded struct fields for processing with next level, // but only if we haven't seen a match yet at this level and only - // if the embedded types haven't alredy been queued. + // if the embedded types haven't already been queued. if ok || ntyp == nil || ntyp.Kind() != Struct { continue } + ntyp = toType(ntyp).common() styp := (*structType)(unsafe.Pointer(ntyp)) if nextCount[styp] > 0 { - nextCount[styp]++ + nextCount[styp] = 2 // exact multiple doesn't matter continue } if nextCount == nil { nextCount = map[*structType]int{} } nextCount[styp] = 1 + if count[t] > 1 { + nextCount[styp] = 2 // exact multiple doesn't matter + } var index []int index = append(index, scan.index...) index = append(index, i) @@ -994,53 +988,6 @@ return t.FieldByNameFunc(func(s string) bool { return s == name }) } -// Convert runtime type to reflect type. -func toCommonType(p *runtimeType) *commonType { - if p == nil { - return nil - } - return (*commonType)(unsafe.Pointer(p)) -} - -// Canonicalize a Type. -var canonicalType = make(map[string]Type) - -var canonicalTypeLock sync.RWMutex - -func canonicalize(t Type) Type { - if t == nil { - return nil - } - u := t.uncommon() - var s string - if u == nil || u.PkgPath() == "" { - s = t.rawString() - } else { - s = u.PkgPath() + "." + u.Name() - } - canonicalTypeLock.RLock() - if r, ok := canonicalType[s]; ok { - canonicalTypeLock.RUnlock() - return r - } - canonicalTypeLock.RUnlock() - canonicalTypeLock.Lock() - if r, ok := canonicalType[s]; ok { - canonicalTypeLock.Unlock() - return r - } - canonicalType[s] = t - canonicalTypeLock.Unlock() - return t -} - -func toType(p *runtimeType) Type { - if p == nil { - return nil - } - return (*commonType)(unsafe.Pointer(p)) -} - // TypeOf returns the reflection Type of the value in the interface{}. // TypeOf(nil) returns nil. func TypeOf(i interface{}) Type { @@ -1051,22 +998,18 @@ // ptrMap is the cache for PtrTo. var ptrMap struct { sync.RWMutex - m map[*commonType]*ptrType -} - -func (t *commonType) runtimeType() *runtimeType { - return (*runtimeType)(unsafe.Pointer(t)) + m map[*rtype]*ptrType } // PtrTo returns the pointer type with element t. // For example, if t represents type Foo, PtrTo(t) represents *Foo. func PtrTo(t Type) Type { - return t.(*commonType).ptrTo() + return t.(*rtype).ptrTo() } -func (ct *commonType) ptrTo() *commonType { - if p := ct.ptrToThis; p != nil { - return toCommonType(p) +func (t *rtype) ptrTo() *rtype { + if p := t.ptrToThis; p != nil { + return p } // Otherwise, synthesize one. @@ -1076,39 +1019,39 @@ // the type structures in read-only memory. ptrMap.RLock() if m := ptrMap.m; m != nil { - if p := m[ct]; p != nil { + if p := m[t]; p != nil { ptrMap.RUnlock() - return &p.commonType + return &p.rtype } } ptrMap.RUnlock() ptrMap.Lock() if ptrMap.m == nil { - ptrMap.m = make(map[*commonType]*ptrType) + ptrMap.m = make(map[*rtype]*ptrType) } - p := ptrMap.m[ct] + p := ptrMap.m[t] if p != nil { // some other goroutine won the race and created it ptrMap.Unlock() - return &p.commonType + return &p.rtype } - s := "*" + *ct.string + s := "*" + *t.string canonicalTypeLock.RLock() r, ok := canonicalType[s] canonicalTypeLock.RUnlock() if ok { - ptrMap.m[ct] = (*ptrType)(unsafe.Pointer(r.(*commonType))) + ptrMap.m[t] = (*ptrType)(unsafe.Pointer(r.(*rtype))) ptrMap.Unlock() - return r.(*commonType) + return r.(*rtype) } // initialize p using *byte's ptrType as a prototype. p = new(ptrType) - var ibyte interface{} = (*byte)(nil) - bp := (*ptrType)(unsafe.Pointer(*(**runtimeType)(unsafe.Pointer(&ibyte)))) - *p = *bp + var iptr interface{} = (*unsafe.Pointer)(nil) + prototype := *(**ptrType)(unsafe.Pointer(&iptr)) + *p = *prototype p.string = &s @@ -1117,50 +1060,58 @@ // Create a good hash for the new string by using // the FNV-1 hash's mixing function to combine the // old hash and the new "*". - // p.hash = ct.hash*16777619 ^ '*' + // p.hash = fnv1(t.hash, '*') // This is the gccgo version. - p.hash = (ct.hash << 4) + 9 + p.hash = (t.hash << 4) + 9 p.uncommonType = nil p.ptrToThis = nil - p.elem = (*runtimeType)(unsafe.Pointer(ct)) + p.elem = t - q := canonicalize(&p.commonType) - p = (*ptrType)(unsafe.Pointer(q.(*commonType))) + q := canonicalize(&p.rtype) + p = (*ptrType)(unsafe.Pointer(q.(*rtype))) - ptrMap.m[ct] = p + ptrMap.m[t] = p ptrMap.Unlock() - return &p.commonType + return &p.rtype } -func (t *commonType) Implements(u Type) bool { +// fnv1 incorporates the list of bytes into the hash x using the FNV-1 hash function. +func fnv1(x uint32, list ...byte) uint32 { + for _, b := range list { + x = x*16777619 ^ uint32(b) + } + return x +} + +func (t *rtype) Implements(u Type) bool { if u == nil { panic("reflect: nil type passed to Type.Implements") } if u.Kind() != Interface { panic("reflect: non-interface type passed to Type.Implements") } - return implements(u.(*commonType), t) + return implements(u.(*rtype), t) } -func (t *commonType) AssignableTo(u Type) bool { +func (t *rtype) AssignableTo(u Type) bool { if u == nil { panic("reflect: nil type passed to Type.AssignableTo") } - uu := u.(*commonType) + uu := u.(*rtype) return directlyAssignable(uu, t) || implements(uu, t) } -func (t *commonType) ConvertibleTo(u Type) bool { +func (t *rtype) ConvertibleTo(u Type) bool { if u == nil { panic("reflect: nil type passed to Type.ConvertibleTo") } - uu := u.(*commonType) + uu := u.(*rtype) return convertOp(uu, t) != nil } // implements returns true if the type V implements the interface type T. -func implements(T, V *commonType) bool { +func implements(T, V *rtype) bool { if T.Kind() != Interface { return false } @@ -1218,7 +1169,7 @@ // http://golang.org/doc/go_spec.html#Assignability // Ignoring the interface rules (implemented elsewhere) // and the ideal constant rules (no ideal constants at run time). -func directlyAssignable(T, V *commonType) bool { +func directlyAssignable(T, V *rtype) bool { // x's type V is identical to T? if T == V { return true @@ -1234,7 +1185,7 @@ return haveIdenticalUnderlyingType(T, V) } -func haveIdenticalUnderlyingType(T, V *commonType) bool { +func haveIdenticalUnderlyingType(T, V *rtype) bool { if T == V { return true } @@ -1330,3 +1281,286 @@ return false } + +// The lookupCache caches ChanOf, MapOf, and SliceOf lookups. +var lookupCache struct { + sync.RWMutex + m map[cacheKey]*rtype +} + +// A cacheKey is the key for use in the lookupCache. +// Four values describe any of the types we are looking for: +// type kind, one or two subtypes, and an extra integer. +type cacheKey struct { + kind Kind + t1 *rtype + t2 *rtype + extra uintptr +} + +// cacheGet looks for a type under the key k in the lookupCache. +// If it finds one, it returns that type. +// If not, it returns nil with the cache locked. +// The caller is expected to use cachePut to unlock the cache. +func cacheGet(k cacheKey) Type { + lookupCache.RLock() + t := lookupCache.m[k] + lookupCache.RUnlock() + if t != nil { + return t + } + + lookupCache.Lock() + t = lookupCache.m[k] + if t != nil { + lookupCache.Unlock() + return t + } + + if lookupCache.m == nil { + lookupCache.m = make(map[cacheKey]*rtype) + } + + return nil +} + +// cachePut stores the given type in the cache, unlocks the cache, +// and returns the type. It is expected that the cache is locked +// because cacheGet returned nil. +func cachePut(k cacheKey, t *rtype) Type { + t = toType(t).common() + lookupCache.m[k] = t + lookupCache.Unlock() + return t +} + +// ChanOf returns the channel type with the given direction and and element type. +// For example, if t represents int, ChanOf(RecvDir, t) represents <-chan int. +// +// The gc runtime imposes a limit of 64 kB on channel element types. +// If t's size is equal to or exceeds this limit, ChanOf panics. +func ChanOf(dir ChanDir, t Type) Type { + typ := t.(*rtype) + + // Look in cache. + ckey := cacheKey{Chan, typ, nil, uintptr(dir)} + if ch := cacheGet(ckey); ch != nil { + return ch + } + + // This restriction is imposed by the gc compiler and the runtime. + if typ.size >= 1<<16 { + lookupCache.Unlock() + panic("reflect.ChanOf: element size too large") + } + + // Look in known types. + // TODO: Precedence when constructing string. + var s string + switch dir { + default: + lookupCache.Unlock() + panic("reflect.ChanOf: invalid dir") + case SendDir: + s = "chan<- " + *typ.string + case RecvDir: + s = "<-chan " + *typ.string + case BothDir: + s = "chan " + *typ.string + } + + // Make a channel type. + var ichan interface{} = (chan unsafe.Pointer)(nil) + prototype := *(**chanType)(unsafe.Pointer(&ichan)) + ch := new(chanType) + *ch = *prototype + ch.string = &s + + // gccgo uses a different hash. + // ch.hash = fnv1(typ.hash, 'c', byte(dir)) + ch.hash = 0 + if dir&SendDir != 0 { + ch.hash += 1 + } + if dir&RecvDir != 0 { + ch.hash += 2 + } + ch.hash += typ.hash << 2 + ch.hash <<= 3 + ch.hash += 15 + + ch.elem = typ + ch.uncommonType = nil + ch.ptrToThis = nil + + return cachePut(ckey, &ch.rtype) +} + +// MapOf returns the map type with the given key and element types. +// For example, if k represents int and e represents string, +// MapOf(k, e) represents map[int]string. +// +// If the key type is not a valid map key type (that is, if it does +// not implement Go's == operator), MapOf panics. TODO(rsc). +func MapOf(key, elem Type) Type { + ktyp := key.(*rtype) + etyp := elem.(*rtype) + + // TODO: Check for invalid key types. + + // Look in cache. + ckey := cacheKey{Map, ktyp, etyp, 0} + if mt := cacheGet(ckey); mt != nil { + return mt + } + + // Look in known types. + s := "map[" + *ktyp.string + "]" + *etyp.string + + // Make a map type. + var imap interface{} = (map[unsafe.Pointer]unsafe.Pointer)(nil) + prototype := *(**mapType)(unsafe.Pointer(&imap)) + mt := new(mapType) + *mt = *prototype + mt.string = &s + + // gccgo uses a different hash + // mt.hash = fnv1(etyp.hash, 'm', byte(ktyp.hash>>24), byte(ktyp.hash>>16), byte(ktyp.hash>>8), byte(ktyp.hash)) + mt.hash = ktyp.hash + etyp.hash + 2 + 14 + + mt.key = ktyp + mt.elem = etyp + mt.uncommonType = nil + mt.ptrToThis = nil + + return cachePut(ckey, &mt.rtype) +} + +// SliceOf returns the slice type with element type t. +// For example, if t represents int, SliceOf(t) represents []int. +func SliceOf(t Type) Type { + typ := t.(*rtype) + + // Look in cache. + ckey := cacheKey{Slice, typ, nil, 0} + if slice := cacheGet(ckey); slice != nil { + return slice + } + + // Look in known types. + s := "[]" + *typ.string + + // Make a slice type. + var islice interface{} = ([]unsafe.Pointer)(nil) + prototype := *(**sliceType)(unsafe.Pointer(&islice)) + slice := new(sliceType) + *slice = *prototype + slice.string = &s + + // gccgo uses a different hash. + // slice.hash = fnv1(typ.hash, '[') + slice.hash = typ.hash + 1 + 13 + + slice.elem = typ + slice.uncommonType = nil + slice.ptrToThis = nil + + return cachePut(ckey, &slice.rtype) +} + +// ArrayOf returns the array type with the given count and element type. +// For example, if t represents int, ArrayOf(5, t) represents [5]int. +// +// If the resulting type would be larger than the available address space, +// ArrayOf panics. +// +// TODO(rsc): Unexported for now. Export once the alg field is set correctly +// for the type. This may require significant work. +func arrayOf(count int, elem Type) Type { + typ := elem.(*rtype) + slice := SliceOf(elem) + + // Look in cache. + ckey := cacheKey{Array, typ, nil, uintptr(count)} + if slice := cacheGet(ckey); slice != nil { + return slice + } + + // Look in known types. + s := "[" + strconv.Itoa(count) + "]" + *typ.string + + // Make an array type. + var iarray interface{} = [1]unsafe.Pointer{} + prototype := *(**arrayType)(unsafe.Pointer(&iarray)) + array := new(arrayType) + *array = *prototype + array.string = &s + + // gccgo uses a different hash. + // array.hash = fnv1(typ.hash, '[') + // for n := uint32(count); n > 0; n >>= 8 { + // array.hash = fnv1(array.hash, byte(n)) + // } + // array.hash = fnv1(array.hash, ']') + array.hash = typ.hash + 1 + 13 + + array.elem = typ + max := ^uintptr(0) / typ.size + if uintptr(count) > max { + panic("reflect.ArrayOf: array size would exceed virtual address space") + } + array.size = typ.size * uintptr(count) + array.align = typ.align + array.fieldAlign = typ.fieldAlign + // TODO: array.alg + // TODO: array.gc + array.uncommonType = nil + array.ptrToThis = nil + array.len = uintptr(count) + array.slice = slice.(*rtype) + + return cachePut(ckey, &array.rtype) +} + +// toType converts from a *rtype to a Type that can be returned +// to the client of package reflect. In gc, the only concern is that +// a nil *rtype must be replaced by a nil Type, but in gccgo this +// function takes care of ensuring that multiple *rtype for the same +// type are coalesced into a single Type. +var canonicalType = make(map[string]Type) + +var canonicalTypeLock sync.RWMutex + +func canonicalize(t Type) Type { + if t == nil { + return nil + } + u := t.uncommon() + var s string + if u == nil || u.PkgPath() == "" { + s = t.rawString() + } else { + s = u.PkgPath() + "." + u.Name() + } + canonicalTypeLock.RLock() + if r, ok := canonicalType[s]; ok { + canonicalTypeLock.RUnlock() + return r + } + canonicalTypeLock.RUnlock() + canonicalTypeLock.Lock() + if r, ok := canonicalType[s]; ok { + canonicalTypeLock.Unlock() + return r + } + canonicalType[s] = t + canonicalTypeLock.Unlock() + return t +} + +func toType(p *rtype) Type { + if p == nil { + return nil + } + return canonicalize(p) +} diff -r 69102534501a libgo/go/reflect/value.go --- a/libgo/go/reflect/value.go Mon Nov 19 08:26:48 2012 -0800 +++ b/libgo/go/reflect/value.go Tue Nov 20 22:23:37 2012 -0800 @@ -60,7 +60,7 @@ // direct operations. type Value struct { // typ holds the type of the value represented by a Value. - typ *commonType + typ *rtype // val holds the 1-word representation of the value. // If flag's flagIndir bit is set, then val is a pointer to the data. @@ -211,7 +211,7 @@ // emptyInterface is the header for an interface{} value. type emptyInterface struct { - typ *runtimeType + typ *rtype word iword } @@ -219,7 +219,7 @@ type nonEmptyInterface struct { // see ../runtime/iface.c:/Itab itab *struct { - typ *runtimeType // dynamic concrete type + typ *rtype // dynamic concrete type fun [100000]unsafe.Pointer // method table } word iword @@ -372,7 +372,7 @@ if m.pkgPath != nil { panic(method + " of unexported method") } - t = toCommonType(m.typ) + t = m.typ iface := (*nonEmptyInterface)(v.val) if iface.itab == nil { panic(method + " of method on nil interface value") @@ -389,7 +389,7 @@ panic(method + " of unexported method") } fn = m.tfn - t = toCommonType(m.mtyp) + t = m.mtyp rcvr = v.iword() } } else if v.flag&flagIndir != 0 { @@ -474,7 +474,7 @@ first_pointer := false for i, pv := range in { pv.mustBeExported() - targ := t.In(i).(*commonType) + targ := t.In(i).(*rtype) pv = pv.assignTo("reflect.Value.Call", targ, nil) if pv.flag&flagIndir == 0 { p := new(unsafe.Pointer) @@ -517,7 +517,7 @@ // gccgo specific test to see if typ is a method. We can tell by // looking at the string to see if there is a receiver. We need this // because for gccgo all methods take pointer receivers. -func isMethod(t *commonType) bool { +func isMethod(t *rtype) bool { if Kind(t.kind) != Func { return false } @@ -553,7 +553,7 @@ off := uintptr(0) in := make([]Value, 0, len(ftyp.in)) for _, arg := range ftyp.in { - typ := toCommonType(arg) + typ := arg off += -off & uintptr(typ.align-1) v := Value{typ, nil, flag(typ.Kind()) << flagKindShift} if typ.size <= ptrSize { @@ -582,7 +582,7 @@ if len(ftyp.out) > 0 { off += -off & (ptrSize - 1) for i, arg := range ftyp.out { - typ := toCommonType(arg) + typ := arg v := out[i] if v.typ != typ { panic("reflect: function created by MakeFunc using " + funcName(f) + @@ -665,7 +665,7 @@ switch k { case Interface: var ( - typ *commonType + typ *rtype val unsafe.Pointer ) if v.typ.NumMethod() == 0 { @@ -674,7 +674,7 @@ // nil interface value return Value{} } - typ = toCommonType(eface.typ) + typ = eface.typ val = unsafe.Pointer(eface.word) } else { iface := (*nonEmptyInterface)(v.val) @@ -682,7 +682,7 @@ // nil interface value return Value{} } - typ = toCommonType(iface.itab.typ) + typ = iface.itab.typ val = unsafe.Pointer(iface.word) } fl := v.flag & flagRO @@ -702,7 +702,7 @@ return Value{} } tt := (*ptrType)(unsafe.Pointer(v.typ)) - typ := toCommonType(tt.elem) + typ := tt.elem fl := v.flag&flagRO | flagIndir | flagAddr fl |= flag(typ.Kind() << flagKindShift) return Value{typ, val, fl} @@ -719,7 +719,7 @@ panic("reflect: Field index out of range") } field := &tt.fields[i] - typ := toCommonType(field.typ) + typ := field.typ // Inherit permission bits from v. fl := v.flag & (flagRO | flagIndir | flagAddr) @@ -802,8 +802,10 @@ panic(&ValueError{"reflect.Value.Float", k}) } +var uint8Type = TypeOf(uint8(0)).(*rtype) + // Index returns v's i'th element. -// It panics if v's Kind is not Array or Slice or i is out of range. +// It panics if v's Kind is not Array, Slice, or String or i is out of range. func (v Value) Index(i int) Value { k := v.kind() switch k { @@ -812,7 +814,7 @@ if i < 0 || i > int(tt.len) { panic("reflect: array index out of range") } - typ := toCommonType(tt.elem) + typ := tt.elem fl := v.flag & (flagRO | flagIndir | flagAddr) // bits same as overall array fl |= flag(typ.Kind()) << flagKindShift offset := uintptr(i) * typ.size @@ -840,10 +842,19 @@ panic("reflect: slice index out of range") } tt := (*sliceType)(unsafe.Pointer(v.typ)) - typ := toCommonType(tt.elem) + typ := tt.elem fl |= flag(typ.Kind()) << flagKindShift val := unsafe.Pointer(s.Data + uintptr(i)*typ.size) return Value{typ, val, fl} + + case String: + fl := v.flag&flagRO | flag(Uint8<= s.Len { + panic("reflect: string index out of range") + } + val := *(*byte)(unsafe.Pointer(s.Data + uintptr(i))) + return Value{uint8Type, unsafe.Pointer(&val), fl} } panic(&ValueError{"reflect.Value.Index", k}) } @@ -925,7 +936,7 @@ // Non-interface value. var eface emptyInterface - eface.typ = v.typ.runtimeType() + eface.typ = toType(v.typ).common() eface.word = v.iword() if v.flag&flagIndir != 0 && v.kind() != Ptr && v.kind() != UnsafePointer { @@ -937,6 +948,10 @@ eface.word = iword(ptr) } + if v.flag&flagIndir == 0 && v.kind() != Ptr && v.kind() != UnsafePointer { + panic("missing flagIndir") + } + return *(*interface{})(unsafe.Pointer(&eface)) } @@ -1026,13 +1041,13 @@ // 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", toCommonType(tt.key), nil) + key = key.assignTo("reflect.Value.MapIndex", tt.key, nil) - word, ok := mapaccess(v.typ.runtimeType(), *(*iword)(v.iword()), key.iword()) + word, ok := mapaccess(v.typ, *(*iword)(v.iword()), key.iword()) if !ok { return Value{} } - typ := toCommonType(tt.elem) + typ := tt.elem fl := (v.flag | key.flag) & flagRO if typ.Kind() != Ptr && typ.Kind() != UnsafePointer { fl |= flagIndir @@ -1048,7 +1063,7 @@ func (v Value) MapKeys() []Value { v.mustBe(Map) tt := (*mapType)(unsafe.Pointer(v.typ)) - keyType := toCommonType(tt.key) + keyType := tt.key fl := v.flag & flagRO fl |= flag(keyType.Kind()) << flagKindShift @@ -1061,7 +1076,7 @@ if m != nil { mlen = maplen(m) } - it := mapiterinit(v.typ.runtimeType(), m) + it := mapiterinit(v.typ, m) a := make([]Value, mlen) var i int for i = 0; i < len(a); i++ { @@ -1160,7 +1175,7 @@ if x < 0 { x = -x } - return math.MaxFloat32 <= x && x <= math.MaxFloat64 + return math.MaxFloat32 < x && x <= math.MaxFloat64 } // OverflowInt returns true if the int64 x cannot be represented by v's type. @@ -1230,9 +1245,9 @@ if ChanDir(tt.dir)&RecvDir == 0 { panic("recv on send-only channel") } - word, selected, ok := chanrecv(v.typ.runtimeType(), *(*iword)(v.iword()), nb) + word, selected, ok := chanrecv(v.typ, *(*iword)(v.iword()), nb) if selected { - typ := toCommonType(tt.elem) + typ := tt.elem fl := flag(typ.Kind()) << flagKindShift if typ.Kind() != Ptr && typ.Kind() != UnsafePointer { fl |= flagIndir @@ -1259,8 +1274,8 @@ panic("send on recv-only channel") } x.mustBeExported() - x = x.assignTo("reflect.Value.Send", toCommonType(tt.elem), nil) - return chansend(v.typ.runtimeType(), *(*iword)(v.iword()), x.iword(), nb) + x = x.assignTo("reflect.Value.Send", tt.elem, nil) + return chansend(v.typ, *(*iword)(v.iword()), x.iword(), nb) } // Set assigns x to the value v. @@ -1382,12 +1397,12 @@ v.mustBeExported() key.mustBeExported() tt := (*mapType)(unsafe.Pointer(v.typ)) - key = key.assignTo("reflect.Value.SetMapIndex", toCommonType(tt.key), nil) + key = key.assignTo("reflect.Value.SetMapIndex", tt.key, nil) if val.typ != nil { val.mustBeExported() - val = val.assignTo("reflect.Value.SetMapIndex", toCommonType(tt.elem), nil) + val = val.assignTo("reflect.Value.SetMapIndex", tt.elem, nil) } - mapassign(v.typ.runtimeType(), *(*iword)(v.iword()), key.iword(), val.iword(), val.typ != nil) + mapassign(v.typ, *(*iword)(v.iword()), key.iword(), val.iword(), val.typ != nil) } // SetUint sets v's underlying value to x. @@ -1429,7 +1444,7 @@ } // Slice returns a slice of v. -// It panics if v's Kind is not Array or Slice. +// It panics if v's Kind is not Array, Slice, or String. func (v Value) Slice(beg, end int) Value { var ( cap int @@ -1439,21 +1454,34 @@ switch k := v.kind(); k { default: panic(&ValueError{"reflect.Value.Slice", k}) + case Array: if v.flag&flagAddr == 0 { panic("reflect.Value.Slice: slice of unaddressable array") } tt := (*arrayType)(unsafe.Pointer(v.typ)) cap = int(tt.len) - typ = (*sliceType)(unsafe.Pointer(toCommonType(tt.slice))) + typ = (*sliceType)(unsafe.Pointer(tt.slice)) base = v.val + case Slice: typ = (*sliceType)(unsafe.Pointer(v.typ)) s := (*SliceHeader)(v.val) base = unsafe.Pointer(s.Data) cap = s.Cap + case String: + s := (*StringHeader)(v.val) + if beg < 0 || end < beg || end > s.Len { + panic("reflect.Value.Slice: string slice index out of bounds") + } + var x string + val := (*StringHeader)(unsafe.Pointer(&x)) + val.Data = s.Data + uintptr(beg) + val.Len = end - beg + return Value{v.typ, unsafe.Pointer(&x), v.flag} } + if beg < 0 || end < beg || end > cap { panic("reflect.Value.Slice: slice index out of bounds") } @@ -1463,7 +1491,7 @@ // Reinterpret as *SliceHeader to edit. s := (*SliceHeader)(unsafe.Pointer(&x)) - s.Data = uintptr(base) + uintptr(beg)*toCommonType(typ.elem).Size() + s.Data = uintptr(base) + uintptr(beg)*typ.elem.Size() s.Len = end - beg s.Cap = cap - beg @@ -1516,7 +1544,7 @@ } if f&flagMethod == 0 { // Easy case - return v.typ.toType() + return toType(v.typ) } // Method value. @@ -1529,7 +1557,7 @@ panic("reflect: broken Value") } m := &tt.methods[i] - return toCommonType(m.typ).toType() + return toType(m.typ) } // Method on concrete type. ut := v.typ.uncommon() @@ -1537,7 +1565,7 @@ panic("reflect: broken Value") } m := &ut.methods[i] - return toCommonType(m.mtyp).toType() + return toType(m.mtyp) } // Uint returns v's underlying value, as a uint64. @@ -1711,10 +1739,10 @@ // A runtimeSelect is a single case passed to rselect. // This must match ../runtime/chan.c:/runtimeSelect type runtimeSelect struct { - dir uintptr // 0, SendDir, or RecvDir - typ *runtimeType // channel type - ch iword // interface word for channel - val iword // interface word for value (for SendDir) + dir uintptr // 0, SendDir, or RecvDir + typ *rtype // channel type + ch iword // interface word for channel + val iword // interface word for value (for SendDir) } // rselect runs a select. It returns the index of the chosen case, @@ -1801,13 +1829,13 @@ panic("reflect.Select: SendDir case using recv-only channel") } rc.ch = *(*iword)(ch.iword()) - rc.typ = tt.runtimeType() + rc.typ = &tt.rtype v := c.Send if !v.IsValid() { panic("reflect.Select: SendDir case missing Send value") } v.mustBeExported() - v = v.assignTo("reflect.Select", toCommonType(tt.elem), nil) + v = v.assignTo("reflect.Select", tt.elem, nil) rc.val = v.iword() case SelectRecv: @@ -1821,7 +1849,7 @@ ch.mustBe(Chan) ch.mustBeExported() tt := (*chanType)(unsafe.Pointer(ch.typ)) - rc.typ = tt.runtimeType() + rc.typ = &tt.rtype if ChanDir(tt.dir)&RecvDir == 0 { panic("reflect.Select: RecvDir case using send-only channel") } @@ -1831,8 +1859,8 @@ chosen, word, recvOK := rselect(runcases) if runcases[chosen].dir == uintptr(SelectRecv) { - tt := (*chanType)(unsafe.Pointer(toCommonType(runcases[chosen].typ))) - typ := toCommonType(tt.elem) + tt := (*chanType)(unsafe.Pointer(runcases[chosen].typ)) + typ := tt.elem fl := flag(typ.Kind()) << flagKindShift if typ.Kind() != Ptr && typ.Kind() != UnsafePointer { fl |= flagIndir @@ -1847,8 +1875,8 @@ */ // implemented in package runtime -func unsafe_New(Type) unsafe.Pointer -func unsafe_NewArray(Type, int) unsafe.Pointer +func unsafe_New(*rtype) unsafe.Pointer +func unsafe_NewArray(*rtype, int) unsafe.Pointer // MakeSlice creates a new zero-initialized slice value // for the specified slice type, length, and capacity. @@ -1871,7 +1899,7 @@ // Reinterpret as *SliceHeader to edit. s := (*SliceHeader)(unsafe.Pointer(&x)) - s.Data = uintptr(unsafe_NewArray(typ.Elem(), cap)) + s.Data = uintptr(unsafe_NewArray(typ.Elem().(*rtype), cap)) s.Len = len s.Cap = cap @@ -1889,7 +1917,7 @@ if typ.ChanDir() != BothDir { panic("reflect.MakeChan: unidirectional channel type") } - ch := makechan(typ.runtimeType(), uint64(buffer)) + ch := makechan(typ.(*rtype), uint64(buffer)) return Value{typ.common(), unsafe.Pointer(ch), flagIndir | (flag(Chan) << flagKindShift)} } @@ -1898,7 +1926,7 @@ if typ.Kind() != Map { panic("reflect.MakeMap of non-map type") } - m := makemap(typ.runtimeType()) + m := makemap(typ.(*rtype)) return Value{typ.common(), unsafe.Pointer(m), flagIndir | (flag(Map) << flagKindShift)} } @@ -1929,7 +1957,7 @@ // For an interface value with the noAddr bit set, // the representation is identical to an empty interface. eface := *(*emptyInterface)(unsafe.Pointer(&i)) - typ := toCommonType(eface.typ) + typ := eface.typ fl := flag(typ.Kind()) << flagKindShift if typ.Kind() != Ptr && typ.Kind() != UnsafePointer { fl |= flagIndir @@ -1951,7 +1979,7 @@ if t.Kind() == Ptr || t.Kind() == UnsafePointer { return Value{t, nil, fl} } - return Value{t, unsafe_New(typ), fl | flagIndir} + return Value{t, unsafe_New(typ.(*rtype)), fl | flagIndir} } // New returns a Value representing a pointer to a new zero value @@ -1960,7 +1988,7 @@ if typ == nil { panic("reflect: New(nil)") } - ptr := unsafe_New(typ) + ptr := unsafe_New(typ.(*rtype)) fl := flag(Ptr) << flagKindShift return Value{typ.common().ptrTo(), ptr, fl} } @@ -1975,7 +2003,7 @@ // assignTo returns a value v that can be assigned directly to typ. // It panics if v is not assignable to typ. // For a conversion to an interface type, target is a suggested scratch space to use. -func (v Value) assignTo(context string, dst *commonType, target *interface{}) Value { +func (v Value) assignTo(context string, dst *rtype, target *interface{}) Value { if v.flag&flagMethod != 0 { panic(context + ": cannot assign method value to type " + dst.String()) } @@ -1997,7 +2025,7 @@ if dst.NumMethod() == 0 { *target = x } else { - ifaceE2I(dst.runtimeType(), x, unsafe.Pointer(target)) + ifaceE2I(dst, x, unsafe.Pointer(target)) } return Value{dst, unsafe.Pointer(target), flagIndir | flag(Interface)< ptrSize { // Assume ptrSize >= 4, so this must be uint64. - ptr := unsafe_New(t) + ptr := unsafe_New(typ) *(*uint64)(unsafe.Pointer(ptr)) = bits - return Value{typ, ptr, f | flag(typ.Kind())< ptrSize { // Assume ptrSize >= 4, so this must be float64. - ptr := unsafe_New(t) + ptr := unsafe_New(typ) *(*float64)(unsafe.Pointer(ptr)) = v - return Value{typ, ptr, f | flag(typ.Kind())< ptrSize { - ptr := unsafe_New(t) + ptr := unsafe_New(typ) switch typ.size { case 8: *(*complex64)(unsafe.Pointer(ptr)) = complex64(v) case 16: *(*complex128)(unsafe.Pointer(ptr)) = v } - return Value{typ, ptr, f | flag(typ.Kind())<= 0 { + _, err1 = raw_ioctl(0, TIOCSCTTY, sys.Ctty) if err1 != 0 { goto childerror } diff -r 69102534501a libgo/go/syscall/libcall_linux.go --- a/libgo/go/syscall/libcall_linux.go Mon Nov 19 08:26:48 2012 -0800 +++ b/libgo/go/syscall/libcall_linux.go Tue Nov 20 22:23:37 2012 -0800 @@ -280,6 +280,9 @@ //sys sendfile(outfd int, infd int, offset *Offset_t, count int) (written int, err error) //sendfile64(outfd int, infd int, offset *Offset_t, count Size_t) Ssize_t func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { + if raceenabled { + raceReleaseMerge(unsafe.Pointer(&ioSync)) + } var soff Offset_t var psoff *Offset_t if offset != nil { diff -r 69102534501a libgo/runtime/go-cgo.c --- a/libgo/runtime/go-cgo.c Mon Nov 19 08:26:48 2012 -0800 +++ b/libgo/runtime/go-cgo.c Tue Nov 20 22:23:37 2012 -0800 @@ -9,16 +9,6 @@ #include "interface.h" #include "go-panic.h" -/* Go memory allocated by code not written in Go. We keep a linked - list of these allocations so that the garbage collector can see - them. */ - -struct cgoalloc -{ - struct cgoalloc *next; - void *alloc; -}; - /* Prepare to call from code written in Go to code written in C or C++. This takes the current goroutine out of the Go scheduler, as though it were making a system call. Otherwise the program can @@ -67,7 +57,7 @@ /* We are going back to Go, and we are not in a recursive call. Let the garbage collector clean up any unreferenced memory. */ - g->cgoalloc = NULL; + g->cgomal = NULL; } /* If we are invoked because the C function called _cgo_panic, then @@ -100,15 +90,15 @@ { void *ret; G *g; - struct cgoalloc *c; + CgoMal *c; ret = __go_alloc (n); g = runtime_g (); - c = (struct cgoalloc *) __go_alloc (sizeof (struct cgoalloc)); - c->next = g->cgoalloc; + c = (CgoMal *) __go_alloc (sizeof (CgoMal)); + c->next = g->cgomal; c->alloc = ret; - g->cgoalloc = c; + g->cgomal = c; return ret; } diff -r 69102534501a libgo/runtime/go-make-slice.c --- a/libgo/runtime/go-make-slice.c Mon Nov 19 08:26:48 2012 -0800 +++ b/libgo/runtime/go-make-slice.c Tue Nov 20 22:23:37 2012 -0800 @@ -15,6 +15,11 @@ #include "arch.h" #include "malloc.h" +/* Dummy word to use as base pointer for make([]T, 0). + Since you cannot take the address of such a slice, + you can't tell that they all have the same base pointer. */ +uintptr runtime_zerobase; + struct __go_open_array __go_make_slice2 (const struct __go_type_descriptor *td, uintptr_t len, uintptr_t cap) @@ -24,7 +29,6 @@ intgo icap; uintptr_t size; struct __go_open_array ret; - unsigned int flag; __go_assert (td->__code == GO_SLICE); std = (const struct __go_slice_type *) td; @@ -44,10 +48,19 @@ ret.__capacity = icap; size = cap * std->__element_type->__size; - flag = ((std->__element_type->__code & GO_NO_POINTERS) != 0 - ? FlagNoPointers - : 0); - ret.__values = runtime_mallocgc (size, flag, 1, 1); + + if (size == 0) + ret.__values = &runtime_zerobase; + else if ((std->__element_type->__code & GO_NO_POINTERS) != 0) + ret.__values = runtime_mallocgc (size, FlagNoPointers, 1, 1); + else + { + ret.__values = runtime_mallocgc (size, 0, 1, 1); + + if (UseSpanType) + runtime_settype (ret.__values, + (uintptr) std->__element_type | TypeInfo_Array); + } return ret; } diff -r 69102534501a libgo/runtime/go-traceback.c --- a/libgo/runtime/go-traceback.c Mon Nov 19 08:26:48 2012 -0800 +++ b/libgo/runtime/go-traceback.c Tue Nov 20 22:23:37 2012 -0800 @@ -32,7 +32,7 @@ intgo line; if (__go_file_line (pcbuf[i], &fn, &file, &line) - && runtime_showframe (fn.str)) + && runtime_showframe (fn)) { runtime_printf ("%S\n", fn); runtime_printf ("\t%S:%D\n", file, (int64) line); diff -r 69102534501a libgo/runtime/go-unsafe-new.c --- a/libgo/runtime/go-unsafe-new.c Mon Nov 19 08:26:48 2012 -0800 +++ b/libgo/runtime/go-unsafe-new.c Tue Nov 20 22:23:37 2012 -0800 @@ -5,28 +5,30 @@ license that can be found in the LICENSE file. */ #include "runtime.h" -#include "go-alloc.h" +#include "arch.h" +#include "malloc.h" #include "go-type.h" #include "interface.h" /* Implement unsafe_New, called from the reflect package. */ -void *unsafe_New (struct __go_empty_interface type) +void *unsafe_New (const struct __go_type_descriptor *) asm ("reflect.unsafe_New"); /* The dynamic type of the argument will be a pointer to a type descriptor. */ void * -unsafe_New (struct __go_empty_interface type) +unsafe_New (const struct __go_type_descriptor *descriptor) { - const struct __go_type_descriptor *descriptor; + uint32 flag; + void *ret; - if (((uintptr_t) type.__type_descriptor & reflectFlags) != 0) - runtime_panicstring ("invalid interface value"); + flag = (descriptor->__code & GO_NO_POINTERS) != 0 ? FlagNoPointers : 0; + ret = runtime_mallocgc (descriptor->__size, flag, 1, 1); - /* FIXME: We should check __type_descriptor to verify that this is - really a type descriptor. */ - descriptor = (const struct __go_type_descriptor *) type.__object; - return __go_alloc (descriptor->__size); + if (UseSpanType && flag == 0) + runtime_settype (ret, (uintptr) descriptor | TypeInfo_SingleObject); + + return ret; } diff -r 69102534501a libgo/runtime/go-unsafe-newarray.c --- a/libgo/runtime/go-unsafe-newarray.c Mon Nov 19 08:26:48 2012 -0800 +++ b/libgo/runtime/go-unsafe-newarray.c Tue Nov 20 22:23:37 2012 -0800 @@ -5,28 +5,37 @@ license that can be found in the LICENSE file. */ #include "runtime.h" -#include "go-alloc.h" +#include "arch.h" +#include "malloc.h" #include "go-type.h" #include "interface.h" /* Implement unsafe_NewArray, called from the reflect package. */ -void *unsafe_NewArray (struct __go_empty_interface type, int n) +void *unsafe_NewArray (const struct __go_type_descriptor *, intgo) asm ("reflect.unsafe_NewArray"); /* The dynamic type of the argument will be a pointer to a type descriptor. */ void * -unsafe_NewArray (struct __go_empty_interface type, int n) +unsafe_NewArray (const struct __go_type_descriptor *descriptor, intgo n) { - const struct __go_type_descriptor *descriptor; + uint64 size; + void *ret; - if (((uintptr_t) type.__type_descriptor & reflectFlags) != 0) - runtime_panicstring ("invalid interface value"); + size = n * descriptor->__size; + if (size == 0) + ret = &runtime_zerobase; + else if ((descriptor->__code & GO_NO_POINTERS) != 0) + ret = runtime_mallocgc (size, FlagNoPointers, 1, 1); + else + { + ret = runtime_mallocgc (size, 0, 1, 1); - /* FIXME: We should check __type_descriptor to verify that this is - really a type descriptor. */ - descriptor = (const struct __go_type_descriptor *) type.__object; - return __go_alloc (descriptor->__size * n); + if (UseSpanType) + runtime_settype (ret, (uintptr) descriptor | TypeInfo_Array); + } + + return ret; } diff -r 69102534501a libgo/runtime/malloc.goc --- a/libgo/runtime/malloc.goc Mon Nov 19 08:26:48 2012 -0800 +++ b/libgo/runtime/malloc.goc Tue Nov 20 22:23:37 2012 -0800 @@ -20,7 +20,7 @@ MHeap runtime_mheap; -extern MStats mstats; // defined in extern.go +extern MStats mstats; // defined in zruntime_def_$GOOS_$GOARCH.go extern volatile intgo runtime_MemProfileRate __asm__ ("runtime.MemProfileRate"); @@ -341,32 +341,30 @@ // enough to hold 4 bits per allocated word. if(sizeof(void*) == 8 && (limit == 0 || limit > (1<<30))) { // On a 64-bit machine, allocate from a single contiguous reservation. - // 16 GB should be big enough for now. + // 128 GB (MaxMem) should be big enough for now. // // The code will work with the reservation at any address, but ask - // SysReserve to use 0x000000f800000000 if possible. - // Allocating a 16 GB region takes away 36 bits, and the amd64 + // SysReserve to use 0x000000c000000000 if possible. + // Allocating a 128 GB region takes away 37 bits, and the amd64 // doesn't let us choose the top 17 bits, so that leaves the 11 bits - // in the middle of 0x00f8 for us to choose. Choosing 0x00f8 means - // that the valid memory addresses will begin 0x00f8, 0x00f9, 0x00fa, 0x00fb. - // None of the bytes f8 f9 fa fb can appear in valid UTF-8, and - // they are otherwise as far from ff (likely a common byte) as possible. - // Choosing 0x00 for the leading 6 bits was more arbitrary, but it - // is not a common ASCII code point either. Using 0x11f8 instead + // in the middle of 0x00c0 for us to choose. Choosing 0x00c0 means + // that the valid memory addresses will begin 0x00c0, 0x00c1, ..., 0x0x00df. + // In little-endian, that's c0 00, c1 00, ..., df 00. None of those are valid + // UTF-8 sequences, and they are otherwise as far away from + // ff (likely a common byte) as possible. An earlier attempt to use 0x11f8 // caused out of memory errors on OS X during thread allocations. // These choices are both for debuggability and to reduce the // odds of the conservative garbage collector not collecting memory // because some non-pointer block of memory had a bit pattern // that matched a memory address. // - // Actually we reserve 17 GB (because the bitmap ends up being 1 GB) - // but it hardly matters: fc is not valid UTF-8 either, and we have to - // allocate 15 GB before we get that far. + // Actually we reserve 136 GB (because the bitmap ends up being 8 GB) + // but it hardly matters: e0 00 is not valid UTF-8 either. // // If this fails we fall back to the 32 bit memory mechanism - arena_size = (uintptr)(16LL<<30); + arena_size = MaxMem; bitmap_size = arena_size / (sizeof(void*)*8/4); - p = runtime_SysReserve((void*)(0x00f8ULL<<32), bitmap_size + arena_size); + p = runtime_SysReserve((void*)(0x00c0ULL<<32), bitmap_size + arena_size); } if (p == nil) { // On a 32-bit machine, we can't typically get away @@ -455,6 +453,8 @@ runtime_SysMap(p, n); h->arena_used += n; runtime_MHeap_MapBits(h); + if(raceenabled) + runtime_racemapshadow(p, n); return p; } @@ -481,6 +481,8 @@ if(h->arena_used > h->arena_end) h->arena_end = h->arena_used; runtime_MHeap_MapBits(h); + if(raceenabled) + runtime_racemapshadow(p, n); } return p; @@ -709,12 +711,13 @@ } void * -runtime_new(Type *typ) +runtime_new(const Type *typ) { void *ret; uint32 flag; - runtime_m()->racepc = runtime_getcallerpc(&typ); + if(raceenabled) + runtime_m()->racepc = runtime_getcallerpc(&typ); flag = typ->__code&GO_NO_POINTERS ? FlagNoPointers : 0; ret = runtime_mallocgc(typ->__size, flag, 1, 1); diff -r 69102534501a libgo/runtime/malloc.h --- a/libgo/runtime/malloc.h Mon Nov 19 08:26:48 2012 -0800 +++ b/libgo/runtime/malloc.h Tue Nov 20 22:23:37 2012 -0800 @@ -114,12 +114,12 @@ HeapAllocChunk = 1<<20, // Chunk size for heap growth // Number of bits in page to span calculations (4k pages). - // On 64-bit, we limit the arena to 16G, so 22 bits suffices. - // On 32-bit, we don't bother limiting anything: 20 bits for 4G. + // On 64-bit, we limit the arena to 128GB, or 37 bits. + // On 32-bit, we don't bother limiting anything, so we use the full 32-bit address. #if __SIZEOF_POINTER__ == 8 - MHeapMap_Bits = 22, + MHeapMap_Bits = 37 - PageShift, #else - MHeapMap_Bits = 20, + MHeapMap_Bits = 32 - PageShift, #endif // Max number of threads to run garbage collection. @@ -133,7 +133,7 @@ // This must be a #define instead of an enum because it // is so large. #if __SIZEOF_POINTER__ == 8 -#define MaxMem (16ULL<<30) /* 16 GB */ +#define MaxMem (1ULL<<(MHeapMap_Bits+PageShift)) /* 128 GB */ #else #define MaxMem ((uintptr)-1) #endif @@ -198,7 +198,7 @@ // Statistics. -// Shared with Go: if you edit this structure, also edit extern.go. +// Shared with Go: if you edit this structure, also edit type MemStats in mem.go. struct MStats { // General statistics. @@ -358,7 +358,7 @@ uintptr npages; // number of pages in span MLink *freelist; // list of free objects uint32 ref; // number of allocated objects in this span - uint32 sizeclass; // size class + int32 sizeclass; // size class uintptr elemsize; // computed from sizeclass or from npages uint32 state; // MSpanInUse etc int64 unusedsince; // First time spotted by GC in MSpanFree state @@ -452,6 +452,8 @@ bool runtime_blockspecial(void*); void runtime_setblockspecial(void*, bool); void runtime_purgecachedstats(MCache*); +void* runtime_new(const Type *); +#define runtime_cnew(T) runtime_new(T) void runtime_settype(void*, uintptr); void runtime_settype_flush(M*, bool); @@ -487,3 +489,8 @@ // Enables type information at the end of blocks allocated from heap DebugTypeAtBlockEnd = 0, }; + +// defined in mgc0.go +void runtime_gc_m_ptr(Eface*); + +void runtime_memorydump(void); diff -r 69102534501a libgo/runtime/mgc0.c --- a/libgo/runtime/mgc0.c Mon Nov 19 08:26:48 2012 -0800 +++ b/libgo/runtime/mgc0.c Tue Nov 20 22:23:37 2012 -0800 @@ -874,6 +874,81 @@ } } +static void +dumpspan(uint32 idx) +{ + int32 sizeclass, n, npages, i, column; + uintptr size; + byte *p; + byte *arena_start; + MSpan *s; + bool allocated, special; + + s = runtime_mheap.allspans[idx]; + if(s->state != MSpanInUse) + return; + arena_start = runtime_mheap.arena_start; + p = (byte*)(s->start << PageShift); + sizeclass = s->sizeclass; + size = s->elemsize; + if(sizeclass == 0) { + n = 1; + } else { + npages = runtime_class_to_allocnpages[sizeclass]; + n = (npages << PageShift) / size; + } + + runtime_printf("%p .. %p:\n", p, p+n*size); + column = 0; + for(; n>0; n--, p+=size) { + uintptr off, *bitp, shift, bits; + + off = (uintptr*)p - (uintptr*)arena_start; + bitp = (uintptr*)arena_start - off/wordsPerBitmapWord - 1; + shift = off % wordsPerBitmapWord; + bits = *bitp>>shift; + + allocated = ((bits & bitAllocated) != 0); + special = ((bits & bitSpecial) != 0); + + for(i=0; (uint32)i= size) { + runtime_printf(allocated ? ") " : "] "); + } + + column++; + if(column == 8) { + runtime_printf("\n"); + column = 0; + } + } + } + runtime_printf("\n"); +} + +// A debugging function to dump the contents of memory +void +runtime_memorydump(void) +{ + uint32 spanidx; + + for(spanidx=0; spanidxnext; for(i=0; i<(uint32)fb->cnt; i++) { diff -r 69102534501a libgo/runtime/mheap.c --- a/libgo/runtime/mheap.c Mon Nov 19 08:26:48 2012 -0800 +++ b/libgo/runtime/mheap.c Tue Nov 20 22:23:37 2012 -0800 @@ -343,6 +343,15 @@ runtime_MSpanList_Insert(&h->large, s); } +static void +forcegchelper(void *vnote) +{ + Note *note = (Note*)vnote; + + runtime_gc(1); + runtime_notewakeup(note); +} + // Release (part of) unused memory to OS. // Goroutine created at startup. // Loop forever. @@ -356,7 +365,7 @@ uintptr released, sumreleased; const byte *env; bool trace; - Note note; + Note note, *notep; USED(dummy); @@ -387,7 +396,15 @@ now = runtime_nanotime(); if(now - mstats.last_gc > forcegc) { runtime_unlock(h); - runtime_gc(1); + // The scavenger can not block other goroutines, + // otherwise deadlock detector can fire spuriously. + // GC blocks other goroutines via the runtime_worldsema. + runtime_noteclear(¬e); + notep = ¬e; + __go_go(forcegchelper, (void*)¬ep); + runtime_entersyscall(); + runtime_notesleep(¬e); + runtime_exitsyscall(); runtime_lock(h); now = runtime_nanotime(); if (trace) diff -r 69102534501a libgo/runtime/mprof.goc --- a/libgo/runtime/mprof.goc Mon Nov 19 08:26:48 2012 -0800 +++ b/libgo/runtime/mprof.goc Tue Nov 20 22:23:37 2012 -0800 @@ -315,8 +315,7 @@ runtime_unlock(&proflock); } -// Go interface to profile data. (Declared in extern.go) -// Assumes Go sizeof(int) == sizeof(int32) +// Go interface to profile data. (Declared in debug.go) // Must match MemProfileRecord in debug.go. typedef struct Record Record; diff -r 69102534501a libgo/runtime/proc.c --- a/libgo/runtime/proc.c Mon Nov 19 08:26:48 2012 -0800 +++ b/libgo/runtime/proc.c Tue Nov 20 22:23:37 2012 -0800 @@ -18,6 +18,7 @@ #include "defs.h" #include "malloc.h" #include "race.h" +#include "go-type.h" #include "go-defer.h" #ifdef USING_SPLIT_STACK @@ -237,7 +238,7 @@ Lock; G *gfree; // available g's (status == Gdead) - int32 goidgen; + int64 goidgen; G *ghead; // g's waiting to run G *gtail; @@ -601,7 +602,7 @@ status = "???"; break; } - runtime_printf("goroutine %d [%s]:\n", gp->goid, status); + runtime_printf("goroutine %D [%s]:\n", gp->goid, status); } void @@ -745,7 +746,7 @@ // If g is the idle goroutine for an m, hand it off. if(gp->idlem != nil) { if(gp->idlem->idleg != nil) { - runtime_printf("m%d idle out of sync: g%d g%d\n", + runtime_printf("m%d idle out of sync: g%D g%D\n", gp->idlem->id, gp->idlem->idleg->goid, gp->goid); runtime_throw("runtime: double idle"); @@ -847,7 +848,7 @@ // Mark runnable. if(gp->status == Grunnable || gp->status == Grunning) { - runtime_printf("goroutine %d has status %d\n", gp->goid, gp->status); + runtime_printf("goroutine %D has status %d\n", gp->goid, gp->status); runtime_throw("bad g->status in ready"); } gp->status = Grunnable; @@ -1204,7 +1205,16 @@ pthread_t tid; size_t stacksize; - mp = runtime_malloc(sizeof(M)); +#if 0 + static const Type *mtype; // The Go type M + if(mtype == nil) { + Eface e; + runtime_gc_m_ptr(&e); + mtype = ((const PtrType*)e.__type_descriptor)->__element_type; + } +#endif + + mp = runtime_mal(sizeof *mp); mcommoninit(mp); mp->g0 = runtime_malg(-1, nil, nil); @@ -1513,9 +1523,9 @@ byte *sp; size_t spsize; G *newg; - int32 goid; + int64 goid; - goid = runtime_xadd((uint32*)&runtime_sched.goidgen, 1); + goid = runtime_xadd64((uint64*)&runtime_sched.goidgen, 1); if(raceenabled) runtime_racegostart(goid, runtime_getcallerpc(&fn)); diff -r 69102534501a libgo/runtime/race.h --- a/libgo/runtime/race.h Mon Nov 19 08:26:48 2012 -0800 +++ b/libgo/runtime/race.h Tue Nov 20 22:23:37 2012 -0800 @@ -15,6 +15,7 @@ // Finalize race detection subsystem, does not return. void runtime_racefini(void); +void runtime_racemapshadow(void *addr, uintptr size); void runtime_racemalloc(void *p, uintptr sz, void *pc); void runtime_racefree(void *p); void runtime_racegostart(int32 goid, void *pc); diff -r 69102534501a libgo/runtime/runtime.c --- a/libgo/runtime/runtime.c Mon Nov 19 08:26:48 2012 -0800 +++ b/libgo/runtime/runtime.c Tue Nov 20 22:23:37 2012 -0800 @@ -159,13 +159,13 @@ } bool -runtime_showframe(const unsigned char *s) +runtime_showframe(String s) { static int32 traceback = -1; if(traceback < 0) traceback = runtime_gotraceback(); - return traceback > 1 || (s != nil && __builtin_strchr((const char*)s, '.') != nil && __builtin_memcmp(s, "runtime.", 7) != 0); + return traceback > 1 || (__builtin_memchr(s.str, '.', s.len) != nil && __builtin_memcmp(s.str, "runtime.", 7) != 0); } static Lock ticksLock; diff -r 69102534501a libgo/runtime/runtime.h --- a/libgo/runtime/runtime.h Mon Nov 19 08:26:48 2012 -0800 +++ b/libgo/runtime/runtime.h Tue Nov 20 22:23:37 2012 -0800 @@ -63,6 +63,7 @@ typedef struct LFNode LFNode; typedef struct ParFor ParFor; typedef struct ParForThread ParForThread; +typedef struct CgoMal CgoMal; typedef struct __go_open_array Slice; typedef struct String String; @@ -72,13 +73,14 @@ typedef struct __go_defer_stack Defer; typedef struct __go_panic_stack Panic; +typedef struct __go_ptr_type PtrType; typedef struct __go_func_type FuncType; typedef struct __go_map_type MapType; typedef struct Traceback Traceback; /* - * per-cpu declaration. + * Per-CPU declaration. */ extern M* runtime_m(void); extern G* runtime_g(void); @@ -159,7 +161,7 @@ void* param; // passed parameter on wakeup bool fromgogo; // reached from gogo int16 status; - int32 goid; + int64 goid; uint32 selgen; // valid sudog pointer const char* waitreason; // if status==Gwaiting G* schedlink; @@ -178,7 +180,7 @@ uintptr gopc; // pc of go statement that created this goroutine int32 ncgo; - struct cgoalloc *cgoalloc; + CgoMal* cgomal; Traceback* traceback; @@ -201,7 +203,7 @@ int32 profilehz; int32 helpgc; uint32 fastrand; - uint64 ncgocall; + uint64 ncgocall; // number of cgo calls in total Note havenextg; G* nextg; M* alllink; // on allm @@ -316,6 +318,14 @@ uint64 nsleep; }; +// Track memory allocated by code not written in Go during a cgo call, +// so that the garbage collector can see them. +struct CgoMal +{ + CgoMal *next; + byte *alloc; +}; + /* * defined macros * you need super-gopher-guru privilege @@ -329,6 +339,7 @@ /* * external data */ +extern uintptr runtime_zerobase; G* runtime_allg; G* runtime_lastg; M* runtime_allm; @@ -569,7 +580,7 @@ void runtime_LockOSThread(void) __asm__("runtime.LockOSThread"); void runtime_UnlockOSThread(void) __asm__("runtime.UnlockOSThread"); -bool runtime_showframe(const unsigned char*); +bool runtime_showframe(String); uintptr runtime_memlimit(void);