Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions compiler/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Comment on lines -1204 to -1205
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This used to be the case, but not anymore as you found out.

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:
Expand Down Expand Up @@ -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:
Expand Down
33 changes: 26 additions & 7 deletions src/reflect/value.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"})
}
}

Expand Down
32 changes: 32 additions & 0 deletions src/runtime/chan.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
9 changes: 8 additions & 1 deletion src/runtime/hashmap.go
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -80,13 +80,20 @@ 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
}
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) {
Expand Down
6 changes: 5 additions & 1 deletion testdata/channel.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions testdata/channel.txt
Original file line number Diff line number Diff line change
@@ -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
Expand Down
20 changes: 10 additions & 10 deletions testdata/float.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
4 changes: 2 additions & 2 deletions testdata/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
1 change: 1 addition & 0 deletions testdata/zeroalloc.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
package main

func main() {
p := []byte{}
for len(p) >= 1 {
Expand Down