1570af302Sopenharmony_ci#include <stdlib.h>
2570af302Sopenharmony_ci#include <stdint.h>
3570af302Sopenharmony_ci#include <limits.h>
4570af302Sopenharmony_ci#include <string.h>
5570af302Sopenharmony_ci#include <sys/mman.h>
6570af302Sopenharmony_ci#ifndef __LITEOS__
7570af302Sopenharmony_ci#include <sys/prctl.h>
8570af302Sopenharmony_ci#endif
9570af302Sopenharmony_ci#include <errno.h>
10570af302Sopenharmony_ci
11570af302Sopenharmony_ci#include "meta.h"
12570af302Sopenharmony_ci
13570af302Sopenharmony_ci#ifdef USE_JEMALLOC
14570af302Sopenharmony_ci#ifdef USE_JEMALLOC_DFX_INTF
15570af302Sopenharmony_ciextern void je_malloc_disable();
16570af302Sopenharmony_ciextern void je_malloc_enable();
17570af302Sopenharmony_ciextern int je_iterate(uintptr_t base, size_t size,
18570af302Sopenharmony_ci	void (*callback)(uintptr_t ptr, size_t size, void* arg), void* arg);
19570af302Sopenharmony_ciextern int je_mallopt(int param, int value);
20570af302Sopenharmony_ci#endif
21570af302Sopenharmony_ci#endif
22570af302Sopenharmony_ci
23570af302Sopenharmony_ci#ifdef MALLOC_SECURE_ALL
24570af302Sopenharmony_ci#include <fcntl.h>
25570af302Sopenharmony_ci#define RANDOM_BUFFER_LEN 512
26570af302Sopenharmony_cistatic uint8_t buffer[RANDOM_BUFFER_LEN] = { 0 };
27570af302Sopenharmony_cistatic size_t ri = RANDOM_BUFFER_LEN;
28570af302Sopenharmony_ci
29570af302Sopenharmony_cistatic uint8_t get_random8()
30570af302Sopenharmony_ci{
31570af302Sopenharmony_ci	uint8_t num;
32570af302Sopenharmony_ci	if ((ri >= RANDOM_BUFFER_LEN) || (buffer[0] == 0)) {
33570af302Sopenharmony_ci		int fd = open("/dev/urandom", O_RDONLY);
34570af302Sopenharmony_ci		if (fd < 0) {
35570af302Sopenharmony_ci			num = (uint8_t)get_random_secret();
36570af302Sopenharmony_ci			return num;
37570af302Sopenharmony_ci		}
38570af302Sopenharmony_ci
39570af302Sopenharmony_ci		read(fd, buffer, RANDOM_BUFFER_LEN);
40570af302Sopenharmony_ci		close(fd);
41570af302Sopenharmony_ci		ri = 0;
42570af302Sopenharmony_ci	}
43570af302Sopenharmony_ci	num = buffer[ri];
44570af302Sopenharmony_ci	ri++;
45570af302Sopenharmony_ci	return num;
46570af302Sopenharmony_ci}
47570af302Sopenharmony_ci
48570af302Sopenharmony_cistatic int get_randomIdx(int avail_mask, int last_idx)
49570af302Sopenharmony_ci{
50570af302Sopenharmony_ci	uint32_t mask;
51570af302Sopenharmony_ci	uint32_t r;
52570af302Sopenharmony_ci	uint32_t cmask;
53570af302Sopenharmony_ci	int idx;
54570af302Sopenharmony_ci
55570af302Sopenharmony_ci	mask = avail_mask;
56570af302Sopenharmony_ci	r = get_random8() % last_idx;
57570af302Sopenharmony_ci	cmask = ~((2u << (last_idx - r)) - 1);
58570af302Sopenharmony_ci
59570af302Sopenharmony_ci	if (mask & cmask) {
60570af302Sopenharmony_ci		idx = 31 - a_clz_32(mask & cmask);
61570af302Sopenharmony_ci	} else {
62570af302Sopenharmony_ci		idx = a_ctz_32(mask);
63570af302Sopenharmony_ci	}
64570af302Sopenharmony_ci
65570af302Sopenharmony_ci	return idx;
66570af302Sopenharmony_ci}
67570af302Sopenharmony_ci#endif
68570af302Sopenharmony_ci
69570af302Sopenharmony_ciLOCK_OBJ_DEF;
70570af302Sopenharmony_ci
71570af302Sopenharmony_ciconst uint16_t size_classes[] = {
72570af302Sopenharmony_ci	1, 2, 3, 4, 5, 6, 7, 8,
73570af302Sopenharmony_ci	9, 10, 12, 15,
74570af302Sopenharmony_ci	18, 20, 25, 31,
75570af302Sopenharmony_ci	36, 42, 50, 63,
76570af302Sopenharmony_ci	72, 84, 102, 127,
77570af302Sopenharmony_ci	146, 170, 204, 255,
78570af302Sopenharmony_ci	292, 340, 409, 511,
79570af302Sopenharmony_ci	584, 682, 818, 1023,
80570af302Sopenharmony_ci	1169, 1364, 1637, 2047,
81570af302Sopenharmony_ci	2340, 2730, 3276, 4095,
82570af302Sopenharmony_ci	4680, 5460, 6552, 8191,
83570af302Sopenharmony_ci};
84570af302Sopenharmony_ci
85570af302Sopenharmony_cistatic const uint8_t small_cnt_tab[][3] = {
86570af302Sopenharmony_ci	{ 30, 30, 30 },
87570af302Sopenharmony_ci	{ 31, 15, 15 },
88570af302Sopenharmony_ci	{ 20, 10, 10 },
89570af302Sopenharmony_ci	{ 31, 15, 7 },
90570af302Sopenharmony_ci	{ 25, 12, 6 },
91570af302Sopenharmony_ci	{ 21, 10, 5 },
92570af302Sopenharmony_ci	{ 18, 8, 4 },
93570af302Sopenharmony_ci	{ 31, 15, 7 },
94570af302Sopenharmony_ci	{ 28, 14, 6 },
95570af302Sopenharmony_ci};
96570af302Sopenharmony_ci
97570af302Sopenharmony_cistatic const uint8_t med_cnt_tab[4] = { 28, 24, 20, 32 };
98570af302Sopenharmony_ci
99570af302Sopenharmony_cistruct malloc_context ctx = { 0 };
100570af302Sopenharmony_ci
101570af302Sopenharmony_cistruct meta *alloc_meta(void)
102570af302Sopenharmony_ci{
103570af302Sopenharmony_ci	struct meta *m;
104570af302Sopenharmony_ci	unsigned char *p;
105570af302Sopenharmony_ci	if (!ctx.init_done) {
106570af302Sopenharmony_ci#ifndef PAGESIZE
107570af302Sopenharmony_ci		ctx.pagesize = get_page_size();
108570af302Sopenharmony_ci#endif
109570af302Sopenharmony_ci		ctx.secret = get_random_secret();
110570af302Sopenharmony_ci		ctx.init_done = 1;
111570af302Sopenharmony_ci	}
112570af302Sopenharmony_ci	size_t pagesize = PGSZ;
113570af302Sopenharmony_ci	if (pagesize < 4096) pagesize = 4096;
114570af302Sopenharmony_ci	if ((m = dequeue_head(&ctx.free_meta_head))) return m;
115570af302Sopenharmony_ci	if (!ctx.avail_meta_count) {
116570af302Sopenharmony_ci		int need_unprotect = 1;
117570af302Sopenharmony_ci		if (!ctx.avail_meta_area_count && ctx.brk!=-1) {
118570af302Sopenharmony_ci			uintptr_t new = ctx.brk + pagesize;
119570af302Sopenharmony_ci			int need_guard = 0;
120570af302Sopenharmony_ci			if (!ctx.brk) {
121570af302Sopenharmony_ci				need_guard = 1;
122570af302Sopenharmony_ci				ctx.brk = brk(0);
123570af302Sopenharmony_ci				// some ancient kernels returned _ebss
124570af302Sopenharmony_ci				// instead of next page as initial brk.
125570af302Sopenharmony_ci				ctx.brk += -ctx.brk & (pagesize-1);
126570af302Sopenharmony_ci				new = ctx.brk + 2*pagesize;
127570af302Sopenharmony_ci			}
128570af302Sopenharmony_ci			if (brk(new) != new) {
129570af302Sopenharmony_ci				ctx.brk = -1;
130570af302Sopenharmony_ci			} else {
131570af302Sopenharmony_ci#ifndef __LITEOS__
132570af302Sopenharmony_ci				prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ctx.brk, new - ctx.brk, "native_heap:meta");
133570af302Sopenharmony_ci#endif
134570af302Sopenharmony_ci				if (need_guard) mmap((void *)ctx.brk, pagesize,
135570af302Sopenharmony_ci					PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
136570af302Sopenharmony_ci				ctx.brk = new;
137570af302Sopenharmony_ci				ctx.avail_meta_areas = (void *)(new - pagesize);
138570af302Sopenharmony_ci				ctx.avail_meta_area_count = pagesize>>12;
139570af302Sopenharmony_ci				need_unprotect = 0;
140570af302Sopenharmony_ci			}
141570af302Sopenharmony_ci		}
142570af302Sopenharmony_ci		if (!ctx.avail_meta_area_count) {
143570af302Sopenharmony_ci			size_t n = 2UL << ctx.meta_alloc_shift;
144570af302Sopenharmony_ci			p = mmap(0, n*pagesize, PROT_NONE,
145570af302Sopenharmony_ci				MAP_PRIVATE|MAP_ANON, -1, 0);
146570af302Sopenharmony_ci			if (p==MAP_FAILED) return 0;
147570af302Sopenharmony_ci			ctx.avail_meta_areas = p + pagesize;
148570af302Sopenharmony_ci			ctx.avail_meta_area_count = (n-1)*(pagesize>>12);
149570af302Sopenharmony_ci			ctx.meta_alloc_shift++;
150570af302Sopenharmony_ci		}
151570af302Sopenharmony_ci		p = ctx.avail_meta_areas;
152570af302Sopenharmony_ci		if ((uintptr_t)p & (pagesize-1)) need_unprotect = 0;
153570af302Sopenharmony_ci		if (need_unprotect)
154570af302Sopenharmony_ci			if (mprotect(p, pagesize, PROT_READ|PROT_WRITE)
155570af302Sopenharmony_ci			    && errno != ENOSYS)
156570af302Sopenharmony_ci				return 0;
157570af302Sopenharmony_ci		ctx.avail_meta_area_count--;
158570af302Sopenharmony_ci		ctx.avail_meta_areas = p + 4096;
159570af302Sopenharmony_ci		if (ctx.meta_area_tail) {
160570af302Sopenharmony_ci			ctx.meta_area_tail->next = (void *)p;
161570af302Sopenharmony_ci		} else {
162570af302Sopenharmony_ci			ctx.meta_area_head = (void *)p;
163570af302Sopenharmony_ci		}
164570af302Sopenharmony_ci		ctx.meta_area_tail = (void *)p;
165570af302Sopenharmony_ci		ctx.meta_area_tail->check = ctx.secret;
166570af302Sopenharmony_ci		ctx.avail_meta_count = ctx.meta_area_tail->nslots
167570af302Sopenharmony_ci			= (4096-sizeof(struct meta_area))/sizeof *m;
168570af302Sopenharmony_ci		ctx.avail_meta = ctx.meta_area_tail->slots;
169570af302Sopenharmony_ci	}
170570af302Sopenharmony_ci	ctx.avail_meta_count--;
171570af302Sopenharmony_ci	m = ctx.avail_meta++;
172570af302Sopenharmony_ci	m->prev = m->next = 0;
173570af302Sopenharmony_ci	return m;
174570af302Sopenharmony_ci}
175570af302Sopenharmony_ci
176570af302Sopenharmony_cistatic uint32_t try_avail(struct meta **pm)
177570af302Sopenharmony_ci{
178570af302Sopenharmony_ci	struct meta *m = *pm;
179570af302Sopenharmony_ci	uint32_t first;
180570af302Sopenharmony_ci	if (!m) return 0;
181570af302Sopenharmony_ci	uint32_t mask = m->avail_mask;
182570af302Sopenharmony_ci	if (!mask) {
183570af302Sopenharmony_ci		if (!m) return 0;
184570af302Sopenharmony_ci		if (!m->freed_mask) {
185570af302Sopenharmony_ci			dequeue(pm, m);
186570af302Sopenharmony_ci			m = *pm;
187570af302Sopenharmony_ci			if (!m) return 0;
188570af302Sopenharmony_ci		} else {
189570af302Sopenharmony_ci			m = m->next;
190570af302Sopenharmony_ci			*pm = m;
191570af302Sopenharmony_ci		}
192570af302Sopenharmony_ci
193570af302Sopenharmony_ci		mask = m->freed_mask;
194570af302Sopenharmony_ci
195570af302Sopenharmony_ci		// skip fully-free group unless it's the only one
196570af302Sopenharmony_ci		// or it's a permanently non-freeable group
197570af302Sopenharmony_ci		if (mask == (2u<<m->last_idx)-1 && m->freeable) {
198570af302Sopenharmony_ci			m = m->next;
199570af302Sopenharmony_ci			*pm = m;
200570af302Sopenharmony_ci			mask = m->freed_mask;
201570af302Sopenharmony_ci		}
202570af302Sopenharmony_ci
203570af302Sopenharmony_ci		// activate more slots in a not-fully-active group
204570af302Sopenharmony_ci		// if needed, but only as a last resort. prefer using
205570af302Sopenharmony_ci		// any other group with free slots. this avoids
206570af302Sopenharmony_ci		// touching & dirtying as-yet-unused pages.
207570af302Sopenharmony_ci		if (!(mask & ((2u<<m->mem->active_idx)-1))) {
208570af302Sopenharmony_ci			if (m->next != m) {
209570af302Sopenharmony_ci				m = m->next;
210570af302Sopenharmony_ci				*pm = m;
211570af302Sopenharmony_ci			} else {
212570af302Sopenharmony_ci				int cnt = m->mem->active_idx + 2;
213570af302Sopenharmony_ci				int size = size_classes[m->sizeclass]*UNIT;
214570af302Sopenharmony_ci				int span = UNIT + size*cnt;
215570af302Sopenharmony_ci				// activate up to next 4k boundary
216570af302Sopenharmony_ci				while ((span^(span+size-1)) < 4096) {
217570af302Sopenharmony_ci					cnt++;
218570af302Sopenharmony_ci					span += size;
219570af302Sopenharmony_ci				}
220570af302Sopenharmony_ci				if (cnt > m->last_idx+1)
221570af302Sopenharmony_ci					cnt = m->last_idx+1;
222570af302Sopenharmony_ci				m->mem->active_idx = cnt-1;
223570af302Sopenharmony_ci			}
224570af302Sopenharmony_ci		}
225570af302Sopenharmony_ci		mask = activate_group(m);
226570af302Sopenharmony_ci		assert(mask);
227570af302Sopenharmony_ci		decay_bounces(m->sizeclass);
228570af302Sopenharmony_ci	}
229570af302Sopenharmony_ci#ifdef MALLOC_SECURE_ALL
230570af302Sopenharmony_ci	int idx = get_randomIdx(mask, m->last_idx);
231570af302Sopenharmony_ci	first = 1 << idx;
232570af302Sopenharmony_ci#else
233570af302Sopenharmony_ci	first = mask&-mask;
234570af302Sopenharmony_ci#endif
235570af302Sopenharmony_ci	m->avail_mask = mask-first;
236570af302Sopenharmony_ci	return first;
237570af302Sopenharmony_ci}
238570af302Sopenharmony_ci
239570af302Sopenharmony_cistatic int alloc_slot(int, size_t);
240570af302Sopenharmony_ci
241570af302Sopenharmony_cistatic struct meta *alloc_group(int sc, size_t req)
242570af302Sopenharmony_ci{
243570af302Sopenharmony_ci	size_t size = UNIT*size_classes[sc];
244570af302Sopenharmony_ci	int i = 0, cnt;
245570af302Sopenharmony_ci	unsigned char *p;
246570af302Sopenharmony_ci	struct meta *m = alloc_meta();
247570af302Sopenharmony_ci	if (!m) return 0;
248570af302Sopenharmony_ci	size_t usage = ctx.usage_by_class[sc];
249570af302Sopenharmony_ci	size_t pagesize = PGSZ;
250570af302Sopenharmony_ci	int active_idx;
251570af302Sopenharmony_ci	if (sc < 9) {
252570af302Sopenharmony_ci		while (i<2 && 4*small_cnt_tab[sc][i] > usage)
253570af302Sopenharmony_ci			i++;
254570af302Sopenharmony_ci		cnt = small_cnt_tab[sc][i];
255570af302Sopenharmony_ci	} else {
256570af302Sopenharmony_ci		// lookup max number of slots fitting in power-of-two size
257570af302Sopenharmony_ci		// from a table, along with number of factors of two we
258570af302Sopenharmony_ci		// can divide out without a remainder or reaching 1.
259570af302Sopenharmony_ci		cnt = med_cnt_tab[sc&3];
260570af302Sopenharmony_ci
261570af302Sopenharmony_ci		// reduce cnt to avoid excessive eagar allocation.
262570af302Sopenharmony_ci		while (!(cnt&1) && 4*cnt > usage)
263570af302Sopenharmony_ci			cnt >>= 1;
264570af302Sopenharmony_ci
265570af302Sopenharmony_ci		// data structures don't support groups whose slot offsets
266570af302Sopenharmony_ci		// in units don't fit in 16 bits.
267570af302Sopenharmony_ci		while (size*cnt >= 65536*UNIT)
268570af302Sopenharmony_ci			cnt >>= 1;
269570af302Sopenharmony_ci	}
270570af302Sopenharmony_ci
271570af302Sopenharmony_ci	// If we selected a count of 1 above but it's not sufficient to use
272570af302Sopenharmony_ci	// mmap, increase to 2. Then it might be; if not it will nest.
273570af302Sopenharmony_ci	if (cnt==1 && size*cnt+UNIT <= pagesize/2) cnt = 2;
274570af302Sopenharmony_ci
275570af302Sopenharmony_ci	// All choices of size*cnt are "just below" a power of two, so anything
276570af302Sopenharmony_ci	// larger than half the page size should be allocated as whole pages.
277570af302Sopenharmony_ci	if (size*cnt+UNIT > pagesize/2) {
278570af302Sopenharmony_ci		// check/update bounce counter to start/increase retention
279570af302Sopenharmony_ci		// of freed maps, and inhibit use of low-count, odd-size
280570af302Sopenharmony_ci		// small mappings and single-slot groups if activated.
281570af302Sopenharmony_ci		int nosmall = is_bouncing(sc);
282570af302Sopenharmony_ci		account_bounce(sc);
283570af302Sopenharmony_ci		step_seq();
284570af302Sopenharmony_ci
285570af302Sopenharmony_ci		// since the following count reduction opportunities have
286570af302Sopenharmony_ci		// an absolute memory usage cost, don't overdo them. count
287570af302Sopenharmony_ci		// coarse usage as part of usage.
288570af302Sopenharmony_ci		if (!(sc&1) && sc<32) usage += ctx.usage_by_class[sc+1];
289570af302Sopenharmony_ci
290570af302Sopenharmony_ci		// try to drop to a lower count if the one found above
291570af302Sopenharmony_ci		// increases usage by more than 25%. these reduced counts
292570af302Sopenharmony_ci		// roughly fill an integral number of pages, just not a
293570af302Sopenharmony_ci		// power of two, limiting amount of unusable space.
294570af302Sopenharmony_ci		if (4*cnt > usage && !nosmall) {
295570af302Sopenharmony_ci			if (0);
296570af302Sopenharmony_ci			else if ((sc&3)==1 && size*cnt>8*pagesize) cnt = 2;
297570af302Sopenharmony_ci			else if ((sc&3)==2 && size*cnt>4*pagesize) cnt = 3;
298570af302Sopenharmony_ci			else if ((sc&3)==0 && size*cnt>8*pagesize) cnt = 3;
299570af302Sopenharmony_ci			else if ((sc&3)==0 && size*cnt>2*pagesize) cnt = 5;
300570af302Sopenharmony_ci		}
301570af302Sopenharmony_ci		size_t needed = size*cnt + UNIT;
302570af302Sopenharmony_ci		needed += -needed & (pagesize-1);
303570af302Sopenharmony_ci
304570af302Sopenharmony_ci		// produce an individually-mmapped allocation if usage is low,
305570af302Sopenharmony_ci		// bounce counter hasn't triggered, and either it saves memory
306570af302Sopenharmony_ci		// or it avoids eagar slot allocation without wasting too much.
307570af302Sopenharmony_ci		if (!nosmall && cnt<=7) {
308570af302Sopenharmony_ci			req += IB + UNIT;
309570af302Sopenharmony_ci			req += -req & (pagesize-1);
310570af302Sopenharmony_ci			if (req<size+UNIT || (req>=4*pagesize && 2*cnt>usage)) {
311570af302Sopenharmony_ci				cnt = 1;
312570af302Sopenharmony_ci				needed = req;
313570af302Sopenharmony_ci			}
314570af302Sopenharmony_ci		}
315570af302Sopenharmony_ci
316570af302Sopenharmony_ci		p = mmap(0, needed, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
317570af302Sopenharmony_ci		if (p==MAP_FAILED) {
318570af302Sopenharmony_ci			free_meta(m);
319570af302Sopenharmony_ci			return 0;
320570af302Sopenharmony_ci		}
321570af302Sopenharmony_ci#ifndef __LITEOS__
322570af302Sopenharmony_ci		prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, p, needed, "native_heap:brk");
323570af302Sopenharmony_ci#endif
324570af302Sopenharmony_ci		m->maplen = needed>>12;
325570af302Sopenharmony_ci		ctx.mmap_counter++;
326570af302Sopenharmony_ci		active_idx = (4096-UNIT)/size-1;
327570af302Sopenharmony_ci		if (active_idx > cnt-1) active_idx = cnt-1;
328570af302Sopenharmony_ci		if (active_idx < 0) active_idx = 0;
329570af302Sopenharmony_ci	} else {
330570af302Sopenharmony_ci		int j = size_to_class(UNIT+cnt*size-IB);
331570af302Sopenharmony_ci		int idx = alloc_slot(j, UNIT+cnt*size-IB);
332570af302Sopenharmony_ci		if (idx < 0) {
333570af302Sopenharmony_ci			free_meta(m);
334570af302Sopenharmony_ci			return 0;
335570af302Sopenharmony_ci		}
336570af302Sopenharmony_ci		struct meta *g = ctx.active[j];
337570af302Sopenharmony_ci		p = enframe(g, idx, UNIT*size_classes[j]-IB, ctx.mmap_counter);
338570af302Sopenharmony_ci		m->maplen = 0;
339570af302Sopenharmony_ci		p[-3] = (p[-3]&31) | (6<<5);
340570af302Sopenharmony_ci		for (int i=0; i<=cnt; i++)
341570af302Sopenharmony_ci			p[UNIT+i*size-4] = 0;
342570af302Sopenharmony_ci		active_idx = cnt-1;
343570af302Sopenharmony_ci	}
344570af302Sopenharmony_ci	ctx.usage_by_class[sc] += cnt;
345570af302Sopenharmony_ci	m->avail_mask = (2u<<active_idx)-1;
346570af302Sopenharmony_ci	m->freed_mask = (2u<<(cnt-1))-1 - m->avail_mask;
347570af302Sopenharmony_ci	m->mem = (void *)p;
348570af302Sopenharmony_ci	m->mem->meta = encode_ptr(m, ctx.secret);
349570af302Sopenharmony_ci	m->mem->active_idx = active_idx;
350570af302Sopenharmony_ci	m->last_idx = cnt-1;
351570af302Sopenharmony_ci	m->freeable = 1;
352570af302Sopenharmony_ci	m->sizeclass = sc;
353570af302Sopenharmony_ci	return m;
354570af302Sopenharmony_ci}
355570af302Sopenharmony_ci
356570af302Sopenharmony_cistatic int alloc_slot(int sc, size_t req)
357570af302Sopenharmony_ci{
358570af302Sopenharmony_ci	uint32_t first = try_avail(&ctx.active[sc]);
359570af302Sopenharmony_ci	if (first) return a_ctz_32(first);
360570af302Sopenharmony_ci
361570af302Sopenharmony_ci	struct meta *g = alloc_group(sc, req);
362570af302Sopenharmony_ci	if (!g) return -1;
363570af302Sopenharmony_ci
364570af302Sopenharmony_ci	g->avail_mask--;
365570af302Sopenharmony_ci	queue(&ctx.active[sc], g);
366570af302Sopenharmony_ci	return 0;
367570af302Sopenharmony_ci}
368570af302Sopenharmony_ci
369570af302Sopenharmony_civoid *malloc(size_t n)
370570af302Sopenharmony_ci{
371570af302Sopenharmony_ci	if (size_overflows(n)) return 0;
372570af302Sopenharmony_ci	struct meta *g;
373570af302Sopenharmony_ci	uint32_t mask, first;
374570af302Sopenharmony_ci	int sc;
375570af302Sopenharmony_ci	int idx;
376570af302Sopenharmony_ci	int ctr;
377570af302Sopenharmony_ci
378570af302Sopenharmony_ci	if (n >= MMAP_THRESHOLD) {
379570af302Sopenharmony_ci		size_t needed = n + IB + UNIT;
380570af302Sopenharmony_ci		void *p = mmap(0, needed, PROT_READ|PROT_WRITE,
381570af302Sopenharmony_ci			MAP_PRIVATE|MAP_ANON, -1, 0);
382570af302Sopenharmony_ci		if (p==MAP_FAILED) return 0;
383570af302Sopenharmony_ci		wrlock();
384570af302Sopenharmony_ci#ifndef __LITEOS__
385570af302Sopenharmony_ci		prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, p, needed, "native_heap:mmap");
386570af302Sopenharmony_ci#endif
387570af302Sopenharmony_ci		step_seq();
388570af302Sopenharmony_ci		g = alloc_meta();
389570af302Sopenharmony_ci		if (!g) {
390570af302Sopenharmony_ci			unlock();
391570af302Sopenharmony_ci			munmap(p, needed);
392570af302Sopenharmony_ci			return 0;
393570af302Sopenharmony_ci		}
394570af302Sopenharmony_ci		g->mem = p;
395570af302Sopenharmony_ci		g->mem->meta = encode_ptr(g, ctx.secret);
396570af302Sopenharmony_ci		g->last_idx = 0;
397570af302Sopenharmony_ci		g->freeable = 1;
398570af302Sopenharmony_ci		g->sizeclass = 63;
399570af302Sopenharmony_ci		g->maplen = (needed+4095)/4096;
400570af302Sopenharmony_ci		g->avail_mask = g->freed_mask = 0;
401570af302Sopenharmony_ci		// use a global counter to cycle offset in
402570af302Sopenharmony_ci		// individually-mmapped allocations.
403570af302Sopenharmony_ci		ctx.mmap_counter++;
404570af302Sopenharmony_ci		idx = 0;
405570af302Sopenharmony_ci		goto success;
406570af302Sopenharmony_ci	}
407570af302Sopenharmony_ci
408570af302Sopenharmony_ci	sc = size_to_class(n);
409570af302Sopenharmony_ci
410570af302Sopenharmony_ci	rdlock();
411570af302Sopenharmony_ci	g = ctx.active[sc];
412570af302Sopenharmony_ci
413570af302Sopenharmony_ci	// use coarse size classes initially when there are not yet
414570af302Sopenharmony_ci	// any groups of desired size. this allows counts of 2 or 3
415570af302Sopenharmony_ci	// to be allocated at first rather than having to start with
416570af302Sopenharmony_ci	// 7 or 5, the min counts for even size classes.
417570af302Sopenharmony_ci	if (!g && sc>=4 && sc<32 && sc!=6 && !(sc&1) && !ctx.usage_by_class[sc]) {
418570af302Sopenharmony_ci		size_t usage = ctx.usage_by_class[sc|1];
419570af302Sopenharmony_ci		// if a new group may be allocated, count it toward
420570af302Sopenharmony_ci		// usage in deciding if we can use coarse class.
421570af302Sopenharmony_ci		if (!ctx.active[sc|1] || (!ctx.active[sc|1]->avail_mask
422570af302Sopenharmony_ci		    && !ctx.active[sc|1]->freed_mask))
423570af302Sopenharmony_ci			usage += 3;
424570af302Sopenharmony_ci		if (usage <= 12)
425570af302Sopenharmony_ci			sc |= 1;
426570af302Sopenharmony_ci		g = ctx.active[sc];
427570af302Sopenharmony_ci	}
428570af302Sopenharmony_ci
429570af302Sopenharmony_ci	for (;;) {
430570af302Sopenharmony_ci		mask = g ? g->avail_mask : 0;
431570af302Sopenharmony_ci#ifdef MALLOC_SECURE_ALL
432570af302Sopenharmony_ci		if (!mask) break;
433570af302Sopenharmony_ci		idx = get_randomIdx(mask, g->last_idx);
434570af302Sopenharmony_ci		first = 1u << idx;
435570af302Sopenharmony_ci
436570af302Sopenharmony_ci		if (RDLOCK_IS_EXCLUSIVE || !MT)
437570af302Sopenharmony_ci			g->avail_mask = mask-first;
438570af302Sopenharmony_ci		else if (a_cas(&g->avail_mask, mask, mask-first)!=mask)
439570af302Sopenharmony_ci			continue;
440570af302Sopenharmony_ci#else
441570af302Sopenharmony_ci		first = mask&-mask;
442570af302Sopenharmony_ci		if (!first) break;
443570af302Sopenharmony_ci		if (RDLOCK_IS_EXCLUSIVE || !MT)
444570af302Sopenharmony_ci			g->avail_mask = mask-first;
445570af302Sopenharmony_ci		else if (a_cas(&g->avail_mask, mask, mask-first)!=mask)
446570af302Sopenharmony_ci			continue;
447570af302Sopenharmony_ci		idx = a_ctz_32(first);
448570af302Sopenharmony_ci#endif
449570af302Sopenharmony_ci		goto success;
450570af302Sopenharmony_ci	}
451570af302Sopenharmony_ci	upgradelock();
452570af302Sopenharmony_ci
453570af302Sopenharmony_ci	idx = alloc_slot(sc, n);
454570af302Sopenharmony_ci	if (idx < 0) {
455570af302Sopenharmony_ci		unlock();
456570af302Sopenharmony_ci		return 0;
457570af302Sopenharmony_ci	}
458570af302Sopenharmony_ci	g = ctx.active[sc];
459570af302Sopenharmony_ci
460570af302Sopenharmony_cisuccess:
461570af302Sopenharmony_ci	ctr = ctx.mmap_counter;
462570af302Sopenharmony_ci	unlock();
463570af302Sopenharmony_ci	return enframe(g, idx, n, ctr);
464570af302Sopenharmony_ci}
465570af302Sopenharmony_ci
466570af302Sopenharmony_ciint is_allzero(void *p)
467570af302Sopenharmony_ci{
468570af302Sopenharmony_ci	struct meta *g = get_meta(p);
469570af302Sopenharmony_ci	return g->sizeclass >= 48 ||
470570af302Sopenharmony_ci		get_stride(g) < UNIT*size_classes[g->sizeclass];
471570af302Sopenharmony_ci}
472570af302Sopenharmony_ci
473570af302Sopenharmony_ciint mallopt(int param, int value)
474570af302Sopenharmony_ci{
475570af302Sopenharmony_ci#ifdef USE_JEMALLOC_DFX_INTF
476570af302Sopenharmony_ci	return je_mallopt(param, value);
477570af302Sopenharmony_ci#endif
478570af302Sopenharmony_ci	return 0;
479570af302Sopenharmony_ci}
480570af302Sopenharmony_ci
481570af302Sopenharmony_civoid malloc_disable(void)
482570af302Sopenharmony_ci{
483570af302Sopenharmony_ci#ifdef USE_JEMALLOC_DFX_INTF
484570af302Sopenharmony_ci	je_malloc_disable();
485570af302Sopenharmony_ci#endif
486570af302Sopenharmony_ci}
487570af302Sopenharmony_ci
488570af302Sopenharmony_civoid malloc_enable(void)
489570af302Sopenharmony_ci{
490570af302Sopenharmony_ci#ifdef USE_JEMALLOC_DFX_INTF
491570af302Sopenharmony_ci	je_malloc_enable();
492570af302Sopenharmony_ci#endif
493570af302Sopenharmony_ci}
494570af302Sopenharmony_ci
495570af302Sopenharmony_ciint malloc_iterate(void* base, size_t size, void (*callback)(void* base, size_t size, void* arg), void* arg)
496570af302Sopenharmony_ci{
497570af302Sopenharmony_ci#ifdef USE_JEMALLOC_DFX_INTF
498570af302Sopenharmony_ci	return je_iterate(base, size, callback, arg);
499570af302Sopenharmony_ci#endif
500570af302Sopenharmony_ci	return 0;
501570af302Sopenharmony_ci}
502570af302Sopenharmony_ci
503570af302Sopenharmony_cissize_t malloc_backtrace(void* pointer, uintptr_t* frames, size_t frame_count)
504570af302Sopenharmony_ci{
505570af302Sopenharmony_ci	return 0;
506570af302Sopenharmony_ci}
507