Files
Asuro/src/app/wasm/app.wasm.cleanup.pas
T

299 lines
8.0 KiB
ObjectPascal

{
Prog->WASM->WASMCleanup - Tears down all WASURO VM allocations.
Called via proc.mgr.bindResource when a WASM process exits
or is killed. Walks the PWASMProcessContext and kfrees every
allocation made by the parser, VM setup, and host-function registry.
Because wasuro/ is read-only, we perform the teardown Asuro-side
by mirroring the known allocation patterns from the parser and VM.
@author(Kieron Morris <[email protected]>)
}
unit app.wasm.cleanup;
interface
{ Signature matches TResourceCleanup = procedure(handle : void) }
procedure wasm_resource_cleanup(handle : void);
implementation
uses
memory.heap,
wasm.types.builtin,
wasm.types.context,
wasm.types.sections,
wasm.types.heap,
wasm.types.values,
app.wasm.shim;
{ ---- Heap teardown ---- }
procedure freeHeap(heap : PWasmHeap);
var
i : uint32;
begin
if heap = nil then exit;
if heap^.Memory <> nil then begin
if heap^.PageCount <> 0 then
for i := 0 to heap^.PageCount - 1 do begin
if heap^.Memory[i] <> nil then
kfree(void(heap^.Memory[i]));
end;
kfree(void(heap^.Memory));
end;
kfree(void(heap));
end;
{ ---- Stack teardown ---- }
procedure freeStack(stack : PWASMStack);
begin
if stack = nil then exit;
if stack^.Entries <> nil then
kfree(void(stack^.Entries));
kfree(void(stack));
end;
{ ---- Globals teardown ---- }
procedure freeGlobals(globals : PWASMGlobals);
begin
if globals = nil then exit;
if globals^.Globals <> nil then
kfree(void(globals^.Globals));
kfree(void(globals));
end;
{ ---- Tables teardown ---- }
procedure freeTables(tables : PWASMTables);
var
i : uint32;
begin
if tables = nil then exit;
if tables^.Tables <> nil then begin
if tables^.TableCount <> 0 then
for i := 0 to tables^.TableCount - 1 do begin
if tables^.Tables[i].Elements <> nil then
kfree(void(tables^.Tables[i].Elements));
end;
kfree(void(tables^.Tables));
end;
kfree(void(tables));
end;
{ ---- Data segments teardown ---- }
procedure freeDataSegments(ds : PWASMDataSegments);
var
i : uint32;
begin
if ds = nil then exit;
if ds^.Segments <> nil then begin
if ds^.SegmentCount <> 0 then
for i := 0 to ds^.SegmentCount - 1 do begin
if ds^.Segments[i].Data <> nil then
kfree(void(ds^.Segments[i].Data));
end;
kfree(void(ds^.Segments));
end;
kfree(void(ds));
end;
{ ---- Element segments teardown ---- }
procedure freeElementSegments(es : PWASMElementSegments);
var
i : uint32;
begin
if es = nil then exit;
if es^.Segments <> nil then begin
if es^.SegmentCount <> 0 then
for i := 0 to es^.SegmentCount - 1 do begin
if es^.Segments[i].FuncIndices <> nil then
kfree(void(es^.Segments[i].FuncIndices));
end;
kfree(void(es^.Segments));
end;
kfree(void(es));
end;
{ ---- Type section teardown ---- }
procedure freeTypeSection(ts : PWASMTypeSection);
var
i : uint32;
begin
if ts = nil then exit;
if ts^.Types <> nil then begin
if ts^.TypeCount <> 0 then
for i := 0 to ts^.TypeCount - 1 do begin
if ts^.Types[i].ParamTypes <> nil then
kfree(void(ts^.Types[i].ParamTypes));
if ts^.Types[i].ReturnTypes <> nil then
kfree(void(ts^.Types[i].ReturnTypes));
end;
kfree(void(ts^.Types));
end;
kfree(void(ts));
end;
{ ---- Import section teardown ---- }
procedure freeImportSection(is_ : PWASMImportSection);
var
i : uint32;
begin
if is_ = nil then exit;
if is_^.Entries <> nil then begin
if is_^.ImportCount <> 0 then
for i := 0 to is_^.ImportCount - 1 do begin
if is_^.Entries[i].ModuleName <> nil then
kfree(void(is_^.Entries[i].ModuleName));
if is_^.Entries[i].FieldName <> nil then
kfree(void(is_^.Entries[i].FieldName));
end;
kfree(void(is_^.Entries));
end;
kfree(void(is_));
end;
{ ---- Function section teardown ---- }
procedure freeFunctionSection(fs : PWASMFunctionSection);
begin
if fs = nil then exit;
if fs^.Functions <> nil then
kfree(void(fs^.Functions));
kfree(void(fs));
end;
{ ---- Export section teardown ---- }
procedure freeExportSection(es : PWASMExportSection);
var
i : uint32;
begin
if es = nil then exit;
if es^.Entries <> nil then begin
if es^.ExportCount <> 0 then
for i := 0 to es^.ExportCount - 1 do begin
if es^.Entries[i].Name <> nil then
kfree(void(es^.Entries[i].Name));
end;
kfree(void(es^.Entries));
end;
kfree(void(es));
end;
{ ---- Code section teardown ---- }
procedure freeCodeSection(cs : PWASMCodeSection);
var
i : uint32;
begin
if cs = nil then exit;
if cs^.Entries <> nil then begin
if cs^.CodeCount <> 0 then
for i := 0 to cs^.CodeCount - 1 do begin
if cs^.Entries[i].Code <> nil then
kfree(void(cs^.Entries[i].Code));
if cs^.Entries[i].Locals.Locals <> nil then
kfree(void(cs^.Entries[i].Locals.Locals));
end;
kfree(void(cs^.Entries));
end;
kfree(void(cs));
end;
{ ---- Memory section teardown ---- }
procedure freeMemorySection(ms : PWASMMemorySection);
begin
if ms = nil then exit;
if ms^.Memories <> nil then
kfree(void(ms^.Memories));
kfree(void(ms));
end;
{ ---- Resolved imports teardown ---- }
{ Note: ModuleName/FieldName pointers alias ImportSection core.strings,
so we must NOT free them here — freeImportSection handles those. }
procedure freeResolvedImports(var ri : TWASMResolvedImports);
begin
if ri.Imports <> nil then begin
kfree(void(ri.Imports));
ri.Imports := nil;
end;
end;
{ ---- Host function registry teardown ---- }
{ Note: ModuleName/FieldName in registry entries are string constants
from the WASI preview1 registration — they are NOT heap allocated. }
procedure freeHostFuncRegistry(var reg : TWASMHostFuncRegistry);
begin
if reg.Entries <> nil then begin
kfree(void(reg.Entries));
reg.Entries := nil;
end;
end;
{ ==== Top-level cleanup ==== }
procedure wasm_resource_cleanup(handle : void);
var
shim : PProcessWASMShim;
wctx : PWASMProcessContext;
begin
if handle = nil then exit;
shim := PProcessWASMShim(handle);
wctx := shim^.WASMCtx;
if wctx <> nil then begin
{ --- Execution state --- }
freeHeap(wctx^.ExecutionState.Memory);
freeStack(wctx^.ExecutionState.Operand_Stack);
freeStack(wctx^.ExecutionState.Control_Stack);
freeGlobals(wctx^.ExecutionState.Globals);
freeTables(wctx^.ExecutionState.Tables);
freeDataSegments(wctx^.ExecutionState.DataSegments);
freeElementSegments(wctx^.ExecutionState.ElementSegments);
{ Flat code buffer (concatenation of all code entries) }
if wctx^.ExecutionState.Code <> nil then
kfree(void(wctx^.ExecutionState.Code));
{ ExecutionState.Locals points into CodeSection entries — no separate free }
{ --- Sections --- }
freeTypeSection(wctx^.Sections.TypeSection);
freeImportSection(wctx^.Sections.ImportSection);
freeFunctionSection(wctx^.Sections.FunctionSection);
freeExportSection(wctx^.Sections.ExportSection);
freeCodeSection(wctx^.Sections.CodeSection);
freeMemorySection(wctx^.Sections.MemorySection);
{ --- Import resolution & host function registry --- }
freeResolvedImports(wctx^.ResolvedImports);
freeHostFuncRegistry(wctx^.HostFuncRegistry);
{ --- The context record itself --- }
kfree(void(wctx));
end;
{ --- Shim-owned allocations --- }
if shim^.FileBuffer <> nil then
kfree(void(shim^.FileBuffer));
if shim^.ArgBuf <> nil then
kfree(void(shim^.ArgBuf));
kfree(void(shim));
end;
end.