From c3c703da44460e0e4a8a51e6b88ce2da0a470282 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fredrik=20H=C3=BCbinette=20=28Hubbe=29?= <hubbe@hubbe.net>
Date: Wed, 4 Dec 1996 16:47:58 -0800
Subject: [PATCH] fixed a small memory leak and added _memory_usage

Rev: bin/test_pike.pike:1.3
Rev: src/ChangeLog:1.32
Rev: src/array.c:1.4
Rev: src/array.h:1.2
Rev: src/builtin_functions.c:1.16
Rev: src/builtin_functions.h:1.3
Rev: src/callback.c:1.4
Rev: src/callback.h:1.3
Rev: src/constants.c:1.4
Rev: src/constants.h:1.2
Rev: src/language.yacc:1.15
Rev: src/las.c:1.10
Rev: src/las.h:1.3
Rev: src/mapping.c:1.8
Rev: src/mapping.h:1.2
Rev: src/modules/call_out/call_out.c:1.4
Rev: src/modules/pipe/pipe.c:1.7
Rev: src/multiset.c:1.2
Rev: src/multiset.h:1.2
Rev: src/object.c:1.6
Rev: src/object.h:1.4
Rev: src/program.c:1.11
Rev: src/program.h:1.4
Rev: src/stralloc.c:1.8
Rev: src/stralloc.h:1.4
---
 bin/test_pike.pike              | 272 +++++++++++++++++++-------------
 src/ChangeLog                   |   5 +
 src/array.c                     |  14 ++
 src/array.h                     |   4 +
 src/builtin_functions.c         |  79 +++++++++-
 src/builtin_functions.h         |   4 +
 src/callback.c                  | 100 ++++++++++--
 src/callback.h                  |   3 +-
 src/constants.c                 |  23 +++
 src/constants.h                 |   2 +
 src/language.yacc               |   3 +-
 src/las.c                       |  57 +++++--
 src/las.h                       |   1 +
 src/mapping.c                   |  23 ++-
 src/mapping.h                   |   2 +
 src/modules/call_out/call_out.c |  19 ++-
 src/modules/pipe/pipe.c         |   3 +-
 src/multiset.c                  |  13 ++
 src/multiset.h                  |   1 +
 src/object.c                    |  19 ++-
 src/object.h                    |   1 +
 src/program.c                   |  16 +-
 src/program.h                   |   1 +
 src/stralloc.c                  |  22 +++
 src/stralloc.h                  |   1 +
 25 files changed, 536 insertions(+), 152 deletions(-)

diff --git a/bin/test_pike.pike b/bin/test_pike.pike
index 258390f97c..8110b5c518 100755
--- a/bin/test_pike.pike
+++ b/bin/test_pike.pike
@@ -12,7 +12,8 @@ int main(int argc, string *argv)
   int e, verbose, successes, errors, t, check;
   string *tests;
   program testprogram;
