void InterpreterExecute(const LinkedProgram *program, int target) { VM *masterVM; IVInit(&temp, 16); vmBytecode = program->bytecode; vmLineNumbers = program->lineNumbers; masterVM = VMCreate(program); initStackFrame(masterVM, &masterVM->ip, &masterVM->bp, target, 0); for (;;) { VMBase *vmBase = &masterVM->base; bool idle = true; /* Traverse VMs, letting all non-idle execute for a while. Note that the tree can change as a result of executing. */ for (;;) { if (vmBase->fullVM) { VM *vm = (VM*)vmBase; if (!vm->idle) { /* TODO: Cloning new VMs can cause infinite traversal. */ vm = execute(vm); idle = false; } else if (vm->child) { vmBase = vm->child; continue; } { VMBase *parent = vm->base.parent; VMBase *child = &vm->base; VMBase **p; if (!parent) { break; } while (parent->fullVM || ((VMBranch*)parent)->children[ ((VMBranch*)parent)->childCount - 1] == child) { child = parent; parent = parent->parent; if (!parent) { goto done; } } for (p = ((VMBranch*)parent)->children; *p != child; p++) { assert(p < ((VMBranch*)parent)->children + ((VMBranch*)parent)->childCount); } vmBase = *(p + 1); } } else { VMBranch *vmBranch = (VMBranch*)vmBase; assert(vmBranch->childCount); vmBase = vmBranch->children[0]; } } done: if (idle) { if (masterVM->job) { JobExecute(masterVM->job); } else if (masterVM->idle) { break; } } } if (masterVM->failMessage) { const char *filename; int line = BytecodeLineNumber(program->lineNumbers, (int)(masterVM->ip - vmBytecode), &filename); char *msg = VGetStringCopy(masterVM->failMessage); fprintf(stderr, "%s:%d: %s\n", filename, line, msg); #ifdef VALGRIND free(msg); #endif cleanShutdown(EXIT_FAILURE); } #ifdef VALGRIND VMDispose(&masterVM->base); IVDispose(&temp); #endif }
/* VMChunkCreate -- create a chunk * * chunkReturn, return parameter for the created chunk. * vmArena, the parent VMArena. * size, approximate amount of virtual address that the chunk should reserve. */ static Res VMChunkCreate(Chunk *chunkReturn, VMArena vmArena, Size size) { Res res; Addr base, limit, chunkStructLimit; Align pageSize; VM vm; BootBlockStruct bootStruct; BootBlock boot = &bootStruct; VMChunk vmChunk; void *p; AVER(chunkReturn != NULL); AVERT(VMArena, vmArena); AVER(size > 0); res = VMCreate(&vm, size, vmArena->vmParams); if (res != ResOK) goto failVMCreate; pageSize = VMAlign(vm); /* The VM will have aligned the userSize; pick up the actual size. */ base = VMBase(vm); limit = VMLimit(vm); res = BootBlockInit(boot, (void *)base, (void *)limit); if (res != ResOK) goto failBootInit; /* Allocate and map the descriptor. */ /* See <design/arena/>.@@@@ */ res = BootAlloc(&p, boot, sizeof(VMChunkStruct), MPS_PF_ALIGN); if (res != ResOK) goto failChunkAlloc; vmChunk = p; /* Calculate the limit of the page where the chunkStruct resides. */ chunkStructLimit = AddrAlignUp((Addr)(vmChunk + 1), pageSize); res = vmArenaMap(vmArena, vm, base, chunkStructLimit); if (res != ResOK) goto failChunkMap; vmChunk->overheadMappedLimit = chunkStructLimit; vmChunk->vm = vm; res = ChunkInit(VMChunk2Chunk(vmChunk), VMArena2Arena(vmArena), base, limit, pageSize, boot); if (res != ResOK) goto failChunkInit; BootBlockFinish(boot); vmChunk->sig = VMChunkSig; AVERT(VMChunk, vmChunk); *chunkReturn = VMChunk2Chunk(vmChunk); return ResOK; failChunkInit: /* No need to unmap, as we're destroying the VM. */ failChunkMap: failChunkAlloc: failBootInit: VMDestroy(vm); failVMCreate: return res; }