diff --git a/compiler/compiler.go b/compiler/compiler.go index e4cd8d4bd1..f5678887ad 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -1201,9 +1201,7 @@ func (b *builder) createBuiltin(args []ssa.Value, callName string, pos token.Pos var llvmCap llvm.Value switch args[0].Type().(type) { case *types.Chan: - // Channel. Buffered channels haven't been implemented yet so always - // return 0. - llvmCap = llvm.ConstInt(b.intType, 0, false) + llvmCap = b.createRuntimeCall("chanCap", []llvm.Value{value}, "cap") case *types.Slice: llvmCap = b.CreateExtractValue(value, 2, "cap") default: @@ -1259,9 +1257,7 @@ func (b *builder) createBuiltin(args []ssa.Value, callName string, pos token.Pos // string or slice llvmLen = b.CreateExtractValue(value, 1, "len") case *types.Chan: - // Channel. Buffered channels haven't been implemented yet so always - // return 0. - llvmLen = llvm.ConstInt(b.intType, 0, false) + llvmLen = b.createRuntimeCall("chanLen", []llvm.Value{value}, "len") case *types.Map: llvmLen = b.createRuntimeCall("hashmapLen", []llvm.Value{value}, "len") default: diff --git a/src/reflect/value.go b/src/reflect/value.go index a1c69370e0..e71eaee8b9 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -304,29 +304,48 @@ func (v Value) Slice(i, j int) Value { panic("unimplemented: (reflect.Value).Slice()") } +//go:linkname maplen runtime.hashmapLenUnsafePointer +func maplen(p unsafe.Pointer) int + +//go:linkname chanlen runtime.chanLenUnsafePointer +func chanlen(p unsafe.Pointer) int + // Len returns the length of this value for slices, strings, arrays, channels, -// and maps. For oter types, it panics. +// and maps. For other types, it panics. func (v Value) Len() int { t := v.Type() switch t.Kind() { + case Array: + return v.Type().Len() + case Chan: + return chanlen(v.value) + case Map: + return maplen(v.value) case Slice: return int((*SliceHeader)(v.value).Len) case String: return int((*StringHeader)(v.value).Len) - case Array: - return v.Type().Len() - default: // Chan, Map - panic("unimplemented: (reflect.Value).Len()") + default: + panic(&ValueError{"Len"}) } } +//go:linkname chancap runtime.chanCapUnsafePointer +func chancap(p unsafe.Pointer) int + +// Cap returns the capacity of this value for arrays, channels and slices. +// For other types, it panics. func (v Value) Cap() int { t := v.Type() switch t.Kind() { + case Array: + return v.Type().Len() + case Chan: + return chancap(v.value) case Slice: return int((*SliceHeader)(v.value).Cap) - default: // Array, Chan - panic("unimplemented: (reflect.Value).Cap()") + default: + panic(&ValueError{"Cap"}) } } diff --git a/src/runtime/chan.go b/src/runtime/chan.go index 929b8c7300..6563d4557f 100644 --- a/src/runtime/chan.go +++ b/src/runtime/chan.go @@ -136,6 +136,38 @@ func chanMake(elementSize uintptr, bufSize uintptr) *channel { } } +// Return the number of entries in this chan, called from the len builtin. +// A nil chan is defined as having length 0. +//go:inline +func chanLen(c *channel) int { + if c == nil { + return 0 + } + return int(c.bufUsed) +} + +// wrapper for use in reflect +func chanLenUnsafePointer(p unsafe.Pointer) int { + c := (*channel)(p) + return chanLen(c) +} + +// Return the capacity of this chan, called from the cap builtin. +// A nil chan is defined as having capacity 0. +//go:inline +func chanCap(c *channel) int { + if c == nil { + return 0 + } + return int(c.bufSize) +} + +// wrapper for use in reflect +func chanCapUnsafePointer(p unsafe.Pointer) int { + c := (*channel)(p) + return chanCap(c) +} + // resumeRX resumes the next receiver and returns the destination pointer. // If the ok value is true, then the caller is expected to store a value into this pointer. func (ch *channel) resumeRX(ok bool) unsafe.Pointer { diff --git a/src/runtime/hashmap.go b/src/runtime/hashmap.go index bd940c759f..d7d60c89fc 100644 --- a/src/runtime/hashmap.go +++ b/src/runtime/hashmap.go @@ -1,7 +1,7 @@ package runtime // This is a hashmap implementation for the map[T]T type. -// It is very rougly based on the implementation of the Go hashmap: +// It is very roughly based on the implementation of the Go hashmap: // // https://golang.org/src/runtime/map.go @@ -80,6 +80,7 @@ func hashmapMake(keySize, valueSize uint8, sizeHint uintptr) *hashmap { // Return the number of entries in this hashmap, called from the len builtin. // A nil hashmap is defined as having length 0. +//go:inline func hashmapLen(m *hashmap) int { if m == nil { return 0 @@ -87,6 +88,12 @@ func hashmapLen(m *hashmap) int { return int(m.count) } +// wrapper for use in reflect +func hashmapLenUnsafePointer(p unsafe.Pointer) int { + m := (*hashmap)(p) + return hashmapLen(m) +} + // Set a specified key to a given value. Grow the map if necessary. //go:nobounds func hashmapSet(m *hashmap, key unsafe.Pointer, value unsafe.Pointer, hash uint32, keyEqual func(x, y unsafe.Pointer, n uintptr) bool) { diff --git a/testdata/channel.go b/testdata/channel.go index 52d498fcbc..e1acea7ead 100644 --- a/testdata/channel.go +++ b/testdata/channel.go @@ -9,7 +9,11 @@ import ( var wg sync.WaitGroup func main() { - ch := make(chan int) + ch := make(chan int, 2) + ch <- 1 + println("len, cap of channel:", len(ch), cap(ch), ch == nil) + + ch = make(chan int) println("len, cap of channel:", len(ch), cap(ch), ch == nil) wg.Add(1) diff --git a/testdata/channel.txt b/testdata/channel.txt index b7036f2b27..883a547a64 100644 --- a/testdata/channel.txt +++ b/testdata/channel.txt @@ -1,3 +1,4 @@ +len, cap of channel: 1 2 false len, cap of channel: 0 0 false recv from open channel: 1 true received num: 2 diff --git a/testdata/float.go b/testdata/float.go index 4063281b71..f2b7c52e32 100644 --- a/testdata/float.go +++ b/testdata/float.go @@ -58,14 +58,14 @@ func main() { println(complex128(c64)) // binops on complex numbers - c64 = 5+2i - println("complex64 add: ", c64 + -3+8i) - println("complex64 sub: ", c64 - -3+8i) - println("complex64 mul: ", c64 * -3+8i) - println("complex64 div: ", c64 / -3+8i) - c128 = -5+2i - println("complex128 add:", c128 + 2+6i) - println("complex128 sub:", c128 - 2+6i) - println("complex128 mul:", c128 * 2+6i) - println("complex128 div:", c128 / 2+6i) + c64 = 5 + 2i + println("complex64 add: ", c64+-3+8i) + println("complex64 sub: ", c64 - -3 + 8i) + println("complex64 mul: ", c64*-3+8i) + println("complex64 div: ", c64/-3+8i) + c128 = -5 + 2i + println("complex128 add:", c128+2+6i) + println("complex128 sub:", c128-2+6i) + println("complex128 mul:", c128*2+6i) + println("complex128 div:", c128/2+6i) } diff --git a/testdata/init.go b/testdata/init.go index 8f81668c53..6e7d9e7baf 100644 --- a/testdata/init.go +++ b/testdata/init.go @@ -38,8 +38,8 @@ var ( uint8SliceSrc = []uint8{3, 100} uint8SliceDst []uint8 - intSliceSrc = []int16{5, 123, 1024} - intSliceDst []int16 + intSliceSrc = []int16{5, 123, 1024} + intSliceDst []int16 ) func init() { diff --git a/testdata/zeroalloc.go b/testdata/zeroalloc.go index 53c6fa0bcb..e5893227fa 100644 --- a/testdata/zeroalloc.go +++ b/testdata/zeroalloc.go @@ -1,4 +1,5 @@ package main + func main() { p := []byte{} for len(p) >= 1 {