-  int start, fail;
+  int start, fail, mem;
+  int loop=1;
 
   for(e=1;e<argc;e++)
   {
@@ -49,6 +50,12 @@ int main(int argc, string *argv)
 	fail+=arg;
 	break;
 
+
+      case "-l":
+      case "--loop":
+	loop+=arg;
+	break;
+
       case "-t":
       case "--trace":
 	t+=arg;
@@ -59,6 +66,13 @@ int main(int argc, string *argv)
 	check++;
 	break;
 
+
+      case "-m":
+      case "--mem":
+      case "--memory":
+	mem++;
+	break;
+
       default:
 	if(tests)
 	{
@@ -81,147 +95,179 @@ int main(int argc, string *argv)
   }
 
   tests=tests[0..sizeof(tests)-2];
-  for(e=start;e<sizeof(tests);e++)
-  {
-    string test,condition;
-    int type;
-    object o;
-    mixed a,b;
-
-    if(check) _verify_internals();
 
-    test=tests[e];	
-    if(sscanf(test,"COND %s\n%s",condition,test)==2)
-    {
-      if(!clone(compile_string("mixed c() { return "+condition+"; }","Cond "+(e+1)))->c())
-      {
-	if(verbose)
-	  perror("Not doing test "+(e+1)+"\n");
-	successes++;
-	continue;
-      }
-    }
- 
-    sscanf(test,"%s\n%s",type,test);
-    sscanf(type,"%*s expected result: %s",type);
-
-    if(verbose)
-    {
-      perror("Doing test "+(e+1)+"\n");
-      if(verbose>1)
-	perror(test+"\n");
-    }
-
-    if(check > 1) _verify_internals();
+  while(loop--)
+  {
+    successes=errors=0;
 
-    switch(type)
+    for(e=start;e<sizeof(tests);e++)
     {
-    case "COMPILE_ERROR":
-      master()->set_inhibit_compile_errors(1);
-      if(catch(compile_string(test,"Test "+(e+1))))
+      string test,condition;
+      int type;
+      object o;
+      mixed a,b;
+      
+      if(check) _verify_internals();
+      
+      test=tests[e];	
+      if(sscanf(test,"COND %s\n%s",condition,test)==2)
       {
-	successes++;
-      }else{
-	perror("Test "+(e+1)+" failed.\n");
-	perror(test+"\n");
-	errors++;
+	if(!clone(compile_string("mixed c() { return "+condition+"; }","Cond "+(e+1)))->c())
+	{
+	  if(verbose)
+	    perror("Not doing test "+(e+1)+"\n");
+	  successes++;
+	  continue;
+	}
       }
-      master()->set_inhibit_compile_errors(0);
-      break;
-
-    case "EVAL_ERROR":
-      master()->set_inhibit_compile_errors(1);
-      if(catch(clone(compile_string(test,"Test "+(e+1)))->a()))
+      
+      sscanf(test,"%s\n%s",type,test);
+      sscanf(type,"%*s expected result: %s",type);
+      
+      if(verbose)
       {
-	successes++;
-      }else{
-	perror("Test "+(e+1)+" failed.\n");
-	perror(test+"\n");
-	errors++;
+	perror("Doing test "+(e+1)+"\n");
+	if(verbose>1)
+	  perror(test+"\n");
       }
-      master()->set_inhibit_compile_errors(0);
-      break;
-
-    default:
-      o=clone(compile_string(test,"Test "+(e+1)));
-
-      if(check > 1) _verify_internals();
-
-      a=b=0;
-      if(t) trace(t);
-      if(functionp(o->a)) a=o->a();
-      if(functionp(o->b)) b=o->b();
-      if(t) trace(0);
-
+      
       if(check > 1) _verify_internals();
-
+      
       switch(type)
       {
-      case "FALSE":
-	a=!a;
-	
-      case "TRUE":
-	if(!a)
+      case "COMPILE_ERROR":
+	master()->set_inhibit_compile_errors(1);
+	if(catch(compile_string(test,"Test "+(e+1))))
 	{
+	  successes++;
+	}else{
 	  perror("Test "+(e+1)+" failed.\n");
 	  perror(test+"\n");
 	  errors++;
-	}else{
-	  successes++;
 	}
+	master()->set_inhibit_compile_errors(0);
 	break;
-
-      case "RUN":
-	successes++;
-	break;
-
-      case "EQ":
-	if(a!=b)
+	
+      case "EVAL_ERROR":
+	master()->set_inhibit_compile_errors(1);
+	if(catch(clone(compile_string(test,"Test "+(e+1)))->a()))
 	{
+	  successes++;
+	}else{
 	  perror("Test "+(e+1)+" failed.\n");
 	  perror(test+"\n");
-	  perror(sprintf("o->a(): %O\n",a));
-	  perror(sprintf("o->b(): %O\n",b));
 	  errors++;
-	}else{
-	  successes++;
 	}
+	master()->set_inhibit_compile_errors(0);
 	break;
-      
-      case "EQUAL":
-	if(!equal(a,b))
+	
+      default:
+	o=clone(compile_string(test,"Test "+(e+1)));
+	
+	if(check > 1) _verify_internals();
+	
+	a=b=0;
+	if(t) trace(t);
+	if(functionp(o->a)) a=o->a();
+	if(functionp(o->b)) b=o->b();
+	if(t) trace(0);
+	
+	if(check > 1) _verify_internals();
+	
+	switch(type)
 	{
-	  perror("Test "+(e+1)+" failed.\n");
-          perror(test+"\n");
-	  perror(sprintf("o->a(): %O\n",a));
-	  perror(sprintf("o->b(): %O\n",b));
-	  errors++;
-	}else{
+	case "FALSE":
+	  a=!a;
+	  
+	case "TRUE":
+	  if(!a)
+	  {
+	    perror("Test "+(e+1)+" failed.\n");
+	    perror(test+"\n");
+	    errors++;
+	  }else{
+	    successes++;
+	  }
+	  break;
+	  
+	case "RUN":
 	  successes++;
+	  break;
+	  
+	case "EQ":
+	  if(a!=b)
+	  {
+	    perror("Test "+(e+1)+" failed.\n");
+	    perror(test+"\n");
+	    perror(sprintf("o->a(): %O\n",a));
+	    perror(sprintf("o->b(): %O\n",b));
+	    errors++;
+	  }else{
+	    successes++;
+	  }
+	  break;
+	  
+	case "EQUAL":
+	  if(!equal(a,b))
+	  {
+	    perror("Test "+(e+1)+" failed.\n");
+	    perror(test+"\n");
+	    perror(sprintf("o->a(): %O\n",a));
+	    perror(sprintf("o->b(): %O\n",b));
+	    errors++;
+	  }else{
+	    successes++;
+	  }
+	  break;
+	  
+	default:
+	  perror(sprintf("Unknown test type (%O).\n",type));
+	  errors++;
 	}
-	break;
-
-      default:
-	perror(sprintf("Unknown test type (%O).\n",type));
-	errors++;
       }
+      
+      if(check > 2) _verify_internals();
+      
+      if(fail && errors)
+	exit(1);
+      
+      a=b=0;
     }
-
-    if(check > 2) _verify_internals();
-
-    if(fail && errors)
-      exit(1);
-  }
-
-  if(errors + successes != sizeof(tests))
-  {
-    perror("Errors + Successes != number of tests!\n");
-    errors++;
+    
+    if(errors + successes != sizeof(tests))
+    {
+      perror("Errors + Successes != number of tests!\n");
+      errors++;
+    }
+    
+    if(errors || verbose)
+    {
+      perror("Failed tests: "+errors+".\n");
+    }
+    
   }
-
-  if(errors || verbose)
+  if(mem)
   {
-    perror("Failed tests: "+errors+".\n");
+    int total;
+    tests=0;
+    gc();
+    mapping tmp=_memory_usage();
+    write(sprintf("%-10s: %6s %10s\n","Category","num","bytes"));
+    foreach(sort(indices(tmp)),string foo)
+    {
+      if(sscanf(foo,"%s_bytes",foo))
+      {
+	write(sprintf("%-10s: %6d %10d\n",
+		      foo+"s",
+		      tmp["num_"+foo+"s"],
+		      tmp[foo+"_bytes"]));
+	total+=tmp[foo+"_bytes"];
+      }
+    }
+    write(sprintf("%-10s: %6s %10d\n",
+		  "Total",
+		  "",
+		  total));
   }
 
   return errors;
diff --git a/src/ChangeLog b/src/ChangeLog
index 009401d3ca..01da6eea9f 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,8 @@
+Wed Dec  4 16:33:53 1996  Fredrik Hubinette  <hubbe@cytocin.hubbe.net>
+
+	* callback.c: fixed a memory leak and added more debug
+	* new efun: _memory_usage
+
 Wed Dec  4 05:01:00 1996  Niels M�ller  <nisse@skuld.infovav.se>
 
 	* modules/ssleay/ssleay.c (init_context): Increment reference count.
diff --git a/src/array.c b/src/array.c
index cd6973e35f..7cdcc0ed46 100644
--- a/src/array.c
+++ b/src/array.c
@@ -1534,3 +1534,17 @@ void zap_all_arrays()
     a=next;
   } while (a != & empty_array);
 }
