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 }