1/***********************************************************************
2*                                                                      *
3*               This software is part of the ast package               *
4*          Copyright (c) 1985-2012 AT&T Intellectual Property          *
5*                      and is licensed under the                       *
6*                 Eclipse Public License, Version 1.0                  *
7*                    by AT&T Intellectual Property                     *
8*                                                                      *
9*                A copy of the License is available at                 *
10*          http://www.eclipse.org/org/documents/epl-v10.html           *
11*         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12*                                                                      *
13*              Information and Software Systems Research               *
14*                            AT&T Research                             *
15*                           Florham Park NJ                            *
16*                                                                      *
17*                 Glenn Fowler <gsf@research.att.com>                  *
18*                  David Korn <dgk@research.att.com>                   *
19*                   Phong Vo <kpv@research.att.com>                    *
20*                                                                      *
21***********************************************************************/
22#if defined(_UWIN) && defined(_BLD_ast)
23
24void _STUB_vmprofile(){}
25
26#else
27
28#include	"vmhdr.h"
29
30/*	Method to profile space usage.
31**
32**	Written by Kiem-Phong Vo, kpv@research.att.com, 03/23/94.
33*/
34
35#define PFHASH(pf)	((pf)->data.data.hash)
36#define PFVM(pf)	((pf)->data.data.vm)
37#define PFFILE(pf)	((pf)->data.data.fm.file)
38#define PFLINE(pf)	((pf)->line)
39#define PFNAME(pf)	((pf)->data.f)
40#define PFNALLOC(pf)	((pf)->data.data.nalloc)
41#define PFALLOC(pf)	((pf)->data.data.alloc)
42#define PFNFREE(pf)	((pf)->data.data.nfree)
43#define PFFREE(pf)	((pf)->data.data.free)
44#define PFREGION(pf)	((pf)->data.data.region)
45#define PFMAX(pf)	((pf)->data.data.fm.max)
46
47typedef struct _pfdata_s	Pfdata_t;
48struct _pfdata_s
49{	Vmulong_t	hash;	/* hash value			*/
50	union
51	{ char*		file;	/* file name			*/
52	  Vmulong_t	max;	/* max busy space for region	*/
53	} fm;
54	Vmalloc_t*	vm;	/* region alloc from 		*/
55	Pfobj_t*	region;	/* pointer to region record	*/
56	Vmulong_t	nalloc;	/* number of alloc calls	*/
57	Vmulong_t	alloc;	/* amount allocated		*/
58	Vmulong_t	nfree;	/* number of free calls		*/
59	Vmulong_t	free;	/* amount freed			*/
60};
61struct _pfobj_s
62{	Pfobj_t*	next;	/* next in linked list	*/
63	int		line;	/* line #, 0 for name holder	*/
64	union
65	{
66	Pfdata_t	data;
67	char		f[1];	/* actual file name		*/
68	} data;
69};
70
71static Pfobj_t**	Pftable;	/* hash table		*/
72#define PFTABLE		1019		/* table size		*/
73static Vmalloc_t*	Vmpf;		/* heap for our own use	*/
74
75#if __STD_C
76static Pfobj_t* pfsearch(Vmalloc_t* vm, char* file, int line)
77#else
78static Pfobj_t* pfsearch(vm, file, line)
79Vmalloc_t*	vm;	/* region allocating from			*/
80char*		file;	/* the file issuing the allocation request	*/
81int		line;	/* line number					*/
82#endif
83{
84	reg Pfobj_t	*pf, *last;
85	reg Vmulong_t	h;
86	reg int		n;
87	reg char	*cp;
88
89	if(!Vmpf && !(Vmpf = vmopen(Vmdcheap,Vmpool,0)) )
90		return NIL(Pfobj_t*);
91
92	/* make hash table; PFTABLE'th slot hold regions' records */
93	if(!Pftable)
94	{	if(!(Pftable = (Pfobj_t**)vmalloc(Vmheap,(PFTABLE+1)*sizeof(Pfobj_t*))) )
95			return NIL(Pfobj_t*);
96		for(n = PFTABLE; n >= 0; --n)
97			Pftable[n] = NIL(Pfobj_t*);
98	}
99
100	/* see if it's there with a combined hash value of vm,file,line */
101	h = line + (((Vmulong_t)vm)>>4);
102	for(cp = file; *cp; ++cp)
103		h += (h<<7) + ((*cp)&0377) + 987654321L;
104	n = (int)(h%PFTABLE);
105	for(last = NIL(Pfobj_t*), pf = Pftable[n]; pf; last = pf, pf = pf->next)
106		if(PFLINE(pf) == line && PFVM(pf) == vm && strcmp(PFFILE(pf),file) == 0)
107			break;
108
109	/* insert if not there yet */
110	if(!pf)
111	{	reg Pfobj_t*	fn;
112		reg Pfobj_t*	pfvm;
113		reg Vmulong_t	hn;
114
115		/* first get/construct the file name slot */
116		hn = 0;
117		for(cp = file; *cp; ++cp)
118			hn += (hn<<7) + ((*cp)&0377) + 987654321L;
119		n = (int)(hn%PFTABLE);
120		for(fn = Pftable[n]; fn; fn = fn->next)
121			if(PFLINE(fn) < 0 && strcmp(PFNAME(fn),file) == 0)
122				break;
123		if(!fn)
124		{	reg size_t	s;
125			s = sizeof(Pfobj_t) - sizeof(Pfdata_t) + strlen(file) + 1;
126			if(!(fn = (Pfobj_t*)vmalloc(Vmheap,s)) )
127				return NIL(Pfobj_t*);
128			fn->next = Pftable[n];
129			Pftable[n] = fn;
130			PFLINE(fn) = -1;
131			strcpy(PFNAME(fn),file);
132		}
133
134		/* get region record; note that these are ordered by vm */
135		last = NIL(Pfobj_t*);
136		for(pfvm = Pftable[PFTABLE]; pfvm; last = pfvm, pfvm = pfvm->next)
137			if(vm >= PFVM(pfvm))
138				break;
139		if(!pfvm || PFVM(pfvm) > vm)
140		{	if(!(pfvm = (Pfobj_t*)vmalloc(Vmpf,sizeof(Pfobj_t))) )
141				return NIL(Pfobj_t*);
142			if(last)
143			{	pfvm->next = last->next;
144				last->next = pfvm;
145			}
146			else
147			{	pfvm->next = Pftable[PFTABLE];
148				Pftable[PFTABLE] = pfvm;
149			}
150			PFNALLOC(pfvm) = PFALLOC(pfvm) = 0;
151			PFNFREE(pfvm) = PFFREE(pfvm) = 0;
152			PFMAX(pfvm) = 0;
153			PFVM(pfvm) = vm;
154			PFLINE(pfvm) = 0;
155		}
156
157		if(!(pf = (Pfobj_t*)vmalloc(Vmpf,sizeof(Pfobj_t))) )
158			return NIL(Pfobj_t*);
159		n = (int)(h%PFTABLE);
160		pf->next = Pftable[n];
161		Pftable[n] = pf;
162		PFLINE(pf) = line;
163		PFFILE(pf) = PFNAME(fn);
164		PFREGION(pf) = pfvm;
165		PFVM(pf) = vm;
166		PFNALLOC(pf) = 0;
167		PFALLOC(pf) = 0;
168		PFNFREE(pf) = 0;
169		PFFREE(pf) = 0;
170		PFHASH(pf) = h;
171	}
172	else if(last)	/* do a move-to-front */
173	{	last->next = pf->next;
174		pf->next = Pftable[n];
175		Pftable[n] = pf;
176	}
177
178	return pf;
179}
180
181#if __STD_C
182static void pfclose(Vmalloc_t* vm)
183#else
184static void pfclose(vm)
185Vmalloc_t*	vm;
186#endif
187{
188	reg int		n;
189	reg Pfobj_t	*pf, *next, *last;
190
191	/* free all records related to region vm */
192	for(n = PFTABLE; n >= 0; --n)
193	{	for(last = NIL(Pfobj_t*), pf = Pftable[n]; pf; )
194		{	next = pf->next;
195
196			if(PFLINE(pf) >= 0 && PFVM(pf) == vm)
197			{	if(last)
198					last->next = next;
199				else	Pftable[n] = next;
200				vmfree(Vmpf,pf);
201			}
202			else	last = pf;
203
204			pf = next;
205		}
206	}
207}
208
209#if __STD_C
210static void pfsetinfo(Vmalloc_t* vm, Vmuchar_t* data, size_t size, char* file, int line)
211#else
212static void pfsetinfo(vm, data, size, file, line)
213Vmalloc_t*	vm;
214Vmuchar_t*	data;
215size_t		size;
216char*		file;
217int		line;
218#endif
219{
220	reg Pfobj_t*	pf;
221	reg Vmulong_t	s;
222
223	/* let vmclose knows that there are records for region vm */
224	_Vmpfclose = pfclose;
225
226	if(!file || line <= 0)
227	{	file = "";
228		line = 0;
229	}
230
231	if((pf = pfsearch(vm,file,line)) )
232	{	PFALLOC(pf) += (Vmulong_t)size;
233		PFNALLOC(pf) += 1;
234	}
235	PFOBJ(data) = pf;
236	PFSIZE(data) = size;
237
238	if(pf)
239	{	/* update region statistics */
240		pf = PFREGION(pf);
241		PFALLOC(pf) += (Vmulong_t)size;
242		PFNALLOC(pf) += 1;
243		if((s = PFALLOC(pf) - PFFREE(pf)) > PFMAX(pf) )
244			PFMAX(pf) = s;
245	}
246}
247
248/* sort by file names and line numbers */
249#if __STD_C
250static Pfobj_t* pfsort(Pfobj_t* pf)
251#else
252static Pfobj_t* pfsort(pf)
253Pfobj_t*	pf;
254#endif
255{
256	reg Pfobj_t	*one, *two, *next;
257	reg int		cmp;
258
259	if(!pf->next)
260		return pf;
261
262	/* partition to two equal size lists */
263	one = two = NIL(Pfobj_t*);
264	while(pf)
265	{	next = pf->next;
266		pf->next = one;
267		one = pf;
268
269		if((pf = next) )
270		{	next = pf->next;
271			pf->next = two;
272			two = pf;
273			pf = next;
274		}
275	}
276
277	/* sort and merge the lists */
278	one = pfsort(one);
279	two = pfsort(two);
280	for(pf = next = NIL(Pfobj_t*);; )
281	{	/* make sure that the "<>" file comes first */
282		if(PFLINE(one) == 0 && PFLINE(two) == 0)
283			cmp = PFVM(one) > PFVM(two) ? 1 : -1;
284		else if(PFLINE(one) == 0)
285			cmp = -1;
286		else if(PFLINE(two) == 0)
287			cmp = 1;
288		else if((cmp = strcmp(PFFILE(one),PFFILE(two))) == 0)
289		{	cmp = PFLINE(one) - PFLINE(two);
290			if(cmp == 0)
291				cmp = PFVM(one) > PFVM(two) ? 1 : -1;
292		}
293
294		if(cmp < 0)
295		{	if(!pf)
296				pf = one;
297			else	next->next = one;
298			next = one;
299			if(!(one = one->next) )
300			{	if(two)
301					next->next = two;
302				return pf;
303			}
304		}
305		else
306		{	if(!pf)
307				pf = two;
308			else	next->next = two;
309			next = two;
310			if(!(two = two->next) )
311			{	if(one)
312					next->next = one;
313				return pf;
314			}
315		}
316	}
317}
318
319#if __STD_C
320static char* pfsummary(char* buf, Vmulong_t na, Vmulong_t sa,
321			Vmulong_t nf, Vmulong_t sf, Vmulong_t max, Vmulong_t size)
322#else
323static char* pfsummary(buf, na, sa, nf, sf, max, size)
324char*		buf;
325Vmulong_t	na;
326Vmulong_t	sa;
327Vmulong_t	nf;
328Vmulong_t	sf;
329Vmulong_t	max;
330Vmulong_t	size;
331#endif
332{
333	buf = (*_Vmstrcpy)(buf,"n_alloc", '=');
334	buf = (*_Vmstrcpy)(buf, (*_Vmitoa)(na,-1), ':');
335	buf = (*_Vmstrcpy)(buf,"n_free", '=');
336	buf = (*_Vmstrcpy)(buf, (*_Vmitoa)(nf,-1), ':');
337	buf = (*_Vmstrcpy)(buf,"s_alloc", '=');
338	buf = (*_Vmstrcpy)(buf, (*_Vmitoa)(sa,-1), ':');
339	buf = (*_Vmstrcpy)(buf,"s_free", '=');
340	buf = (*_Vmstrcpy)(buf, (*_Vmitoa)(sf,-1), ':');
341	if(max > 0)
342	{	buf = (*_Vmstrcpy)(buf,"max_busy", '=');
343		buf = (*_Vmstrcpy)(buf, (*_Vmitoa)(max,-1), ':');
344		buf = (*_Vmstrcpy)(buf,"extent", '=');
345		buf = (*_Vmstrcpy)(buf, (*_Vmitoa)(size,-1), ':');
346	}
347	*buf++ = '\n';
348
349	return buf;
350}
351
352/* print profile data */
353#if __STD_C
354int vmprofile(Vmalloc_t* vm, int fd)
355#else
356int vmprofile(vm, fd)
357Vmalloc_t*	vm;
358int		fd;
359#endif
360{
361	reg Pfobj_t	*pf, *list, *next, *last;
362	reg int		n;
363	reg Vmulong_t	nalloc, alloc, nfree, free;
364	reg Seg_t	*seg;
365	char		buf[1024], *bufp, *endbuf;
366#define INITBUF()	(bufp = buf, endbuf = buf+sizeof(buf)-128)
367#define CHKBUF()	(bufp >= endbuf ? (write(fd,buf,bufp-buf), bufp=buf) : bufp)
368#define FLSBUF()	(bufp > buf ? write(fd,buf,bufp-buf) : 0)
369
370	if(fd < 0)
371		return -1;
372
373	/* initialize functions from vmtrace.c that we use below */
374	if((n = vmtrace(-1)) >= 0)
375		vmtrace(n);
376
377	alloc = free = nalloc = nfree = 0;
378	list = NIL(Pfobj_t*);
379	for(n = PFTABLE-1; n >= 0; --n)
380	{	for(pf = Pftable[n], last = NIL(Pfobj_t*); pf; )
381		{	next = pf->next;
382
383			if(PFLINE(pf) < 0  || (vm && vm != PFVM(pf)) )
384			{	last = pf;
385				goto next_pf;
386			}
387
388			/* remove from hash table */
389			if(last)
390				last->next = next;
391			else	Pftable[n] = next;
392
393			/* put on output list */
394			pf->next = list;
395			list = pf;
396			nalloc += PFNALLOC(pf);
397			alloc += PFALLOC(pf);
398			nfree += PFNFREE(pf);
399			free += PFFREE(pf);
400
401		next_pf:
402			pf = next;
403		}
404	}
405
406	INITBUF();
407	bufp = (*_Vmstrcpy)(bufp,"ALLOCATION USAGE SUMMARY", ':');
408	bufp = pfsummary(bufp,nalloc,alloc,nfree,free,0,0);
409
410	/* print regions' summary data */
411	for(pf = Pftable[PFTABLE]; pf; pf = pf->next)
412	{	if(vm && PFVM(pf) != vm)
413			continue;
414		alloc = 0;
415		for(seg = PFVM(pf)->data->seg; seg; seg = seg->next)
416			alloc += (Vmulong_t)seg->extent;
417		bufp = (*_Vmstrcpy)(bufp,"region", '=');
418		bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(PFVM(pf)),0), ':');
419		bufp = pfsummary(bufp,PFNALLOC(pf),PFALLOC(pf),
420				 PFNFREE(pf),PFFREE(pf),PFMAX(pf),alloc);
421	}
422
423	/* sort then output detailed profile */
424	list = pfsort(list);
425	for(pf = list; pf; )
426	{	/* compute summary for file */
427		alloc = free = nalloc = nfree = 0;
428		for(last = pf; last; last = last->next)
429		{	if(strcmp(PFFILE(last),PFFILE(pf)) != 0)
430				break;
431			nalloc += PFNALLOC(pf);
432			alloc += PFALLOC(last);
433			nfree += PFNFREE(last);
434			free += PFFREE(last);
435		}
436		CHKBUF();
437		bufp = (*_Vmstrcpy)(bufp,"file",'=');
438		bufp = (*_Vmstrcpy)(bufp,PFFILE(pf)[0] ? PFFILE(pf) : "<>" ,':');
439		bufp = pfsummary(bufp,nalloc,alloc,nfree,free,0,0);
440
441		while(pf != last)	/* detailed data */
442		{	CHKBUF();
443			bufp = (*_Vmstrcpy)(bufp,"\tline",'=');
444			bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(PFLINE(pf),-1), ':');
445			bufp = (*_Vmstrcpy)(bufp, "region", '=');
446			bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(PFVM(pf)),0), ':');
447			bufp = pfsummary(bufp,PFNALLOC(pf),PFALLOC(pf),
448					 PFNFREE(pf),PFFREE(pf),0,0);
449
450			/* reinsert into hash table */
451			next = pf->next;
452			n = (int)(PFHASH(pf)%PFTABLE);
453			pf->next = Pftable[n];
454			Pftable[n] = pf;
455			pf = next;
456		}
457	}
458
459	FLSBUF();
460	return 0;
461}
462
463#if __STD_C
464static Void_t* pfalloc(Vmalloc_t* vm, size_t size, int local)
465#else
466static Void_t* pfalloc(vm, size, local)
467Vmalloc_t*	vm;
468size_t		size;
469int		local;
470#endif
471{
472	reg size_t	s;
473	reg Void_t	*data;
474	reg char	*file;
475	reg int		line;
476	reg Void_t	*func;
477	reg Vmdata_t	*vd = vm->data;
478
479	VMFLF(vm,file,line,func);
480
481	SETLOCK(vm, local);
482
483	s = ROUND(size,ALIGN) + PF_EXTRA;
484	if((data = KPVALLOC(vm,s,(*(Vmbest->allocf))) ) )
485	{	pfsetinfo(vm,(Vmuchar_t*)data,size,file,line);
486
487		if(!local && (vd->mode&VM_TRACE) && _Vmtrace)
488		{	vm->file = file; vm->line = line; vm->func = func;
489			(*_Vmtrace)(vm,NIL(Vmuchar_t*),(Vmuchar_t*)data,size,0);
490		}
491	}
492
493	CLRLOCK(vm, local);
494
495	return data;
496}
497
498#if __STD_C
499static int pffree(Vmalloc_t* vm, Void_t* data, int local)
500#else
501static int pffree(vm, data, local)
502Vmalloc_t*	vm;
503Void_t*		data;
504int		local;
505#endif
506{
507	reg Pfobj_t	*pf;
508	reg size_t	s;
509	reg char	*file;
510	reg int		line, rv;
511	reg Void_t	*func;
512	reg Vmdata_t	*vd = vm->data;
513
514	VMFLF(vm,file,line,func);
515
516	if(!data)
517		return 0;
518
519	SETLOCK(vm,local);
520
521	/**/ASSERT(KPVADDR(vm, data, Vmbest->addrf) == 0 );
522	pf = PFOBJ(data);
523	s = PFSIZE(data);
524	if(pf)
525	{	PFNFREE(pf) += 1;
526		PFFREE(pf) += (Vmulong_t)s;
527		pf = PFREGION(pf);
528		PFNFREE(pf) += 1;
529		PFFREE(pf) += (Vmulong_t)s;
530	}
531
532	if(!local && (vd->mode&VM_TRACE) && _Vmtrace)
533	{	vm->file = file; vm->line = line; vm->func = func;
534		(*_Vmtrace)(vm,(Vmuchar_t*)data,NIL(Vmuchar_t*),s,0);
535	}
536
537	rv = KPVFREE((vm), (Void_t*)data, (*Vmbest->freef));
538
539        CLRLOCK(vm, local);
540
541	return rv;
542}
543
544#if __STD_C
545static Void_t* pfresize(Vmalloc_t* vm, Void_t* data, size_t size, int type, int local)
546#else
547static Void_t* pfresize(vm, data, size, type, local)
548Vmalloc_t*	vm;
549Void_t*		data;
550size_t		size;
551int		type;
552int		local;
553#endif
554{
555	reg Pfobj_t	*pf;
556	reg size_t	s, news;
557	reg Void_t	*addr;
558	reg char	*file;
559	reg int		line;
560	reg Void_t	*func;
561	reg size_t	oldsize;
562	reg Vmdata_t	*vd = vm->data;
563
564	if(!data)
565	{	addr = pfalloc(vm, size, local);
566		if(addr && (type&VM_RSZERO) )
567			memset(addr, 0, size);
568		return addr;
569	}
570	if(size == 0)
571	{	(void)pffree(vm, data, local);
572		return NIL(Void_t*);
573	}
574
575	VMFLF(vm,file,line,func);
576
577	SETLOCK(vm, local);
578
579	/**/ASSERT(KPVADDR(vm,data,Vmbest->addrf) == 0 );
580	pf = PFOBJ(data);
581	s = oldsize = PFSIZE(data);
582
583	news = ROUND(size,ALIGN) + PF_EXTRA;
584	if((addr = KPVRESIZE(vm,data,news,(type&~VM_RSZERO),Vmbest->resizef)) )
585	{	if(pf)
586		{	PFFREE(pf) += (Vmulong_t)s;
587			PFNFREE(pf) += 1;
588			pf = PFREGION(pf);
589			PFFREE(pf) += (Vmulong_t)s;
590			PFNFREE(pf) += 1;
591			pfsetinfo(vm,(Vmuchar_t*)addr,size,file,line);
592		}
593
594		if(!local && (vd->mode&VM_TRACE) && _Vmtrace)
595		{	vm->file = file; vm->line = line; vm->func = func;
596			(*_Vmtrace)(vm,(Vmuchar_t*)data,(Vmuchar_t*)addr,size,0);
597		}
598	}
599	else if(pf)	/* reset old info */
600	{	PFALLOC(pf) -= (Vmulong_t)s;
601		PFNALLOC(pf) -= 1;
602		pf = PFREGION(pf);
603		PFALLOC(pf) -= (Vmulong_t)s;
604		PFNALLOC(pf) -= 1;
605		file = PFFILE(pf);
606		line = PFLINE(pf);
607		pfsetinfo(vm,(Vmuchar_t*)data,s,file,line);
608	}
609
610	if(addr && (type&VM_RSZERO) && oldsize < size)
611	{	reg Vmuchar_t *d = (Vmuchar_t*)addr+oldsize, *ed = (Vmuchar_t*)addr+size;
612		do { *d++ = 0; } while(d < ed);
613	}
614
615	CLRLOCK(vm, local);
616
617	return addr;
618}
619
620#if __STD_C
621static long pfsize(Vmalloc_t* vm, Void_t* addr, int local)
622#else
623static long pfsize(vm, addr, local)
624Vmalloc_t*	vm;
625Void_t*		addr;
626int		local;
627#endif
628{
629	return (*Vmbest->addrf)(vm, addr, local) != 0 ? -1L : (long)PFSIZE(addr);
630}
631
632#if __STD_C
633static long pfaddr(Vmalloc_t* vm, Void_t* addr, int local)
634#else
635static long pfaddr(vm, addr, local)
636Vmalloc_t*	vm;
637Void_t*		addr;
638int		local;
639#endif
640{
641	return (*Vmbest->addrf)(vm, addr, local);
642}
643
644#if __STD_C
645static int pfcompact(Vmalloc_t* vm, int local)
646#else
647static int pfcompact(vm, local)
648Vmalloc_t*	vm;
649int		local;
650#endif
651{
652	return (*Vmbest->compactf)(vm, local);
653}
654
655#if __STD_C
656static Void_t* pfalign(Vmalloc_t* vm, size_t size, size_t align, int local)
657#else
658static Void_t* pfalign(vm, size, align, local)
659Vmalloc_t*	vm;
660size_t		size;
661size_t		align;
662int		local;
663#endif
664{
665	reg size_t	s;
666	reg Void_t	*data;
667	reg char	*file;
668	reg int		line;
669	reg Void_t	*func;
670	reg Vmdata_t	*vd = vm->data;
671
672	VMFLF(vm,file,line,func);
673
674	SETLOCK(vm, local);
675
676	s = (size <= TINYSIZE ? TINYSIZE : ROUND(size,ALIGN)) + PF_EXTRA;
677	if((data = KPVALIGN(vm,s,align,Vmbest->alignf)) )
678	{	pfsetinfo(vm,(Vmuchar_t*)data,size,file,line);
679
680		if(!local && (vd->mode&VM_TRACE) && _Vmtrace)
681		{	vm->file = file; vm->line = line; vm->func = func;
682			(*_Vmtrace)(vm,NIL(Vmuchar_t*),(Vmuchar_t*)data,size,align);
683		}
684	}
685
686	CLRLOCK(vm, local);
687
688	return data;
689}
690
691static Vmethod_t _Vmprofile =
692{
693	pfalloc,
694	pfresize,
695	pffree,
696	pfaddr,
697	pfsize,
698	pfcompact,
699	pfalign,
700	VM_MTPROFILE
701};
702
703__DEFINE__(Vmethod_t*,Vmprofile,&_Vmprofile);
704
705#ifdef NoF
706NoF(vmprofile)
707#endif
708
709#endif
710