+
+void count_memory_in_arrays(INT32 *num_, INT32 *size_)
+{
+  INT32 num=0, size=0;
+  struct array *m;
+  for(m=empty_array.next;m!=&empty_array;m=m->next)
+  {
+    num++;
+    size+=sizeof(struct array)+
+      sizeof(struct svalue) *  (m->malloced_size - 1);
+  }
+  *num_=num;
+  *size_=size;
+}
diff --git a/src/array.h b/src/array.h
index 8e31a29fd3..9300beb256 100644
--- a/src/array.h
+++ b/src/array.h
@@ -128,6 +128,10 @@ void gc_mark_array_as_referenced(struct array *a);
 void gc_check_all_arrays();
 void gc_mark_all_arrays();
 void gc_free_all_unreferenced_arrays();
+void debug_dump_type_field(TYPE_FIELD t);
+void debug_dump_array(struct array *a);
+void zap_all_arrays();
+void count_memory_in_arrays(INT32 *num_, INT32 *size_);
 /* Prototypes end here */
 
 
diff --git a/src/builtin_functions.c b/src/builtin_functions.c
index 6b1615cd6e..4533f770d3 100644
--- a/src/builtin_functions.c
+++ b/src/builtin_functions.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: builtin_functions.c,v 1.15 1996/12/03 21:41:15 hubbe Exp $");
+RCSID("$Id: builtin_functions.c,v 1.16 1996/12/05 00:47:11 hubbe Exp $");
 #include "interpret.h"
 #include "svalue.h"
 #include "macros.h"
@@ -1433,6 +1433,82 @@ void f_glob(INT32 args)
   }
 }
 
