github.com/primecitizens/pcz/std@v0.2.1/core/alloc/alloc.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright 2023 The Prime Citizens 3 4 package alloc 5 6 import ( 7 "unsafe" 8 9 stdtype "github.com/primecitizens/pcz/std/builtin/type" 10 "github.com/primecitizens/pcz/std/core/abi" 11 "github.com/primecitizens/pcz/std/core/assert" 12 "github.com/primecitizens/pcz/std/core/mark" 13 "github.com/primecitizens/pcz/std/core/math" 14 "github.com/primecitizens/pcz/std/core/mem" 15 "github.com/primecitizens/pcz/std/core/os" 16 ) 17 18 // Hint for freeing the allocated memory 19 // 20 // TODO: TBD 21 type Hint uint32 22 23 // P for persistant allocations. 24 type P interface { 25 Palloc(size uintptr) unsafe.Pointer 26 } 27 28 // M for general purpose allocations. 29 type M interface { 30 // Malloc allocates memory for n elements of typ. 31 // 32 // NOTE: for bytes allocations, typ may be nil. 33 Malloc(typ *abi.Type, n uintptr, zeroize bool) unsafe.Pointer 34 35 // Free memory allocated for n elements. 36 // 37 // NOTE: for freeing types without heap pointer, typ may be nil 38 // and in that case, n is the bytes allocated. 39 Free(typ *abi.Type, n uintptr, ptr unsafe.Pointer) Hint 40 } 41 42 func SizeOutOfRange(typSz uintptr, n int) (outOfRange bool) { 43 if n < 0 { 44 return true 45 } 46 47 mem, overflow := math.MulUintptr(typSz, uintptr(n)) 48 if overflow || mem > os.MaxAlloc { 49 return true 50 } 51 52 return false 53 } 54 55 func elemTypeOf(ptr any) *abi.Type { 56 return stdtype.TypeOf(ptr).PointerTypeUnsafe().Elem 57 } 58 59 func New[T any](alloc M) *T { 60 return (*T)(alloc.Malloc(elemTypeOf((*T)(nil)), 1, true)) 61 } 62 63 func Make[E any](alloc M, len, cap int) []E { 64 return unsafe.Slice( 65 (*E)(MakeTyped(alloc, elemTypeOf((*E)(nil)), len, cap)), 66 cap, 67 )[:len] 68 } 69 70 func MakeTyped(alloc M, et *abi.Type, len, cap int) unsafe.Pointer { 71 if len > cap { 72 assert.Throw("makeslice:", "len", ">", "cap") 73 } 74 75 if et != nil && SizeOutOfRange(et.Size_, cap) { 76 assert.Throw("makeslice:", "size", "out", "of", "range") 77 } 78 79 return alloc.Malloc(et, uintptr(cap), true) 80 } 81 82 func Clone[T any](alloc M, x T) T { 83 typ := elemTypeOf((*T)(nil)) 84 switch typ.Kind() { 85 case abi.KindString: 86 str := *(*string)(mark.NoEscapePointer(&x)) 87 data := unsafe.Slice( 88 (*byte)(alloc.Malloc(nil, uintptr(len(str)), false)), 89 len(str), 90 ) 91 92 str = unsafe.String(unsafe.SliceData(data), copy(data, str)) 93 return *(*T)(mark.NoEscapePointer(&str)) 94 case abi.KindSlice: 95 slice := *(*[]byte)(mark.NoEscapePointer(&x)) 96 typ = typ.SliceType().Elem 97 data := MakeTyped(alloc, typ, len(slice), len(slice)) 98 mem.Move(data, mark.NoEscapeSliceDataPointer(slice), uintptr(len(slice))*typ.Size_) 99 return *(*T)(mark.NoEscapePointer(&slice)) 100 case abi.KindPointer: 101 typ = typ.PointerType().Elem 102 ptr := alloc.Malloc(typ, 1, false) 103 mem.TypedMove(typ, ptr, mark.NoEscapePointer(&x)) 104 return *(*T)(mark.NoEscapePointer(&ptr)) 105 default: 106 assert.TODO() 107 } 108 109 return x 110 } 111 112 func Free[T any](alloc M, x T) Hint { 113 typ := elemTypeOf((*T)(nil)) 114 switch typ.Kind() { 115 case abi.KindPointer: 116 return alloc.Free(typ.PointerType().Elem, 1, *(*unsafe.Pointer)(unsafe.Pointer(&x))) 117 case abi.KindString: 118 str := *(*string)(mark.NoEscapePointer(&x)) 119 return alloc.Free(nil, uintptr(len(str)), unsafe.Pointer(unsafe.StringData(str))) 120 case abi.KindSlice: 121 slice := *(*[]byte)(mark.NoEscapePointer(&x)) 122 return alloc.Free(typ.SliceType().Elem, uintptr(len(slice)), unsafe.Pointer(unsafe.SliceData(slice))) 123 default: 124 assert.TODO() 125 } 126 127 return 0 128 } 129 130 // DenyNoneZero implements M that only allows allocation of zero sized types. 131 type DenyNoneZero struct{} 132 133 func (DenyNoneZero) Malloc(typ *abi.Type, n uintptr, zeroize bool) unsafe.Pointer { 134 if n == 0 { 135 return ZeroSized() 136 } 137 138 assert.Throw("no", "non-zero", "allocation", "allowed") 139 return nil 140 } 141 142 func (DenyNoneZero) Palloc(size uintptr) unsafe.Pointer { 143 if size == 0 { 144 return ZeroSized() 145 } 146 147 assert.Throw("no", "non-zero", "allocation", "allowed") 148 return nil 149 } 150 151 func (DenyNoneZero) Free(typ *abi.Type, n uintptr, ptr unsafe.Pointer) Hint { return 0 } 152 153 // S for stack allocations. 154 type S interface { 155 NewStack(size uintptr) unsafe.Pointer 156 } 157 158 // H for heap allocations. 159 type H interface { 160 M 161 MallocHeap(typ *abi.Type, n uintptr, zerioze bool) unsafe.Pointer 162 }