view interp.c @ 75:0083b2f7b3c7

Partially working implementation of List. Modified build scripts to allow use of other compilers. Fixed some bugs involving method implementations on different types returning different numbers of outputs. Added Fold to the 'builtins' in the comipler.
author Mike Pavone <pavone@retrodev.com>
date Tue, 06 Jul 2010 07:52:59 -0400
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;
}