+static struct callback_list memory_usage_callback;
+
+struct callback *add_memory_usage_callback(callback_func call,
+					  void *arg,
+					  callback_func free_func)
+{
+  return add_to_callback(&memory_usage_callback, call, arg, free_func);
+}
+
+
+void f__memory_usage(INT32 args)
+{
+  INT32 num,size;
+  struct svalue *ss;
+  pop_n_elems(args);
+  ss=sp;
+
+  count_memory_in_mappings(&num, &size);
+  push_text("num_mappings");
+  push_int(num);
+  push_text("mapping_bytes");
+  push_int(size);
+
+  count_memory_in_strings(&num, &size);
+  push_text("num_strings");
+  push_int(num);
+  push_text("string_bytes");
+  push_int(size);
+
+  count_memory_in_arrays(&num, &size);
+  push_text("num_arrays");
+  push_int(num);
+  push_text("array_bytes");
+  push_int(size);
+
+  count_memory_in_programs(&num,&size);
+  push_text("num_programs");
+  push_int(num);
+  push_text("program_bytes");
+  push_int(size);
+
+  count_memory_in_multisets(&num, &size);
+  push_text("num_multisets");
+  push_int(num);
+  push_text("multiset_bytes");
+  push_int(size);
+
+  count_memory_in_objects(&num, &size);
+  push_text("num_objects");
+  push_int(num);
+  push_text("object_bytees");
+  push_int(size);
+
+  count_memory_in_callbacks(&num, &size);
+  push_text("num_callbacks");
+  push_int(num);
+  push_text("callback_bytes");
+  push_int(size);
+
+  count_memory_in_constants(&num, &size);
+  push_text("num_constants");
+  push_int(num);
+  push_text("constant_bytes");
+  push_int(size);
+
+  count_memory_in_callables(&num, &size);
+  push_text("num_callables");
+  push_int(num);
+  push_text("callable_bytes");
+  push_int(size);
+
+  call_callback(&memory_usage_callback, (void *)0);
+
+  f_aggregate_mapping(sp-ss);
+}
+
 void init_builtin_efuns()
 {
   init_operators();
@@ -1501,6 +1577,7 @@ void init_builtin_efuns()
 #ifdef DEBUG
   add_efun("_verify_internals",f__verify_internals,"function(:void)",OPT_SIDE_EFFECT|OPT_EXTERNAL_DEPEND);
 #endif
+  add_efun("_memory_usage",f__memory_usage,"function(:mapping(string:int))",OPT_EXTERNAL_DEPEND);
 
 #ifdef GC2
   add_efun("gc",f_gc,"function(:int)",OPT_SIDE_EFFECT);
diff --git a/src/builtin_functions.h b/src/builtin_functions.h
index d9ac9d8273..eb2b465b0d 100644
--- a/src/builtin_functions.h
+++ b/src/builtin_functions.h
@@ -70,6 +70,10 @@ void f_column(INT32 args);
 void f__verify_internals(INT32 args);
 void f_localtime(INT32 args);
 void f_glob(INT32 args);
+struct callback *add_memory_usage_callback(callback_func call,
+					   void *arg,
+					   callback_func free_func);
+void f__memory_usage(INT32 args);
 void init_builtin_efuns();
 /* Prototypes end here */
 
diff --git a/src/callback.c b/src/callback.c
index ff150380d4..6294d8d742 100644
--- a/src/callback.c
+++ b/src/callback.c
@@ -34,23 +34,66 @@ static struct callback *first_callback =0;
 static struct callback *free_callbacks =0;
 
 #ifdef DEBUG
+extern int d_flag;
+
 static void check_callback_chain(struct callback_list *lst)
 {
-  int len=0;
+  int e,len=0;
+  struct callback_block *tmp;
   struct callback *foo;
-  for(foo=lst->callbacks;foo;foo=foo->next)
+  if(d_flag)
   {
-    if((len & 1024)==1023)
+    for(foo=lst->callbacks;foo;foo=foo->next)
     {
-      int len2=0;
-      struct callback *tmp;
-      for(tmp=foo->next;tmp && len2<=len;tmp=tmp->next)
+      if((len & 1024)==1023)
       {
-	if(tmp==foo)
-	  fatal("Callback list is cyclic!!!\n");
+	int len2=0;
+	struct callback *tmp;
+	for(tmp=foo->next;tmp && len2<=len;tmp=tmp->next)
+	{
+	  if(tmp==foo)
+	    fatal("Callback list is cyclic!!!\n");
+	}
       }
+      len++;
     }
-    len++;
+    
+    for(tmp=callback_chunks;tmp;tmp=tmp->next)
+    {
+      for(e=0;e<CALLBACK_CHUNK;e++)
+      {
+	int d;
+	struct callback_block *tmp2;
+	
+	if(tmp->callbacks[e].free_func == (callback_func)remove_callback)
+	{
+	  for(foo=free_callbacks;foo;foo=foo->next)
+	    if(foo==tmp->callbacks+e)
+	      break;
+	  
+	  if(!foo)
+	    fatal("Lost track of a struct callback!\n");
+	}
+	
+	if(tmp->callbacks[e].next)
+	{
+	  d=CALLBACK_CHUNK;
+	  for(tmp2=callback_chunks;tmp2;tmp2=tmp2->next)
+	  {
+	    for(d=0;d<CALLBACK_CHUNK;d++)
+	    {
+	      if(tmp2->callbacks+d == tmp->callbacks[e].next)
+		break;
+	      
+	      if(d < CALLBACK_CHUNK) break;
+	    }
+	  }
+	  
+	  if(d == CALLBACK_CHUNK)
+	    fatal("Callback next pointer pointing to Z'ha'dum\n");
+	}
+      }
+  }
   }
 }
 #else
@@ -61,7 +104,7 @@ static void check_callback_chain(struct callback_list *lst)
 static struct callback *get_free_callback()
 {
   struct callback *tmp;
-  if(!(tmp=free_callbacks))
+  if(!free_callbacks)
   {
     int e;
     struct callback_block *tmp2;
@@ -69,12 +112,14 @@ static struct callback *get_free_callback()
     tmp2->next=callback_chunks;
     callback_chunks=tmp2;
 
-    for(e=0;e<(int)sizeof(CALLBACK_CHUNK);e++)
+    for(e=0;e<CALLBACK_CHUNK;e++)
     {
-      tmp2->callbacks[e].next=tmp;
-      tmp=tmp2->callbacks+e;
+      tmp2->callbacks[e].next=free_callbacks;
+      tmp2->callbacks[e].free_func=(callback_func)remove_callback;
+      free_callbacks=tmp2->callbacks+e;
     }
   }
+  tmp=free_callbacks;
   free_callbacks=tmp->next;
   return tmp;
 }
@@ -103,9 +148,15 @@ void call_callback(struct callback_list *lst, void *arg)
 
     if(!l->call)
     {
+      if(l->free_func)
+	l->free_func(l, l->arg, 0);
+
       *ptr=l->next;
       l->next=free_callbacks;
       free_callbacks=l;
+#ifdef DEBUG
+      l->free_func=(callback_func)remove_callback;
+#endif
     }else{
       ptr=& l->next;
     }
@@ -123,6 +174,7 @@ struct callback *add_to_callback(struct callback_list *lst,
   l=get_free_callback();
   l->call=call;
   l->arg=arg;
+  l->free_func=free_func;
 
   l->next=lst->callbacks;
   lst->callbacks=l;
@@ -138,6 +190,7 @@ struct callback *add_to_callback(struct callback_list *lst,
 void *remove_callback(struct callback *l)
 {
   l->call=0;
+  l->free_func=0;
   return l->arg;
 }
 
@@ -149,11 +202,14 @@ void free_callback(struct callback_list *lst)
   ptr=& lst->callbacks;
   while(l=*ptr)
   {
-    if(l->arg && l->free_func)
+    if(l->free_func)
       l->free_func(l, l->arg, 0);
     *ptr=l->next;
     l->next=free_callbacks;
     free_callbacks=l;
+#ifdef DEBUG
+    l->free_func=(callback_func)remove_callback;
+#endif
   }
 }
 
@@ -167,3 +223,19 @@ void cleanup_callbacks()
   }
   free_callbacks=0;
 }
