github.com/patricebensoussan/go/codec@v1.2.99/helper_unsafe_compiler_gc.go (about)

     1  // Copyright (c) 2012-2020 Ugorji Nwoke. All rights reserved.
     2  // Use of this source code is governed by a MIT license found in the LICENSE file.
     3  
     4  //go:build !safe && !codec.safe && !appengine && go1.9 && gc
     5  // +build !safe,!codec.safe,!appengine,go1.9,gc
     6  
     7  package codec
     8  
     9  import (
    10  	"reflect"
    11  	_ "runtime" // needed for go linkname(s)
    12  	"unsafe"
    13  )
    14  
    15  // keep in sync with
    16  //    $GOROOT/src/cmd/compile/internal/gc/reflect.go: MAXKEYSIZE, MAXELEMSIZE
    17  //    $GOROOT/src/runtime/map.go: maxKeySize, maxElemSize
    18  //    $GOROOT/src/reflect/type.go: maxKeySize, maxElemSize
    19  //
    20  // We use these to determine whether the type is stored indirectly in the map or not.
    21  const (
    22  	// mapMaxKeySize  = 128
    23  	mapMaxElemSize = 128
    24  )
    25  
    26  func unsafeGrowslice(typ unsafe.Pointer, old unsafeSlice, cap, incr int) (v unsafeSlice) {
    27  	return growslice(typ, old, cap+incr)
    28  }
    29  
    30  func rvType(rv reflect.Value) reflect.Type {
    31  	return rvPtrToType(((*unsafeReflectValue)(unsafe.Pointer(&rv))).typ) // rv.Type()
    32  }
    33  
    34  // mapStoresElemIndirect tells if the element type is stored indirectly in the map.
    35  //
    36  // This is used to determine valIsIndirect which is passed into mapSet/mapGet calls.
    37  //
    38  // If valIsIndirect doesn't matter, then just return false and ignore the value
    39  // passed in mapGet/mapSet calls
    40  func mapStoresElemIndirect(elemsize uintptr) bool {
    41  	return elemsize > mapMaxElemSize
    42  }
    43  
    44  func mapSet(m, k, v reflect.Value, keyFastKind mapKeyFastKind, valIsIndirect, valIsRef bool) {
    45  	var urv = (*unsafeReflectValue)(unsafe.Pointer(&k))
    46  	var kptr = unsafeMapKVPtr(urv)
    47  	urv = (*unsafeReflectValue)(unsafe.Pointer(&v))
    48  	var vtyp = urv.typ
    49  	var vptr = unsafeMapKVPtr(urv)
    50  
    51  	urv = (*unsafeReflectValue)(unsafe.Pointer(&m))
    52  	mptr := rvRefPtr(urv)
    53  
    54  	var vvptr unsafe.Pointer
    55  
    56  	// mapassign_fastXXX don't take indirect into account.
    57  	// It was hard to infer what makes it work all the time.
    58  	// Sometimes, we got vvptr == nil when we dereferenced vvptr (if valIsIndirect).
    59  	// Consequently, only use fastXXX functions if !valIsIndirect
    60  
    61  	if valIsIndirect {
    62  		vvptr = mapassign(urv.typ, mptr, kptr)
    63  		typedmemmove(vtyp, vvptr, vptr)
    64  		// reflect_mapassign(urv.typ, mptr, kptr, vptr)
    65  		return
    66  	}
    67  
    68  	switch keyFastKind {
    69  	case mapKeyFastKind32:
    70  		vvptr = mapassign_fast32(urv.typ, mptr, *(*uint32)(kptr))
    71  	case mapKeyFastKind32ptr:
    72  		vvptr = mapassign_fast32ptr(urv.typ, mptr, *(*unsafe.Pointer)(kptr))
    73  	case mapKeyFastKind64:
    74  		vvptr = mapassign_fast64(urv.typ, mptr, *(*uint64)(kptr))
    75  	case mapKeyFastKind64ptr:
    76  		vvptr = mapassign_fast64ptr(urv.typ, mptr, *(*unsafe.Pointer)(kptr))
    77  	case mapKeyFastKindStr:
    78  		vvptr = mapassign_faststr(urv.typ, mptr, *(*string)(kptr))
    79  	default:
    80  		vvptr = mapassign(urv.typ, mptr, kptr)
    81  	}
    82  
    83  	// if keyFastKind != 0 && valIsIndirect {
    84  	// 	vvptr = *(*unsafe.Pointer)(vvptr)
    85  	// }
    86  
    87  	typedmemmove(vtyp, vvptr, vptr)
    88  }
    89  
    90  func mapGet(m, k, v reflect.Value, keyFastKind mapKeyFastKind, valIsIndirect, valIsRef bool) (_ reflect.Value) {
    91  	var urv = (*unsafeReflectValue)(unsafe.Pointer(&k))
    92  	var kptr = unsafeMapKVPtr(urv)
    93  	urv = (*unsafeReflectValue)(unsafe.Pointer(&m))
    94  	mptr := rvRefPtr(urv)
    95  
    96  	var vvptr unsafe.Pointer
    97  	var ok bool
    98  
    99  	// Note that mapaccess2_fastXXX functions do not check if the value needs to be copied.
   100  	// if they do, we should dereference the pointer and return that
   101  
   102  	switch keyFastKind {
   103  	case mapKeyFastKind32, mapKeyFastKind32ptr:
   104  		vvptr, ok = mapaccess2_fast32(urv.typ, mptr, *(*uint32)(kptr))
   105  	case mapKeyFastKind64, mapKeyFastKind64ptr:
   106  		vvptr, ok = mapaccess2_fast64(urv.typ, mptr, *(*uint64)(kptr))
   107  	case mapKeyFastKindStr:
   108  		vvptr, ok = mapaccess2_faststr(urv.typ, mptr, *(*string)(kptr))
   109  	default:
   110  		vvptr, ok = mapaccess2(urv.typ, mptr, kptr)
   111  	}
   112  
   113  	if !ok {
   114  		return
   115  	}
   116  
   117  	urv = (*unsafeReflectValue)(unsafe.Pointer(&v))
   118  
   119  	if keyFastKind != 0 && valIsIndirect {
   120  		urv.ptr = *(*unsafe.Pointer)(vvptr)
   121  	} else if helperUnsafeDirectAssignMapEntry || valIsRef {
   122  		urv.ptr = vvptr
   123  	} else {
   124  		typedmemmove(urv.typ, urv.ptr, vvptr)
   125  	}
   126  
   127  	return v
   128  }
   129  
   130  //go:linkname unsafeZeroArr runtime.zeroVal
   131  var unsafeZeroArr [1024]byte
   132  
   133  //go:linkname rvPtrToType reflect.toType
   134  //go:noescape
   135  func rvPtrToType(typ unsafe.Pointer) reflect.Type
   136  
   137  //go:linkname growslice runtime.growslice
   138  //go:noescape
   139  func growslice(typ unsafe.Pointer, old unsafeSlice, cap int) unsafeSlice
   140  
   141  //go:linkname mapassign_fast32 runtime.mapassign_fast32
   142  //go:noescape
   143  func mapassign_fast32(typ unsafe.Pointer, m unsafe.Pointer, key uint32) unsafe.Pointer
   144  
   145  //go:linkname mapassign_fast32ptr runtime.mapassign_fast32ptr
   146  //go:noescape
   147  func mapassign_fast32ptr(typ unsafe.Pointer, m unsafe.Pointer, key unsafe.Pointer) unsafe.Pointer
   148  
   149  //go:linkname mapassign_fast64 runtime.mapassign_fast64
   150  //go:noescape
   151  func mapassign_fast64(typ unsafe.Pointer, m unsafe.Pointer, key uint64) unsafe.Pointer
   152  
   153  //go:linkname mapassign_fast64ptr runtime.mapassign_fast64ptr
   154  //go:noescape
   155  func mapassign_fast64ptr(typ unsafe.Pointer, m unsafe.Pointer, key unsafe.Pointer) unsafe.Pointer
   156  
   157  //go:linkname mapassign_faststr runtime.mapassign_faststr
   158  //go:noescape
   159  func mapassign_faststr(typ unsafe.Pointer, m unsafe.Pointer, s string) unsafe.Pointer
   160  
   161  //go:linkname mapaccess2_fast32 runtime.mapaccess2_fast32
   162  //go:noescape
   163  func mapaccess2_fast32(typ unsafe.Pointer, m unsafe.Pointer, key uint32) (val unsafe.Pointer, ok bool)
   164  
   165  //go:linkname mapaccess2_fast64 runtime.mapaccess2_fast64
   166  //go:noescape
   167  func mapaccess2_fast64(typ unsafe.Pointer, m unsafe.Pointer, key uint64) (val unsafe.Pointer, ok bool)
   168  
   169  //go:linkname mapaccess2_faststr runtime.mapaccess2_faststr
   170  //go:noescape
   171  func mapaccess2_faststr(typ unsafe.Pointer, m unsafe.Pointer, key string) (val unsafe.Pointer, ok bool)