299 lines
8.0 KiB
ObjectPascal
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.
|