+
+
+void count_memory_in_callbacks(INT32 *num_, INT32 *size_)
+{
+  INT32 num=0, size=0;
+  struct callback_block *tmp;
+  struct callback *tmp2;
+  for(tmp=callback_chunks;tmp;tmp=tmp->next)
+  {
+    num+=CALLBACK_CHUNK;
+    size+=sizeof(struct callback_block);
+  }
+  for(tmp2=free_callbacks;tmp2;tmp2=tmp2->next) num--;
+  *num_=num;
+  *size_=size;
+}
diff --git a/src/callback.h b/src/callback.h
index 104847cf2d..43bd077232 100644
--- a/src/callback.h
+++ b/src/callback.h
@@ -27,8 +27,9 @@ struct callback *add_to_callback(struct callback_list *lst,
 				 void *arg,
 				 callback_func free_func);
 void *remove_callback(struct callback *l);
-void free_callback(struct callback_list *ptr);
+void free_callback(struct callback_list *lst);
 void cleanup_callbacks();
+void count_memory_in_callbacks(INT32 *num_, INT32 *size_);
 /* Prototypes end here */
 
 #endif
diff --git a/src/constants.c b/src/constants.c
index 8f329c6738..77fead603b 100644
--- a/src/constants.c
+++ b/src/constants.c
@@ -13,6 +13,7 @@
 #include "interpret.h"
 
 static struct hash_table *efun_hash = 0;
