view interp.c @ 159:d1e206ff75f9

Fix some bugs involving calling a worker object
author Mike Pavone <pavone@retrodev.com>
date Fri, 07 Jan 2011 03:17:20 -0500
parents 6202b866d72c
children
line wrap: on
line source

#ifdef WIN32
	#include <windows.h>
	#include <winsock.h>
	#include <crtdbg.h>
#else
#ifdef SYLLABLE
	#include <unistd.h>
	#include <atheos/threads.h>
#else
	#ifdef NINTENDO_DS
		#include <nds.h>
	#else
		#include <unistd.h>
		#include <pthread.h>
	#endif
#endif
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "mt19937ar.h"
#include "interp.h"
#include "vis_threading.h"
#include "datum.h"
#include "parser.h"
#include "saveload.h"

#ifdef TEXT_FILE_DEBUG
	FILE * debugfile;
#endif
char debugbuffer[1024];

//extern HWND	hWnd;
extern char new_name_buf[256];
extern int buf_size;

int lock_fail_counter;
int lock_counter;

VIS_CRITICAL_SECTION(data_lock)
VIS_CRITICAL_SECTION(worker_queue_lock)
VIS_CRITICAL_SECTION(randlock)
VIS_Event(queue_add_event)

int program_count=1;
VIS_CRITICAL_SECTION(program_count_lock)

//#define	ENABLE_PROFILING	1

#ifdef	ENABLE_PROFILING

__int64	vis_profile_start_times[NUM_PROFS];
__int64 vis_profile_running_total[NUM_PROFS];
int	vis_profile_counts[NUM_PROFS];

__declspec(naked)
unsigned __int64 __cdecl rdtsc(void)
{
   __asm
   {
      rdtsc
      ret       ; return value at EDX:EAX
   }
}


#define PROF_INIT_CUSTOM			0
#define	PROF_WORKER_THREAD			1
#define	PROF_PROCESS_WORKER			2
#define	PROF_CLEANUP_CUSTOM 		3
#define	PROF_SUB_CALLBACK			4
#define	PROF_CLEANUP_RELEASE_REFS	5
#define	PROF_CLEANUP_CHECK			6
#define	PROF_CLEANUP_FREELISTS		7
#define	PROF_PROCESS_OUTPUTS		8
#define	PROF_OPT_PREP_INPUT			9
#define	PROF_RUN_OPT				10
#define	PROF_ADDQUEUE				11
#define	PROF_ADDQUEUE_MALLOC		12
#define	PROF_OPT_LOOP				13
#define	PROF_EXECUTE_WORKER			14
#define	PROF_EXECUTE_OTHER			15
#define	PROF_PREP_MAGIC				16
#define	PROF_CONVERT_INPUTS			17
#define	PROF_EXECUTE_CUSTOM			18
#define	PROF_EXECUTE_BUILTIN		19
#define	PROF_EMPTYFUNC				20
#define	PROF_NOCODE					21
#define	PROF_LESSERWHOLE			22
#define	PROF_EQUALWHOLE				23
#define	PROF_PARTIAL_EXEC			24
#define	PROF_ADDWHOLE				25
#define	PROF_FULL_EXEC				26
#define PROF_OPT_EXEC_USER			27
#define PROF_OPT_EXEC_BUILT			28
#define PROF_VIRTUAL_DECODE			27
#define PROF_VIRTUAL_EXECUTE		28


/*#define VIS_PROFILE_START(index)	vis_profile_start_times[index] = rdtsc()
#define	VIS_PROFILE_END(index)		vis_profile_running_total[index] += (rdtsc()-vis_profile_start_times[index]); ++vis_profile_counts[index]

#else

#define VIS_PROFILE_START(index)
#define	VIS_PROFILE_END(index)*/

#endif

queue_entry * worker_queue;
queue_section first_section;
queue_section * current_section;
int queue_start;
int queue_len;

BOOL execute_active=FALSE;

char text_buf[256];
int text_buf_size;
VIS_CRITICAL_SECTION(text_buf_lock)

#ifdef WIN32
	WSADATA wsa_data;
	#ifdef GUI_LIB
		char errorbuffer[1024];
	#endif
#endif


worker_instance * main_instance;

//company companylist[40];
//int num_companies=0;

datum * global_store_dict;
VIS_CRITICAL_SECTION(global_store_lock);


int empty_func(datum ** a, queue_entry * worker_entry)
{
	return 0;
}

worker_impl empty_test = empty_func;
/*
 void set_in_child(worker_def * parent, int worker_num, BOOL * in_child, BOOL value, int exclude_worker)
{
	int j,i = parent->workerlist[worker_num].wire_down_lookup;
	if(exclude_worker >= 0 && exclude_worker == worker_num)
		return;
	in_child[worker_num] = value;
	while(parent->wirelist[j=parent->workers_to_wires_down[i]].start_worker == worker_num && j >= 0)
		set_in_child(parent, parent->wirelist[j].end_worker, in_child, value);
}

void build_child_worker(worker_def * parent, int worker_num, int output_num)
{
	int i,j, num_child_workers, num_child_wires, child_def;
	BOOL * in_child = malloc(sizeof(BOOL)* parent->num_workers);
	int * child_offsets = malloc(sizeof(int) * parent->num_workers);
	for(i = 0; i < parent->num_workers; ++i)
	{
		in_child[i] = FALSE;
		child_offsets[i] = -1;
	}
	i = parent->workerlist[worker_num].wire_down_lookup;
	while(parent->wirelist[j=parent->workers_to_wires_down[i]].start_worker == worker_num && j >= 0)
	{
		if(parent->wirelist[j].output_num == output_num)
			set_in_child(parent, parent->wirelist[j].end_worker, in_child, TRUE,-1);
	}
	i = parent->workerlist[worker_num].wire_down_lookup;
	while(parent->wirelist[j=parent->workers_to_wires_down[i]].start_worker == worker_num && j >= 0)
	{
		if(parent->wirelist[j].output_num != output_num)
			set_in_child(parent, parent->wirelist[j].end_worker, in_child, FALSE,-1);
	}
	for(i = 0; i < parent->num_workers; ++i)
	{
		if(i != worker_num && (parent->workerlist[i].type == 4 || (parent->workerlist[i].type == 2 && !in_child[i])))
			set_in_child(parent, i, in_child, FALSE);
	}
	for(i = 0; i < parent->num_workers; ++i)
	{
		if(in_child[i])
			child_offests[i] = num_child_workers++;
	}
	for(i = 0; i < parent->num_wires; ++i)
	{
		if(in_child[parent->wirelist[i].start_worker] || in_child[parent->wirelist[i].end_worker])
			++num_child_wires;
	}
	child_def = num_defs++;//needs lock or atomic incrememnt
	deflist[child_def].workerlist = malloc(sizeof(worker)*num_child_workers);
	deflist[child_def].wirelist = malloc(sizeof(wire)*num_child_wires);
	for(i = 0; i < parent->num_workers; ++i)
	{
		if(in_child[i])
			deflist[child_def].workerlist[child_offests[i]] = parent->workerlist[i];
	}
} */

#define MAX_TRACE_DEPTH	40

void print_stack_trace(worker_instance * stack_instance)
{
	int i = 0;
	ERRORPUTS("Stack trace:\n");
	while(stack_instance && i < MAX_TRACE_DEPTH)
	{
		ERRORPRINTF("%s\n", stack_instance->def->name);
		stack_instance = stack_instance->caller_instance;
		++i;
	}
	if(stack_instance)
	{
		ERRORPUTS("Stack trace aborted after 40 entries\n");
	}
}

void check_tail(worker_def * def)
{
	custom_worker * worker = def->implement_func;
	int i,j,k,endworker;
	BOOL can_tail, outputs_handled[32];
	for(i = 0; i < worker->num_workers; ++i)
	{
		if(worker->workerlist[i].type == WORKER)
		{
			can_tail = TRUE;
			for(j = 0; j < def->num_outputs; ++j)
				outputs_handled[j] = FALSE;
			j = worker->workerlist[i].wire_down_lookup;
			while((k=worker->workers_to_wires_down[j]) >= 0 && worker->wirelist[k].start_worker == i)
			{
				endworker = worker->wirelist[k].end_worker;
				if(worker->workerlist[endworker].type != OUTPUT || worker->workerlist[endworker].io_num != worker->wirelist[k].output_num)
				{
					can_tail = FALSE;
					break;
				}
				else
					outputs_handled[worker->wirelist[k].output_num] = TRUE;
				++j;
			}
			if(can_tail)
			{
				for(j = 0; j < def->num_outputs; ++j)
					if(!outputs_handled[j])
					{
						can_tail = FALSE;
						break;
					}
				if(can_tail)
					if(worker->workerlist[i].value_index == def)
						worker->workerlist[i].type = TAIL_RECURSE;
					else if(!def->num_stores)
						worker->workerlist[i].type = TAIL_CALL;
			}
		}
	}
}

BOOL method_match(char * name, char * method_name)
{
	int i = 0;
	while(name[i] != '\0' && method_name[i] != '@' && method_name[i] != '\0')
	{
		if(name[i] != method_name[i])
			return FALSE;
		++i;
	}
	if(name[i] != '\0' || method_name[i] != '@')
		return FALSE;
	return TRUE;
}

worker_def * find_method(int type, char * name, int num_inputs, program * prog)
{
	int i;
	worker_def * output = NULL;
	company * companylist = prog->companylist;
	VIS_EnterCriticalSection(companylist[type].lock);
	for(i = 0; i < companylist[type].num_methods; ++i)
	{
		//DEBUGPRINTF( "Checking method %s(%d,%d)\n", companylist[type].methodlist[i]->name, companylist[type].methodlist[i]->num_inputs, companylist[type].methodlist[i]->num_outputs);
		if(companylist[type].methodlist[i]->num_inputs == num_inputs && method_match(name, companylist[type].methodlist[i]->name))
		{
			DEBUGPRINTF( "Found method: %s\n", companylist[type].methodlist[i]->name);
			output = companylist[type].methodlist[i];
			break;
		}
	}
	VIS_LeaveCriticalSection(companylist[type].lock);
	return output;
}

worker_def * find_method_noinputcheck(int type, char * name, program * prog)
{
	int i;
	worker_def * output = NULL;
	company * companylist = prog->companylist;
	VIS_EnterCriticalSection(companylist[type].lock);
	for(i = 0; i < companylist[type].num_methods; ++i)
	{
		//DEBUGPRINTF( "Checking method %s(%d,%d)\n", companylist[type].methodlist[i]->name, companylist[type].methodlist[i]->num_inputs, companylist[type].methodlist[i]->num_outputs);
		if(method_match(name, companylist[type].methodlist[i]->name))
		{
			DEBUGPRINTF( "Found method: %s\n", companylist[type].methodlist[i]->name);
			output = companylist[type].methodlist[i];
			break;
		}
	}
	VIS_LeaveCriticalSection(companylist[type].lock);
	return output;
}

worker_def * find_converter_method(int totype, int fromtype, program * prog)
{
	int i;
	company * companylist = prog->companylist;
	DEBUGPRINTF( "Finding converter from %s to %s\n", companylist[fromtype].name, companylist[totype].name);
	//DEBUGPRINTF( "Num methods %d\n", companylist[totype].num_methods);
	for(i = 0; i < companylist[totype].num_methods; ++i)
	{
		//DEBUGPRINTF("methodlist[i]: %X\n", companylist[totype].methodlist[i]);
		DEBUGPRINTF( "Checking method %s\n", companylist[totype].methodlist[i]->name);
		
		if(companylist[totype].methodlist[i]->name[0] == '<' && method_match(companylist[fromtype].name, companylist[totype].methodlist[i]->name+1))
		{
			DEBUGPRINTF( "Found Method %s\n", companylist[totype].methodlist[i]->name);
			
			return companylist[totype].methodlist[i];
		}
	}
	return NULL;
}

worker_instance *  init_custom_worker_type(int aworker, worker_instance * caller, worker_def * def, instance_callback callback, void * callback_data, datum ** params, int type)
{
	int i, workerlist_size, j, add_index_count=0;
	int add_index[32];
	datum * work_params[32];
	datum * temp_params[3];
	global_store * store;
	worker_instance * instance;
	BOOL release_params = TRUE;
	def_make_lookup(def);
	workerlist_size = sizeof(worker_instance_data)*(def->implement_func->num_workers);
	//DEBUGPRINTF("workerlist_size: %d * %d = %d, wirelist_size: %d * %d = %d.\n", sizeof(worker_instance_data), def->implement_func->num_workers, workerlist_size, sizeof(wire_instance_data), def->implement_func->num_wires, sizeof(wire_instance_data)*(def->implement_func->num_wires));
	//DEBUGPRINTF("Before malloc(%d)\n",sizeof(worker_instance) + workerlist_size + sizeof(wire_instance_data)*(def->implement_func->num_wires));
	if(type == TAIL_RECURSE || type == TAIL_CALL)
	{
		VIS_EnterCriticalSection(caller->counter_lock);
			if(caller->in_progress_count <= 1 && !caller->in_queue_count)
			{
		VIS_LeaveCriticalSection(caller->counter_lock);
				instance = caller;
				for(i = 0; i < instance->num_workers; ++i)
				{
					if(instance->def->implement_func->workerlist[i].type != WORKER && instance->def->implement_func->workerlist[i].type != TAIL_RECURSE && instance->def->implement_func->workerlist[i].type != TAIL_CALL && instance->workerlist[i].value)
						release_ref(instance->workerlist[i].value);
					if(instance->workerlist[i].ready_count && instance->workerlist[i].ready_count < (instance->def->implement_func->workerlist[i].num_inputs + (instance->def->implement_func->workerlist[i].null_input ? 1 : 0)))
					{
						DEBUGPRINTF("Freeing params for worker number %d, ready_count: %d, num_inputs: %d, null_input: %d, instance: %X\n", i, instance->workerlist[i].ready_count,instance->def->implement_func->workerlist[i].num_inputs, instance->def->implement_func->workerlist[i].null_input, instance);
						for(j = 0; j <= instance->def->implement_func->workerlist[i].num_inputs; ++j)
						{
							DEBUGPRINTF("Releasing param %d of worker %d\n", j, i);
							release_ref(instance->workerlist[i].params[j]);
						}
					}
				}
				for(i = 0; i < def->num_inputs; ++i)
					work_params[i] = params[i];
				params = work_params;
				if(type == TAIL_RECURSE)
				{
					instance->in_progress_count = 0;
					//TODO: adjust profile counter?
					goto init_workerlist;
				}
				else
				{
					aworker = instance->worker_in_caller;
					callback = instance->callback;
					callback_data = instance->callback_data;
					caller = instance->caller_instance;
					VIS_DeleteCriticalSection(instance->counter_lock);
					free(instance);
				}
			}
			else
			{
		VIS_LeaveCriticalSection(caller->counter_lock);
			}
	}
				
			
	instance = MALLOC(sizeof(worker_instance) + workerlist_size/* + sizeof(wire_instance_data)*(def->implement_func->num_wires) */,"instance");

	//DEBUGPRINTF("malloc returned %X.\n", instance);
	VIS_PROFILE_START(PROF_INIT_CUSTOM);
	//DEBUGPRINTF("init_custom_worker, instance: %X\n", instance);
#ifdef USER_PROFILE
	QueryPerformanceCounter(&(instance->start));
#endif
	instance->def = def;
	instance->num_workers = def->implement_func->num_workers;
	instance->workerlist = (worker_instance_data *)(((char *)instance) + sizeof(worker_instance));//malloc(sizeof(worker_instance_data)*(def->implement_func->num_workers));
	//DEBUGPRINTF("workerlist at %X\n", instance->workerlist);
	
	/*instance->num_wires = def->implement_func->num_wires;
	instance->wirelist = (wire_instance_data *)(((char *)(instance->workerlist)) + workerlist_size);//malloc(sizeof(wire_instance_data)*(def->implement_func->num_wires));
	DEBUGPRINTF("wirelist at %X\n", instance->wirelist);*/
	
	
	instance->callback = callback;
	instance->worker_in_caller = aworker;
	instance->callback_data = callback_data;
	instance->caller_instance = caller;
	VIS_InitializeCriticalSection(instance->counter_lock);
	instance->in_progress_count = 0;
	instance->in_queue_count = 0;
	
	if(def->num_stores)
	{
		instance->trans = MALLOC(sizeof(transaction) + sizeof(global_store_use) *(def->num_stores - 1),"transaction");
		VIS_EnterCriticalSection(global_store_lock);
			for(i = 0; i < def->num_stores; ++i)
			{
				temp_params[0] = add_ref(global_store_dict);
				temp_params[1] = make_string(def->uses_stores[i], -1, def->program);
				vis_dict_index(temp_params, NULL);
				if(!temp_params[0])
				{
					printf("Error: Global store %s is not initialized\n", def->uses_stores[i]);
					DEBUGPRINTF("Error: Global store %s is not initialized\n", def->uses_stores[i]);
					VIS_LeaveCriticalSection(global_store_lock);
					return NULL;
				}
				instance->trans->stores[i].store = temp_params[0]->c.generic.data;
				instance->trans->stores[i].instance_data = instance->trans->stores[i].begin_data = add_ref(instance->trans->stores[i].store->data);
				VIS_InitializeCriticalSection(instance->trans->stores[i].lock);
				//Is this really necessary?
				release_ref(temp_params[0]);
			}
		VIS_LeaveCriticalSection(global_store_lock);
		instance->trans->num_stores = def->num_stores;
		if((def->transaction_flags & TRANSACTION_WRITE) && (def->transaction_flags & TRANSACTION_TYPE_MASK) == TRANSACTION_RETRY)
		{
			release_params = FALSE;
			for(i = 0; i < def->num_inputs; ++i)
				instance->trans->params[i] = params[i];
		}
	} else {
		instance->trans = NULL;
	}
	

init_workerlist:	
	//DEBUGPUTS("init worker values\n");
	for(i = 0; i < instance->num_workers; ++i)
	{
//		DEBUGPRINTF("InitializeCriticalSection on workerlist[%d].worker_lock (%X)\n", i, &(instance->workerlist[i].worker_lock));
		VIS_InitializeCriticalSection(instance->workerlist[i].worker_lock);
		//DEBUGPUTS("ready_count = 0\n");
		instance->workerlist[i].ready_count = 0;
		if(def->implement_func->workerlist[i].type == INPUT && params)
			instance->workerlist[i].value = add_ref(params[def->implement_func->workerlist[i].io_num]);
		else //if(def->implement_func->workerlist[i].type != 2)
			instance->workerlist[i].value = NULL;
		//DEBUGPRINTF("instance->workerlist[%d].value = %X\n", i, instance->workerlist[i].value);
		for(j = 0; j <= def->implement_func->workerlist[i].num_inputs; ++j)
			instance->workerlist[i].params[j] = NULL;
		//DEBUGPRINTF("num_inputs: %d, null_input: %d\n", def->implement_func->workerlist[i].num_inputs, def->implement_func->workerlist[i].null_input);

		//There's still a potential race condition here, but it's unlikely to occur except on a system with an insane number of cores/processors
		//and only on custom workers that have more than 32 items that will be initially ready
		if(!def->implement_func->workerlist[i].num_inputs && !def->implement_func->workerlist[i].null_input)
		{
			DEBUGPRINTF("adding worker %s(%d) to queue\n", def->implement_func->workerlist[i].name, i);
			add_index[add_index_count++] = i;
			if(add_index_count == 32)
			{
				add_multiple(add_index, add_index_count, instance);
				add_index_count = 0;
			}
			//add_queue(i,instance);
		}
	}

	if(params)
	{
		if(release_params)
		{
			//DEBUGPUTS("release params\n");
			for(i = 0; i < def->num_inputs; ++i)
				release_ref(params[i]);
		}
	}
	if(add_index_count > 0)
		add_multiple(add_index, add_index_count, instance);
	VIS_PROFILE_END(PROF_INIT_CUSTOM);

	return instance;
}

worker_instance *  init_custom_worker(int aworker, worker_instance * caller, worker_def * def, instance_callback callback, void * callback_data, datum ** params)
{
	return init_custom_worker_type(aworker, caller, def, callback, callback_data, params, WORKER);
}

void cleanup_check(queue_entry aworker)
{
	char msg[256];
	VIS_EnterCriticalSection(aworker.instance->counter_lock);
		--(aworker.instance->in_progress_count);
		DEBUGPRINTF( "Cleanup Check on %s<%d>:%X, in_progress: %d, in_queue: %d\n", aworker.instance->def->name, aworker.instance->worker_in_caller, aworker.instance, aworker.instance->in_progress_count,aworker.instance->in_queue_count);
		
		if(aworker.instance->in_progress_count == 0 && aworker.instance->in_queue_count == 0)
		{
	VIS_LeaveCriticalSection(aworker.instance->counter_lock);
			cleanup_custom_worker(aworker.instance, aworker.worker_num);
		}
		else
		{
	VIS_LeaveCriticalSection(aworker.instance->counter_lock);
		}
}

