aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/cgocall.go
diff options
context:
space:
mode:
authorEgon Elbre <egonelbre@gmail.com>2019-10-01 18:12:55 +0300
committerIan Lance Taylor <iant@golang.org>2019-10-02 20:51:29 +0000
commite85ffec784b867f016805873eec5dc91eec1c99a (patch)
tree840eca7df5abeaef6cfa9065f6c22c112facdf53 /src/runtime/cgocall.go
parent30d7b6400860d87d810a0db3593b28dfb72879f2 (diff)
downloadgo-e85ffec784b867f016805873eec5dc91eec1c99a.tar.gz
go-e85ffec784b867f016805873eec5dc91eec1c99a.zip
cmd/cgo: optimize cgoCheckPointer call
Currently cgoCheckPointer is only used with one optional argument. Using a slice for the optional arguments is quite expensive, hence replace it with a single interface{}. This results in ~30% improvement. When checking struct fields, they quite often end up being without pointers. Check this before calling cgoCheckPointer, which results in additional ~20% improvement. Inline some p == nil checks from cgoIsGoPointer which gives additional ~15% improvement. All of this translates to: name old time/op new time/op delta CgoCall/add-int-32 46.9ns ± 1% 46.6ns ± 1% -0.75% (p=0.000 n=18+20) CgoCall/one-pointer-32 143ns ± 1% 87ns ± 1% -38.96% (p=0.000 n=20+20) CgoCall/eight-pointers-32 767ns ± 0% 327ns ± 1% -57.30% (p=0.000 n=18+16) CgoCall/eight-pointers-nil-32 110ns ± 1% 89ns ± 2% -19.10% (p=0.000 n=19+19) CgoCall/eight-pointers-array-32 5.09µs ± 1% 3.56µs ± 2% -30.09% (p=0.000 n=19+19) CgoCall/eight-pointers-slice-32 3.92µs ± 0% 2.57µs ± 2% -34.48% (p=0.000 n=20+20) Change-Id: I2aa9f5ae8962a9a41a7fb1db0c300893109d0d75 Reviewed-on: https://go-review.googlesource.com/c/go/+/198081 Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
Diffstat (limited to 'src/runtime/cgocall.go')
-rw-r--r--src/runtime/cgocall.go18
1 files changed, 12 insertions, 6 deletions
diff --git a/src/runtime/cgocall.go b/src/runtime/cgocall.go
index a881ae1489..3595e49ed5 100644
--- a/src/runtime/cgocall.go
+++ b/src/runtime/cgocall.go
@@ -406,7 +406,7 @@ var racecgosync uint64 // represents possible synchronization in C code
// cgoCheckPointer checks if the argument contains a Go pointer that
// points to a Go pointer, and panics if it does.
-func cgoCheckPointer(ptr interface{}, args ...interface{}) {
+func cgoCheckPointer(ptr interface{}, arg interface{}) {
if debug.cgocheck == 0 {
return
}
@@ -415,15 +415,15 @@ func cgoCheckPointer(ptr interface{}, args ...interface{}) {
t := ep._type
top := true
- if len(args) > 0 && (t.kind&kindMask == kindPtr || t.kind&kindMask == kindUnsafePointer) {
+ if arg != nil && (t.kind&kindMask == kindPtr || t.kind&kindMask == kindUnsafePointer) {
p := ep.data
if t.kind&kindDirectIface == 0 {
p = *(*unsafe.Pointer)(p)
}
- if !cgoIsGoPointer(p) {
+ if p == nil || !cgoIsGoPointer(p) {
return
}
- aep := (*eface)(unsafe.Pointer(&args[0]))
+ aep := (*eface)(unsafe.Pointer(&arg))
switch aep._type.kind & kindMask {
case kindBool:
if t.kind&kindMask == kindUnsafePointer {
@@ -460,7 +460,7 @@ const cgoResultFail = "cgo result has Go pointer"
// depending on indir. The top parameter is whether we are at the top
// level, where Go pointers are allowed.
func cgoCheckArg(t *_type, p unsafe.Pointer, indir, top bool, msg string) {
- if t.ptrdata == 0 {
+ if t.ptrdata == 0 || p == nil {
// If the type has no pointers there is nothing to do.
return
}
@@ -517,7 +517,7 @@ func cgoCheckArg(t *_type, p unsafe.Pointer, indir, top bool, msg string) {
st := (*slicetype)(unsafe.Pointer(t))
s := (*slice)(p)
p = s.array
- if !cgoIsGoPointer(p) {
+ if p == nil || !cgoIsGoPointer(p) {
return
}
if !top {
@@ -548,11 +548,17 @@ func cgoCheckArg(t *_type, p unsafe.Pointer, indir, top bool, msg string) {
return
}
for _, f := range st.fields {
+ if f.typ.ptrdata == 0 {
+ continue
+ }
cgoCheckArg(f.typ, add(p, f.offset()), true, top, msg)
}
case kindPtr, kindUnsafePointer:
if indir {
p = *(*unsafe.Pointer)(p)
+ if p == nil {
+ return
+ }
}
if !cgoIsGoPointer(p) {