VMFrame *VMFrameStack::PopFrame() { if (Blocks == NULL) { return NULL; } VMFrame *frame = Blocks->LastFrame; if (frame == NULL) { return NULL; } auto Func = static_cast<VMScriptFunction *>(frame->Func); if (Func->SpecialInits.Size()) { Func->DestroyExtra(frame->GetExtra()); } // Free any string registers this frame had. FString *regs = frame->GetRegS(); for (int i = frame->NumRegS; i != 0; --i) { (regs++)->~FString(); } VMFrame *parent = frame->ParentFrame; if (parent == NULL) { // Popping the last frame off the stack. if (Blocks != NULL) { assert(Blocks->NextBlock == NULL); Blocks->LastFrame = NULL; Blocks->InitFreeSpace(); } return NULL; } if ((VM_UBYTE *)parent < (VM_UBYTE *)Blocks || (VM_UBYTE *)parent >= (VM_UBYTE *)Blocks + Blocks->BlockSize) { // Parent frame is in a different block, so move this one to the unused list. BlockHeader *next = Blocks->NextBlock; assert(next != NULL); assert((VM_UBYTE *)parent >= (VM_UBYTE *)next && (VM_UBYTE *)parent < (VM_UBYTE *)next + next->BlockSize); Blocks->NextBlock = UnusedBlocks; UnusedBlocks = Blocks; Blocks = next; } else { Blocks->LastFrame = parent; Blocks->FreeSpace = (VM_UBYTE *)frame; } return parent; }
VMFrame *VMFrameStack::AllocFrame(VMScriptFunction *func) { VMFrame *frame = Alloc(func->StackSize); frame->Func = func; frame->NumRegD = func->NumRegD; frame->NumRegF = func->NumRegF; frame->NumRegS = func->NumRegS; frame->NumRegA = func->NumRegA; frame->MaxParam = func->MaxParam; frame->Func = func; frame->InitRegS(); if (func->SpecialInits.Size()) { func->InitExtra(frame->GetExtra()); } return frame; }