void cleanup_custom_worker(worker_instance * instance, int worker_num)
{
	BOOL do_commit = TRUE;
	int i,j;
	queue_entry incaller;
	global_store * store;
	#ifdef USER_PROFILE
		LARGE_INTEGER end;
		LARGE_INTEGER duration;
	#endif
	if(instance->trans)
	{
		if(instance->def->transaction_flags & TRANSACTION_WRITE)
		{
			VIS_EnterCriticalSection(global_store_lock);
				if((instance->def->transaction_flags & TRANSACTION_TYPE_MASK) != TRANSACTION_FORCE)
				{
					for(i = 0; i < instance->trans->num_stores; ++i)
					{
						if(instance->trans->stores[i].begin_data != instance->trans->stores[i].store->data)
						{
							do_commit = FALSE;
							break;
						}
					}
				}
				if(do_commit)
				{
					for(i = 0; i < instance->trans->num_stores; ++i)
					{
						release_ref(instance->trans->stores[i].store->data);
						instance->trans->stores[i].store->data = instance->trans->stores[i].instance_data;
					}
				}
			VIS_LeaveCriticalSection(global_store_lock);
			if(!do_commit)//retry transaction
			{
				for(i = 0; i < instance->trans->num_stores; ++i)
					release_ref(instance->trans->stores[i].instance_data);
				puts("retrying transaction");
				init_custom_worker(instance->worker_in_caller, instance->caller_instance, instance->def, instance->callback, instance->callback_data, instance->trans->params);
			}
			else if((instance->def->transaction_flags & TRANSACTION_TYPE_MASK) == TRANSACTION_RETRY)
				for(i = 0; i < instance->def->num_inputs; ++i)
					release_ref(instance->trans->params[i]);
		}
		else
		{
			for(i = 0; i < instance->trans->num_stores; ++i)
				release_ref(instance->trans->stores[i].instance_data);
		}
		VIS_FREE(instance->trans, "transaction");
	}
	VIS_PROFILE_START(PROF_CLEANUP_CUSTOM);
	DEBUGPRINTF("Cleaning up custom worker: %s:%X\n", instance->def->name, instance);
	
	VIS_PROFILE_START(PROF_SUB_CALLBACK);
	if(instance->callback && do_commit)
		instance->callback(instance->caller_instance, instance->worker_in_caller, instance, instance->callback_data);
	//DEBUGPUTS("About to release refs\n");
	VIS_PROFILE_END(PROF_SUB_CALLBACK);
	VIS_PROFILE_START(PROF_CLEANUP_RELEASE_REFS);
	/*for(i = 0; i < instance->def->implement_func->num_wires; ++i)
	{
		if(instance->wirelist[i].data)
		{
			DEBUGPRINTF("release_ref on wire %d\n", i);
			
			release_ref(instance->wirelist[i].data);
		}
	}*/
	for(i = 0; i < instance->num_workers; ++i)
	{
		if(instance->def->implement_func->workerlist[i].type != WORKER && instance->def->implement_func->workerlist[i].type != TAIL_RECURSE && instance->def->implement_func->workerlist[i].type != TAIL_CALL && instance->workerlist[i].value)
		{
			DEBUGPRINTF( "release_ref on worker %d in instance %X\n", i, instance);
			release_ref(instance->workerlist[i].value);
		}
		if(instance->workerlist[i].ready_count && instance->workerlist[i].ready_count < (instance->def->implement_func->workerlist[i].num_inputs + (instance->def->implement_func->workerlist[i].null_input ? 1 : 0)))
		{
			DEBUGPRINTF("Freeing params for worker number %d, ready_count: %d, num_inputs: %d, null_input: %d, instance: %X\n", i, instance->workerlist[i].ready_count,instance->def->implement_func->workerlist[i].num_inputs, instance->def->implement_func->workerlist[i].null_input, instance);
			for(j = 0; j <= instance->def->implement_func->workerlist[i].num_inputs; ++j)
			{
				DEBUGPRINTF("Releasing param %d of worker %d\n", j, i);
				release_ref(instance->workerlist[i].params[j]);
			}
		}
		VIS_DeleteCriticalSection(instance->workerlist[i].worker_lock);
	}
	VIS_PROFILE_END(PROF_CLEANUP_RELEASE_REFS);
	VIS_DeleteCriticalSection(instance->counter_lock);
	//DEBUGPUTS("freeing lists\n");
	#ifdef USER_PROFILE
		if(do_commit)
		{
			QueryPerformanceCounter(&end);
			duration.QuadPart = end.QuadPart - instance->start.QuadPart;
			VIS_EnterCriticalSection(instance->def->lock);
				instance->def->total.QuadPart += duration.QuadPart;
				++instance->def->count;
				if(duration.QuadPart > instance->def->worst.QuadPart)
					instance->def->worst.QuadPart = duration.QuadPart;
			VIS_LeaveCriticalSection(instance->def->lock);
		}
	#endif
	/*VIS_PROFILE_START(PROF_CLEANUP_FREELISTS);
	free(instance->workerlist);
	free(instance->wirelist);
	VIS_PROFILE_END(PROF_CLEANUP_FREELISTS);*/
	VIS_PROFILE_START(PROF_CLEANUP_CHECK);
	if(instance->caller_instance && do_commit)
	{
		incaller.worker_num = instance->worker_in_caller;
		incaller.instance = instance->caller_instance;
		DEBUGPUTS("Calling cleanup_check on parent\n");
		cleanup_check(incaller);
	}
	if(do_commit && instance->callback == main_callback)
		release_program_ref(instance->def->program);
	VIS_PROFILE_END(PROF_CLEANUP_CHECK);
	VIS_PROFILE_START(PROF_CLEANUP_FREELISTS);
	VIS_FREE(instance, "worker instance");
	VIS_PROFILE_END(PROF_CLEANUP_FREELISTS);
	VIS_PROFILE_END(PROF_CLEANUP_CUSTOM);
}
/*
void worker_complete(queue_entry aworker)
{
	int i,j;
	wire * wirelist;
	int * workers_to_wires_down;
	VIS_PROFILE_START(PROF_WORKER_COMPLETE);
	DEBUGPUTS("worker_complete()\n");
	
	
	i = aworker.instance->def->implement_func->workerlist[aworker.worker_num].wire_down_lookup;
	wirelist = aworker.instance->def->implement_func->wirelist;
	workers_to_wires_down = aworker.instance->def->implement_func->workers_to_wires_down;
	while(wirelist[j=workers_to_wires_down[i]].start_worker == aworker.worker_num && j >= 0)
	{
		if(aworker.instance->wirelist[j].data)
		{
			DEBUGPRINTF("end_worker: %d, wirelist[%d].data = %X\n", wirelist[j].end_worker, j, aworker.instance->wirelist[j].data);
				add_if_ready(wirelist[j].end_worker, aworker.instance);
		}
		++i;
	}
	DEBUGPUTS("worker_complete done\n");
	VIS_PROFILE_END(PROF_WORKER_COMPLETE);
}*/

void process_outputs(datum ** params, int aworker, worker_instance * instance)
{
	BOOL flag=FALSE;
	int i,j;
	worker_def * def = instance->def;
	//custom_worker *implement_func = def->implement_func;
	wire * def_wires = def->implement_func->wirelist;
	worker * def_workers = def->implement_func->workerlist;
	VIS_PROFILE_START(PROF_PROCESS_OUTPUTS);
	DEBUGPRINTF("Process outputs for worker %d in instance %X\n", aworker, instance);
	DEBUGPRINTF("Num_inputs: %d, num_outputs: %d\n", def_workers[aworker].num_inputs, def_workers[aworker].num_outputs);
	if(def_workers[aworker].num_outputs && instance->workerlist)
	{
		//DEBUGPRINTF("num_outputs: %d\n", def_workers[aworker].num_outputs);
		i = def_workers[aworker].wire_down_lookup;
		while((j=def->implement_func->workers_to_wires_down[i]) >= 0 && def_wires[j].start_worker == aworker)
		{
			//DEBUGPRINTF("Checking output: %d\n", def_wires[j].output_num);
			DEBUGPRINTF("output[%d] = %X\n", def_wires[j].output_num, params[def_wires[j].output_num]);
			DEBUGPRINTF("wire leads to worker %d, instance->workerlist: %X\n", def_wires[j].end_worker, instance->workerlist);
			VIS_EnterCriticalSection(instance->workerlist[def_wires[j].end_worker].worker_lock);
				if(params[def_wires[j].output_num] && !instance->workerlist[def_wires[j].end_worker].params[def_wires[j].input_num+1])
				{
					//DEBUGPRINTF( "add_ref on output %d\n", def_wires[j].output_num);
					instance->workerlist[def_wires[j].end_worker].params[def_wires[j].input_num+1]=add_ref(params[def_wires[j].output_num]);
					//DEBUGPRINTF("Ready count was: %d, ", instance->workerlist[def_wires[j].end_worker].ready_count);
					++instance->workerlist[def_wires[j].end_worker].ready_count;
					DEBUGPRINTF("Ready count is now: %d\n", instance->workerlist[def_wires[j].end_worker].ready_count);
					DEBUGPRINTF("num inputs: %d, null input: %d\n", instance->def->implement_func->workerlist[def_wires[j].end_worker].num_inputs, instance->def->implement_func->workerlist[def_wires[j].end_worker].null_input);
					if(instance->workerlist[def_wires[j].end_worker].ready_count >= (instance->def->implement_func->workerlist[def_wires[j].end_worker].num_inputs + (instance->def->implement_func->workerlist[def_wires[j].end_worker].null_input ? 1 : 0)))
					{
						//DEBUGPUTS("flag = true\n");
						flag = TRUE;
						instance->workerlist[def_wires[j].end_worker].ready_count=0;
					}
				}
			VIS_LeaveCriticalSection(instance->workerlist[def_wires[j].end_worker].worker_lock);
			if(flag)
			{
				DEBUGPUTS("add_queue\n");
				add_queue(def_wires[j].end_worker, instance);
				//add_if_ready(def_wires[j].end_worker, instance);
				flag = FALSE;
			}
			++i;
		}
		//DEBUGPUTS("releasing refs\n");
		
		for(i = 0; i < def_workers[aworker].num_outputs; ++i)
			release_ref(params[i]);
	}
	VIS_PROFILE_END(PROF_PROCESS_OUTPUTS);
}

void main_callback(worker_instance * junkinst, int junk, worker_instance * main_instance, void * data)
{
	//MessageBox(NULL, "Main Callback", "Visuality Debug", MB_OK);
	VIS_EnterCriticalSection(program_count_lock);
		--program_count;
		if(program_count <= 0)
		{
			execute_active = FALSE;
			VIS_SetEvent(queue_add_event);
		}
	VIS_LeaveCriticalSection(program_count_lock);
	if(data)
		release_ref((datum *)data);
}

void sub_callback(worker_instance * caller_instance, int caller_workernum, worker_instance * done_instance, void * data)
{
	int i;
	queue_entry incaller;
	datum * params[32];
	worker_def * def = done_instance->def;
	custom_worker * implement_func = def->implement_func;

	incaller.worker_num = caller_workernum;
	incaller.instance = caller_instance;
	for(i = 0; i < def->num_outputs; ++i)
		params[i] = NULL;
	for(i = 0; i < implement_func->num_workers; ++i)
	{
		if(implement_func->workerlist[i].type == 4)
		{
			if(!params[implement_func->workerlist[i].io_num])
			{
				params[implement_func->workerlist[i].io_num] = done_instance->workerlist[i].value;
				DEBUGPRINTF("Output[%d] = %X\n", implement_func->workerlist[i].io_num, done_instance->workerlist[i].value);
				done_instance->workerlist[i].value = NULL;
			}
		}
	}
	process_outputs(params, caller_workernum, caller_instance);
	//worker_complete(incaller);
}

void pack_list_sub_callback(worker_instance * caller_instance, int caller_workernum, worker_instance * done_instance, void * data)
{
	int i;
	queue_entry incaller;
	datum * params[32];
	datum * workparams[2];
	
	incaller.worker_num = caller_workernum;
	incaller.instance = caller_instance;
	for(i = 0; i < done_instance->def->num_outputs; ++i)
		params[i] = NULL;
	for(i = 0; i < done_instance->def->implement_func->num_workers; ++i)
	{
		if(done_instance->def->implement_func->workerlist[i].type == 4)
		{
			if(!params[done_instance->def->implement_func->workerlist[i].io_num])
			{
				params[done_instance->def->implement_func->workerlist[i].io_num] = done_instance->workerlist[i].value;
				done_instance->workerlist[i].value = NULL;
			}
		}
	}
	workparams[0] = create_list(done_instance->def->program);
	for(i = 0; i < done_instance->def->num_outputs; ++i)
	{
		workparams[1] = params[i];
		vis_list_append(workparams, NULL);
	}
	process_outputs(workparams, caller_workernum, caller_instance);
	//worker_complete(incaller);
}

void transaction_sub_callback(worker_instance * caller_instance, int caller_workernum, worker_instance * done_instance, void * data)
{
	int i;
	
	pack_list_sub_callback(caller_instance, caller_workernum, done_instance, NULL);
}

int global_argc;
char ** global_argv;
int spin_counter;

void prep_program(program * prog)
{
	defchunk * current;
	int i,j;
	make_lookup_arrays(prog);
	current = prog->defs;
	while(current)
	{
		for(i = 0; i < current->num_defs; ++i)
		{
			#ifdef USER_PROFILE
				current->deflist[i].count = 0;
				current->deflist[i].total.QuadPart = 0;
				current->deflist[i].worst.QuadPart = 0;
				VIS_InitializeCriticalSection(current->deflist[i].lock);
			#endif // USER_PROFILE
			//DEBUGPRINTF("Checking worker %s with type %X\n", current->deflist[i].name, current->deflist[i].type);
			if(current->deflist[i].type & USER_FLAG && (current->deflist[i].type & TYPE_MASK) == WORKER_TYPE)
			{
				//DEBUGPRINTF("Checking for constants in worker %s\n", current->deflist[i].name);
				for(j = 0; j < current->deflist[i].implement_func->num_workers; ++j)
					if(current->deflist[i].implement_func->workerlist[j].type == CONSTANT)
					{
						//current->deflist[i].implement_func->workerlist[j].value_index = (int)(get_constant(current->deflist[i].implement_func->workerlist[j].name,-1, initial_prog));
						//DEBUGPRINTF("Set value_index for constant to %X in worker %s at index %d\n", current->deflist[i].implement_func->workerlist[j].value_index, current->deflist[i].name, j); 
					}
					else if(current->deflist[i].implement_func->workerlist[j].type == WORKER || current->deflist[i].implement_func->workerlist[j].type == TAIL_CALL || current->deflist[i].implement_func->workerlist[j].type == TAIL_RECURSE)
					{
						current->deflist[i].implement_func->workerlist[j].num_inputs = ((worker_def *)current->deflist[i].implement_func->workerlist[j].value_index)->num_inputs;
						current->deflist[i].implement_func->workerlist[j].num_outputs = ((worker_def *)current->deflist[i].implement_func->workerlist[j].value_index)->num_outputs;
					}
					else
						current->deflist[i].implement_func->workerlist[j].value_index = 0;
				//DEBUGPRINTF("optimize %d\n", i);
			#ifdef ENABLE_OPT
				optimize(current->deflist + i);
			#endif
			}
		}
		current = current->next;
	}
}

void interp_start(int num_threads, BOOL use_this_thread, int argc, char ** argv, program * initial_prog)
{
	defchunk * current;
	datum * params[2];
	int i, junk,create_threads,j;
	#ifdef USER_PROFILE
		LARGE_INTEGER frequency;
	#endif
	lock_fail_counter = 0;
	lock_counter = 0;
	spin_counter = 0;
	
	#ifdef WIN32
		//_CrtSetDbgFlag(_CRTDBG_CHECK_ALWAYS_DF | _CRTDBG_CHECK_CRT_DF | _CRTDBG_ALLOC_MEM_DF);
		WSAStartup(MAKEWORD(1, 1), &wsa_data);
	#endif
	VIS_InitializeCriticalSection(randlock);

	DEBUGPUTS("interp_start\n");
#ifdef ENABLE_PROFILING
	for(i = 0; i < NUM_PROFS; ++i)
	{
		vis_profile_running_total[i] = 0;
		vis_profile_counts[i] = 0;
	}
	VIS_PROFILE_START(PROF_EMPTYFUNC);
	empty_test(NULL,NULL);
	VIS_PROFILE_END(PROF_EMPTYFUNC);
	VIS_PROFILE_START(PROF_NOCODE);
	VIS_PROFILE_END(PROF_NOCODE);
#endif
	global_argc  = argc;
	global_argv = argv;
	init_sync_primitives();
	init_datum_storage();
	init_global_storage(initial_prog);
	//init queue
	current_section = &first_section;
	DEBUGPRINTF("current_section = %X, &current_section = %X\n", current_section, &current_section);
	worker_queue = current_section->entries;
	current_section->last = NULL;
	current_section->next = NULL;
	queue_start = queue_len = 0;
//	deflist[0].num_workers = num_workers;
//	deflist[0].num_wires = num_wires;
	prep_program(initial_prog);
	//MessageBox(NULL, "Before fopen", "visdbg", MB_OK);
	init_genrand(time(NULL));
	
	execute_active = TRUE;
	DEBUGPUTS("Before init_custom_worker on Main\n");
	params[0] = create_list(initial_prog);
	for(i = 0; i < argc; ++i)
	{
		params[1] = make_string(argv[i], -1, initial_prog);
		vis_list_append(params, NULL);
	}
	main_instance = init_custom_worker(-1, NULL, initial_prog->defs->deflist, main_callback, NULL, params);
	
	//num_datum = 0;
	#if	COMPILE_THREADS > 0
	create_threads = COMPILE_THREADS;
	if(num_threads > 0)
		create_threads = num_threads;
	if(use_this_thread)
		--create_threads;

	for(i = 0; i < create_threads; ++i)
	{
		#ifdef WIN32
			CreateThread(NULL, 0, worker_thread, NULL, 0, &junk);
		#else
		#ifdef SYLLABLE
			resume_thread(spawn_thread("vis_worker", worker_thread, 1, 0, NULL));
		#else
			pthread_t pid;
			pthread_create(&pid, NULL, worker_thread, NULL);
		#endif
		#endif
	}
	if(use_this_thread)
		worker_thread(NULL);
	#else
		worker_thread(NULL);
	#endif
#ifdef ENABLE_PROFILING
	for(i = 0; i < NUM_PROFS; ++i)
		printf("%d:\t%f,\tcount: %d,\taverage: %f\n", i, (double)vis_profile_running_total[i], vis_profile_counts[i], ((double)vis_profile_running_total[i])/((double)vis_profile_counts[i]));
#endif

#ifdef USER_PROFILE
	printf("%-33s%12s%7s%15s%12s\n\n", "Worker", "Total", "Count", "Average", "Worst");
	current = initial_prog->defs;
	while(current)
	{
		for(i = 0; i < current->num_defs; ++i)
		{
			if(current->deflist[i].count > 0)
			{
				printf("%-33s%12.0f%7d%15.2f%12.0f\n", current->deflist[i].name, (double)current->deflist[i].total.QuadPart, current->deflist[i].count, (double)current->deflist[i].total.QuadPart / (double)current->deflist[i].count, (double)current->deflist[i].worst.QuadPart);
			}
		}
		current = current->next;
	}
	QueryPerformanceFrequency(&frequency);
	printf("%.0f ticks per second\n", (double)frequency.QuadPart);
#endif
	interp_stop();
}

void interp_stop()
{
	int i;
	execute_active = FALSE;
	close_sync_primitives();
//	Doesn't make sense in the context of multiple programs
//	cleanup_custom_worker(main_instance);
#ifdef WIN32
	WSACleanup();
#endif
#ifdef TEXT_FILE_DEBUG
	fclose(debugfile);
#endif
}
	
extern 
void init_sync_primitives()
{
	int i;
	DEBUGPUTS("Initializing data_lock\n");
	VIS_InitializeCriticalSection(data_lock);
	DEBUGPUTS("Initializing worker_queue_lock\n");
	VIS_InitializeCriticalSection(worker_queue_lock);
	DEBUGPUTS("Initializing text_buf_lock\n");
	VIS_InitializeCriticalSection(text_buf_lock);
#ifdef GUI_LIB
#ifdef SYLLABLE
	DEBUGPUTS("vis_window_init\n");
	vis_window_init();
#endif
#endif //GUI_LIB
	VIS_CreateEvent(queue_add_event);//No security parameter, auto reset, starts signaled, no name
	
}

