From 5bdef935f9b674313cf9ecae69696bbb9f9b88b9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Micha=C3=ABl=20Van=20Canneyt?= <michael@freepascal.org>
Date: Tue, 28 May 2024 09:31:17 +0200
Subject: [PATCH] * Fix memleak, objects created directly are owned by
 webassembly

---
 packages/wasm-job/src/job.js.pas | 84 +++++++++++++++-----------------
 1 file changed, 40 insertions(+), 44 deletions(-)

diff --git a/packages/wasm-job/src/job.js.pas b/packages/wasm-job/src/job.js.pas
index 97167e50df..1ab81c1211 100644
--- a/packages/wasm-job/src/job.js.pas
+++ b/packages/wasm-job/src/job.js.pas
@@ -335,7 +335,8 @@ type
     constructor JOBCast(const Intf: IJSObject); overload;
     constructor JOBCreateFromID(aID: TJOBObjectID); virtual; // use this only for the owner (it will release it on free)
     constructor JOBCreateGlobal(const aID: UnicodeString); virtual;
-    constructor JOBCreate(Args : Array of const);
+    constructor JOBCreate(const Args : Array of const);
+    constructor JOBCreate(aOwnsObjectID : Boolean; const Args : Array of const);
     class function JSClassName : UnicodeString; virtual;
     class function Cast(const Intf: IJSObject): IJSObject; overload;
     constructor Create; virtual;
@@ -1470,7 +1471,7 @@ var
 
 begin
   Data:=TJOB_ArrayOfByte.Create(aBytes,aLen);
-  JobCreate([Data]);
+  JobCreate(True,[Data]);
 end;
 
 constructor TJSTypedArray.Create(aBytes: TBytes);
@@ -1478,7 +1479,7 @@ var
   Data : TJOB_JSValue;
 begin
   Data:=TJOB_ArrayOfByte.Create(aBytes);
-  JobCreate([Data]);
+  JobCreate(True,[Data]);
 end;
 
 class function TJSTypedArray.Cast(const Intf: IJSObject): IJSTypedArray;
@@ -2422,11 +2423,8 @@ end;
 constructor TJOB_ArrayOfByte.Create(const TheValues: PByte; TheLen: NativeUInt);
 begin
   inherited Create(jjvkArrayOfByte);
-  Writeln('A');
   Values:=TheValues;
-  Writeln('B');
   Len:=TheLen;
-  Writeln('C');
 end;
 
 constructor TJOB_ArrayOfByte.Create(const TheValues: TBytes);
@@ -3016,8 +3014,13 @@ begin
   FJOBObjectIDOwner:=true;
 end;
 
-constructor TJSObject.JOBCreate(Args : Array of const);
+constructor TJSObject.JOBCreate(const Args: array of const);
 
+begin
+  JOBCreate(True,Args);
+end;
+
+constructor TJSObject.JOBCreate(aOwnsObjectID: Boolean; const Args: array of const);
 var
   N : Unicodestring;
   InvokeArgs: PByte;
@@ -3028,6 +3031,7 @@ begin
     InvokeArgs:=CreateInvokeJSArgs(Args)
   else
     InvokeArgs:=Nil;
+  FJOBObjectIDOwner:=aOwnsObjectID;
   FJobObjectID:=__job_create_object(PWideChar(N),Length(N),InvokeArgs);
   {$IFDEF VERBOSEJOB}
   Writeln('[',ClassName,'] Created new object with ID: ',FJobObjectID);
@@ -3049,11 +3053,14 @@ end;
 constructor TJSObject.Create;
 
 begin
-  JOBCreate([]);
+  JOBCreate(True,[]);
 end;
 
 destructor TJSObject.Destroy;
 begin
+  {$IFDEF VERBOSEJOB}
+  Writeln('Destroying ',ClassName,': Owning JOB object ID: ',FJOBObjectIDOwner);
+  {$ENDIF}
   if FJOBCastSrc<>nil then
     FJOBCastSrc:=nil
   else if (JOBObjectID>=0) and JOBObjectIDOwner then
