inline dj_global_id dj_vm_resolveRuntimeClass(dj_vm *vm, runtime_id_t id) { dj_global_id ret; dj_infusion *infusion = vm->infusions; runtime_id_t base = 0; // TODO: optimize this! (binary search?) // TODO: test for multiple loaded infusions while (infusion!=NULL) { base = infusion->class_base; PRINTF("Comparing with infusion %d having base id %d\n",dj_vm_getInfusionId(dj_exec_getVM(), infusion), infusion->class_base); if ((id>=base)&&(id<base + dj_di_parentElement_getListSize(infusion->classList))) { ret.infusion = infusion; ret.entity_id = id - base; return ret; } infusion = infusion->next; } // TODO raise error, class not found printf("error: class not found: %d\n", id); // dead code to make compiler happy ret.entity_id=255; ret.infusion=NULL; return ret; }
/** * Unloads an infusion. Make sure you check whether it's safe to do so using dj_vm_safeToUnload! If you * unload an infusion that another infusion depends on you'll leave the VM in an undefined state. Also, * a kitten will die. * @param vm the virtual machine context * @param unloadInfusion the infusion to unload */ void dj_vm_unloadInfusion(dj_vm *vm, dj_infusion * unloadInfusion) { dj_thread * thread; dj_frame * frame; dj_infusion * infusion; dj_infusion * prev; int index; // kill any thread that is currently executing any method in the infusion that we're unloading thread = vm->threads; while (thread!=NULL) { // check each frame frame = thread->frameStack; while (frame!=NULL) { if (frame->method.infusion==unloadInfusion) { // kill the thread thread->status = THREADSTATUS_FINISHED; break; } frame = frame->parent; } // next thread thread = thread->next; } // shift runtime IDs dj_mem_shiftRuntimeIDs(unloadInfusion->class_base, dj_di_parentElement_getListSize(unloadInfusion->classList)); // update other infusions infusion = vm->infusions; while (infusion!=NULL) { if (infusion->class_base>unloadInfusion->class_base) infusion->class_base -= dj_di_parentElement_getListSize(unloadInfusion->classList); infusion = infusion->next; } prev = NULL; index = dj_vm_getInfusionId(vm, unloadInfusion); // remove the infusion from the list if (index==0) { vm->infusions = unloadInfusion->next; } else { prev = dj_vm_getInfusion(vm, index - 1); prev->next = unloadInfusion->next; } }
// TODO niels clean up this function dj_infusion* dj_vm_runClassInitialisers(dj_vm *vm, dj_infusion *infusion) { int i, threadId; dj_thread * thread; dj_frame * frame; dj_global_id methodImplId; uint8_t infusionId; // store infusion ID so that we can get an up-to-date infusion pointer later infusionId = dj_vm_getInfusionId(vm, infusion); // create a new thread object to run the <CLINIT> methods in thread = dj_thread_create(); infusion = dj_vm_getInfusion(vm, infusionId); if (thread == NULL) { DARJEELING_PRINTF("Not enough space for class initializer in infusion %s\n", (char *) dj_di_header_getInfusionName(infusion->header)); dj_panic(DJ_PANIC_OUT_OF_MEMORY); } dj_vm_addThread(dj_exec_getVM(), thread); threadId = thread->id; // iterate over the class list and execute any class initialisers that are encountered int size = dj_di_parentElement_getListSize(infusion->classList); for (i=0; i<size; i++) { infusion = dj_vm_getInfusion(dj_exec_getVM(), infusionId); dj_di_pointer classDef = dj_di_parentElement_getChild(infusion->classList, i); methodImplId.entity_id = dj_di_classDefinition_getCLInit(classDef); methodImplId.infusion = infusion; if (methodImplId.entity_id!=255) { // create a frame to run the initialiser in methodImplId.infusion = infusion; frame = dj_frame_create(methodImplId); // if we're out of memory, panic if (frame==NULL) { DEBUG_LOG(DBG_DARJEELING, "dj_vm_runClassInitialisers: could not create frame. Panicking\n"); DARJEELING_PRINTF("Not enough space to create a frame\n"); dj_panic(DJ_PANIC_OUT_OF_MEMORY); } // the thread we're running the class initialisers in. thread = dj_vm_getThreadById(dj_exec_getVM(), threadId); thread->frameStack = frame; thread->status = THREADSTATUS_RUNNING; dj_exec_activate_thread(thread); // execute the method while (dj_vm_getThreadById(dj_exec_getVM(), threadId)->status!=THREADSTATUS_FINISHED) { // running the CLINIT method may trigger garbage collection dj_exec_run(RUNSIZE); } } } // clean up the thread thread = dj_vm_getThreadById(dj_exec_getVM(), threadId); dj_vm_removeThread(vm, thread); dj_thread_destroy(thread); vm->currentThread = NULL; return infusion; }