void close_sync_primitives()
{
	int i;
	VIS_DeleteCriticalSection(data_lock);
	VIS_DeleteCriticalSection(worker_queue_lock);
	VIS_DestroyEvent(queue_add_event);

}

void init_global_storage(program * prog)
{
	VIS_InitializeCriticalSection(global_store_lock);
	global_store_dict = create_dict(prog);
}

void add_multiple(int * data, int num, worker_instance * instance)
{
	int i, index;
	queue_section * temp;
	DEBUGPRINTF( "Adding %d workers\n", num);
	
	VIS_EnterCriticalSection(instance->counter_lock);
		instance->in_queue_count += num;
	VIS_LeaveCriticalSection(instance->counter_lock);
	VIS_EnterCriticalSection(worker_queue_lock);
		for(i = 0; i < num; ++i)
		{
			if(queue_len >= QUEUE_SIZE)
			{
				if(current_section->next)
				{
					//DEBUGPUTS("Moving to next queue_section\n");
					current_section = current_section->next;
				}
				else
				{
					//DEBUGPUTS("Allocating new queue_section\n");
					VIS_PROFILE_START(PROF_ADDQUEUE_MALLOC);
					temp = MALLOC(sizeof(queue_section),"queue section");
					VIS_PROFILE_END(PROF_ADDQUEUE_MALLOC);
					temp->last = current_section;
					temp->next = NULL;
					current_section->next = temp;
					current_section = temp;
				}
				worker_queue = current_section->entries;
				queue_start = queue_len = 0;
			}
			if(queue_start+queue_len < QUEUE_SIZE)
				index = queue_start+queue_len;
			else
				index = queue_start+queue_len-QUEUE_SIZE;
			worker_queue[index].worker_num=data[i];
			worker_queue[index].instance = instance;
			++queue_len;
		}
	VIS_LeaveCriticalSection(worker_queue_lock);
	//DEBUGPUTS("SetEvent\n");
	VIS_SetEvent(queue_add_event);
}

void requeue(int data, worker_instance * instance)
{
	add_queue(data, instance);
	VIS_EnterCriticalSection(instance->counter_lock);
		--(instance->in_progress_count);
	VIS_LeaveCriticalSection(instance->counter_lock);
}

void add_queue(int data, worker_instance * instance)
{
	int index;
	queue_section * temp;
	VIS_PROFILE_START(PROF_ADDQUEUE);
	VIS_EnterCriticalSection(instance->counter_lock);
		++(instance->in_queue_count);
	VIS_LeaveCriticalSection(instance->counter_lock);
	VIS_EnterCriticalSection(worker_queue_lock);
		if(queue_len >= QUEUE_SIZE)
		{
			if(current_section->next)
			{
				//DEBUGPUTS("Moving to next queue_section\n");
				current_section = current_section->next;
			}
			else
			{
				//DEBUGPUTS("Allocating new queue_section\n");
				VIS_PROFILE_START(PROF_ADDQUEUE_MALLOC);
				temp = MALLOC(sizeof(queue_section),"queue section");
				VIS_PROFILE_END(PROF_ADDQUEUE_MALLOC);
				temp->last = current_section;
				temp->next = NULL;
				current_section->next = temp;
				current_section = temp;
			}
			worker_queue = current_section->entries;
			queue_start = queue_len = 0;
		}
		else if(queue_len == 0)
		{
			VIS_SetEvent(queue_add_event);
			//DEBUGPUTS("SetEvent\n");
		}
			
		if(queue_start+queue_len < QUEUE_SIZE)
			index = queue_start+queue_len;
		else
			index = queue_start+queue_len-QUEUE_SIZE;
		worker_queue[index].worker_num=data;
		worker_queue[index].instance = instance;
		++queue_len;
		
	VIS_LeaveCriticalSection(worker_queue_lock);
	VIS_PROFILE_END(PROF_ADDQUEUE);
}

/**
* Retrieves a ready worker from the queue
*/
queue_entry get_queue()
{
	queue_entry data;
	queue_section * temp;
	//DEBUGPUTS("Begin get_queue()\n");
	
	VIS_EnterCriticalSection(worker_queue_lock);
		while(!queue_len && execute_active)
		{
			//DEBUGPUTS("Queue empty, resetting event\n");
			VIS_ResetEvent(queue_add_event);
			VIS_LeaveCriticalSection(worker_queue_lock);
			//DEBUGPUTS("Waiting for queue_add_event\n");
			VIS_WaitEvent(queue_add_event);
#ifdef NINTENDO_DS
			//TODO make the processor sleep while waiting for IRQs
			if(irq_queue_count > 0)
				run_queued_irqs();
#endif
			VIS_EnterCriticalSection(worker_queue_lock);
		}
		if(queue_len > 0)
		{
			data = worker_queue[queue_start];
			//DEBUGPRINTF( "Next worker in queue: %d\n", data.worker_num);
			//DEBUGPRINTF("data.instance: %X, data.instance->workerlist: %X\n", data.instance, data.instance->workerlist);
			/*VIS_EnterCriticalSection(data.instance->workerlist[data.worker_num].worker_lock);
				DEBUGPUTS("Adjusting ready_count");
				data.instance->workerlist[data.worker_num].ready_count=0;
			VIS_LeaveCriticalSection(data.instance->workerlist[data.worker_num].worker_lock);*/
			++queue_start;
			--queue_len;
			//DEBUGPUTS("Adjusted ready count.\n");
			//DEBUGPRINTF("current_section: %X\n", current_section);
			if(queue_len == 0 && current_section->last)
			{
				if(current_section->next != NULL)
				{
					//DEBUGPUTS("Freeing current_section->next.\n");
					VIS_FREE(current_section->next, "ready queue node");
					current_section->next = NULL;
				}
				current_section = current_section->last;
				worker_queue = current_section->entries;
				queue_start = 0;
				queue_len = QUEUE_SIZE;
			}
			else if(queue_start == QUEUE_SIZE)
				queue_start = 0;
		}
		else
		{
			//DEBUGPUTS("Queue empty\n");
			data.worker_num = -2;
		}
	VIS_LeaveCriticalSection(worker_queue_lock);
	//DEBUGPUTS("Left worker_queue_lock\n");
	//MessageBox(NULL,"AfterLeave","visdbg",MB_OK);
	if(data.worker_num >= 0)
	{
		VIS_EnterCriticalSection(data.instance->counter_lock);
			//DEBUGPUTS("Adjusting in_queue/in_progress counts.\n");
			--(data.instance->in_queue_count);
			++(data.instance->in_progress_count);
			DEBUGPRINTF( "Counts for %s<%d> Instance:%X after get_queue: in_queue: %d in_progress: %d\n",data.instance->def->name, data.instance->worker_in_caller, data.instance, data.instance->in_queue_count, data.instance->in_progress_count);
			
		VIS_LeaveCriticalSection(data.instance->counter_lock);
	}
	//DEBUGPUTS("End get_queue()\n");
	
	return data;
}

void def_make_lookup(worker_def * def)
{
	int i, j, upoffset, offset;
	VIS_EnterCriticalSection(def->implement_func->lock);
		if(def->implement_func->dirty)
		{
			upoffset = offset = 0;
			for(i = 0; i < def->implement_func->num_workers; ++i)
			{
				def->implement_func->workerlist[i].wire_down_lookup=offset;
				def->implement_func->workerlist[i].wire_up_lookup=upoffset;
				for(j = 0; j < def->implement_func->num_wires; ++j)
				{
					if(def->implement_func->wirelist[j].start_worker == i)
						def->implement_func->workers_to_wires_down[offset++]=j;
					if(def->implement_func->wirelist[j].end_worker == i)
						def->implement_func->workers_to_wires_up[upoffset++]=j;
				}
				//Clear tail call info
				if(def->implement_func->workerlist[i].type == TAIL_CALL || def->implement_func->workerlist[i].type == TAIL_RECURSE)
					def->implement_func->workerlist[i].type = WORKER;
			}
			def->implement_func->workers_to_wires_down[offset]=-1;
			def->implement_func->workers_to_wires_up[upoffset]=-1;
			check_tail(def);
			def->implement_func->dirty = FALSE;
		}
	VIS_LeaveCriticalSection(def->implement_func->lock);
}

