/*
 * garbage collector program copyright (C) 2009 H.Niwa 
 */

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.

 * This program 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 General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA.
 */
#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

#include <string>

#include "syserr.h"

#include "bin_node.h"
#include "gc.h"
#include "var.h"
#include "pred.h"
#include "context.h"
#include "builtin.h"
#include "unify.h"
#include "context.h"
#include "gc.h"
#include "module.h"


void GCmark(Node* nd)
{
	
	nd->gcmark();
}

void GC()
{
	GC(Nil);
}

static int gcloop = 0;

void GC(Node* bd)
{
	Node*	nd;
	Node*	ndprev;
	int	n;

// return;
#if 1
	if (gcloop++ < 1000) {
		return;
	} else {
		gcloop = 0;
	}
#endif
	// clear mark
	n = 0;
	for (nd = AllNodes; nd != NULL; nd = nd->nextnode) {
		nd->ref = 0;
		n++;
	}

//printf("GC start [%d]\n", n);
	

	GCmark(True);
	GCmark(Nil);
	GCmark(__UNDEF__);
	GCmark(dlibpathnode);

	GCmark(bd);

	GCmark(Module);

	Context* cxp;
	for (cxp = CXNode; cxp != NULL; cxp = cxp->Next()) {
		GCmark(cxp->inherit);
		GCmark(cxp->env_stack);
		GCmark(cxp->env);
		GCmark(cxp->misc_stack);
	}
	

//printf("GCmark\n");

	// free node
	if (AllNodes != NULL) {
		while(AllNodes->ref == 0) {
			nd = AllNodes;
			AllNodes = nd->nextnode;
			delete nd;
			nd = 0;
			if (AllNodes == NULL) {
				break;
			}
		}
		
		if (AllNodes != NULL) {
			for (ndprev = AllNodes, nd = AllNodes->nextnode; 
					nd != NULL; ) {
				
				if (nd->ref == 0) {
					Node* ndold = nd;
					ndprev->nextnode = nd->nextnode;
					nd = nd->nextnode;
//printf("GC delete "); nd->print(); printf("\n");
					delete ndold;
					ndold = 0;
				} else {
					ndprev = ndprev->nextnode;
					nd = nd->nextnode;
				}
			}
		}
	}

//printf("free node \n");

	// count all nodes		
	n = 0;
	for (nd = AllNodes; nd != NULL; nd = nd->nextnode) {
		n++;
	}
//printf("GC end [%d]\n", n);
}

int CountNode()
{
	Node*	nd;
	int	n;

	n = 0;
	for (nd = AllNodes; nd != NULL; nd = nd->nextnode) {
		n++;
	}

	return n;
}


