Mercurial > repos > rhope
diff interp.c @ 0:76568becd6d6
Rhope Alpha 2a source import
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Tue, 28 Apr 2009 23:06:07 +0000 |
parents | |
children | 23dd9c766699 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/interp.c Tue Apr 28 23:06:07 2009 +0000 @@ -0,0 +1,4102 @@ +#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, ¤t_section = %X\n", current_section, ¤t_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 SYLLABLE + DEBUGPUTS("vis_window_init\n"); + vis_window_init(); +#endif + 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; + + //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; + + //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, "New@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, "New@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, "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, "New@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, "New@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, "New@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, "New@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, "New@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, "New@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, "New@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, "New@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, "New@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 SYLLABLE + create_company(prog, "Checkbox", 2, 0, FALSE); + + aworker = create_worker(prog, "New@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, "New@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 + + /*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; + 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; + 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\n", process_def->name); + 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); + } 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 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; +}