+static INT32 num_callable=0;
 
 struct efun *lookup_efun(struct pike_string *name)
 {
@@ -63,6 +64,7 @@ struct callable *make_callable(c_fun fun,
 {
   struct callable *f;
   f=ALLOC_STRUCT(callable);
+  num_callable++;
   f->refs=1;
   f->function=fun;
   f->name=make_shared_string(name);
@@ -78,6 +80,7 @@ void really_free_callable(struct callable *fun)
   free_string(fun->type);
   free_string(fun->name);
   free((char *)fun);
+  num_callable--;
 }
 
 void add_efun2(char *name,
@@ -138,3 +141,23 @@ void cleanup_added_efuns()
   }
   
 }
+
+void count_memory_in_constants(INT32 *num_, INT32 *size_)
+{
+  INT32 size=0, num=0;
+  if(efun_hash)
+  {
+    size+=sizeof(struct hash_table) +
+      efun_hash->mask*sizeof(struct hash_entry)+
+    efun_hash->entries*sizeof(struct efun);
+  }
+  *num_=num;
+  *size_=size;
+}
+
+void count_memory_in_callables(INT32 *num_, INT32 *size_)
+{
+  *num_=num_callable;
+  *size_=num_callable*sizeof(struct callable);
+}
+
diff --git a/src/constants.h b/src/constants.h
index 83a9c56ae9..b6e274c7f4 100644
--- a/src/constants.h
+++ b/src/constants.h
@@ -50,6 +50,8 @@ void add_efun2(char *name,
 void add_efun(char *name, c_fun fun, char *type, INT16 flags);
 void push_all_efuns_on_stack();
 void cleanup_added_efuns();
+void count_memory_in_constants(INT32 *num_, INT32 *size_);
+void count_memory_in_callables(INT32 *num_, INT32 *size_);
 /* Prototypes end here */
 
 #endif
diff --git a/src/language.yacc b/src/language.yacc
index 002786ca0b..bda3aafb97 100644
--- a/src/language.yacc
+++ b/src/language.yacc
@@ -156,7 +156,7 @@
 /* This is the grammar definition of Pike. */
 
 #include "global.h"
-RCSID("$Id: language.yacc,v 1.14 1996/12/04 00:27:10 hubbe Exp $");
+RCSID("$Id: language.yacc,v 1.15 1996/12/05 00:47:14 hubbe Exp $");
 #ifdef HAVE_MEMORY_H
 #include <memory.h>
 #endif
@@ -1295,6 +1295,7 @@ void yyerror(char *str)
 
   if (num_parse_error > 5) return;
   num_parse_error++;
+  cumulative_parse_error++;
 
   if ( get_master() )
   {
diff --git a/src/las.c b/src/las.c
index 2cf80c8f4d..d68ecec038 100644
--- a/src/las.c
+++ b/src/las.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: las.c,v 1.9 1996/12/04 00:27:11 hubbe Exp $");
+RCSID("$Id: las.c,v 1.10 1996/12/05 00:47:14 hubbe Exp $");
 
 #include "language.h"
 #include "interpret.h"
@@ -36,6 +36,7 @@ static void optimize(node *n);
 dynamic_buffer areas[NUM_AREAS];
 node *init_node = 0;
 int num_parse_error;
+int cumulative_parse_error=0;
 extern char *get_type_name(int);
 
 #define MAX_GLOBAL 256
@@ -139,28 +140,51 @@ void free_all_nodes()
   {
     node *tmp;
     struct node_chunk *tmp2;
-#ifdef DEBUG
     int e=0;
-    for(tmp2=node_chunks;tmp2;tmp2=tmp2->next) e+=NODES;
-    for(tmp=free_nodes;tmp;tmp=CAR(tmp)) e--;
-    if(e)
+
+
+    if(cumulative_parse_error)
     {
-      int e2=e;
-      for(tmp2=node_chunks;tmp2;tmp2=tmp2->next)
+      
+      for(tmp2=node_chunks;tmp2;tmp2=tmp2->next) e+=NODES;
+      for(tmp=free_nodes;tmp;tmp=CAR(tmp)) e--;
+      if(e)
       {
-	for(e=0;e<NODES;e++)
+	int e2=e;
+	for(tmp2=node_chunks;tmp2;tmp2=tmp2->next)
 	{
-	  for(tmp=free_nodes;tmp;tmp=CAR(tmp))
-	    if(tmp==tmp2->nodes+e)
-	      break;
-
-	  if(!tmp)
-	    fprintf(stderr,"Free node at %p.\n",(tmp2->nodes+e));
+	  for(e=0;e<NODES;e++)
+	  {
+	    for(tmp=free_nodes;tmp;tmp=CAR(tmp))
+	      if(tmp==tmp2->nodes+e)
+		break;
+	    
+	    if(!tmp)
+	    {
+	      tmp=tmp2->nodes+e;
+#ifdef DEBUG
+	      if(!cumulative_parse_error)
+	      {
+		fprintf(stderr,"Free node at %p.\n",tmp);
+	      }
+	      else
+#endif
+	      {
+		/* Free the node and be happy */
+		/* Make sure we don't free any nodes twice */
+		if(car_is_node(tmp)) CAR(tmp)=0;
+		if(cdr_is_node(tmp)) CDR(tmp)=0;
+		free_node(tmp);
+	      }
+	    }
+	  }
 	}
+#ifdef DEBUG
+	if(!cumulative_parse_error)
+	  fatal("Failed to free %d nodes when compiling!\n",e2);
+#endif
       }
-      fatal("Failed to free %d nodes when compiling!\n",e2);
     }
-#endif
     while(node_chunks)
     {
       tmp2=node_chunks;
@@ -168,6 +192,7 @@ void free_all_nodes()
       free((char *)tmp2);
     }
     free_nodes=0;
+    cumulative_parse_error=0;
   }
 }
 
diff --git a/src/las.h b/src/las.h
index 736754f4a0..6d97e60d7b 100644
--- a/src/las.h
+++ b/src/las.h
@@ -58,6 +58,7 @@ typedef struct node_s node;
 extern struct locals *local_variables;
 extern node *init_node;
 extern int num_parse_error;
+extern int cumulative_parse_error;
 
 #define OPT_OPTIMIZED       0x1    /* has been processed by optimize(),
 				    * only used in node_info
diff --git a/src/mapping.c b/src/mapping.c
index 7b792a6a9f..38ef53c929 100644
--- a/src/mapping.c
+++ b/src/mapping.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: mapping.c,v 1.7 1996/11/14 01:36:29 hubbe Exp $");
+RCSID("$Id: mapping.c,v 1.8 1996/12/05 00:47:15 hubbe Exp $");
 #include "main.h"
 #include "types.h"
 #include "object.h"
@@ -20,7 +20,6 @@ RCSID("$Id: mapping.c,v 1.7 1996/11/14 01:36:29 hubbe Exp $");
 #include "las.h"
 #include "gc.h"
 
-
 #define AVG_LINK_LENGTH 4
 #define MIN_LINK_LENGTH 1
 #define MAP_SLOTS(X) ((X)+((X)>>4)+8)
@@ -1048,3 +1047,23 @@ void zap_all_mappings()
     free_mapping(m);
   }
 }
