1 module spasm.rt.memory; 2 3 import spasm.rt.allocator : WasmAllocator; 4 import stdx.allocator.building_blocks.null_allocator; 5 private __gshared SpasmGCAllocator gcAllocator; 6 7 version (LDC) 8 import ldc.attributes; 9 import spasm.intrinsics; 10 import spasm.rt.gc; 11 12 enum wasmPageSize = 64 * 1024; 13 14 @safe nothrow void alloc_init(uint heap_base) { 15 version (WebAssembly) WasmAllocator.init(heap_base); 16 } 17 18 version (unittest) { 19 struct Allocator { 20 nothrow: 21 void[] allocate(size_t n) { 22 auto mem = new byte[n]; 23 return mem; 24 } 25 bool deallocate(void[] b) { 26 return true; 27 } 28 } 29 __gshared Allocator unittestAllocator; 30 __gshared Allocator* allocator = &unittestAllocator; 31 } else { 32 __gshared auto allocator = &gcAllocator; 33 } 34 35 @trusted template make(T) { 36 import spasm.types; 37 static if (is(T == Item[], Item)) { 38 Item[] make(A)(A allocator, size_t size) nothrow { 39 void[] raw = allocator.allocate(Item.sizeof * size); 40 auto t = cast(Item*) raw.ptr; 41 return t[0 .. size]; 42 } 43 } else static if (is(T == Item[size], Item, size_t size)) { 44 Item[] make(A)(A allocator) 45 { 46 void[] raw = allocator.allocate(Item.sizeof * size); 47 auto t = cast(Item*) raw.ptr; 48 return t[0..size]; 49 } 50 } else { 51 T* make(A, Args...)(A allocatorOld, auto ref Args args) nothrow { 52 import spasm.rt.allocator : PoolAllocatorList; 53 static __gshared allocator = PoolAllocatorList!(T)(); 54 void[] raw = allocator.allocate(T.sizeof); 55 auto t = cast(T*) raw.ptr; 56 *t = T.init; 57 static if (Args.length) { 58 import core.lifetime: forward; 59 *t = T(forward!args); 60 } 61 return t; 62 } 63 } 64 } 65 66 extern (C) void * memcpy(void * destination, const void * source, size_t num) { 67 foreach(i; 0..num) { 68 (cast(ubyte*)destination)[i] = (cast(ubyte*)source)[i]; 69 } 70 return destination; 71 } 72 73 extern (C) void * memset(void* ptr, int value, size_t num) { 74 ubyte val = cast(ubyte)value; 75 ubyte* p = cast(ubyte*)ptr; 76 foreach(i;0..num) 77 p[i] = val; 78 return ptr; 79 } 80 81 extern(C) { 82 int memcmp(void*a,void*b,size_t cnt) { 83 foreach(i;0..cnt) { 84 if ((cast(byte*)a)[i] < (cast(byte*)b)[i]) 85 return -1; 86 if ((cast(byte*)a)[i] > (cast(byte*)b)[i]) 87 return 1; 88 } 89 return 0; 90 } 91 // per-element array init routines 92 93 void _d_array_init_i16(ushort* a, size_t n, ushort v) 94 { 95 auto p = a; 96 auto end = a+n; 97 while (p !is end) 98 *p++ = v; 99 } 100 101 void _d_array_init_i32(uint* a, size_t n, uint v) 102 { 103 auto p = a; 104 auto end = a+n; 105 while (p !is end) 106 *p++ = v; 107 } 108 109 void _d_array_init_i64(ulong* a, size_t n, ulong v) 110 { 111 auto p = a; 112 auto end = a+n; 113 while (p !is end) 114 *p++ = v; 115 } 116 117 void _d_array_init_float(float* a, size_t n, float v) 118 { 119 auto p = a; 120 auto end = a+n; 121 while (p !is end) 122 *p++ = v; 123 } 124 125 void _d_array_init_double(double* a, size_t n, double v) 126 { 127 auto p = a; 128 auto end = a+n; 129 while (p !is end) 130 *p++ = v; 131 } 132 133 void _d_array_init_real(real* a, size_t n, real v) 134 { 135 auto p = a; 136 auto end = a+n; 137 while (p !is end) 138 *p++ = v; 139 } 140 141 void _d_array_init_cfloat(cfloat* a, size_t n, cfloat v) 142 { 143 auto p = a; 144 auto end = a+n; 145 while (p !is end) 146 *p++ = v; 147 } 148 149 void _d_array_init_cdouble(cdouble* a, size_t n, cdouble v) 150 { 151 auto p = a; 152 auto end = a+n; 153 while (p !is end) 154 *p++ = v; 155 } 156 157 void _d_array_init_creal(creal* a, size_t n, creal v) 158 { 159 auto p = a; 160 auto end = a+n; 161 while (p !is end) 162 *p++ = v; 163 } 164 165 void _d_array_init_pointer(void** a, size_t n, void* v) 166 { 167 auto p = a; 168 auto end = a+n; 169 while (p !is end) 170 *p++ = v; 171 } 172 173 void _d_array_init_mem(void* a, size_t na, void* v, size_t nv) 174 { 175 auto p = a; 176 auto end = a + na*nv; 177 while (p !is end) { 178 version (LDC) { 179 import ldc.intrinsics; 180 llvm_memcpy(p,v,nv,0); 181 } else 182 memcpy(p,v,nv); 183 p += nv; 184 } 185 } 186 187 deprecated("since ldc 1.14.0") 188 size_t _d_array_cast_len(size_t len, size_t elemsz, size_t newelemsz) 189 { 190 if (newelemsz == 1) { 191 return len*elemsz; 192 } 193 else if ((len*elemsz) % newelemsz) { 194 assert(0); 195 } 196 return (len*elemsz)/newelemsz; 197 } 198 199 @trusted nothrow 200 size_t _d_arraycast_len(size_t len, size_t elemsz, size_t newelemsz) { 201 const size = len * elemsz; 202 const newlen = size / newelemsz; 203 if (newlen * newelemsz != size) 204 assert(0); 205 return newlen; 206 } 207 208 // slice copy when assertions are enabled 209 void _d_array_slice_copy(void* dst, size_t dstlen, void* src, size_t srclen, size_t elemsz) 210 { 211 if (dstlen != 0) assert(dst); 212 if (dstlen != 0) assert(src); 213 if (dstlen != srclen) 214 assert(0); 215 else if (dst+dstlen*elemsz <= src || src+srclen*elemsz <= dst) { 216 version (LDC) { 217 import ldc.intrinsics; 218 llvm_memcpy!size_t(dst, src, dstlen * elemsz, 0); 219 } else 220 memcpy(dst, src, dstlen * elemsz); 221 } 222 else 223 assert(0); 224 } 225 226 void _d_arraybounds(string file, int line) { 227 } 228 extern (C) export void* _d_allocmemory(size_t sz) 229 { 230 import spasm.rt.memory : WasmAllocator; 231 return WasmAllocator.instance.allocate(sz).ptr; 232 } 233 }