/**
* Generates lookup array to ease navigation between workers
*/
void make_lookup_arrays(program * prog)
{
	int i,j,k, offset, upoffset;
	worker_def * deflist;
	defchunk * current = prog->defs;
	while(current)
	{
		deflist = current->deflist;
		for(k = 0; k < current->num_defs; ++k)
		{
			if(deflist[k].type & USER_FLAG && (deflist[k].type & TYPE_MASK) == WORKER_TYPE)
				def_make_lookup(deflist + k);
		}
		current = current->next;
	}
}
extern char _end_bss[];
void initpredefworkers(program * prog)
{
	int current_def = 1;
	int current_company = 0;
	int current_method;
	int comp_room;
	company * this_comp;
	worker_def * aworker;
	create_company(prog, "Any Type", 0, 0, FALSE);
	create_company(prog, "Yes No", 0, 0, FALSE);
	
	aworker = create_worker(prog, "Print", 1, 1, WORKER_TYPE);
	aworker->implement_func = (custom_worker *)vis_print;
	aworker->input_types[0] = BUILTIN_TYPE_STRING;
	
	aworker = create_worker(prog, "Random", 0, 1, WORKER_TYPE);
	aworker->implement_func = (custom_worker *)vis_random;
	
	aworker = create_worker(prog, "Build", 1, 1, WORKER_TYPE);
	aworker->implement_func = (custom_worker *)vis_build;
	aworker->input_types[0] = BUILTIN_TYPE_STRING;

	aworker = create_worker(prog, "End", 1, 0, WORKER_TYPE);
	aworker->implement_func = (custom_worker *)vis_end;
	aworker->input_types[0] = ANY_TYPE;
	
	create_worker(prog, "Append", 2, 1, MAGIC_TYPE);
	create_worker(prog, "+", 2, 1, MAGIC_TYPE);
	create_worker(prog, "-", 2, 1, MAGIC_TYPE);
	create_worker(prog, "*", 2, 1, MAGIC_TYPE);
	create_worker(prog, "/", 2, 1, MAGIC_TYPE);
	create_worker(prog, ">", 2, 1, MAGIC_TYPE);
	create_worker(prog, "<", 2, 1, MAGIC_TYPE);
	create_worker(prog, "=", 2, 1, MAGIC_TYPE);

	aworker = create_worker(prog, "Get Input", 0, 1, WORKER_TYPE);
	aworker->implement_func = (custom_worker *)vis_getinput;
	
	aworker = create_worker(prog, "If",1, 2, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_if;
	aworker->input_types[0] = BUILTIN_TYPE_YESNO;
	
	aworker = create_worker(prog, "Type Of",1, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_type_of;
	aworker->input_types[0] = ANY_TYPE;
	
	aworker = create_worker(prog, "Init Store",1, 0, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)init_global_store;
	aworker->input_types[0] = BUILTIN_TYPE_STRING;
	
	aworker = create_worker(prog, "Wait Forever", 0, 0, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_wait_forever;

#ifdef NINTENDO_DS
	aworker = create_worker(prog, "Register Handler", 2, 1, WORKER_TYPE);
	aworker->implement_func = (custom_worker *)vis_register_handler;
	aworker->input_types[0] = BUILTIN_TYPE_WHOLE;
	aworker->input_types[1] = BUILTIN_TYPE_WORKER;

	aworker = create_worker(prog, "Clear Handler", 1, 1, WORKER_TYPE);
	aworker->implement_func = (custom_worker *)vis_clear_handler;
	aworker->input_types[0] = BUILTIN_TYPE_WHOLE;

	aworker = create_worker(prog, "Held Keys", 0, 1, WORKER_TYPE);
	aworker->implement_func = (custom_worker *)vis_held_keys;

	aworker = create_worker(prog, "Touch Position", 0, 2, WORKER_TYPE);
	aworker->implement_func = (custom_worker *)vis_touch_position;
#endif
	
	current_method = 0;
	//strcpy(companylist[current_company].name, "String");
#ifdef SEGA
	this_comp = create_company(prog, "String", 6, 0, FALSE);
#else
	this_comp = create_company(prog, "String", 7, 0, FALSE);
#endif
	aworker = create_worker(prog, "<Whole Number@String",1, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_inttostring;
	aworker->input_types[0] = BUILTIN_TYPE_WHOLE;
	//add_method(this_comp, aworker);

#ifndef SEGA
	
	aworker = create_worker(prog, "<Real Number@String",1, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_realtostring;
	aworker->input_types[0] = BUILTIN_TYPE_REAL;
	//add_method(this_comp, aworker);
#endif
	
	aworker = create_worker(prog, "=@String",2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_stringequal;
	aworker->input_types[0] = BUILTIN_TYPE_STRING;
	aworker->input_types[1] = BUILTIN_TYPE_STRING;
	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "<Yes No@String",1, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_yesnotostring;
	aworker->input_types[0] = BUILTIN_TYPE_YESNO;
	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, ">@String",2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_greaterstring;
	aworker->input_types[0] = BUILTIN_TYPE_STRING;
	aworker->input_types[1] = BUILTIN_TYPE_STRING;
	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "<@String",2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_lesserstring;
	aworker->input_types[0] = BUILTIN_TYPE_STRING;
	aworker->input_types[1] = BUILTIN_TYPE_STRING;
	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "Append@String",2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_append;
	aworker->input_types[0] = BUILTIN_TYPE_STRING;
	aworker->input_types[1] = BUILTIN_TYPE_STRING;
	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "Split@String",2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_string_split;
	aworker->input_types[0] = BUILTIN_TYPE_STRING;
	aworker->input_types[1] = BUILTIN_TYPE_STRING;
	
	aworker = create_worker(prog, "Get Raw@String",2, 2, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_string_get_raw;
	aworker->input_types[0] = BUILTIN_TYPE_STRING;
	aworker->input_types[1] = ANY_TYPE;
	
	aworker = create_worker(prog, "Put Raw@String",2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_string_put_raw;
	aworker->input_types[0] = BUILTIN_TYPE_STRING;
	aworker->input_types[1] = ANY_TYPE;

	aworker = create_worker(prog, "Slice@String",2, 2, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_string_slice;
	aworker->input_types[0] = BUILTIN_TYPE_STRING;
	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;

	aworker = create_worker(prog, "Reverse@String",1, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_string_reverse;
	aworker->input_types[0] = BUILTIN_TYPE_STRING;
	
	aworker = create_worker(prog, "Length@String",1, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_string_length;
	aworker->input_types[0] = BUILTIN_TYPE_STRING;
	
	aworker = create_worker(prog, "Put Byte@String",2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_string_put_byte;
	aworker->input_types[0] = BUILTIN_TYPE_STRING;
	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
	
	aworker = create_worker(prog, "Get DString@String",2, 4, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_string_get_dstring;
	aworker->input_types[0] = BUILTIN_TYPE_STRING;
	aworker->input_types[1] = ANY_TYPE;
	
	current_method = 0;
	this_comp = create_company(prog, "Whole Number", 6, 0, FALSE);
	aworker = create_worker(prog, "<String@Whole Number",1, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_stringtoint;
	aworker->input_types[0] = BUILTIN_TYPE_STRING;
	
	aworker = create_worker(prog, "From Hex@Whole Number",1, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_whole_fromhex;
	aworker->input_types[0] = BUILTIN_TYPE_STRING;
	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "=@Whole Number",2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_wholeequal;
	aworker->input_types[0] = BUILTIN_TYPE_WHOLE;
	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, ">@Whole Number",2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_greaterint;
	aworker->input_types[0] = BUILTIN_TYPE_WHOLE;
	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "<@Whole Number",2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_lesserint;
	aworker->input_types[0] = BUILTIN_TYPE_WHOLE;
	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;

	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "+@Whole Number", 2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_whole_add;
	aworker->input_types[0] = BUILTIN_TYPE_WHOLE;
	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;

	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "-@Whole Number", 2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_whole_subtract;
	aworker->input_types[0] = BUILTIN_TYPE_WHOLE;
	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
	
	aworker = create_worker(prog, "*@Whole Number", 2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_whole_mult;
	aworker->input_types[0] = BUILTIN_TYPE_WHOLE;
	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;

	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "/@Whole Number", 2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_whole_div;
	aworker->input_types[0] = BUILTIN_TYPE_WHOLE;
	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;

	aworker = create_worker(prog, "&@Whole Number", 2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_whole_and;
	aworker->input_types[0] = BUILTIN_TYPE_WHOLE;
	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;

	aworker = create_worker(prog, "|@Whole Number", 2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_whole_or;
	aworker->input_types[0] = BUILTIN_TYPE_WHOLE;
	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;

	aworker = create_worker(prog, "LShift@Whole Number", 2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_whole_lsh;
	aworker->input_types[0] = BUILTIN_TYPE_WHOLE;
	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;

	aworker = create_worker(prog, "RShift@Whole Number", 2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_whole_rsh;
	aworker->input_types[0] = BUILTIN_TYPE_WHOLE;
	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;

	aworker = create_worker(prog, "%@Whole Number", 2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_whole_modulus;
	aworker->input_types[0] = BUILTIN_TYPE_WHOLE;
	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;

	//add_method(this_comp, aworker);
	
	current_method = 0;
	this_comp = create_company(prog, "Real Number", 6, 0, FALSE);//<string, =, >, <, +, -
	aworker = create_worker(prog, "<String@Real Number", 1, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_stringtoreal;
	aworker->input_types[0] = BUILTIN_TYPE_STRING;
	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "=@Real Number", 2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_realequal;
	aworker->input_types[0] = BUILTIN_TYPE_REAL;
	aworker->input_types[1] = BUILTIN_TYPE_REAL;

	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, ">@Real Number", 2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_greaterreal;
	aworker->input_types[0] = BUILTIN_TYPE_REAL;
	aworker->input_types[1] = BUILTIN_TYPE_REAL;

	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "<@Real Number", 2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_lesserreal;
	aworker->input_types[0] = BUILTIN_TYPE_REAL;
	aworker->input_types[1] = BUILTIN_TYPE_REAL;

	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "+@Real Number", 2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_real_add;
	aworker->input_types[0] = BUILTIN_TYPE_REAL;
	aworker->input_types[1] = BUILTIN_TYPE_REAL;

	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "-@Real Number", 2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_real_subtract;
	aworker->input_types[0] = BUILTIN_TYPE_REAL;
	aworker->input_types[1] = BUILTIN_TYPE_REAL;
	
	aworker = create_worker(prog, "/@Real Number", 2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_real_div;
	aworker->input_types[0] = BUILTIN_TYPE_REAL;
	aworker->input_types[1] = BUILTIN_TYPE_REAL;
	
	aworker = create_worker(prog, "*@Real Number", 2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_real_mult;
	aworker->input_types[0] = BUILTIN_TYPE_REAL;
	aworker->input_types[1] = BUILTIN_TYPE_REAL;
	
	aworker = create_worker(prog, "Cosine@Real Number", 1, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_real_cos;
	aworker->input_types[0] = BUILTIN_TYPE_REAL;

	aworker = create_worker(prog, "Sine@Real Number", 1, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_real_sin;
	aworker->input_types[0] = BUILTIN_TYPE_REAL;

	aworker = create_worker(prog, "Tangent@Real Number", 1, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_real_tan;
	aworker->input_types[0] = BUILTIN_TYPE_REAL;

	aworker = create_worker(prog, "Arc Cosine@Real Number", 1, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_real_arccos;
	aworker->input_types[0] = BUILTIN_TYPE_REAL;

	aworker = create_worker(prog, "Arc Sine@Real Number", 1, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_real_arcsin;
	aworker->input_types[0] = BUILTIN_TYPE_REAL;

	aworker = create_worker(prog, "Arc Tangent@Real Number", 1, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_real_arctan;
	aworker->input_types[0] = BUILTIN_TYPE_REAL;

	aworker = create_worker(prog, "^@Real Number", 2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_real_exp;
	aworker->input_types[0] = BUILTIN_TYPE_REAL;
	aworker->input_types[1] = BUILTIN_TYPE_REAL;

	aworker = create_worker(prog, "Square Root@Real Number", 1, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_real_sqrt;
	aworker->input_types[0] = BUILTIN_TYPE_REAL;

	aworker = create_worker(prog, "Truncate to Whole@Real Number", 1, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_whole_fromreal;
	aworker->input_types[0] = BUILTIN_TYPE_REAL;

	aworker = create_worker(prog, "<Whole Number@Real Number", 1, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_real_fromwhole;
	aworker->input_types[0] = BUILTIN_TYPE_WHOLE;

	//add_method(this_comp, aworker);
	
	current_method = 0;
	this_comp = create_company(prog, "List", 7, 1, FALSE);//Index, Append, Swap, Insert, Remove, Set, Length, New
	comp_room = add_comp_room(this_comp, "Length", 0, 0, ROOM_NO_ACCESS, ROOM_LONG);
	
	aworker = create_worker(prog, "Index@List", 2, 2, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_list_index;
	aworker->input_types[0] = BUILTIN_TYPE_LIST;
	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;

	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "Append@List", 2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_list_append;
	aworker->input_types[0] = BUILTIN_TYPE_LIST;
	aworker->input_types[1] = ANY_TYPE;

	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "Swap@List",3, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_list_swap;
	aworker->input_types[0] = BUILTIN_TYPE_LIST;
	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
	aworker->input_types[2] = BUILTIN_TYPE_WHOLE;

	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "Insert@List",3, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_list_insert;
	aworker->input_types[0] = BUILTIN_TYPE_LIST;
	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
	aworker->input_types[2] = ANY_TYPE;

	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "Remove@List", 2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_list_remove;
	aworker->input_types[0] = BUILTIN_TYPE_LIST;
	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;

	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "Set@List",3, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_list_set;
	aworker->input_types[0] = BUILTIN_TYPE_LIST;
	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
	aworker->input_types[2] = ANY_TYPE;

	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "Length@List", 1, 1, WORKER_TYPE);
	aworker->implement_func = (custom_worker *)vis_list_length;
	aworker->input_types[0] = BUILTIN_TYPE_LIST;
	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "List",0, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_list_new;
	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "First@List", 1, 2, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_list_first;
	aworker->input_types[0] = BUILTIN_TYPE_LIST;
	
	aworker = create_worker(prog, "Next@List", 2, 2, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_list_next;
	aworker->input_types[0] = BUILTIN_TYPE_LIST;
	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
	
	current_method = 0;
	this_comp = create_company(prog, "Dictionary", 5, 0, FALSE);//Index, Swap, Remove, Set, Length, New
	aworker = create_worker(prog, "Index@Dictionary", 2, 2, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_dict_index;
	aworker->input_types[0] = BUILTIN_TYPE_DICT;
	aworker->input_types[1] = BUILTIN_TYPE_STRING;

	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "Swap@Dictionary",3, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_dict_swap;
	aworker->input_types[0] = BUILTIN_TYPE_DICT;
	aworker->input_types[1] = BUILTIN_TYPE_STRING;
	aworker->input_types[2] = BUILTIN_TYPE_STRING;

	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "Remove@Dictionary", 2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_dict_remove;
	aworker->input_types[0] = BUILTIN_TYPE_DICT;
	aworker->input_types[1] = BUILTIN_TYPE_STRING;

	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "Set@Dictionary",3, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_dict_set;
	aworker->input_types[0] = BUILTIN_TYPE_DICT;
	aworker->input_types[1] = BUILTIN_TYPE_STRING;
	aworker->input_types[2] = ANY_TYPE;
	
	aworker = create_worker(prog, "Length@Dictionary", 1, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_dict_length;
	aworker->input_types[0] = BUILTIN_TYPE_DICT;

	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "Dictionary",0, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_dict_new;
	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "First@Dictionary", 1, 2, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_dict_first;
	aworker->input_types[0] = BUILTIN_TYPE_DICT;
	
	aworker = create_worker(prog, "Next@Dictionary", 2, 2, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_dict_next;
	aworker->input_types[0] = BUILTIN_TYPE_DICT;
	aworker->input_types[1] = BUILTIN_TYPE_STRING;

	current_method = 0;
#ifdef SEGA
	this_comp = create_company(prog, "File", 0, 0, FALSE);
#else
	
	this_comp = create_company(prog, "File", 7, 0, FALSE);//<String, Get FString, Get DString, Get Byte, Get Word, Get Long, Put String
	aworker = create_worker(prog, "<String@File", 1, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_file_from_string;
	aworker->input_types[0] = BUILTIN_TYPE_STRING;
	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "Get FString@File", 2, 2, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_file_get_fstring;
	aworker->input_types[0] = BUILTIN_TYPE_FILE;
	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;

	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "Get DString@File", 2, 4, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_file_get_dstring;
	aworker->input_types[0] = BUILTIN_TYPE_FILE;
	aworker->input_types[1] = ANY_TYPE;

	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "Get Byte@File", 1, 3, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_file_get_byte;
	aworker->input_types[0] = BUILTIN_TYPE_FILE;
	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "Get Word@File", 1, 3, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_file_get_word;
	aworker->input_types[0] = BUILTIN_TYPE_FILE;
	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "Get Long@File", 1, 3, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_file_get_long;
	aworker->input_types[0] = BUILTIN_TYPE_FILE;
	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "Get Double@File", 1, 3, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_file_get_double;
	aworker->input_types[0] = BUILTIN_TYPE_FILE;
	
	aworker = create_worker(prog, "Put String@File", 2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_file_put_string;
	aworker->input_types[0] = BUILTIN_TYPE_FILE;
	aworker->input_types[1] = BUILTIN_TYPE_STRING;
	
	aworker = create_worker(prog, "Length@File", 1, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_file_length;
	aworker->input_types[0] = BUILTIN_TYPE_FILE;

	//add_method(this_comp, aworker);
#endif
	
	current_method = 0;
	
	this_comp = create_company(prog, "Worker", 3, 0, FALSE);//<String, Do, Later: methods for manipulating 
	
	aworker = create_worker(prog, "<String@Worker", 1, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_worker_from_string;
	aworker->input_types[0] = BUILTIN_TYPE_STRING;
	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "Do@Worker", 2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_worker_do;
	aworker->input_types[0] = BUILTIN_TYPE_WORKER;
	aworker->input_types[1] = BUILTIN_TYPE_LIST;
	
	aworker = create_worker(prog, "Set Input@Worker", 3, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_worker_setinput;
	aworker->input_types[0] = BUILTIN_TYPE_WORKER;
	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
	aworker->input_types[2] = ANY_TYPE;
	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "Add Worker Call@Worker", 2, 2, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_worker_add_worker_call;
	aworker->input_types[0] = BUILTIN_TYPE_WORKER;
	aworker->input_types[1] = BUILTIN_TYPE_WORKER;
	
	aworker = create_worker(prog, "Add Wire@Worker", 5, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_worker_add_wire;
	aworker->input_types[0] = BUILTIN_TYPE_WORKER;
	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
	aworker->input_types[2] = BUILTIN_TYPE_WHOLE;
	aworker->input_types[3] = BUILTIN_TYPE_WHOLE;
	aworker->input_types[4] = BUILTIN_TYPE_WHOLE;
	
	aworker = create_worker(prog, "Add Constant@Worker", 2, 2, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_worker_add_constant;
	aworker->input_types[0] = BUILTIN_TYPE_WORKER;
	aworker->input_types[1] = ANY_TYPE;
	
	aworker = create_worker(prog, "Add Input@Worker", 3, 2, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_worker_add_input;
	aworker->input_types[0] = BUILTIN_TYPE_WORKER;
	aworker->input_types[1] = BUILTIN_TYPE_STRING;
	aworker->input_types[2] = BUILTIN_TYPE_WHOLE;
	
	aworker = create_worker(prog, "Add Output@Worker", 3, 2, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_worker_add_output;
	aworker->input_types[0] = BUILTIN_TYPE_WORKER;
	aworker->input_types[1] = BUILTIN_TYPE_STRING;
	aworker->input_types[2] = BUILTIN_TYPE_WHOLE;
	
	aworker = create_worker(prog, "Add Object Get@Worker", 2, 2, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_worker_add_objectget;
	aworker->input_types[0] = BUILTIN_TYPE_WORKER;
	aworker->input_types[1] = BUILTIN_TYPE_STRING;
	
	aworker = create_worker(prog, "Add Object Set@Worker", 2, 2, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_worker_add_objectset;
	aworker->input_types[0] = BUILTIN_TYPE_WORKER;
	aworker->input_types[1] = BUILTIN_TYPE_STRING;
	
	aworker = create_worker(prog, "Add Global Get@Worker", 3, 2, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_worker_add_globalget;
	aworker->input_types[0] = BUILTIN_TYPE_WORKER;
	aworker->input_types[1] = BUILTIN_TYPE_STRING;
	aworker->input_types[2] = BUILTIN_TYPE_STRING;
	
	aworker = create_worker(prog, "Add Global Set@Worker", 3, 2, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_worker_add_globalset;
	aworker->input_types[0] = BUILTIN_TYPE_WORKER;
	aworker->input_types[1] = BUILTIN_TYPE_STRING;
	aworker->input_types[2] = BUILTIN_TYPE_STRING;
	
	aworker = create_worker(prog, "Clear@Worker", 1, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_worker_clear;
	aworker->input_types[0] = BUILTIN_TYPE_WORKER;
	
	aworker = create_worker(prog, "Uses@Worker", 2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_worker_uses;
	aworker->input_types[0] = BUILTIN_TYPE_WORKER;
	aworker->input_types[1] = BUILTIN_TYPE_LIST;
	
	aworker = create_worker(prog, "Set IO Counts@Worker", 3, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_worker_setio_counts;
	aworker->input_types[0] = BUILTIN_TYPE_WORKER;
	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
	aworker->input_types[2] = BUILTIN_TYPE_WHOLE;
	
	aworker = create_worker(prog, "Worker", 1, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_worker_new;
	aworker->input_types[0] = BUILTIN_TYPE_STRING;
	
#ifdef GUI_LIB
	current_method = 0;
	
	this_comp = create_company(prog, "Window", 3, 0, FALSE);
	
	aworker = create_worker(prog, "Window", 3, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_window_new;
	aworker->input_types[0] = BUILTIN_TYPE_STRING;
	aworker->input_types[1] = BUILTIN_TYPE_REAL;
	aworker->input_types[2] = BUILTIN_TYPE_REAL;
	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "Add Widget@Window", 5, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_window_add_widget;
	aworker->input_types[0] = BUILTIN_TYPE_WINDOW;
	aworker->input_types[1] = BUILTIN_TYPE_STRING;
	aworker->input_types[2] = ANY_TYPE;
	aworker->input_types[3] = BUILTIN_TYPE_REAL;
	aworker->input_types[4] = BUILTIN_TYPE_REAL;
	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "Show@Window", 3, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_window_show;
	aworker->input_types[0] = BUILTIN_TYPE_WINDOW;
	aworker->input_types[1] = BUILTIN_TYPE_REAL;
	aworker->input_types[2] = BUILTIN_TYPE_REAL;
	//add_method(this_comp, aworker);
	
	current_method = 0;
	this_comp = create_company(prog, "Screen Window", 3, 0, FALSE);
	
	aworker = create_worker(prog, "Get Value@Screen Window", 2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_window_get_value;
	aworker->input_types[0] = BUILTIN_TYPE_WINDOW_SHOWN;
	aworker->input_types[1] = BUILTIN_TYPE_STRING;
	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "Set Value@Screen Window", 3, 0, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_window_set_value;
	aworker->input_types[0] = BUILTIN_TYPE_WINDOW_SHOWN;
	aworker->input_types[1] = BUILTIN_TYPE_STRING;
#ifdef SYLLABLE
	aworker->input_types[2] = ANY_TYPE;
#else
	aworker->input_types[2] = BUILTIN_TYPE_STRING;
#endif
	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "Wait Close@Screen Window", 1, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_window_wait_close;
	aworker->input_types[0] = BUILTIN_TYPE_WINDOW_SHOWN;
	//add_method(this_comp, aworker);

#ifdef SYLLABLE
	aworker = create_worker(prog, "Add Widget@Screen Window", 5, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_window_shown_addwidget;
	aworker->input_types[0] = BUILTIN_TYPE_WINDOW_SHOWN;
	aworker->input_types[1] = BUILTIN_TYPE_STRING;
	aworker->input_types[2] = ANY_TYPE;
	aworker->input_types[3] = BUILTIN_TYPE_REAL;
	aworker->input_types[4] = BUILTIN_TYPE_REAL;
#endif
	
	current_method = 0;
	create_company(prog, "Button", 2, 0, FALSE);
	
	aworker = create_worker(prog, "Button", 3, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_button_new;
	aworker->input_types[0] = BUILTIN_TYPE_STRING;
	aworker->input_types[1] = BUILTIN_TYPE_REAL;
	aworker->input_types[2] = BUILTIN_TYPE_REAL;
	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "Set Handler@Button", 3, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_button_set_handler;
	aworker->input_types[0] = BUILTIN_TYPE_BUTTON;
	aworker->input_types[1] = BUILTIN_TYPE_STRING;
	aworker->input_types[2] = BUILTIN_TYPE_WORKER;
	//add_method(this_comp, aworker);
	
	current_method = 0;
	create_company(prog, "Input Box", 2, 0, FALSE);
		
	aworker = create_worker(prog, "Input Box", 3, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_inputbox_new;
	aworker->input_types[0] = BUILTIN_TYPE_STRING;
	aworker->input_types[1] = BUILTIN_TYPE_REAL;
	aworker->input_types[2] = BUILTIN_TYPE_REAL;
	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "Set Type@Input Box", 2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_inputbox_settype;
	aworker->input_types[0] = BUILTIN_TYPE_INPUTBOX;
	aworker->input_types[1] = BUILTIN_TYPE_STRING;
	//add_method(this_comp, aworker);
	
#endif
#ifndef NO_NET
	this_comp = create_company(prog, "Net Client", 3, 0, FALSE);
	aworker = create_worker(prog, "Net Client", 2, 1, WORKER_TYPE);
	aworker->implement_func =(custom_worker *)net_client_new;
	aworker->input_types[0] = BUILTIN_TYPE_STRING;
	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
	
	aworker = create_worker(prog, "Put String@Net Client", 2, 2, WORKER_TYPE);
	aworker->implement_func = (custom_worker *)net_client_put_string;
	aworker->input_types[0] = BUILTIN_TYPE_NETCLIENT;
	aworker->input_types[1] = BUILTIN_TYPE_STRING;
	
	aworker = create_worker(prog, "Get FString@Net Client", 2, 3, WORKER_TYPE);
	aworker->implement_func = (custom_worker *)net_client_get_fstring;
	aworker->input_types[0] = BUILTIN_TYPE_NETCLIENT;
	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
	
	aworker = create_worker(prog, "Get DString@Net Client", 2, 4, WORKER_TYPE);
	aworker->implement_func = (custom_worker *)net_client_get_dstring;
	aworker->input_types[0] = BUILTIN_TYPE_NETCLIENT;
	aworker->input_types[1] = ANY_TYPE;
	
	aworker = create_worker(prog, "Put Raw@Net Client", 2, 2, WORKER_TYPE);
	aworker->implement_func = (custom_worker *)net_client_put_raw;
	aworker->input_types[0] = BUILTIN_TYPE_NETCLIENT;
	aworker->input_types[1] = ANY_TYPE;
	
	aworker = create_worker(prog, "Get Raw@Net Client", 2, 3, WORKER_TYPE);
	aworker->implement_func = (custom_worker *)net_client_get_raw;
	aworker->input_types[0] = BUILTIN_TYPE_NETCLIENT;
	aworker->input_types[1] = ANY_TYPE;
	
	aworker = create_worker(prog, "Listen on Port", 2, 0, WORKER_TYPE);
	aworker->implement_func = (custom_worker *)vis_net_listenport;
	aworker->input_types[0] = BUILTIN_TYPE_WHOLE;
	aworker->input_types[1] = BUILTIN_TYPE_WORKER;
#endif

	create_company(prog, "Global Store", 0, 0, FALSE);
	
	create_company(prog, "Program", 5, 0, FALSE);
	
	aworker = create_worker(prog, "Program", 0, 1, WORKER_TYPE);
	aworker->implement_func = (custom_worker *)vis_program_new;
	
	aworker = create_worker(prog, "New Worker@Program", 2, 2, WORKER_TYPE);
	aworker->implement_func = (custom_worker *)vis_program_new_worker;
	aworker->input_types[0] = BUILTIN_TYPE_PROGRAM;
	aworker->input_types[1] = BUILTIN_TYPE_STRING;
	
	aworker = create_worker(prog, "Add Worker@Program", 2, 2, WORKER_TYPE);
	aworker->implement_func = (custom_worker *)vis_program_add_worker;
	aworker->input_types[0] = BUILTIN_TYPE_PROGRAM;
	aworker->input_types[1] = BUILTIN_TYPE_WORKER;
	
	aworker = create_worker(prog, "Add Builtins@Program", 1, 1, WORKER_TYPE);
	aworker->implement_func = (custom_worker *)vis_program_add_builtins;
	aworker->input_types[0] = BUILTIN_TYPE_PROGRAM;
	
	aworker = create_worker(prog, "Run@Program", 2, 1, WORKER_TYPE);
	aworker->implement_func = (custom_worker *)vis_program_run;
	aworker->input_types[0] = BUILTIN_TYPE_PROGRAM;
	aworker->input_types[1] = ANY_TYPE;
	
	aworker = create_worker(prog, "Find Worker@Program", 2, 2, WORKER_TYPE);
	aworker->implement_func = (custom_worker *)vis_program_find_worker;
	aworker->input_types[0] = BUILTIN_TYPE_PROGRAM;
	aworker->input_types[1] = BUILTIN_TYPE_STRING;

#ifdef GUI_LIB
#ifdef SYLLABLE
	create_company(prog, "Custom Widget", 2, 0, FALSE);
	
	aworker = create_worker(prog, "Custom Widget", 3, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_customwidget_new;
	aworker->input_types[0] = BUILTIN_TYPE_STRING;
	aworker->input_types[1] = BUILTIN_TYPE_REAL;
	aworker->input_types[2] = BUILTIN_TYPE_REAL;
	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "Set Handler@Custom Widget", 3, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_button_set_handler;
	aworker->input_types[0] = BUILTIN_TYPE_CUSTOM_WIDGET;
	aworker->input_types[1] = BUILTIN_TYPE_STRING;
	aworker->input_types[2] = BUILTIN_TYPE_WORKER;
	//add_method(this_comp, aworker);
	
	create_company(prog, "Screen Custom Widget", 3, 0, FALSE);
	
	aworker = create_worker(prog, "Default Draw@Screen Custom Widget", 1, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_screen_custom_defaultpaint;
	aworker->input_types[0] = BUILTIN_TYPE_SCREEN_CUSTOM;
	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "Draw Line@Screen Custom Widget", 5, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_screen_custom_drawline;
	aworker->input_types[0] = BUILTIN_TYPE_SCREEN_CUSTOM;
	aworker->input_types[1] = BUILTIN_TYPE_REAL;
	aworker->input_types[2] = BUILTIN_TYPE_REAL;
	aworker->input_types[3] = BUILTIN_TYPE_REAL;
	aworker->input_types[4] = BUILTIN_TYPE_REAL;
	//add_method(this_comp, aworker);
	
	aworker = create_worker(prog, "Draw String@Screen Custom Widget", 4, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_screen_custom_drawstring;
	aworker->input_types[0] = BUILTIN_TYPE_SCREEN_CUSTOM;
	aworker->input_types[1] = BUILTIN_TYPE_STRING;
	aworker->input_types[2] = BUILTIN_TYPE_REAL;
	aworker->input_types[3] = BUILTIN_TYPE_REAL;
	
	aworker = create_worker(prog, "Set Draw Color@Screen Custom Widget", 5, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_screen_custom_setdrawcolor;
	aworker->input_types[0] = BUILTIN_TYPE_SCREEN_CUSTOM;
	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
	aworker->input_types[2] = BUILTIN_TYPE_WHOLE;
	aworker->input_types[3] = BUILTIN_TYPE_WHOLE;
	aworker->input_types[4] = BUILTIN_TYPE_WHOLE;
	
	aworker = create_worker(prog, "Move By@Screen Custom Widget", 3, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_screen_custom_moveby;
	aworker->input_types[0] = BUILTIN_TYPE_SCREEN_CUSTOM;
	aworker->input_types[1] = BUILTIN_TYPE_REAL;
	aworker->input_types[2] = BUILTIN_TYPE_REAL;
	
	aworker = create_worker(prog, "Set Handler@Screen Custom Widget", 3, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_screen_custom_sethandler;
	aworker->input_types[0] = BUILTIN_TYPE_SCREEN_CUSTOM;
	aworker->input_types[1] = BUILTIN_TYPE_STRING;
	aworker->input_types[2] = BUILTIN_TYPE_WORKER;
	
	aworker = create_worker(prog, "Remove Handler@Screen Custom Widget", 2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_screen_custom_removehandler;
	aworker->input_types[0] = BUILTIN_TYPE_SCREEN_CUSTOM;
	aworker->input_types[1] = BUILTIN_TYPE_STRING;
	
	aworker = create_worker(prog, "Give Focus@Screen Custom Widget", 2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_screen_custom_givefocus;
	aworker->input_types[0] = BUILTIN_TYPE_SCREEN_CUSTOM;
	aworker->input_types[1] = BUILTIN_TYPE_YESNO;
	
	aworker = create_worker(prog, "Add Widget@Screen Custom Widget", 5, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_screen_custom_addwidget;
	aworker->input_types[0] = BUILTIN_TYPE_SCREEN_CUSTOM;
	aworker->input_types[1] = BUILTIN_TYPE_STRING;
	aworker->input_types[2] = ANY_TYPE;
	aworker->input_types[3] = BUILTIN_TYPE_REAL;
	aworker->input_types[4] = BUILTIN_TYPE_REAL;
	
#endif
#endif
	create_company(prog, "Buffer", 7, 0, FALSE);
	
	aworker = create_worker(prog, "Buffer", 1, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_buffer_new;
	aworker->input_types[0] = BUILTIN_TYPE_WHOLE;
	
	aworker = create_worker(prog, "Lock@Buffer", 1, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_buffer_lock;
	aworker->input_types[0] = BUILTIN_TYPE_BUFFER;
	
	aworker = create_worker(prog, "Unlock@Buffer", 1, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_buffer_unlock;
	aworker->input_types[0] = BUILTIN_TYPE_BUFFER;
	
	aworker = create_worker(prog, "Put Byte@Buffer", 2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_buffer_putbyte;
	aworker->input_types[0] = BUILTIN_TYPE_BUFFER;
	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
	
	aworker = create_worker(prog, "Write Byte@Buffer", 2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_buffer_writebyte;
	aworker->input_types[0] = BUILTIN_TYPE_BUFFER;
	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
	
	aworker = create_worker(prog, "Put Word@Buffer", 2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_buffer_putshort;
	aworker->input_types[0] = BUILTIN_TYPE_BUFFER;
	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
	
	aworker = create_worker(prog, "Write Word@Buffer", 2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_buffer_writeshort;
	aworker->input_types[0] = BUILTIN_TYPE_BUFFER;
	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
	
	aworker = create_worker(prog, "Put Long@Buffer", 2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_buffer_putlong;
	aworker->input_types[0] = BUILTIN_TYPE_BUFFER;
	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
	
	aworker = create_worker(prog, "Write Long@Buffer", 2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_buffer_writelong;
	aworker->input_types[0] = BUILTIN_TYPE_BUFFER;
	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
	
	aworker = create_worker(prog, "Reset@Buffer", 1, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_buffer_reset;
	aworker->input_types[0] = BUILTIN_TYPE_BUFFER;
	
#if defined(SEGA) || defined(NINTENDO_DS)

	aworker = create_worker(prog, "From Address@Buffer", 2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_buffer_fromaddress;
	aworker->input_types[0] = BUILTIN_TYPE_WHOLE;
	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
#endif //SEGA

	create_company(prog, "Blueprint", 4, 0, FALSE);
	
	aworker = create_worker(prog, "Blueprint", 1, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_blueprint_new;
	aworker->input_types[0] = BUILTIN_TYPE_STRING;
	
	aworker = create_worker(prog, "Add Field@Blueprint", 3, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_blueprint_addfield;
	aworker->input_types[0] = BUILTIN_TYPE_BLUEPRINT;
	aworker->input_types[1] = BUILTIN_TYPE_STRING;
	aworker->input_types[2] = BUILTIN_TYPE_STRING;
	
	aworker = create_worker(prog, "Name@Blueprint", 1, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_blueprint_name;
	aworker->input_types[0] = BUILTIN_TYPE_BLUEPRINT;
	
	aworker = create_worker(prog, "Get Fields@Blueprint", 1, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_blueprint_getfields;
	aworker->input_types[0] = BUILTIN_TYPE_BLUEPRINT;
	
	aworker = create_worker(prog, "Blueprint Of", 1, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_get_blueprint;
	aworker->input_types[0] = ANY_TYPE;
	
	aworker = create_worker(prog, "Get Field", 2, 2, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_get_field;
	aworker->input_types[0] = ANY_TYPE;
	aworker->input_types[1] = BUILTIN_TYPE_STRING;
	
	aworker = create_worker(prog, "Set Field", 3, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_set_field;
	aworker->input_types[0] = ANY_TYPE;
	aworker->input_types[1] = BUILTIN_TYPE_STRING;
	aworker->input_types[2] = ANY_TYPE;
	
	aworker = create_worker(prog, "New Blueprint@Program", 2, 2, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_program_newblueprint;
	aworker->input_types[0] = BUILTIN_TYPE_PROGRAM;
	aworker->input_types[1] = BUILTIN_TYPE_STRING;

#ifdef GUI_LIB
#ifdef SYLLABLE
	create_company(prog, "Checkbox", 2, 0, FALSE);

	aworker = create_worker(prog, "Checkbox", 4, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_checkbox_new;
	aworker->input_types[0] = BUILTIN_TYPE_STRING;
	aworker->input_types[1] = BUILTIN_TYPE_REAL;
	aworker->input_types[2] = BUILTIN_TYPE_REAL;
	aworker->input_types[3] = BUILTIN_TYPE_YESNO;

	aworker = create_worker(prog, "Set Handler@Checkbox", 3, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_button_set_handler;
	aworker->input_types[0] = BUILTIN_TYPE_CHECKBOX;
	aworker->input_types[1] = BUILTIN_TYPE_STRING;
	aworker->input_types[2] = BUILTIN_TYPE_WORKER;

	create_company(prog, "Dropdown", 4, 0, FALSE);

	aworker = create_worker(prog, "Dropdown", 3, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_dropdown_new;
	aworker->input_types[0] = BUILTIN_TYPE_LIST;
	aworker->input_types[1] = BUILTIN_TYPE_REAL;
	aworker->input_types[2] = BUILTIN_TYPE_REAL;

	aworker = create_worker(prog, "Set Handler@Dropdown", 3, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_button_set_handler;
	aworker->input_types[0] = BUILTIN_TYPE_DROPDOWN;
	aworker->input_types[1] = BUILTIN_TYPE_STRING;
	aworker->input_types[2] = BUILTIN_TYPE_WORKER;

	aworker = create_worker(prog, "Set Text@Dropdown", 2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_dropdown_settext;
	aworker->input_types[0] = BUILTIN_TYPE_DROPDOWN;
	aworker->input_types[1] = BUILTIN_TYPE_STRING;

	aworker = create_worker(prog, "Select@Dropdown", 2, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)vis_dropdown_select;
	aworker->input_types[0] = BUILTIN_TYPE_DROPDOWN;
	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
#endif
#endif
	aworker = create_worker(prog, "Unix Time", 0, 1, WORKER_TYPE);
	aworker->implement_func=(custom_worker *)unix_time;
	/*if(current_def > num_defs)
		num_defs = current_def;
	if(current_company > num_companies)
		num_companies = current_company;*/
}

void initworkers(program * prog)
{
	//num_defs=0;
	//num_companies=0;
	create_worker(prog, "Main", 0, 0, USER_FLAG | WORKER_TYPE);

	initpredefworkers(prog);	
	
}
/*
void add_if_ready(int workerNum, worker_instance * instance)
{
	//int i, j, n, old_ready_count;
	BOOL ready=FALSE;
	//int paramstore[32];
	//int * params = paramstore;
	DEBUGPUTS("add_if_ready\n");
	if(!instance || !instance->def)
		return;
	VIS_PROFILE_START(PROF_ADDREADY);
	DEBUGPRINTF( "add_if_ready on %s\n", instance->def->implement_func->workerlist[workerNum].name);
	VIS_EnterCriticalSection(instance->workerlist[workerNum].worker_lock);
		++instance->workerlist[workerNum].ready_count;
		if(instance->workerlist[workerNum].ready_count >= (instance->def->implement_func->workerlist[workerNum].num_inputs + (instance->def->implement_func->workerlist[workerNum].null_input ? 1 : 0)))
		{
			ready = TRUE;
			instance->workerlist[workerNum].ready_count = 0;
		}
	VIS_LeaveCriticalSection(instance->workerlist[workerNum].worker_lock);
	if(ready)
	{
		DEBUGPRINTF("add_queue on %s\n", instance->def->implement_func->workerlist[workerNum].name);
		add_queue(workerNum, instance);
	}
	VIS_PROFILE_END(PROF_ADDREADY);
}*/
#define RETURN_CODE_EXIT		0xABCE1234
#define	RETURN_CODE_IDLE		0x00BADFAD
#define	RETURN_CODE_NORMAL		0xABBAABBA
#define RETURN_CODE_PARALLEL	0xC001D00D
#define GET_OP1(opcode)			((opcode & 0xF0000000) >> 28)
#define GET_OP2(opcode)			((opcode & 0x0F000000) >> 24)
#define	GET_INST(opcode)		((opcode & 0x00FF0000) >> 16)

#define MOVE_INST		0x00
#define ADDREF_INST		0x01
#define	RELEASE_INST	0x02
#define LOAD_INST		0x03
#define	CALL_INST		0x04
#define CALLB_INST		0x05
#define	CALLP_INST		0x06
#define	CALLBP_INST		0x07
#define RETURN_INST		0x08
#define	BRANCH_INST		0x09
#define	BRANCHT_INST	0x0A
#define	BRANCHF_INST	0x0B
#define WAIT_INST		0x0C
#define ADD_INST		0x0D
#define SUB_INST		0x0E
#define SUBR_INST		0x0F
#define GREATER_INST	0x10
#define	LESSER_INST		0x11

#define REGISTER_BIT	0x8
#define NO_OPERAND		0x7
#define OP_REG_MASK		0x7
#define GET_REGNUM1(opcode)		((opcode & 0x0000FF00) >> 8)
#define GET_REGNUM2(opcode)		(opcode & 0x000000FF)

#define REG_DIRECT		0
#define REG_INDIRECT	1
#define IMMED_8			2
#define IMMED_32		3
#define STACK_8			4
#define REG_REL_32		5
#define PC_REL_8		6

#define STACK_REG		31
#define PC_REG			30

#define OPC(inst, op1, reg1, op2, reg2)	((op1 << 28) | (op2 << 24) | (inst << 16) | ((reg1 & 0xff) << 8) | (reg2 & 0xFF))

//unsigned long test_program[] =
//{
//	OPC(LOAD_INST, PC_REL_8, 8 /* Hi */, REG_DIRECT, 0),
//	OPC(CALLB_INST, IMMED_8, 1/* Print */, NO_OPERAND, 0),
//	OPC(RETURN_INST, NO_OPERAND, 0, NO_OPERAND, 0),
//	26952//Hi
//};

unsigned long test_program[] =
{
	//Main:
	OPC(LOAD_INST, PC_REL_8, 20/* 10 */, REG_DIRECT, 0),
	OPC(LOAD_INST, PC_REL_8, 20/* 2 */, PC_REL_8, 28),
	OPC(LOAD_INST, PC_REL_8, 20/* 1 */, PC_REL_8, 28),
	OPC(CALL_INST, PC_REL_8, 28/* Fib: */, NO_OPERAND, 0),
	OPC(CALLB_INST, IMMED_8, 1/* Print */, NO_OPERAND, 0),
	OPC(RETURN_INST, NO_OPERAND, 0, NO_OPERAND, 0),
	0x3033,//'30'
	0x32,//'2'
	0x31,//'1'
	0,//2 storage
	0,//1 storage
	//Fib:
	OPC(ADD_INST, IMMED_8, 8, REG_DIRECT, STACK_REG),
	OPC(MOVE_INST, REG_DIRECT, 0, STACK_8, -4),
	OPC(ADDREF_INST, REG_INDIRECT, 0, NO_OPERAND, 0),
	OPC(ADDREF_INST, REG_INDIRECT, 0, NO_OPERAND, 0),
	OPC(MOVE_INST, PC_REL_8, -28/* 2 */, REG_DIRECT, 1),
	OPC(ADDREF_INST, REG_INDIRECT, 1, NO_OPERAND, 0),
	OPC(CALLB_INST, IMMED_8, 8/* < */, NO_OPERAND, 0),
	OPC(CALLB_INST, IMMED_8, 11/* If */, NO_OPERAND, 0),
	OPC(BRANCHT_INST, PC_REL_8, 64/* _Base */, REG_DIRECT, 0),
	
	OPC(RELEASE_INST, REG_INDIRECT, 1, NO_OPERAND, 0),
	OPC(MOVE_INST, STACK_8, -4, REG_DIRECT, 0),
	OPC(MOVE_INST, PC_REL_8, -56/* 2 */, REG_DIRECT, 1),
	OPC(ADDREF_INST, REG_INDIRECT, 1, NO_OPERAND, 0),
	OPC(CALLB_INST, IMMED_8, 6/* - */, NO_OPERAND, 0),
	OPC(CALL_INST, PC_REL_8, -60/* Fib */, NO_OPERAND, 0),
	OPC(MOVE_INST, REG_DIRECT, 0, STACK_8, -8),
	OPC(MOVE_INST, STACK_8, -4, REG_DIRECT, 0),
	OPC(MOVE_INST, PC_REL_8, -76/* 1 */, REG_DIRECT, 1),
	OPC(ADDREF_INST, REG_INDIRECT, 1, NO_OPERAND, 0),
	OPC(CALLB_INST, IMMED_8, 6/* - */, NO_OPERAND, 0),
	OPC(CALL_INST, PC_REL_8, -84/* Fib */, NO_OPERAND, 0),
	OPC(MOVE_INST, STACK_8, -8, REG_DIRECT, 1),
	OPC(CALLB_INST, IMMED_8, 5/* + */, NO_OPERAND, 0),
	OPC(SUBR_INST, IMMED_8, 8, REG_DIRECT, STACK_REG),
	OPC(RETURN_INST, NO_OPERAND, 0, NO_OPERAND, 0),
	//_Base:
	OPC(RELEASE_INST, REG_INDIRECT, 0, NO_OPERAND, 0),
	OPC(MOVE_INST, PC_REL_8, -112/* 1 */, REG_DIRECT, 0),
	OPC(ADDREF_INST, REG_INDIRECT, 0, NO_OPERAND, 0),
	OPC(SUBR_INST, IMMED_8, 8, REG_DIRECT, STACK_REG),
	OPC(RETURN_INST, NO_OPERAND, 0, NO_OPERAND, 0),
	
};

unsigned long * get_effective_address(char op, unsigned short regnum, unsigned long ** pc, unsigned long * registers, unsigned long * immed)
{
	unsigned long * add = NULL;
	unsigned long work;
	if(op != NO_OPERAND)
	{
		if(op & REGISTER_BIT)
			add = (unsigned long *)(registers[regnum] + registers[op & OP_REG_MASK]);
		else
		{
			switch(op)
			{
				case REG_DIRECT:
					add = registers + regnum;
					break;
				case REG_INDIRECT:
					add = (unsigned long *) registers[regnum];
					break;
				case IMMED_8:
					*immed = (char)regnum;
					add = (unsigned long *)immed;
					break;
				case IMMED_32:
					*immed = *((*pc)++);
					add = (unsigned long *)immed;
					break;
				case STACK_8:
					work = (char)regnum;
					add = (unsigned long *)(registers[STACK_REG] + work);
					break;
				case REG_REL_32:
					work = *((*pc)++);
					add = (unsigned long *)(registers[regnum] + work);
					break;
				case PC_REL_8:
					work = (char)regnum;
					add = (unsigned long *)(registers[PC_REG] + work);
					break;
				default:
					break;
			}
		}
	}
	return add;
}

DWORD WINAPI virtual_processor(unsigned long * program, BOOL main)
{
	int i;
	unsigned long **pc;
	unsigned long **stack;
	unsigned long registers[32];
	unsigned long opcode;
	unsigned long extra, extra2;
	queue_entry entry;
	stack_segment initial_stack;
	stack_segment * current = &initial_stack;
	char slot_usage[7];
	char op1, op2;
	char inst;
	unsigned long *add1, *add2;
	long immed1, immed2;
	initial_stack.size = MIN_STACK_SIZE;
	initial_stack.parent = initial_stack.child = NULL;
	initial_stack.data[0] = main ? RETURN_CODE_EXIT : RETURN_CODE_IDLE;
	pc = (unsigned long **)(&(registers[PC_REG]));
	stack = (unsigned long **)(&(registers[STACK_REG]));
	*pc = program;
	*stack = (unsigned long *)(initial_stack.data + 1);
	entry.instance = NULL;
	entry.worker_num = 0;
	DEBUGPRINTF("Virtual processor, Program start: %X\n", program);
	#ifdef ENABLE_PROFILING
	for(i = 0; i < NUM_PROFS; ++i)
	{
		vis_profile_running_total[i] = 0;
		vis_profile_counts[i] = 0;
	}
	VIS_PROFILE_START(PROF_EMPTYFUNC);
	empty_test(NULL,NULL);
	VIS_PROFILE_END(PROF_EMPTYFUNC);
	VIS_PROFILE_START(PROF_NOCODE);
	VIS_PROFILE_END(PROF_NOCODE);
#endif
	while(execute_active)
	{
		VIS_PROFILE_START(PROF_VIRTUAL_DECODE);
		DEBUGPRINTF("PC: %X\n", *pc);
		opcode = *((*pc)++);
		op1 = GET_OP1(opcode);
		op2 = GET_OP2(opcode);
		add1 = get_effective_address(op1, GET_REGNUM1(opcode), pc, registers, &immed1);
		add2 = get_effective_address(op2, GET_REGNUM2(opcode), pc, registers, &immed2);
		DEBUGPRINTF("Opcode: %X, Instruction: %X, op1 %X, op2 %X\n", opcode, GET_INST(opcode), op1, op2);
		inst = GET_INST(opcode);
		VIS_PROFILE_END(PROF_VIRTUAL_DECODE);
		VIS_PROFILE_START(PROF_VIRTUAL_EXECUTE);
		switch(inst)
		{
		case MOVE_INST:
			*add2 = *add1;
			break;
		case ADDREF_INST:
			add_ref((datum *)add1);
			break;
		case RELEASE_INST:
			release_ref((datum *)add1);
			break;
/*
Temporarily commented out until multiple program support is finished
		case LOAD_INST:
			*add2 = (long)get_constant((char *)add1, -1);
			break;
*/
		case CALL_INST:
			*((*stack)++) = (unsigned long)*pc;
			*((*stack)++) = RETURN_CODE_NORMAL;
			*pc = add1;
			break;
/*
Temporarily commented out until multiple program support is finished
		case CALLB_INST:
			//TODO: Needs to be made 100% correct
			DEBUGPRINTF("Calling builtin: %s\n", deflist[*add1].name);
			execute_def(deflist + *add1, entry, (datum **)registers, NULL);
			break;*/
		case CALLP_INST:
			//TODO Implement me
			break;
		case CALLBP_INST:
			//TODO Implement me
			break;
		case RETURN_INST:
			switch(*(--(*stack)))
			{
				case RETURN_CODE_EXIT:
					execute_active = FALSE;
					break;
				case RETURN_CODE_IDLE:
					//TODO: Implement me
					break;
				case RETURN_CODE_NORMAL:
					*pc = (unsigned long *)*(--(*stack));
					break;
				default:
					break;
			}
			break;
		case BRANCH_INST:
			*pc = add1;
			break;
		case BRANCHT_INST:
			if(*add2)
				*pc = add1;
			break;
		case BRANCHF_INST:
			if(!*add2)
				*pc = add1;
			break;
		case WAIT_INST:
			//TODO: Implement Me
			break;
		case ADD_INST:
			*add2 = *add1 + *add2;
			break;
		case SUB_INST:
			*add2 = *add1 - *add2;
			break;
		case SUBR_INST:
			*add2 = *add2 - *add1;
			break;
		case GREATER_INST:
			*add2 = *add1 > *add2;
			break;
		case LESSER_INST:
			*add2 = *add1 < *add2;
			break;
		default:
			break;
		}
		VIS_PROFILE_END(PROF_VIRTUAL_EXECUTE);
	}
#ifdef ENABLE_PROFILING
	for(i = 0; i < NUM_PROFS; ++i)
		printf("%d:\t%f,\tcount: %d,\taverage: %f\n", i, (double)vis_profile_running_total[i], vis_profile_counts[i], ((double)vis_profile_running_total[i])/((double)vis_profile_counts[i]));
#endif
	return 0;
}

void test_virtual()
{
//	int i,j,k;
	program * prog = new_program(START_DEF_STORAGE, START_COMP_STORAGE);
	initpredefworkers(prog);
	init_sync_primitives();
	init_datum_storage();
//TODO Uncomment me
//	init_global_storage();
	execute_active = TRUE;
/*	for(i = MOVE_INST; i <= LESSER_INST; ++i)
	{
		for(j = 0; j < 0x10; ++j)
		{
			for(k = 0; k < 0x10; ++k)
			{
				DEBUGPRINTF("i: %X, j: %X, k: %X, OPC: %X\n", i, j, k, OPC(i, j, j, k, k));
			}
		}
	}*/
	virtual_processor(test_program, TRUE);
}

DWORD WINAPI worker_thread(LPVOID param)
{
	queue_entry aworker;
	int	temp_queue_len;
	while(execute_active)
	{
		VIS_PROFILE_START(PROF_WORKER_THREAD);
#ifdef NINTENDO_DS
		if(irq_queue_count > 0)
			run_queued_irqs();
#endif
		//DEBUGPUTS("Before WaitForSingleObect\n");
		/*VIS_EnterCriticalSection(worker_queue_lock);
			temp_queue_len = queue_len;
		VIS_LeaveCriticalSection(worker_queue_lock);*/
		//DEBUGPUTS("After WaitForSingleObject\n");
		aworker = get_queue();
		//DEBUGPUTS("After get_queue()\n");
		//while(execute_active && aworker.worker_num < 0)//temp_queue_len == 0 && execute_active)
		//{
		//	VIS_WaitEvent(queue_add_event);
		//	aworker = get_queue();
			/*#if COMPILE_THREADS > 0
				#ifdef WIN32
					Sleep(0);
				#else
					sleep(0);
				#endif
			#endif
			VIS_EnterCriticalSection(worker_queue_lock);
				temp_queue_len = queue_len;
			VIS_LeaveCriticalSection(worker_queue_lock);*/
		//}
		
		if(aworker.worker_num >= 0)
		{
			//DEBUGPUTS("Before EnterCriticalSection\n");
			
		/*	VIS_EnterCriticalSection(worker_queue_lock);
				if(queue_len > 0)
				{
					DEBUGPUTS("SetEvent\n");
					VIS_SetEvent(queue_add_event);
				}
			VIS_LeaveCriticalSection(worker_queue_lock);*/
			DEBUGPRINTF( "\nExecuting: %s<%d>, Instance: %X\n", aworker.instance->def->implement_func->workerlist[aworker.worker_num].name,aworker.worker_num,aworker.instance);
			
			if(process_worker(aworker) == 0)
			{
				//worker_complete(aworker);
				cleanup_check(aworker);
				//DEBUGPUTS("After cleanup_check\n");
				
			}

		}
		VIS_PROFILE_END(PROF_WORKER_THREAD);
	}
	VIS_SetEvent(queue_add_event);
	return 0;
}

int set_comp_room(datum ** params, int room_index, queue_entry * entry, program * prog)
{
	int i;
	char * data;
	//DEBUGPRINTF("params[0]->ref_count: %d\n", params[0]->ref_count);
	params[0] = copy_datum(params[0], 0);
	data = ((char *)(params[0]->c.generic.data) + (int)params[0]->company->room_list[room_index].set_func);
	DEBUGPRINTF("Set comp room: c.generic.data = %X, +get_func = %X\n", params[0]->c.generic.data, data);
	//TODO: input conversion
	switch(params[0]->company->room_list[room_index].get_func_type)
	{
	case ROOM_BYTE:
		*data = params[1]->c.integers.num_a;
		release_ref(params[1]);
		break;
	case ROOM_SHORT:
		*((short *)data) = params[1]->c.integers.num_a;
		release_ref(params[1]);
		break;
	case ROOM_LONG:
		*((long *)data) = params[1]->c.integers.num_a;
		release_ref(params[1]);
		break;
	case ROOM_SINGLE:
		*((float *)data) = params[1]->c.real;
		release_ref(params[1]);
		break;
	case ROOM_DOUBLE:
		*((double *)data) = params[1]->c.real;
		release_ref(params[1]);
		break;
	case ROOM_VIS_REF:
		release_ref(*((datum **)data));
		*((datum **)data) = params[1];
		break;
	case ROOM_CSTRING:	//not implemented
	case ROOM_CSTRING_STRUCT:
	case ROOM_PSTRING:
	case ROOM_PSTRING_STRUCT:
	case ROOM_WORKER://not implemented
	case ROOM_VIS_OBJECT://not implemented
	default:
		release_ref(params[0]);
		release_ref(params[1]);
		params[0] = params[1] = NULL;
		puts("unimplemented company room type\n");
		break;
	}
	return 0;
}

int set_comp_room_by_name(datum ** company, char * name, int * room_index_ret, queue_entry * entry, program * prog)
{
	int i;
	for (i = 0; i < company[0]->company->num_rooms; ++i)
		if(!strcmp(name,company[0]->company->room_list[i].name))
		{
			if(room_index_ret)
				*room_index_ret = i;
			return set_comp_room(company, i, entry, prog);
		}
	if(room_index_ret)
		*room_index_ret = -1;
	printf("Error: Can't set field %s on object with blueprint %s\n", name, company[0]->company);
	return -1;
}

int get_comp_room(datum ** company, int room_index, queue_entry * entry, program * prog)
{
	int i;
	datum * out;
	queue_entry empty;
	char * data = ((char *)(company[0]->c.generic.data) + (int)company[0]->company->room_list[room_index].get_func);
	company[1] = NULL;
	DEBUGPRINTF("Get comp room: c.generic.data = %X, +get_func = %X\n", company[0]->c.generic.data, data);
	switch(company[0]->company->room_list[room_index].get_func_type)
	{
	case ROOM_BYTE:
		out = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, prog);
		out->c.integers.num_a = *data;
		break;
	case ROOM_SHORT:
		out = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, prog);
		out->c.integers.num_a = *((short *)data);
		break;
	case ROOM_LONG:
		out = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, prog);
		out->c.integers.num_a = *((long *)data);
		break;
	case ROOM_SINGLE:
		out = new_datum(BUILTIN_TYPE_REAL, 3, 0, prog);
		out->c.real = *((float *)data);
		break;
	case ROOM_DOUBLE:
		out = new_datum(BUILTIN_TYPE_REAL, 3, 0, prog);
		out->c.real = *((double *)data);
		break;
	case ROOM_CSTRING:
		data = *((char **)data);
	case ROOM_CSTRING_STRUCT:
		out = new_datum(BUILTIN_TYPE_STRING, 1, strlen(data)+1, prog);
		strcpy(out->c.generic.data, data);
		break;
	case ROOM_PSTRING:
		data = *((char **)data);
	case ROOM_PSTRING_STRUCT:
		out = new_datum(BUILTIN_TYPE_STRING, 1, *((unsigned char *)data), prog);
		memcpy(out->c.generic.data, data, *((unsigned char *)data));
		((char *)out->c.generic.data)[*((unsigned char *)data)] = '\0';
		break;
	case ROOM_VIS_REF:
		out = add_ref(*((datum **)data));
		if(!out) {
			company[1] = company[0];
			company[0] = NULL;
		}
		break;
	case ROOM_WORKER:
		if(entry)
			return execute_def((worker_def *)(company[0]->company->room_list[room_index].get_func), *entry, company, sub_callback);
		else
		{
			empty.instance = NULL;
			empty.worker_num = -1;
			return execute_def((worker_def *)(company[0]->company->room_list[room_index].get_func), empty, company, sub_callback);
		}
	case ROOM_VIS_OBJECT://not implemented
	default:
		out = NULL;
		puts("unimplemented company room type\n");
		break;
	}
	release_ref(company[0]);
	company[0] = out;
	return 0;
}

int get_comp_room_by_name(datum ** company, char * name, int * room_index_ret, queue_entry * entry, program * prog)
{
	int i;
	for (i = 0; i < company[0]->company->num_rooms; ++i)
		if(!strcmp(name,company[0]->company->room_list[i].name))
		{
			if(room_index_ret)
				*room_index_ret = i;
			return get_comp_room(company, i, entry, prog);
		}
	if(room_index_ret)
		*room_index_ret = -1;
	printf("Error: Can't get field %s from object with blueprint %s\n", name, company[0]->company);
	print_stack_trace(entry->instance);
	return -1;
}

datum * literal_string(char * value, int len, program * prog)
{
	char literalchar;
	BOOL literal;
	int i, bufpos, lenstr;
	datum * returnval;
	
	if(len < 0) {
		len = strlen(value);
	}
	
	literal = FALSE;
	lenstr = 0;
	for(i = 0; i < len; ++i)
		if(literal)
			literal = FALSE;
		else
		{
			++lenstr;
			if(value[i] == '\\')
				literal = TRUE;
		}
	//DEBUGPRINTF("Allocating %d bytes for string constant\n", lenstr+1);
	returnval = new_datum(BUILTIN_TYPE_STRING, 1, lenstr+1, prog);
	bufpos = 0;
	for(i = 0; i < len; ++i)
	{
		if(literal)
		{
			literal = FALSE;
			switch(value[i])
			{
			case 'n':	//newline
				literalchar = '\n';
				break;
			case 'r':	//carriage return
				literalchar = '\r';
				break;
			case 't':	// tab
				literalchar = '\t';
				break;
			case '0':	//NULL
				literalchar = '\0';
				break;
			default:
				literalchar = value[i];
				break;
			}
			((char *)returnval->c.generic.data)[bufpos++] = literalchar;
		}
		else
		{
			if(value[i] == '\\')
				literal = TRUE;
			else
			{
				((char *)returnval->c.generic.data)[bufpos++] = value[i];
			}
		}
	}
	//DEBUGPRINTF("bufpos: %d\n", bufpos);
	((char *)returnval->c.generic.data)[bufpos] = '\0';
	DEBUGPUTS("Constant Type: String\n");
	return returnval;
}

datum * get_constant(char * value, int len, program * prog)
{
	datum * params[2];
	datum * returnval;
	int i = 0,bufpos;
	int start;
	int lenstr;
	int leftcurly;
	int dotcount = 0;
	char literalchar;
	unsigned short const_type = ANY_TYPE;
	BOOL literal;
	if((len == 3 && memcmp(value, "Yes", len) == 0) || (len < 0 && strcmp(value, "Yes") == 0)) 
	{
		DEBUGPUTS("Constnat: Yes\n");
		returnval = new_datum(BUILTIN_TYPE_YESNO, 2, 0, prog);
		returnval->c.integers.num_a = 1;
		DEBUGPRINTF("Company: %s, integers.num_a: %d\n", returnval->company->name, returnval->c.integers.num_a);
		return returnval;
	} 
	else if((len == 2 && memcmp(value, "No", len) == 0) || (len < 0 && strcmp(value, "No") == 0)) 
	{
		DEBUGPUTS("Constant: No\n");
		returnval = new_datum(BUILTIN_TYPE_YESNO, 2, 0, prog);
		returnval->c.integers.num_a = 0;
		DEBUGPRINTF("Company: %s, integers.num_a: %d\n", returnval->company->name, returnval->c.integers.num_a);
		return returnval;
	}
	if(value[0] == '{')
	{
		DEBUGPUTS("Constant type: List");
		params[0] = create_list(prog);
		i = start = 1;
		literal = FALSE;
		leftcurly = 0;
		for(;value[i] != 0 && (len < 0 || i < len); ++i)
		{
			if(literal)
				literal = FALSE;
			else
			{
				if(value[i] == '\\')
					literal = TRUE;
				else if(value[i] == '}')
					if(leftcurly)
						--leftcurly;
					else
						break;
				else if(value[i] == '{')
					++leftcurly;
				else if(value[i] == ',' && !leftcurly)
				{
					params[1] = get_constant(value+start, i-start, prog);
					vis_list_append(params, NULL);
					start = i+1;
				}
			}
		}
		params[1]= get_constant(value+start, i-start, prog);
		vis_list_append(params, NULL);
		returnval = params[0];
	}
	else if(value[0] == '"')
	{
		if(len < 0) {
			len = strlen(value);
		}
		len -= 2;
		returnval = literal_string(value+1, len, prog);
		
	}
	else
	{
		while(value[i] != 0 && (len < 0 || i < len))
		{
			if(value[i] >= '0' && value[i] <= '9')
			{
				if(const_type == ANY_TYPE)
					const_type = BUILTIN_TYPE_WHOLE;
			}
			else if(value[i] == '.')
			{
				if(dotcount)
				{
					const_type = BUILTIN_TYPE_STRING;
				}
				else
				{
					++dotcount;
					if(const_type == BUILTIN_TYPE_WHOLE)
						const_type = BUILTIN_TYPE_REAL;
				}
			}
			else
			{
				//DEBUGPRINTF("Current character: %c resulted in String\n", value[i]);
				const_type = BUILTIN_TYPE_STRING;
				break;
			}
			++i;
		}
	
		if(const_type == BUILTIN_TYPE_WHOLE)
		{
			returnval = new_datum(const_type, 2, 0, prog);
			returnval->c.integers.num_a = atol(value);
			DEBUGPUTS("Constant Type: Whole Number\n");
		}
		else if(const_type == BUILTIN_TYPE_REAL)
		{
			returnval = new_datum(const_type, 3, 0, prog);
			returnval->c.real = atof(value);
			DEBUGPUTS("Constant Type: Real Number\n");
		}
		else
		{
			/* literal = FALSE;
			lenstr = 0;
			for(i = 0; (i < len || len < 0) && value[i] != 0; ++i)
				if(literal)
					literal = FALSE;
				else
				{
					++lenstr;
					if(value[i] == '\\')
						literal = TRUE;
				}
			DEBUGPRINTF("Allocating %d bytes for string constant\n", lenstr+1);
			returnval = new_datum(BUILTIN_TYPE_STRING, 1, lenstr+1, prog);
			bufpos = 0;
			for(i = 0; (i < len || len < 0) && value[i] != 0; ++i)
			{
				DEBUGPRINTF("bufpos: %d\n", bufpos);
				if(literal)
				{
					literal = FALSE;
					switch(value[i])
					{
					case 'n':	//newline
						literalchar = '\n';
						break;
					case 'r':	//carriage return
						literalchar = '\r';
						break;
					case 't':	// tab
						literalchar = '\t';
						break;
					case '0':	//NULL
						literalchar = '\0';
						break;
					default:
						literalchar = value[i];
						break;
					}
					((char *)returnval->c.generic.data)[bufpos++] = literalchar;
				}
				else
				{
					if(value[i] == '\\')
						literal = TRUE;
					else
					{
						((char *)returnval->c.generic.data)[bufpos++] = value[i];
					}
				}
			}
			DEBUGPRINTF("bufpos: %d\n", bufpos);
			((char *)returnval->c.generic.data)[bufpos] = '\0';
			DEBUGPUTS("Constant Type: String\n"); */
			returnval = literal_string(value, len, prog);
		}
	}
	return returnval;
}

int execute_def(worker_def * process_def, queue_entry worker_entry, datum ** params, instance_callback callback)
{
	return execute_def_type(process_def, worker_entry, params, callback, NULL, WORKER);
}
int execute_def_data(worker_def * process_def, queue_entry worker_entry, datum ** params, instance_callback callback, void * data)
{
	return execute_def_type(process_def, worker_entry, params, callback, data, WORKER);
}

int execute_def_type(worker_def * process_def, queue_entry worker_entry, datum ** params, instance_callback callback, void * data, int type)
{
	int returnval, i;
	worker_instance * stack_instance;
	worker_def *temp_def, *converter;
	worker_def *parent_def = worker_entry.instance->def;
	unsigned short magic_cache_type;
	#ifdef USER_PROFILE
		LARGE_INTEGER start, end, duration;
	#endif
	VIS_PROFILE_START(PROF_PREP_MAGIC);
	if((process_def->type & TYPE_MASK) == MAGIC_TYPE)
	{
		DEBUGPRINTF( "Magic method: %s\n", process_def->name);
		if(!params || !params[0])
		{
			ERRORPRINTF("Error: null first parmeter or null parameter array for worker %s, params: %X, params[0]: %X\n", process_def->name, params, params[0]);
			print_stack_trace(worker_entry.instance);
			execute_active = FALSE;
			return -1;
		}
		VIS_EnterCriticalSection(parent_def->implement_func->workerlist[worker_entry.worker_num].lock);
			temp_def = parent_def->implement_func->workerlist[worker_entry.worker_num].magic_cache_implement;
			magic_cache_type = parent_def->implement_func->workerlist[worker_entry.worker_num].magic_cache_type;
		VIS_LeaveCriticalSection(parent_def->implement_func->workerlist[worker_entry.worker_num].lock);
		if(!temp_def || magic_cache_type != params[0]->company->type_id)
		{
			DEBUGPRINTF("Finding method %s with %d inputs for type %s(%d)\n", process_def->name, process_def->num_inputs, params[0]->company->name, params[0]->company->type_id);
			temp_def = find_method(params[0]->company->type_id,process_def->name, process_def->num_inputs, process_def->program);
			if(!temp_def) 
			{
				for(i = 1; i < process_def->program->num_companies; ++i)
				{
					temp_def = find_method(i,process_def->name, process_def->num_inputs, process_def->program);
					if(temp_def)
					{
						converter = find_converter_method(temp_def->input_types[0], params[0]->company->type_id, process_def->program);
						if(converter)
						{
							((worker_impl)converter->implement_func)(params, &worker_entry);
							break;
						}
						else
						{
							//DEBUGPRINTF("Error: Needed conversion from %s to %s for input %d of %s\n", params[0]->company->name, process_def->program->companylist[temp_def->input_types[0]].name, 0, temp_def->name);
							//printf("Warning: Needed conversion from %s to %s for input %d of %s for loose method call\n", params[0]->company->name, process_def->program->companylist[temp_def->input_types[0]].name, 0, temp_def->name);
							temp_def = NULL;
						}
					}
				}
			}
			if(temp_def)
			{
				VIS_EnterCriticalSection(parent_def->implement_func->workerlist[worker_entry.worker_num].lock);
					parent_def->implement_func->workerlist[worker_entry.worker_num].magic_cache_implement = temp_def;
					parent_def->implement_func->workerlist[worker_entry.worker_num].magic_cache_type = temp_def->input_types[0];
				VIS_LeaveCriticalSection(parent_def->implement_func->workerlist[worker_entry.worker_num].lock);
			}
			else
			{
				ERRORPRINTF("Error: Company %s doesn't implement worker %s. It implements the following:\n", params[0]->company->name, process_def->name);
				for(i = 0; i < params[0]->company->num_methods; ++i)
				{
					ERRORPRINTF("%s\n", params[0]->company->methodlist[i]->name);
				}
				print_stack_trace(worker_entry.instance);
			}
		}
		process_def = temp_def;
	}
	VIS_PROFILE_END(PROF_PREP_MAGIC);
	if(!process_def)
	{
		//DEBUGPUTS("Invalid def\n");
		VIS_PROFILE_END(PROF_EXECUTE_WORKER);
		execute_active = FALSE;
		return -2;
	}
	
	VIS_PROFILE_START(PROF_CONVERT_INPUTS);
	for(i = 0; i < process_def->num_inputs; ++i)
	{
		DEBUGPRINTF("params[%d] = %X\n", i, params[i]);
		if(process_def->input_types[i] != ANY_TYPE && process_def->input_types[i] != params[i]->company->type_id)
		{
			DEBUGPRINTF("Input %d needs conversion from %d to %d\n", i, params[i]->company->type_id, process_def->input_types[i]);
			converter = find_converter_method(process_def->input_types[i], params[i]->company->type_id, process_def->program);
			if(!converter)
			{
				if(worker_entry.instance) {
					ERRORPRINTF("Error: Needed conversion from %s to %s for input %d of %s in worker %s\n", params[i]->company->name, process_def->program->companylist[process_def->input_types[i]].name, i, process_def->name, worker_entry.instance->def->name);
					print_stack_trace(worker_entry.instance);
				} else {
					DEBUGPRINTF("Error: Needed conversion from %s to %s for input %d of %s\n", params[i]->company->name, process_def->program->companylist[process_def->input_types[i]].name, i, process_def->name);
					printf("Error: Needed conversion from %s to %s for input %d of %s", params[i]->company->name, process_def->program->companylist[process_def->input_types[i]].name, i, process_def->name);
				}
				execute_active = FALSE;
				VIS_PROFILE_END(PROF_PROCESS_WORKER);
				return -3;
			}
			((worker_impl)(converter->implement_func))(params+i, &worker_entry);
		}
	}
	VIS_PROFILE_END(PROF_CONVERT_INPUTS);
			
	if(process_def->type & USER_FLAG)
	{
		VIS_PROFILE_START(PROF_EXECUTE_CUSTOM);
		//
		init_custom_worker_type(worker_entry.worker_num, worker_entry.instance, process_def, callback, data, params, type);
		VIS_PROFILE_END(PROF_EXECUTE_CUSTOM);
		VIS_PROFILE_END(PROF_PROCESS_WORKER);
		VIS_PROFILE_END(PROF_EXECUTE_WORKER);
		return 1;
	}
	else
	{
		VIS_PROFILE_START(PROF_EXECUTE_BUILTIN);
		//DEBUGPRINTF("%s: before deflist[%d].implement_func: %X. vis_append: %X vis_print: %X\n",def->implement_func->workerlist[aworker].name, def->implement_func->workerlist[aworker].value_index, (int)deflist[def->implement_func->workerlist[aworker].value_index].implement_func, (int)vis_append, (int)vis_print);
		#ifdef USER_PROFILE
		QueryPerformanceCounter(&start);
		#endif
		returnval = ((worker_impl)(process_def->implement_func))(params, &worker_entry);
		#ifdef USER_PROFILE
		if(!returnval)
		{
			QueryPerformanceCounter(&end);
			duration.QuadPart = end.QuadPart - start.QuadPart;
			VIS_EnterCriticalSection(process_def->lock);
				process_def->total.QuadPart += duration.QuadPart;
				++process_def->count;
				if(duration.QuadPart > process_def->worst.QuadPart)
					process_def->worst.QuadPart = duration.QuadPart;
			VIS_LeaveCriticalSection(process_def->lock);
		}
		#endif
		//DEBUGPUTS("Builtin worker returned\n");
		VIS_PROFILE_END(PROF_EXECUTE_BUILTIN);
		return returnval;
	}
}

void wait_callback(worker_instance * caller_instance, int caller_workerenum, worker_instance * done_instance, void * data)
{
	int i;
	def_done * done = (def_done *)data;
	//DEBUGPUTS("begin wait_callback\n");
	for(i = 0; i < done_instance->def->num_outputs; ++i)
		done->params[i] = NULL;
	for(i = 0; i < done_instance->def->implement_func->num_workers; ++i)
	{
		if(done_instance->def->implement_func->workerlist[i].type == 4)
		{
			if(!(done->params[done_instance->def->implement_func->workerlist[i].io_num]))
			{
				done->params[done_instance->def->implement_func->workerlist[i].io_num] = done_instance->workerlist[i].value;
				done_instance->workerlist[i].value = NULL;
			}
		}
	}
	//DEBUGPUTS("Before EnterCritical\n");
	VIS_EnterCriticalSection(done->lock);
		done->done_flag = TRUE;
	VIS_LeaveCriticalSection(done->lock);
	//DEBUGPUTS("After EnterCritical\n");
}


BOOL execute_def_wait(worker_def * def, datum ** params)
{
	int val;
	def_done done;
	queue_entry entry;
	entry.worker_num = 0;
	entry.instance = NULL;
	VIS_InitializeCriticalSection(done.lock);
	done.done_flag = FALSE;
	done.params = params;
	val = execute_def_data(def, entry, params, wait_callback, &done);
	if(val == 0)
		return TRUE;
	else if (val < 0)
		return FALSE;
	while(1)
	{
		VIS_EnterCriticalSection(done.lock);
			if(done.done_flag)
			{
				VIS_DeleteCriticalSection(done.lock);
				break;
			}
		VIS_LeaveCriticalSection(done.lock);
#if COMPILE_THREADS > 1
	#ifdef WIN32
		Sleep(0);
	#else
		sleep(0);
	#endif
#endif
	}
	return TRUE;
}

int process_worker(queue_entry worker_entry)
{
	//datum * paramstore[32];
	datum ** params;// = paramstore;
	int i, j, start=0;
	global_store * store;
	char * varname;
	datum * varname_dat;
	datum * tempvalindex, *todelete;
	int got_params=0;
	int aworker = worker_entry.worker_num;
	worker_instance * instance = worker_entry.instance;
	worker_def * def = instance->def;
	worker_def * process_def;
	worker_def * temp_def;
	worker_def * converter;
	int returnval = 0;
	short const_type;
	char * last;
	
	VIS_PROFILE_START(PROF_PROCESS_WORKER);

	DEBUGPRINTF( "Processing worker %d with %d inputs and %d outputs\n", aworker,def->implement_func->workerlist[aworker].num_inputs, def->implement_func->workerlist[aworker].num_outputs);
	/*VIS_EnterCriticalSection(instance->workerlist[aworker].worker_lock);
		for(i = 0; i < def->implement_func->workerlist[aworker].num_inputs; ++i)
		{
			params[i] = instance->workerlist[aworker].params[i+1];
			DEBUGPRINTF("params[%d] = %X\n", i, params[i]);
			instance->workerlist[aworker].params[i+1] = NULL;
		}*/
		if(def->implement_func->workerlist[aworker].null_input)
		{
			//DEBUGPUTS("About to call release_ref\n");
			release_ref(instance->workerlist[aworker].params[0]);
			instance->workerlist[aworker].params[0] = NULL;
		}
	//VIS_LeaveCriticalSection(instance->workerlist[aworker].worker_lock);
	//DEBUGPRINTF("Param check complete. returnval: %d, start: %d\n", returnval, start);
	params = instance->workerlist[aworker].params+1;
	
	if(def->implement_func->workerlist[aworker].type == WORKER || def->implement_func->workerlist[aworker].type == TAIL_RECURSE || def->implement_func->workerlist[aworker].type == TAIL_CALL)//Worker
	{
		VIS_PROFILE_START(PROF_EXECUTE_WORKER);
		//DEBUGPUTS("Worker\n");
		process_def = (worker_def *)(def->implement_func->workerlist[aworker].value_index);
		//DEBUGPUTS("Got process_def\n");
		DEBUGPRINTF("process_def->type: %X, type & TYPE_MASK: %X\n", process_def->type, (process_def->type & TYPE_MASK));
		
		returnval = execute_def_type(process_def, worker_entry, params, sub_callback, NULL, def->implement_func->workerlist[aworker].type);
		DEBUGPRINTF("execute_def returned %d\n", returnval);
		if(returnval != 0)
		{
			VIS_PROFILE_END(PROF_PROCESS_WORKER);
			VIS_PROFILE_END(PROF_EXECUTE_WORKER);
			return returnval;
		}
		//DEBUGPRINTF("params[0] after execute_def: %X\n", params[0]);
		
		//DEBUGPUTS("Before process_outputs\n");
		
		process_outputs(params, aworker, instance);
		//DEBUGPUTS("After process_outputs\n");
		
		VIS_PROFILE_END(PROF_EXECUTE_WORKER);
		
	}
	else if(def->implement_func->workerlist[aworker].type == GET_GLOBAL)
	{
		varname = def->implement_func->workerlist[aworker].name + def->implement_func->workerlist[aworker].io_num;
		varname_dat = make_string(varname, -1, def->program);
		if(def->implement_func->workerlist[aworker].value_index < 0)
		{
			for(i = 0; i < instance->trans->num_stores; ++i)
			{
				VIS_EnterCriticalSection(instance->trans->stores[i].lock);
					params[0] = add_ref(instance->trans->stores[i].instance_data);
				VIS_LeaveCriticalSection(instance->trans->stores[i].lock);
				params[1] = add_ref(varname_dat);
				vis_dict_index(params, NULL);
				
				if(params[0])
				{
					def->implement_func->workerlist[aworker].value_index = i;
					break;
				}
			}
			if(def->implement_func->workerlist[aworker].value_index < 0)
			{
				printf("Error: Variable %s not found in any global stores used by worker %s\n", varname, def->name);
				DEBUGPRINTF("Error: Variable %s not found in any global stores used by worker %s\n", varname, def->name);
				execute_active = FALSE;
				return -1;
			}
		}
		else
		{
			VIS_EnterCriticalSection(instance->trans->stores[(int)def->implement_func->workerlist[aworker].value_index].lock);
				params[0] = add_ref(instance->trans->stores[(int)def->implement_func->workerlist[aworker].value_index].instance_data);
			VIS_LeaveCriticalSection(instance->trans->stores[(int)def->implement_func->workerlist[aworker].value_index].lock);
			params[1] = varname_dat;
			vis_dict_index(params, NULL);
			if(!params[0])
			{
				printf("Error: Global variable %s not found in worker %s\n", def->implement_func->workerlist[aworker].name, def->name);
				DEBUGPRINTF("Error: Global variable %s not found in worker %s\n", def->implement_func->workerlist[aworker].name, def->name);
				execute_active = FALSE;
				return -1;
			}
		}
		process_outputs(params, aworker, instance);
		
			
	}
	else if(def->implement_func->workerlist[aworker].type == SET_GLOBAL)
	{
		varname = def->implement_func->workerlist[aworker].name + def->implement_func->workerlist[aworker].io_num;
		varname_dat = make_string(varname, -1, def->program);
		params[2] = params[0];
		params[1] = varname_dat;
		VIS_EnterCriticalSection(instance->trans->stores[(int)def->implement_func->workerlist[aworker].value_index].lock);
			//no add_ref here because we'll be replacing instance_data with the result of vis_dict set
			params[0] = instance->trans->stores[(int)def->implement_func->workerlist[aworker].value_index].instance_data;
			vis_dict_set(params, NULL);
			instance->trans->stores[(int)def->implement_func->workerlist[aworker].value_index].instance_data = params[0];
		VIS_LeaveCriticalSection(instance->trans->stores[(int)def->implement_func->workerlist[aworker].value_index].lock);
		//no outputs to process
	}
	else if(def->implement_func->workerlist[aworker].type == GET_COMP)
	{
		returnval = get_comp_room_by_name(params, def->implement_func->workerlist[aworker].name, NULL, &worker_entry, def->program);
		if(returnval)
			return returnval;
		process_outputs(params, aworker, instance);
	}
	else if(def->implement_func->workerlist[aworker].type == SET_COMP)
	{
		returnval = set_comp_room_by_name(params, def->implement_func->workerlist[aworker].name, NULL, &worker_entry, def->program);
		if(returnval)
			return returnval;
		process_outputs(params, aworker, instance);
	}
	else//Variable
	{
		VIS_PROFILE_START(PROF_EXECUTE_OTHER);
		if(def->implement_func->workerlist[aworker].num_inputs > 0 || def->implement_func->workerlist[aworker].type == INPUT) //Is this a Room or a constant?
		{
			todelete = NULL;
			VIS_EnterCriticalSection(instance->workerlist[aworker].worker_lock);
				if(def->implement_func->workerlist[aworker].type == OUTPUT)
				{
					todelete = instance->workerlist[aworker].value;
					instance->workerlist[aworker].value = params[0];
					DEBUGPRINTF("Setting room/output at pos %d to %X in instance %X\n", aworker, params[0], instance);
				}
				//tempvalindex = instance->workerlist[aworker].value;
			VIS_LeaveCriticalSection(instance->workerlist[aworker].worker_lock);
			if(def->implement_func->workerlist[aworker].type == INPUT)
			{
				params[0] = instance->workerlist[aworker].value;
				instance->workerlist[aworker].value = NULL;
			}
			if(todelete)
				release_ref(todelete);
			if(def->implement_func->workerlist[aworker].num_outputs)
			{
				//add_ref(tempvalindex);
				process_outputs(params/*&tempvalindex*/, aworker, instance);
			}
			
		}
		else
		{
			//Hmm, do I potentially need another lock here?
			/*if(!(instance->def->implement_func->workerlist[aworker].value_index))
			{
				instance->def->implement_func->workerlist[aworker].value_index = (int)(tempvalindex=get_constant(def->implement_func->workerlist[aworker].name,-1));//(int)tempvalindex;
			}
			else*/
				tempvalindex = (datum *)instance->def->implement_func->workerlist[aworker].value_index;
			add_ref(tempvalindex);
			process_outputs(&tempvalindex, aworker, instance);
		}
		VIS_PROFILE_END(PROF_EXECUTE_OTHER);
	}
	VIS_PROFILE_END(PROF_PROCESS_WORKER);
	return returnval;
}

#define OPT_RESULT		0
#define OPT_CUST_RESULT	0x10000000
#define OPT_CONST		0x20000000
#define OPT_INPUT		0x30000000

int find_input_worker(custom_worker * cust, int aworker, int input, int *ret_output)
{
	int o, p, wire_count;
	int out_worker;
	o = cust->workerlist[aworker].wire_up_lookup;
	wire_count = 0;
	while(cust->wirelist[p=cust->workers_to_wires_up[o]].end_worker == aworker && p >= 0)
	{
		if(cust->wirelist[p].input_num == input)
		{
			++wire_count;
			out_worker = cust->wirelist[p].start_worker;
			DEBUGPRINTF("Input %d attached to %s(%d)\n", input, cust->workerlist[out_worker].name, out_worker);
			if(ret_output)
				*ret_output = cust->wirelist[p].output_num;
		}
		++o;
	}
	DEBUGPRINTF("wire_count: %d\n", wire_count);
	if(wire_count == 1)
		return out_worker;
	return -1;
}

int make_input_code(custom_worker * cust, BOOL * in_opt, int * pos_in_opt, int source_worker, int output_num, int index, opt_entry * opts, int * branch_flags, opt_entry ** branch_refs, int input_num, program * prog)
{
	/*if(in_opt[source_worker])
	{
		if(prog->deflist[cust->workerlist[source_worker].value_index].type & USER_FLAG)
		{
			return OPT_CUST_RESULT | ((pos_in_opt[source_worker] & 0xFFFF) << 8) | (output_num & 0xFF);
		}
		else
		{
			if(strcmp(prog->deflist[cust->workerlist[source_worker].value_index].name, "If") == 0)
			{
				if(output_num == 0)
				{
					branch_flags[index] = 1;
					if(opts[pos_in_opt[source_worker]].branch1 <= index)
						opts[pos_in_opt[source_worker]].branch1 = index+1;
				}
				else
				{
					branch_flags[index] = 2;
					if(opts[pos_in_opt[source_worker]].branch2 <= index)
						opts[pos_in_opt[source_worker]].branch2 = index+1;
				}
				branch_refs[index] = opts + pos_in_opt[source_worker];
			}
			else if(branch_flags[pos_in_opt[source_worker]])
			{
				if(branch_flags[pos_in_opt[source_worker]] == 1)
				{
					branch_refs[pos_in_opt[source_worker]]->branch1 = index + 1;
					branch_flags[index] = 1;
				}
				else
				{
					branch_refs[pos_in_opt[source_worker]]->branch1 = index + 2;
					branch_flags[index] = 2;
				}
				branch_refs[index] = branch_refs[pos_in_opt[source_worker]];
			}
			else
				branch_flags[index] = 0;
			if(input_num >= 0)
				++opts[pos_in_opt[source_worker]].output_refs[output_num];
			DEBUGPRINTF("OPT_RESULT: opt_num: %d, output_num: %d\n", pos_in_opt[source_worker], output_num);
			return OPT_RESULT | ((pos_in_opt[source_worker] & 0xFFFF) << 8) | (output_num & 0xFF);
		}
	}
	else if(cust->workerlist[source_worker].type == CONSTANT)
	{
		branch_flags[index] = 0;
		DEBUGPRINTF("OPT_CONST: %d\n", source_worker);
		return OPT_CONST | source_worker;
	}
	else if(cust->workerlist[source_worker].type == INPUT)
	{
		branch_flags[index] = 0;
		DEBUGPRINTF("OPT_INPUT: %d\n", cust->workerlist[source_worker].io_num);
		return OPT_INPUT | cust->workerlist[source_worker].io_num;
	}*/
	return -1;
}

void optimize(worker_def * def)
{
	/*
	int i,j,k,m,o,p;
	int * const_in;
	int num_entries = 0;
	int aworker;
	int adjust;
	int source_worker;
	int source_output;
	int source_null;
	int null_output;
	int wire_count;
	int * input_data;
	int current_null;
	int cust_result_count;
	int new_start;
	custom_worker * cust = def->implement_func;
	int start_current, end_current, new_current;
	worker_def * deflist = def->program->deflist;
	opt_entry * output = malloc(sizeof(opt_entry) * def->implement_func->num_workers);
	BOOL * in_opt = malloc(sizeof(BOOL) * cust->num_workers);
	int * branch_flags = malloc(sizeof(int) * cust->num_workers);
	opt_entry ** branch_refs = malloc(sizeof(int) * cust->num_workers);
	//BOOL * real_in_opt = malloc(sizeof(BOOL) * cust->num_workers);
	int * pos_in_opt = malloc(sizeof(int) * cust->num_workers);
	DEBUGPRINTF("deflist: %X\n", deflist);
	for(i = 0; i < cust->num_workers; ++i)
	{
		branch_flags[i] = 0;
		DEBUGPRINTF("%d: No input pass\n", i);
		DEBUGPRINTF("Examining: %s\n", cust->workerlist[i].name);
		if(cust->workerlist[i].num_inputs == 0 && !cust->workerlist[i].null_input && cust->workerlist[i].type == WORKER)
		{
			output[num_entries].def = deflist + cust->workerlist[i].value_index;
			DEBUGPRINTF("Set output[%d].def = %X\n", num_entries, output[num_entries].def);
			DEBUGPRINTF("opt: %d is %s\n\n", num_entries, cust->workerlist[i].name);
			output[num_entries].original_pos = i;
			output[num_entries].input_data = NULL;
			if(cust->workerlist[i].num_outputs)
			{
				output[num_entries].output_refs = malloc(sizeof(int)*cust->workerlist[i].num_outputs);
				for(j = 0; j < cust->workerlist[i].num_outputs; ++j)
					output[num_entries].output_refs[j] = 0;
			}
			else
				output[num_entries].output_refs = NULL;
			output[num_entries].branch1 = output[num_entries].branch2 = -1;
			//if(!(deflist[cust->workerlist[i].value_index].type & USER_FLAG))
			//{
				in_opt[i] = TRUE;
				pos_in_opt[i] = num_entries;
			//}
			//real_in_opt[i] = TRUE;
			++num_entries;
		}
		else
		{
			//real_in_opt[i] = FALSE;
			in_opt[i] = FALSE;
		}
	}
	start_current = num_entries;
	for(i = 0; i < cust->num_workers; ++i)
	{
		DEBUGPRINTF("%d: Second pass\n", i);
		if(cust->workerlist[i].num_inputs == 0  && !cust->workerlist[i].null_input)
		{
			j = cust->workerlist[i].wire_down_lookup;
			while(cust->wirelist[k=cust->workers_to_wires_down[j]].start_worker == i && k >= 0)
			{
				aworker = cust->wirelist[k].end_worker;
				if(!in_opt[aworker])
				{
					DEBUGPRINTF("Examining: %s(%d)\n", cust->workerlist[aworker].name, aworker);
					if(cust->workerlist[i].null_input)
						adjust = 1;
					else
						adjust = 0;
					input_data = malloc(sizeof(int)* (cust->workerlist[aworker].num_inputs+adjust));
					for(m = (0-adjust); m < cust->workerlist[aworker].num_inputs; ++m)
					{
						DEBUGPRINTF("Input: %d\n", m);
						source_worker = find_input_worker(cust, aworker, m, &source_output);
						DEBUGPRINTF("source_worker: %d\n", source_worker);
						if(source_worker == -1)
							break;
						source_worker = make_input_code(cust, in_opt, pos_in_opt, source_worker, source_output, num_entries, output, branch_flags, branch_refs, m, def->program);
						DEBUGPRINTF("input code: %X\n", source_worker);
						if(source_worker == -1)
							break;
						input_data[m+adjust] = source_worker;
						if(source_worker == -1)
							break;
					}
					if(source_worker == -1)
						free(input_data);
					else
					{
						if(cust->workerlist[aworker].type == OUTPUT)
							output[num_entries].def = NULL;
						else
							output[num_entries].def = deflist + cust->workerlist[aworker].value_index;
						DEBUGPRINTF("Set output[%d].def = %X\n", num_entries, output[num_entries].def);
						DEBUGPRINTF("opt: %d is %s\n\n", num_entries, cust->workerlist[aworker].name);
						output[num_entries].original_pos = aworker;
						output[num_entries].input_data = input_data;
						output[num_entries].null_inputs = adjust;
						output[num_entries].branch1 = output[num_entries].branch2 = -1;
						if(cust->workerlist[aworker].num_outputs)
						{
							output[num_entries].output_refs = malloc(sizeof(int)*cust->workerlist[aworker].num_outputs);
							for(m = 0; m < cust->workerlist[aworker].num_outputs; ++m)
								output[num_entries].output_refs[m] = 0;
						}
						else
							output[num_entries].output_refs = NULL;
						//if(cust->workerlist[aworker].type != OUTPUT && !(deflist[cust->workerlist[aworker].value_index].type & USER_FLAG))
						//{
							in_opt[aworker] = TRUE;
							pos_in_opt[aworker] = num_entries;
						//}
						//real_in_opt[aworker] = TRUE;
						++num_entries;
						
					}
				}
				++j;
			}
		}
	}
	DEBUGPUTS("Before While\n");
	end_current = num_entries;
	while(start_current != end_current)
	{
		DEBUGPRINTF("start_current: %d, end_current: %d\n", start_current, end_current);
		new_start = num_entries;
		for(i = start_current; i < end_current; ++i)
		{
			DEBUGPRINTF("opt: %d, def: %X, name: %s\n", i, output[i].def, cust->workerlist[output[i].original_pos].name);
			j = cust->workerlist[output[i].original_pos].wire_down_lookup;
			DEBUGPRINTF("wire_down_lookup: %d\n", j);
			while(cust->wirelist[k=cust->workers_to_wires_down[j]].start_worker == output[i].original_pos && k >= 0)
			{
				DEBUGPRINTF("Wire %d is attached to worker %d output %d and worker %d input %d\n", k, cust->wirelist[k].start_worker, cust->wirelist[k].output_num, cust->wirelist[k].end_worker, cust->wirelist[k].input_num);
				aworker = cust->wirelist[k].end_worker;
				//FIXME: Only works if constant/input attached to only one destination
				if(cust->workerlist[aworker].type == CONSTANT || cust->workerlist[aworker].type == INPUT)
				{
					DEBUGPRINTF("Worker is of type %d, ", cust->workerlist[aworker].type);
					aworker = cust->wirelist[cust->workers_to_wires_down[cust->workerlist[aworker].wire_down_lookup]].end_worker;
					DEBUGPRINTF("reruting to worker %d\n", aworker);
				}
				if(!in_opt[aworker])
				{
					DEBUGPRINTF("Examining: %s(%d)\n", cust->workerlist[aworker].name, aworker);
					if(cust->workerlist[i].null_input)
						adjust = 1;
					else
						adjust = 0;
					for(m = (0-adjust); m < cust->workerlist[aworker].num_inputs; ++m)
					{	
						source_worker = find_input_worker(cust, aworker, m, &source_output);
						if(source_worker == -1)
							break;
						if(cust->workerlist[source_worker].null_input && cust->workerlist[source_worker].type != WORKER)
							++adjust;
					}
					if(source_worker != -1)
					{
						current_null = 0;
						input_data = malloc(sizeof(int)* (cust->workerlist[aworker].num_inputs+adjust));
						cust_result_count = 0;
						for(m = (cust->workerlist[i].null_input ? -1 : 0); m < cust->workerlist[aworker].num_inputs; ++m)
						{
							DEBUGPRINTF("Input: %d\n", m);
							source_worker = find_input_worker(cust, aworker, m, &source_output);
							if(cust->workerlist[source_worker].null_input && cust->workerlist[source_worker].type != WORKER)
							{
								source_null = find_input_worker(cust, source_worker, -1, &null_output);
								if(source_null == -1)
								{
									source_worker = -1;
									break;
								}
								source_null = make_input_code(cust, in_opt, pos_in_opt, source_null, null_output, num_entries, output, branch_flags, branch_refs,-2, def->program);
								if((source_null & 0xF0000000) == OPT_CUST_RESULT)
									++cust_result_count;
								if(source_null == -1)
								{
									source_worker = -1;
									break;
								}
								input_data[current_null++] = source_null;
							}
							DEBUGPRINTF("source_worker: %d\n", source_worker);
							source_worker = make_input_code(cust, in_opt, pos_in_opt, source_worker, source_output, num_entries, output, branch_flags, branch_refs, m, def->program);
							if((source_worker & 0xF0000000) == OPT_CUST_RESULT)
									++cust_result_count;
							DEBUGPRINTF("input code: %d\n", source_worker);
							if(cust_result_count >= (cust->workerlist[aworker].num_inputs + adjust))
								source_worker = -1;
							if(source_worker == -1)
								break;
							input_data[m+adjust] = source_worker;
						}
						if(source_worker == -1)
							free(input_data);
						else
						{
							if(cust->workerlist[aworker].type == OUTPUT)
								output[num_entries].def = NULL;
							else
								output[num_entries].def = deflist + cust->workerlist[aworker].value_index;
							DEBUGPRINTF("Set output[%d].def = %X\n", num_entries, output[num_entries].def);
							DEBUGPRINTF("opt: %d is %s\n\n", num_entries, cust->workerlist[aworker].name);
							output[num_entries].original_pos = aworker;
							output[num_entries].input_data = input_data;
							output[num_entries].null_inputs = adjust;
							output[num_entries].branch1 = output[num_entries].branch2 = -1;
							if(cust->workerlist[aworker].num_outputs)
							{
								output[num_entries].output_refs = malloc(sizeof(int)*cust->workerlist[aworker].num_outputs);
								for(m = 0; m < cust->workerlist[aworker].num_outputs; ++m)
									output[num_entries].output_refs[m] = 0;
							}
							else
								output[num_entries].output_refs = NULL;
							//if(cust->workerlist[aworker].type != OUTPUT && !(deflist[cust->workerlist[aworker].value_index].type & USER_FLAG))
							//{
								in_opt[aworker] = TRUE;
								pos_in_opt[aworker] = num_entries;
							//}
							//real_in_opt[aworker] = TRUE;
							++num_entries;
							
						}
					}
				}
				++j;
			}
		}
		start_current = new_start;
		end_current = num_entries;
	}
	def->optimized = output;
	def->opt_count = num_entries;
	DEBUGPUTS("optimize done\n\n\n");
	*/
}


void run_optimized(worker_instance * instance, datum ** params)
{
	int i = 0,j,k;
	unsigned short output, opt_num;
	datum * this_params[32];
	queue_entry entry;
	datum * val;
	BOOL skip;
	BOOL partial_flag;
	BOOL continue_flag;
	int count;
	int ready;
	int jump_from = -1;
	int jump_to = -1;
	int tmp, addnum;
	opt_entry * exec_list = instance->def->optimized;
	datum ** results = instance->opt_results;//malloc(sizeof(datum *) * instance->def->opt_count * 32);
	VIS_PROFILE_START(PROF_RUN_OPT);
	entry.instance = instance;
	for(i = 0; i < instance->def->opt_count; ++i)
	{
		VIS_PROFILE_START(PROF_OPT_LOOP);
		skip = FALSE;
		partial_flag = FALSE;
		continue_flag = FALSE;
		DEBUGPRINTF("\nPeparing exec_list[%d]\n", i);
		if(exec_list[i].def)
		{
			DEBUGPRINTF("Name: %s\n", exec_list[i].def->name);
			count = exec_list[i].def->num_inputs;
		}
		else
			count = 1;
		count += exec_list[i].null_inputs;
		//DEBUGPRINTF("Input count: %d\n", count);
		if(count && !exec_list[i].input_data)
			puts("Runtime Error: input data is NULL\n");
		//DEBUGPRINTF("input_data: %X\n", exec_list[i].input_data);
		VIS_PROFILE_START(PROF_OPT_PREP_INPUT);
		for(j = 0; j < count; ++j)
		{
			val = NULL;
			continue_flag = FALSE;
			switch(exec_list[i].input_data[j] & 0xF0000000)
			{
				case OPT_RESULT:
					output = exec_list[i].input_data[j] & 0xFF;
					opt_num = (exec_list[i].input_data[j] >> 8)& 0xFFFF;
					DEBUGPRINTF("OPT_RESULT for input %d, opt_num: %d, output: %d\n", j, opt_num, output);
					val = results[(opt_num * 32) | output];
					break;
				case OPT_CUST_RESULT:
					val = NULL;
					partial_flag = TRUE;
					continue_flag = TRUE;
					break;
				case OPT_INPUT:
					DEBUGPRINTF("OPT_INPUT for input %d\n", j);
					val = add_ref(params[exec_list[i].input_data[j] & 0xFF]);
					break;
				case OPT_CONST:
					DEBUGPRINTF("OPT_CONST for input %d\n", j);
					val = add_ref((datum *)(instance->def->implement_func->workerlist[exec_list[i].input_data[j] & 0xFFFFFF].value_index));
					break;
				default:
					puts("Runtime Error: Invalid bytecode\n");
					val = NULL;
					break;
			}
			if(!val && !continue_flag)
			{
				for(k = exec_list[i].null_inputs; k < j; ++k)
					release_ref(this_params[k]);
				skip = TRUE;
				break;
			}
			DEBUGPRINTF("this_params[%d] = %X\n", j, val);
			if(j >= exec_list[i].null_inputs)
				if(val)
					this_params[j] = /*add_ref(*/val/*)*/;
				else
					this_params[j] = NULL;

		}
		VIS_PROFILE_END(PROF_OPT_PREP_INPUT);
		if(!skip)
		{
			if(partial_flag)
			{
				VIS_PROFILE_START(PROF_PARTIAL_EXEC);
				ready = 0;
				for(j = exec_list[i].null_inputs; j < count; ++j)
					if(this_params[j])
					{
						instance->workerlist[exec_list[i].original_pos].params[j-exec_list[i].null_inputs+1] = this_params[j];
						++ready;
					}
				if(instance->def->implement_func->workerlist[exec_list[i].original_pos].null_input && this_params[exec_list[i].null_inputs-1])
					++ready;
				DEBUGPRINTF("ready: %d\n", ready);
				skip = TRUE;
				VIS_EnterCriticalSection(instance->workerlist[exec_list[i].original_pos].worker_lock);
					instance->workerlist[exec_list[i].original_pos].ready_count += ready;
					if(instance->workerlist[exec_list[i].original_pos].ready_count >= (exec_list[i].def->num_inputs + (instance->def->implement_func->workerlist[exec_list[i].original_pos].null_input ? 1 : 0)))
					{
						skip = FALSE;
						instance->workerlist[exec_list[i].original_pos].ready_count = 0;
						
					}
					DEBUGPRINTF("ready_count: %d\n", instance->workerlist[exec_list[i].original_pos].ready_count);
				VIS_LeaveCriticalSection(instance->workerlist[exec_list[i].original_pos].worker_lock);
				if(!skip)
					add_queue(exec_list[i].original_pos, instance);
				VIS_PROFILE_END(PROF_PARTIAL_EXEC);
			}
			else if(exec_list[i].def)
			{
				VIS_PROFILE_START(PROF_FULL_EXEC);
				DEBUGPRINTF("opt_exec: %s(%d)\n", exec_list[i].def->name, exec_list[i].original_pos);
				entry.worker_num = exec_list[i].original_pos;
				if(exec_list[i].def->type & USER_FLAG)
				{
					VIS_PROFILE_START(PROF_OPT_EXEC_USER);
					instance->workerlist[exec_list[i].original_pos].params[0] = NULL;
					memcpy(instance->workerlist[exec_list[i].original_pos].params+1, this_params + exec_list[i].null_inputs, sizeof(datum *) * exec_list[i].def->num_inputs);
					add_queue(exec_list[i].original_pos, instance);
					VIS_PROFILE_END(PROF_OPT_EXEC_USER);
				}
				else
				{
					VIS_PROFILE_START(PROF_OPT_EXEC_BUILT);
					if(execute_def(exec_list[i].def, entry, this_params + exec_list[i].null_inputs, sub_callback) == 0)
					{
						DEBUGPUTS("Exectuted with reslts\n");
						if(exec_list[i].output_refs)
						{
							for(j = exec_list[i].null_inputs; j < (exec_list[i].def->num_outputs+exec_list[i].null_inputs); ++j)
							{
								DEBUGPRINTF("output_refs[%d] = %d\n", j-exec_list[i].null_inputs, exec_list[i].output_refs[j-exec_list[i].null_inputs]);
								if(!exec_list[i].output_refs[j-exec_list[i].null_inputs])
									release_ref(this_params[j]);
								else if(exec_list[i].output_refs[j-exec_list[i].null_inputs] > 1)
								{
									/*DEBUGPRINTF("multi_add_ref(%X): %d\n", this_params[j], exec_list[i].output_refs[j-exec_list[i].null_inputs]-1);
									tmp = (int)(&(this_params[j]->ref_count));
									addnum = exec_list[i].output_refs[j-exec_list[i].null_inputs]-1;
									__asm
									{
										mov ebx, tmp
										mov eax, addnum
										lock xadd dword ptr [ebx], eax
									}*/
									VIS_EnterCriticalSection(this_params[j]->lock);
										this_params[j]->ref_count += exec_list[i].output_refs[j-exec_list[i].null_inputs]-1;
										
									VIS_LeaveCriticalSection(this_params[j]->lock);
								}
							}
							memcpy(results + i*32, this_params + exec_list[i].null_inputs, sizeof(datum *) * exec_list[i].def->num_outputs);
							if(exec_list[i].branch1 >= 0)
							{
								if(this_params[exec_list[i].null_inputs])
								{
									jump_from = exec_list[i].branch1;
									jump_to = exec_list[i].branch2;
								}
								else
								{
									i = exec_list[i].branch1-1;
								}
							}
						}
					}
					/*else
					{
						for(j = exec_list[i].null_inputs; j < (exec_list[i].def->num_outputs + exec_list[i].null_inputs); ++j)
							results[(i*32)|j] = NULL;
					}*/
					VIS_PROFILE_END(PROF_OPT_EXEC_BUILT);
				}
				VIS_PROFILE_END(PROF_FULL_EXEC);
				DEBUGPUTS("Executed\n");
			}
			else
				instance->workerlist[exec_list[i].original_pos].value = this_params[exec_list[i].null_inputs];
		}
		else
		{
			DEBUGPUTS("Skipped\n");
			if(exec_list[i].def)
			{
				for(j = 0; j < exec_list[i].def->num_outputs; ++j)
					results[(i*32)|j] = NULL;
			}
		}
		if(jump_from >= 0 && (i+1) == jump_from)
		{
			i = jump_to-1;
			jump_from = -1;
		}
		VIS_PROFILE_END(PROF_OPT_LOOP);
	}
	DEBUGPUTS("run_optimized calling cleanup_check\n");
	for(i = 0; i < instance->def->num_inputs; ++i)
		release_ref(params[i]);
	cleanup_check(entry);
	VIS_PROFILE_END(PROF_RUN_OPT);
}

int vis_print(datum ** inputlist, queue_entry * worker_entry)
{
	int result;
#ifdef	CONSOLE
	puts((char *)inputlist[0]->c.generic.data);
#else
	MessageBox(NULL, (char *)inputlist[0]->c.generic.data, "Visuality Output", MB_OK);
#endif
	result = 1;

	release_ref(inputlist[0]);
	inputlist[0] = new_datum(BUILTIN_TYPE_YESNO, 2, 0, worker_entry->instance->def->program);
	//No one else knows about this new datum yet so we can skip getting a lock
	datum_set_yesno(inputlist[0], result);
	return 0;
}

int unix_time(datum ** inputlist, queue_entry * worker_entry)
{
	inputlist[0] = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, worker_entry->instance->def->program);
	inputlist[0]->c.integers.num_a = time(NULL);
	return 0;
}

int vis_end(datum ** inputlist, queue_entry * worker_entry)
{
//	fprintf(outfile, "End worker reached.\n");
	execute_active=FALSE;
	release_ref(inputlist[0]);
	//interp_stop();
	return 0;
}

#ifdef NINTENDO_DS
const char keyLetters[15] = "ABESRLUD><XYMC";
#define MAX_KEY_BITS	14
#endif

int vis_getinput(datum ** inputlist, queue_entry * worker_entry)
{
	#ifdef NINTENDO_DS
		int held,i,pos;
		char tempstring[14];
		scanKeys();
		held = keysHeld();
		if(held)
		{
			pos = 0;
			for(i = 0; i < MAX_KEY_BITS; ++i)
				if(held & (1 << i))
					tempstring[pos++] = keyLetters[i];
			inputlist[0] = new_datum(BUILTIN_TYPE_STRING, 1, pos+1, worker_entry->instance->def->program);
			memcpy(inputlist[0]->c.generic.data, tempstring, pos);
			((char *)inputlist[0]->c.generic.data)[pos]='\0';
			return 0;
		}
		else
		{
			requeue(worker_entry->worker_num, worker_entry->instance);
			return 1;
		}
	#else
		#ifdef CONSOLE
			gets(text_buf);
			text_buf_size = strlen(text_buf);
			//Nasty hack for testing until I get around to supporting command line args propery
			//text_buf_size = strlen(global_argv[1]);
		#else
		
		while(text_buf_size <= 0)
		{
			Sleep(30); //TODO: replace with I/O queue mechanism
		}
		#endif
	//	VIS_EnterCriticalSection(text_buf_lock);
			DEBUGPRINTF("Allocating %d bytes\n", text_buf_size+1);
			inputlist[0] = new_datum(BUILTIN_TYPE_STRING, 1, text_buf_size+1, worker_entry->instance->def->program);
			DEBUGPUTS("Allocated datum.\n");
			memcpy(inputlist[0]->c.generic.data, text_buf, text_buf_size);
			DEBUGPUTS("Copied string.\n");
			((char *)inputlist[0]->c.generic.data)[text_buf_size]='\0';
			DEBUGPRINTF("Input is %s\n", inputlist[0]->c.generic.data);
			text_buf_size = 0;
	//	VIS_LeaveCriticalSection(text_buf_lock);
		return 0;
	#endif
}

int vis_if(datum ** inputlist, queue_entry * worker_entry)
{
	if(!(inputlist[0]->c.integers.num_a))
	{
		inputlist[1] = inputlist[0];
		inputlist[0] = NULL;
	}
	else
		inputlist[1] = NULL;
	return 0;
}

int vis_build(datum ** inputlist, queue_entry * worker_entry)
{
	int i,j;
	company * companylist = worker_entry->instance->def->program->companylist;
	int num_companies = worker_entry->instance->def->program->num_companies;
	DEBUGPRINTF("Looking for company named %s\n", inputlist[0]->c.generic.data);
	for(i = 0; i < num_companies; ++i)
	{
		DEBUGPRINTF("Checking company %d:%s\n", i, companylist[i].name);
		if(!strcmp(inputlist[0]->c.generic.data, companylist[i].name))
			break;
	}
	release_ref(inputlist[0]);
	if(i < num_companies && companylist[i].build_size > 0)
	{
		DEBUGPRINTF("Building company with size %d\n", companylist[i].build_size);
		inputlist[0] = new_datum(i, 1, companylist[i].build_size, worker_entry->instance->def->program);
		for(j = 0; j < companylist[i].build_size; ++j)
			((char*)(inputlist[0]->c.generic.data))[j] = 0;
	}
	else
	{
		DEBUGPUTS("Could not find company\n");
		inputlist[0] = NULL;
	}
	return 0;
}

int vis_wait_forever(datum ** inputlist, queue_entry * worker_entry)
{
	return 1;
}

int init_global_store(datum ** inputlist, queue_entry * worker_entry)
{
	datum * params[3];
	global_store * store;
	datum * store_dat = new_datum(BUILTIN_TYPE_GLOBAL_STORE, 1, sizeof(global_store), worker_entry->instance->def->program);
	store = store_dat->c.generic.data;
	store->name = add_ref(inputlist[0]);
	store->data = create_dict(worker_entry->instance->def->program);
	VIS_EnterCriticalSection(global_store_lock);
		params[0] = global_store_dict;
		params[1] = inputlist[0];
		params[2] = store_dat;
		vis_dict_set(params, NULL);
		global_store_dict = params[0];
		DEBUGPUTS("Global store init complete\n");
	VIS_LeaveCriticalSection(global_store_lock);
	DEBUGPUTS("Released global_store_lock\n");
	inputlist[0] = NULL;
	return 0;
}

int vis_type_of(datum ** inputlist, queue_entry * worker_entry)
{
	datum * output = make_string(inputlist[0]->company->name, -1, worker_entry->instance->def->program);
	release_ref(inputlist[0]);
	inputlist[0] = output;
	return 0;
}

int vis_random(datum ** inputlist, queue_entry * worker_entry)
{
	inputlist[0] = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, worker_entry->instance->def->program);
	VIS_EnterCriticalSection(randlock);
		inputlist[0]->c.integers.num_a = genrand_int32();
	VIS_LeaveCriticalSection(randlock);
	return 0;
}