+
+void count_memory_in_mappings(INT32 *num_, INT32 *size_)
+{
+  INT32 num=0, size=0;
+  struct mapping *m;
+  for(m=first_mapping;m;m=m->next)
+  {
+    struct keypair *k;
+    num++;
+    size+=sizeof(struct mapping)+
+      sizeof(struct keypair *) * m->hashsize+
+      sizeof(struct keypair) *  m->size;
+
+    for(k=m->free_list;k;k=k->next)
+      size+=sizeof(struct keypair);
+  }
+
+  *num_=num;
+  *size_=size;
+}
diff --git a/src/mapping.h b/src/mapping.h
index 55f1d04597..12d0a296ba 100644
--- a/src/mapping.h
+++ b/src/mapping.h
@@ -65,5 +65,7 @@ void gc_mark_mapping_as_referenced(struct mapping *m);
 void gc_check_all_mappings();
 void gc_mark_all_mappings();
 void gc_free_all_unreferenced_mappings();
+void zap_all_mappings();
+void count_memory_in_mappings(INT32 *num_, INT32 *size_);
 /* Prototypes end here */
 #endif
diff --git a/src/modules/call_out/call_out.c b/src/modules/call_out/call_out.c
index f46dda09bc..3a45ede2e8 100644
--- a/src/modules/call_out/call_out.c
+++ b/src/modules/call_out/call_out.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: call_out.c,v 1.3 1996/11/14 01:36:33 hubbe Exp $");
+RCSID("$Id: call_out.c,v 1.4 1996/12/05 00:47:43 hubbe Exp $");
 #include "array.h"
 #include "dynamic_buffer.h"
 #include "object.h"
@@ -16,6 +16,8 @@ RCSID("$Id: call_out.c,v 1.3 1996/11/14 01:36:33 hubbe Exp $");
 #include "backend.h"
 #include "time_stuff.h"
 #include "constants.h"
+#include "stralloc.h"
+#include "builtin_functions.h"
 
 #include "callback.h"
 
@@ -166,7 +168,19 @@ static struct array * new_call_out(int num_arg,struct svalue *argp)
   return new->args;
 }
 
+static void count_memory_in_call_outs(struct callback *foo,
+				      void *bar,
+				      void *gazonk)
+{
+  push_text("num_call_outs");
+  push_int(num_pending_calls);
+  push_text("call_out_memory");
+  push_int(call_buffer_size * sizeof(call_out **)+
+	   num_pending_calls * sizeof(call_out));
+}
+
 static struct callback *call_out_backend_callback=0;
+static struct callback *mem_callback=0;
 void do_call_outs(struct callback *ignored, void *ignored_too, void *arg);
 
 void f_call_out(INT32 args)
@@ -193,6 +207,9 @@ void f_call_out(INT32 args)
    */
   if(!call_out_backend_callback)
     call_out_backend_callback=add_backend_callback(do_call_outs,0,0);
+
+  if(!mem_callback)
+    mem_callback=add_memory_usage_callback(count_memory_in_call_outs,0,0);
 }
 
 void do_call_outs(struct callback *ignored, void *ignored_too, void *arg)
diff --git a/src/modules/pipe/pipe.c b/src/modules/pipe/pipe.c
index e6ceed60bf..2d7c631568 100644
--- a/src/modules/pipe/pipe.c
+++ b/src/modules/pipe/pipe.c
@@ -20,7 +20,7 @@
 #include <fcntl.h>
 
 #include "global.h"
-RCSID("$Id: pipe.c,v 1.6 1996/11/14 01:36:35 hubbe Exp $");
+RCSID("$Id: pipe.c,v 1.7 1996/12/05 00:47:58 hubbe Exp $");
 
 #include "stralloc.h"
 #include "types.h"
@@ -1108,6 +1108,7 @@ void init_pipe_programs()
    
    pipe_program->refs++;
    
+   /* Why is this here?? /Hubbe */
    port_setup_program();
    
    offset_output_close_callback=find_identifier("_output_close_callback",
diff --git a/src/multiset.c b/src/multiset.c
index eda1ac0f63..ae6c32c87f 100644
--- a/src/multiset.c
+++ b/src/multiset.c
@@ -305,3 +305,16 @@ void gc_free_all_unreferenced_multisets()
 }
 
 #endif /* GC2 */