@@ -3206,8 +3213,7 @@ begin
   Result:=UTF8Encode(InvokeJSUnicodeStringResult(aName,Args,Invoke));
 end;
 
-function TJSObject.InvokeJSLongIntResult(const aName: UTF8string;
-  const args: array of const; Invoke: TJOBInvokeType): LongInt;
+function TJSObject.InvokeJSLongIntResult(const aName: UTF8String; const args: array of const; Invoke: TJOBInvokeType): LongInt;
 var
   d: Double;
 begin
@@ -3218,8 +3224,7 @@ begin
     Result:=Trunc(d);
 end;
 
-function TJSObject.InvokeJSMaxIntResult(const aName: UTF8string;
-  const args: array of const; Invoke: TJOBInvokeType): int64;
+function TJSObject.InvokeJSMaxIntResult(const aName: UTF8String; const args: array of const; Invoke: TJOBInvokeType): int64;
 var
   d: Double;
 begin
@@ -3230,14 +3235,13 @@ begin
     Result:=Trunc(d);
 end;
 
-function TJSObject.InvokeJSTypeOf(const aName: UTF8string;
-  const Args: array of const): TJOBResult;
+function TJSObject.InvokeJSTypeOf(const aName: UTF8String; const Args: array of const): TJOBResult;
 begin
   Result:=InvokeJSNoResultFunc(aName,Args,@__job_invoke_noresult,jiGetTypeOf);
 end;
 
-function TJSObject.InvokeJSUnicodeStringArrayResult(const aName: UTF8string;
-  const Args: array of const; Invoke: TJOBInvokeType): TUnicodeStringDynArray;
+function TJSObject.InvokeJSUnicodeStringArrayResult(const aName: UTF8String; const Args: array of const; Invoke: TJOBInvokeType
+  ): TUnicodeStringDynArray;
 var
   ResultP: NativeInt;
   aError: TJOBResult;
@@ -3253,110 +3257,102 @@ begin
   end;
 end;
 
-function TJSObject.ReadJSPropertyBoolean(const aName: UTF8string): boolean;
+function TJSObject.ReadJSPropertyBoolean(const aName: UTF8String): boolean;
 begin
   Result:=InvokeJSBooleanResult(aName,[],jiGet);
 end;
 
-function TJSObject.ReadJSPropertyDouble(const aName: UTF8string): double;
+function TJSObject.ReadJSPropertyDouble(const aName: UTF8String): double;
 begin
   Result:=InvokeJSDoubleResult(aName,[],jiGet);
 end;
 
-function TJSObject.ReadJSPropertyUnicodeString(const aName: UTF8string
-  ): UnicodeString;
+function TJSObject.ReadJSPropertyUnicodeString(const aName: UTF8String): UnicodeString;
 begin
   Result:=InvokeJSUnicodeStringResult(aName,[],jiGet);
 end;
 
-function TJSObject.ReadJSPropertyObject(const aName: UTF8string;
-  aResultClass: TJSObjectClass): TJSObject;
+function TJSObject.ReadJSPropertyObject(const aName: UTF8String; aResultClass: TJSObjectClass): TJSObject;
 begin
   Result:=InvokeJSObjectResult(aName,[],aResultClass,jiGet);
 end;
 
-function TJSObject.ReadJSPropertyUtf8String(const aName: UTF8string): UTF8string;
+function TJSObject.ReadJSPropertyUtf8String(const aName: UTF8String): UTF8String;
 begin
   Result:=InvokeJSUtf8StringResult(aName,[],jiGet);
 end;
 
-function TJSObject.ReadJSPropertyLongInt(const aName: UTF8string): LongInt;
+function TJSObject.ReadJSPropertyLongInt(const aName: UTF8String): LongInt;
 begin
   Result:=InvokeJSLongIntResult(aName,[],jiGet);
 end;
 
-function TJSObject.ReadJSPropertyInt64(const aName: UTF8string): Int64;
+function TJSObject.ReadJSPropertyInt64(const aName: UTF8String): Int64;
 begin
   Result:=Trunc(InvokeJSDoubleResult(aName,[],jiGet));
 end;
 
