/** * Gets a loaded infusion for a given infusion name. * @param vm the virtual machine to lookup the infusion in * @param name the name of the infusion. Has to be a NULL-terminated ascii string in program memory. * @return the infusion for the given name, or NULL if no such infusion is found */ dj_infusion *dj_vm_lookupInfusion(dj_vm *vm, dj_di_pointer name) { dj_infusion *finger = vm->infusions; while (finger!=NULL) { if (dj_di_strEquals(dj_di_header_getInfusionName(finger->header), name)) return finger; finger = finger->next; } return NULL; }
/** * Loads an infusion into the virtual machine. * @param vm the virtual machine object to load the infusion into * @param di a di pointer to the infusion file in program space * @return a newly loaded infusion, or NULL in case of fail */ dj_infusion *dj_vm_loadInfusion(dj_vm *vm, dj_di_pointer di, dj_named_native_handler native_handlers[], unsigned char numHandlers) { int i; dj_infusion *infusion; dj_di_pointer element; dj_di_pointer staticFieldInfo = DJ_DI_NOT_SET; dj_di_pointer infusionList = DJ_DI_NOT_SET; dj_thread * thread; dj_global_id entryPoint; // iterate over the child elements, and find the static // field size info block. We need this info to allocate // the memory to hold the static fields for this // infusion for (i=0; i<dj_di_getListSize(di); i++) { element = dj_di_getListElement(di, i); switch (dj_di_element_getId(element)) { case STATICFIELDINFO: staticFieldInfo = element; break; case INFUSIONLIST: infusionList = element; break; } } // Check if each of the required elements were found if (staticFieldInfo==DJ_DI_NOT_SET||infusionList==DJ_DI_NOT_SET) dj_panic(DJ_PANIC_MALFORMED_INFUSION); // allocate the Infusion struct infusion = dj_infusion_create(staticFieldInfo, dj_di_infusionList_getSize(infusionList)); // if we're out of memory, let the caller handle it if (infusion==NULL) return NULL; // iterate over the child elements and get references // to the class list and method implementation list, // and get the header for (i=0; i<dj_di_getListSize(di); i++) { element = dj_di_getListElement(di, i); switch (dj_di_element_getId(element)) { case HEADER: infusion->header = element; break; case CLASSLIST: infusion->classList = element; break; case METHODIMPLLIST: infusion->methodImplementationList = element; break; case STRINGTABLE: infusion->stringTable = element; break; } } // Check if each of the required elements was found if (infusion->stringTable==DJ_DI_NOT_SET||infusion->classList==DJ_DI_NOT_SET||infusion->methodImplementationList==DJ_DI_NOT_SET||infusion->header==DJ_DI_NOT_SET) dj_panic(DJ_PANIC_MALFORMED_INFUSION); // iterate over the referenced infusion list and set the appropriate pointers for (i=0; i<dj_di_infusionList_getSize(infusionList); i++) { dj_di_pointer name = dj_di_infusionList_getChild(infusionList, i); dj_infusion *referenced_infusion = dj_vm_lookupInfusion(vm, name); if (infusion==NULL) dj_panic(DJ_PANIC_UNSATISFIED_LINK); infusion->referencedInfusions[i] = referenced_infusion; } // add the new infusion to the VM dj_vm_addInfusion(vm, infusion); // We're assuming here that base.di is the first file in the archive if (vm->systemInfusion == NULL) vm->systemInfusion = infusion; // This code was originally in load dj_vm_loadInfusionArchive. // Moved here because the application is not in an archive, but needs // some of the same code (not native_handlers, but class initialisers // and creating a thread) #ifdef DARJEELING_DEBUG char name[64]; dj_infusion_getName(infusion, name, 64); DEBUG_LOG(DBG_DARJEELING, "Loaded infusion %s.", name); #endif for (i=0; i<numHandlers; i++) { if (dj_di_strEqualsDirectStr(dj_di_header_getInfusionName(infusion->header), native_handlers[i].name)) { infusion->native_handler = native_handlers[i].handler; #ifdef DARJEELING_DEBUG DEBUG_LOG(DBG_DARJEELING, "Attached native handler to infusion %s.", name); #endif } } // run class initialisers for this infusion infusion = dj_vm_runClassInitialisers(vm, infusion); // find the entry point for the infusion if ((entryPoint.entity_id=dj_di_header_getEntryPoint(infusion->header))!=255) { // create a new thread and add it to the VM entryPoint.infusion = infusion; thread = dj_thread_create_and_run(entryPoint); if (thread==NULL) dj_panic(DJ_PANIC_OUT_OF_MEMORY); dj_vm_addThread(vm, thread); } return infusion; }
// 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; }
void dj_vm_loadInfusionArchive(dj_vm * vm, dj_archive* archive, dj_named_native_handler native_handlers[], unsigned char numHandlers) { dj_thread * thread; dj_infusion * infusion = NULL; dj_di_pointer archive_start = archive->start; dj_di_pointer archive_end = archive->end; unsigned char digit, i; dj_global_id entryPoint; unsigned long size, pos; bool first = true; // skip header, we'll just assume you're not passing something silly into this method archive_start += 8; while (archive_start<archive_end-1) { // read size size = 0; pos = AR_EHEADER_SIZE_START; while (((digit=dj_di_getU8(archive_start+pos))!=' ')&&(pos<AR_EHEADER_SIZE_END)) { size *= 10; size += digit - '0'; pos++; } // if filename starts with '/' skip this entry, since it's part of a // GNU extension on the common AR format if (dj_di_getU8(archive_start)!='/') { // Read infusion file. We're assuming here that base.di is the first file in the archive if (first) infusion = dj_vm_loadSystemInfusion(vm, archive_start + AR_EHEADER_SIZE); else infusion = dj_vm_loadInfusion(vm, archive_start + AR_EHEADER_SIZE); // If infusion is not loaded a critical error has occured if (infusion == NULL){ DARJEELING_PRINTF("Not enough space to create the infusion : %c%c%c%c%c%c%c%c\n", dj_di_getU8(archive_start+0), dj_di_getU8(archive_start+1), dj_di_getU8(archive_start+2), dj_di_getU8(archive_start+3), dj_di_getU8(archive_start+4), dj_di_getU8(archive_start+5), dj_di_getU8(archive_start+6), dj_di_getU8(archive_start+7) ); dj_panic(DJ_PANIC_OUT_OF_MEMORY); } /* else DARJEELING_PRINTF("[%s.di] %ld\n", (char *) dj_di_header_getInfusionName(infusion->header), size ); */ #ifdef DARJEELING_DEBUG char name[64]; dj_infusion_getName(infusion, name, 64); DEBUG_LOG("Loaded infusion %s.", name); #endif for (i=0; i<numHandlers; i++) { if (dj_di_strEqualsDirectStr(dj_di_header_getInfusionName(infusion->header), native_handlers[i].name)) { infusion->native_handler = native_handlers[i].handler; #ifdef DARJEELING_DEBUG DEBUG_LOG("Attached native handler to infusion %s.", name); #endif } } // run class initialisers for this infusion infusion = dj_vm_runClassInitialisers(vm, infusion); // find the entry point for the infusion if ((entryPoint.entity_id=dj_di_header_getEntryPoint(infusion->header))!=255) { // create a new thread and add it to the VM entryPoint.infusion = infusion; thread = dj_thread_create_and_run(entryPoint); if (thread==NULL) dj_panic(DJ_PANIC_OUT_OF_MEMORY); dj_vm_addThread(vm, thread); } first = false; } // files are 2-byte aligned if (size&1) size++; archive_start += size + AR_EHEADER_SIZE; } }