+
+void count_memory_in_multisets(INT32 *num_, INT32 *size_)
+{
+  struct multiset *m;
+  INT32 size=0, num=0;
+  for(m=first_multiset;m;m=m->next)
+  {
+    num++;
+    size+=sizeof(struct multiset);
+  }
+  *num_=num;
+  *size_=size;
+}
diff --git a/src/multiset.h b/src/multiset.h
index 538b71431a..1b83a92598 100644
--- a/src/multiset.h
+++ b/src/multiset.h
@@ -43,6 +43,7 @@ void gc_mark_multiset_as_referenced(struct multiset *l);
 void gc_check_all_multisets();
 void gc_mark_all_multisets();
 void gc_free_all_unreferenced_multisets();
+void count_memory_in_multisets(INT32 *num_, INT32 *size_);
 /* Prototypes end here */
 
 #endif
diff --git a/src/object.c b/src/object.c
index e0ca94a113..7702305abe 100644
--- a/src/object.c
+++ b/src/object.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: object.c,v 1.5 1996/11/14 01:36:29 hubbe Exp $");
+RCSID("$Id: object.c,v 1.6 1996/12/05 00:47:17 hubbe Exp $");
 #include "object.h"
 #include "dynamic_buffer.h"
 #include "interpret.h"
@@ -808,3 +808,20 @@ void gc_free_all_unreferenced_objects()
 
 #endif /* GC2 */
 
+void count_memory_in_objects(INT32 *num_, INT32 *size_)
+{
+  INT32 num=0, size=0;
+  struct object *o;
+  for(o=first_object;o;o=o->next)
+  {
+    num++;
+    if(o->prog)
+    {
+      size+=sizeof(struct object);
+    }else{
+      size+=sizeof(struct object)-1+o->prog->storage_needed;
+    }
+  }
+  *num_=num;
+  *size_=size;
+}
diff --git a/src/object.h b/src/object.h
index 9abde9f91c..b7ff6fb774 100644
--- a/src/object.h
+++ b/src/object.h
@@ -67,6 +67,7 @@ void gc_mark_object_as_referenced(struct object *o);
 void gc_check_all_objects();
 void gc_mark_all_objects();
 void gc_free_all_unreferenced_objects();
+void count_memory_in_objects(INT32 *num_, INT32 *size_);
 /* Prototypes end here */
 
 #endif /* OBJECT_H */
diff --git a/src/program.c b/src/program.c
index 9f34f7aadf..5d58844d27 100644
--- a/src/program.c
+++ b/src/program.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: program.c,v 1.10 1996/12/04 00:27:12 hubbe Exp $");
+RCSID("$Id: program.c,v 1.11 1996/12/05 00:47:18 hubbe Exp $");
 #include "program.h"
 #include "object.h"
 #include "dynamic_buffer.h"
@@ -1452,3 +1452,17 @@ void gc_free_all_unreferenced_programs()
 }
 
 #endif /* GC2 */
+
+
+void count_memory_in_programs(INT32 *num_, INT32 *size_)
+{
+  INT32 size=0, num=0;
+  struct program *p;
+  for(p=first_program;p;p=p->next)
+  {
+    num++;
+    size+=p->total_size;
+  }
+  *num_=num;
+  *size_=size;
+}
diff --git a/src/program.h b/src/program.h
index e327cb1906..5849c82c5a 100644
--- a/src/program.h
+++ b/src/program.h
@@ -223,6 +223,7 @@ void gc_mark_program_as_referenced(struct program *p);
 void gc_check_all_programs();
 void gc_mark_all_programs();
 void gc_free_all_unreferenced_programs();
+void count_memory_in_programs(INT32 *num_, INT32 *size_);
 /* Prototypes end here */
 
 
diff --git a/src/stralloc.c b/src/stralloc.c
index 5be92fab38..4d8d4c0c82 100644
--- a/src/stralloc.c
+++ b/src/stralloc.c
@@ -526,3 +526,25 @@ void cleanup_shared_string_table()
   }
   free((char *)base_table);
 }
+
+void count_memory_in_strings(INT32 *num, INT32 *size)
+{
+  unsigned INT32 e, num_=0, size_=0;
+  if(!base_table) return;
+  size_+=htable_size * sizeof(struct pike_string *);
+  for(e=0;e<htable_size;e++)
+  {
+    struct pike_string *p;
+    for(p=base_table[e];p;p=p->next)
+    {
+      num_++;
+      size_+=sizeof(struct pike_string)+p->len;
+    }
+  }
+#ifdef DEBUG
+  if(num_strings != num_)
+    fatal("Num strings is wrong!.\n");
+#endif
+  num[0]=num_;
+  size[0]=size_;
+}
diff --git a/src/stralloc.h b/src/stralloc.h
index a0201a1b55..6b3575679b 100644
--- a/src/stralloc.h
+++ b/src/stralloc.h
@@ -56,6 +56,7 @@ struct pike_string *string_replace(struct pike_string *str,
 				     struct pike_string *to);
 void init_shared_string_table();
 void cleanup_shared_string_table();
+void count_memory_in_strings(INT32 *num, INT32 *size);
 /* Prototypes end here */
 
 #endif /* STRALLOC_H */
-- 
GitLab