-function TJSObject.ReadJSPropertyValue(const aName: UTF8string): TJOB_JSValue;
+function TJSObject.ReadJSPropertyValue(const aName: UTF8String): TJOB_JSValue;
 begin
   Result:=InvokeJSValueResult(aName,[],jiGet);
 end;
 
-function TJSObject.ReadJSPropertyVariant(const aName: UTF8string): Variant;
+function TJSObject.ReadJSPropertyVariant(const aName: UTF8String): Variant;
 begin
   Result:=InvokeJSVariantResult(aName,[],jiGet);
 end;
 
-function TJSObject.ReadJSPropertyMethod(const aName: UTF8string): TMethod;
+function TJSObject.ReadJSPropertyMethod(const aName: UTF8String): TMethod;
 begin
 //  Result:=InvokeJSVariantResult(aName,[],jiGet);
 end;
 
-procedure TJSObject.WriteJSPropertyBoolean(const aName: UTF8string; Value: Boolean);
+procedure TJSObject.WriteJSPropertyBoolean(const aName: UTF8String; Value: Boolean);
 begin
   InvokeJSNoResult(aName,[Value],jiSet);
 end;
 
-procedure TJSObject.WriteJSPropertyDouble(const aName: UTF8string; Value: Double);
+procedure TJSObject.WriteJSPropertyDouble(const aName: UTF8String; Value: Double);
 begin
   InvokeJSNoResult(aName,[Value],jiSet);
 end;
 
-procedure TJSObject.WriteJSPropertyUnicodeString(const aName: UTF8string;
-  const Value: UnicodeString);
+procedure TJSObject.WriteJSPropertyUnicodeString(const aName: UTF8String; const Value: UnicodeString);
 begin
   InvokeJSNoResult(aName,[Value],jiSet);
 end;
 
-procedure TJSObject.WriteJSPropertyUtf8String(const aName: UTF8string;
-  const Value: UTF8String);
+procedure TJSObject.WriteJSPropertyUtf8String(const aName: UTF8String; const Value: UTF8String);
 begin
   InvokeJSNoResult(aName,[Value],jiSet);
 end;
 
-procedure TJSObject.WriteJSPropertyObject(const aName: UTF8string; Value: IJSObject
-  );
+procedure TJSObject.WriteJSPropertyObject(const aName: UTF8String; Value: IJSObject);
 begin
   InvokeJSNoResult(aName,[Value],jiSet);
 end;
 
-procedure TJSObject.WriteJSPropertyLongInt(const aName: UTF8string; Value: LongInt);
+procedure TJSObject.WriteJSPropertyLongInt(const aName: UTF8String; Value: LongInt);
 begin
   InvokeJSNoResult(aName,[Value],jiSet);
 end;
 
-procedure TJSObject.WriteJSPropertyInt64(const aName: UTF8string; Value: Int64);
+procedure TJSObject.WriteJSPropertyInt64(const aName: UTF8String; Value: Int64);
 begin
   InvokeJSNoResult(aName,[Value],jiSet);
 end;
 
-procedure TJSObject.WriteJSPropertyValue(const aName: UTF8string;
-  Value: TJOB_JSValue);
+procedure TJSObject.WriteJSPropertyValue(const aName: UTF8String; Value: TJOB_JSValue);
 begin
   InvokeJSNoResult(aName,[Value],jiSet);
 end;
 
-procedure TJSObject.WriteJSPropertyVariant(const aName: UTF8string;
-  const Value: Variant);
+procedure TJSObject.WriteJSPropertyVariant(const aName: UTF8String; const Value: Variant);
 begin
   InvokeJSNoResult(aName,[Value],jiSet);
 end;
 
-procedure TJSObject.WriteJSPropertyMethod(const aName: UTF8string;
-  const Value: TMethod);
+procedure TJSObject.WriteJSPropertyMethod(const aName: UTF8String; const Value: TMethod);
 begin
   // TODO InvokeJSNoResult(aName,[Value],jiSet);
 end;