diff --git a/compiler/compiler.go b/compiler/compiler.go index e4cd8d4b..f5678887 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/runtime/chan.go b/src/runtime/chan.go index 929b8c73..6563d455 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/testdata/channel.go b/testdata/channel.go index 52d498fc..e1acea7e 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 b7036f2b..883a547a 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