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