/* ************************************************************************ */ /* */ /* Neko Standard Library */ /* Copyright (c)2005 Motion-Twin */ /* */ /* This library is free software; you can redistribute it and/or */ /* modify it under the terms of the GNU Lesser General Public */ /* License as published by the Free Software Foundation; either */ /* version 2.1 of the License, or (at your option) any later version. */ /* */ /* This library is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */ /* Lesser General Public License or the LICENSE file for more details. */ /* */ /* ************************************************************************ */ #include #include #include /**

Memory

An API for memory manipulation and statistics.

**/ typedef struct _vtree { int_val v; struct _vtree *left; struct _vtree *right; } vtree; typedef struct { vtree **t; int s; } vparams; static int mem_cache( void *v, vtree **t ) { vtree *p = *t; vtree *prev = NULL; while( p != NULL ) { if( p->v == (int_val)v ) return 1; prev = p; if( p->v > (int_val)v ) p = p->left; else p = p->right; } p = (vtree*)alloc(sizeof(vtree)); p->v = (int_val)v; p->left = NULL; p->right = NULL; if( prev == NULL ) *t = p; else { if( prev->v > p->v ) prev->left = p; else prev->right = p; } return 0; } static void mem_obj_field( value v, field f, void *_p ); static int mem_module( neko_module *m, vtree **l ); static int mem_size_rec( value v, vtree **l ) { switch( val_type(v) ) { case VAL_INT: case VAL_BOOL: case VAL_NULL: return 0; case VAL_FLOAT: if( mem_cache(v,l) ) return 0; return sizeof(vfloat); case VAL_STRING: if( mem_cache(v,l) ) return 0; return sizeof(value) + val_strlen(v); case VAL_OBJECT: if( mem_cache(v,l) ) return 0; { vparams p; p.t = l; p.s = sizeof(vobject) + sizeof(struct _objtable); val_iter_fields(v,mem_obj_field,&p); if( ((vobject*)v)->proto != NULL ) p.s += mem_size_rec((value)((vobject*)v)->proto,l); return p.s; } case VAL_ARRAY: if( mem_cache(v,l) ) return 0; { int t = sizeof(value); int size = val_array_size(v); int i; t += size * sizeof(value); for(i=0;ienv,l); if( val_tag(v) == VAL_PRIMITIVE ) t += mem_size_rec((value)((vfunction*)v)->module,l); else t += mem_module(((vfunction*)v)->module,l); return t; } case VAL_ABSTRACT: { int t = sizeof(vabstract); if( val_kind(v) == neko_kind_module ) t += mem_module((neko_module*)val_data(v),l); else if( val_kind(v) == k_hash ) { vhash *h = (vhash*)val_data(v); int i; t += sizeof(vhash); t += sizeof(hcell*) * h->ncells; for(i=0;incells;i++) { hcell *c = h->cells[i]; while( c != NULL ) { t += sizeof(hcell); t += mem_size_rec(c->key,l); t += mem_size_rec(c->val,l); c = c->next; } } } return t; } default: val_throw(alloc_string("mem_size : Unexpected value")); break; } return 0; } static void mem_obj_field( value v, field f, void *_p ) { vparams *p = (vparams*)_p; p->s += sizeof(cell); p->s += mem_size_rec(v,p->t); } static int mem_module( neko_module *m, vtree **l ) { int t = 0; unsigned int i; if( mem_cache(m,l) ) return 0; t += sizeof(neko_module); t += m->codesize * sizeof(int_val); t += m->nglobals * sizeof(int_val); for(i=0;inglobals;i++) t += mem_size_rec(m->globals[i],l); t += m->nfields * sizeof(value*); for(i=0;infields;i++) t += mem_size_rec(m->fields[i],l); t += mem_size_rec(m->loader,l); t += mem_size_rec(m->exports,l); t += mem_size_rec(m->dbgtbl,l); if( m->dbgidxs ) t += sizeof(neko_debug) * (m->codesize >> 5); t += mem_size_rec(m->name,l); return t; } /** mem_size : any -> int Calculate the quite precise amount of VM memory reachable from this value **/ static value mem_size( value v ) { vtree *t = NULL; return alloc_int(mem_size_rec(v,&t)); } DEFINE_PRIM(mem_size,1); /* ************************************************************************ */