Browse Source

wasmjob: fixed callback returning object passed by arg

mattias 3 years ago
parent
commit
b819dc02c7

+ 62 - 4
demo/wasienv/dom/WasiDomTest1.lpr

@@ -16,12 +16,14 @@ uses
 type
 type
   EWasiTest = class(Exception);
   EWasiTest = class(Exception);
 
 
+  IJSBird = interface;
   TJSBird = class;
   TJSBird = class;
 
 
   TBirdCallBoolean = function(const v: Boolean): Boolean of object;
   TBirdCallBoolean = function(const v: Boolean): Boolean of object;
   TBirdCallInteger = function(const v: integer): integer of object;
   TBirdCallInteger = function(const v: integer): integer of object;
   TBirdCallDouble = function(const v: double): double of object;
   TBirdCallDouble = function(const v: double): double of object;
   TBirdCallUnicodeString = function(const v: UnicodeString): UnicodeString of object;
   TBirdCallUnicodeString = function(const v: UnicodeString): UnicodeString of object;
+  TBirdCallBird = function(const v: IJSBird): IJSBird of object;
   TBirdCallVariant = function(const v: variant): variant of object;
   TBirdCallVariant = function(const v: variant): variant of object;
 
 
   { IJSBird }
   { IJSBird }
@@ -42,6 +44,7 @@ type
     function EchoInteger(const v: integer; const Call: TBirdCallInteger): integer;
     function EchoInteger(const v: integer; const Call: TBirdCallInteger): integer;
     function EchoDouble(const v: Double; const Call: TBirdCallDouble): Double;
     function EchoDouble(const v: Double; const Call: TBirdCallDouble): Double;
     function EchoUnicodeString(const v: UnicodeString; const Call: TBirdCallUnicodeString): UnicodeString;
     function EchoUnicodeString(const v: UnicodeString; const Call: TBirdCallUnicodeString): UnicodeString;
+    function EchoBird(const v: IJSBird; const Call: TBirdCallBird): IJSBird;
     function EchoVariant(const v: Variant; const Call: TBirdCallVariant): Variant;
     function EchoVariant(const v: Variant; const Call: TBirdCallVariant): Variant;
     // properties
     // properties
     function GetCaption: UnicodeString;
     function GetCaption: UnicodeString;
@@ -84,6 +87,7 @@ type
     function EchoInteger(const v: integer; const Call: TBirdCallInteger): integer;
     function EchoInteger(const v: integer; const Call: TBirdCallInteger): integer;
     function EchoDouble(const v: Double; const Call: TBirdCallDouble): Double;
     function EchoDouble(const v: Double; const Call: TBirdCallDouble): Double;
     function EchoUnicodeString(const v: UnicodeString; const Call: TBirdCallUnicodeString): UnicodeString;
     function EchoUnicodeString(const v: UnicodeString; const Call: TBirdCallUnicodeString): UnicodeString;
+    function EchoBird(const v: IJSBird; const Call: TBirdCallBird): IJSBird;
     function EchoVariant(const v: Variant; const Call: TBirdCallVariant): Variant;
     function EchoVariant(const v: Variant; const Call: TBirdCallVariant): Variant;
     // properties
     // properties
     function GetCaption: UnicodeString;
     function GetCaption: UnicodeString;
@@ -115,6 +119,7 @@ type
     function OnBirdCallInteger(const v: integer): integer;
     function OnBirdCallInteger(const v: integer): integer;
     function OnBirdCallDouble(const v: double): double;
     function OnBirdCallDouble(const v: double): double;
     function OnBirdCallUnicodeString(const v: UnicodeString): UnicodeString;
     function OnBirdCallUnicodeString(const v: UnicodeString): UnicodeString;
+    function OnBirdCallBird(const v: IJSBird): IJSBird;
     function OnBirdCallVariant(const v: Variant): Variant;
     function OnBirdCallVariant(const v: Variant): Variant;
   public
   public
     Prefix: string;
     Prefix: string;
@@ -157,6 +162,7 @@ type
     procedure TestFuncArgMethod_Integer;
     procedure TestFuncArgMethod_Integer;
     procedure TestFuncArgMethod_Double;
     procedure TestFuncArgMethod_Double;
     procedure TestFuncArgMethod_UnicodeString;
     procedure TestFuncArgMethod_UnicodeString;
+    procedure TestFuncArgMethod_Object;
     procedure TestFuncArgMethod_Variant;
     procedure TestFuncArgMethod_Variant;
 
 
     // dictionaries
     // dictionaries
@@ -199,6 +205,17 @@ begin
   Result:=H.AllocString(TBirdCallUnicodeString(aMethod)(v));
   Result:=H.AllocString(TBirdCallUnicodeString(aMethod)(v));
 end;
 end;
 
 
+function JOBCallTBirdCallBird(const aMethod: TMethod; var H: TJOBCallbackHelper): PByte;
+var
+  v: IJSBird;
+begin
+  //writeln('JOBCallTBirdCallBird START');
+  v:=H.GetObject(TJSBird) as IJSBird;
+  //writeln('JOBCallTBirdCallBird ',v<>nil);
+  Result:=H.AllocIntf(TBirdCallBird(aMethod)(v));
+  //writeln('JOBCallTBirdCallBird ',ptruint(Result));
+end;
+
 function JOBCallTBirdCallVariant(const aMethod: TMethod; var H: TJOBCallbackHelper): PByte;
 function JOBCallTBirdCallVariant(const aMethod: TMethod; var H: TJOBCallbackHelper): PByte;
 var
 var
   v: Variant;
   v: Variant;
@@ -242,6 +259,11 @@ begin
   Result:=v;
   Result:=v;
 end;
 end;
 
 
+function TWasmApp.OnBirdCallBird(const v: IJSBird): IJSBird;
+begin
+  Result:=v;
+end;
+
 function TWasmApp.OnBirdCallVariant(const v: Variant): Variant;
 function TWasmApp.OnBirdCallVariant(const v: Variant): Variant;
 begin
 begin
   Result:=v;
   Result:=v;
@@ -274,6 +296,7 @@ begin
   TestFuncArgMethod_Integer;
   TestFuncArgMethod_Integer;
   TestFuncArgMethod_Double;
   TestFuncArgMethod_Double;
   TestFuncArgMethod_UnicodeString;
   TestFuncArgMethod_UnicodeString;
+  TestFuncArgMethod_Object;
   TestFuncArgMethod_Variant;
   TestFuncArgMethod_Variant;
 end;
 end;
 
 
@@ -742,19 +765,15 @@ begin
   Prefix:='TWasmApp.TestFuncArgMethod_UnicodeString';
   Prefix:='TWasmApp.TestFuncArgMethod_UnicodeString';
   Bird.Name:='TestFuncArgMethod_UnicodeString';
   Bird.Name:='TestFuncArgMethod_UnicodeString';
 
 
-  writeln('AAA1 TWasmApp.TestFuncArgMethod_UnicodeString ');
   v:=Bird.EchoUnicodeString('',@OnBirdCallUnicodeString);
   v:=Bird.EchoUnicodeString('',@OnBirdCallUnicodeString);
   AssertEqualUS('Bird.EchoUnicodeString('''',...)','',v);
   AssertEqualUS('Bird.EchoUnicodeString('''',...)','',v);
 
 
-  writeln('AAA2 TWasmApp.TestFuncArgMethod_UnicodeString ');
   v:=Bird.EchoUnicodeString('c',@OnBirdCallUnicodeString);
   v:=Bird.EchoUnicodeString('c',@OnBirdCallUnicodeString);
   AssertEqualUS('Bird.EchoUnicodeString(''c'',...)','c',v);
   AssertEqualUS('Bird.EchoUnicodeString(''c'',...)','c',v);
 
 
-  writeln('AAA3 TWasmApp.TestFuncArgMethod_UnicodeString ');
   v:=Bird.EchoUnicodeString('abc',@OnBirdCallUnicodeString);
   v:=Bird.EchoUnicodeString('abc',@OnBirdCallUnicodeString);
   AssertEqualUS('Bird.EchoUnicodeString(''abc'',...)','abc',v);
   AssertEqualUS('Bird.EchoUnicodeString(''abc'',...)','abc',v);
 
 
-  writeln('AAA4 TWasmApp.TestFuncArgMethod_UnicodeString ');
   v:=Bird.EchoUnicodeString(#10,@OnBirdCallUnicodeString);
   v:=Bird.EchoUnicodeString(#10,@OnBirdCallUnicodeString);
   AssertEqualUS('Bird.EchoUnicodeString(#10,...)',#10,v);
   AssertEqualUS('Bird.EchoUnicodeString(#10,...)',#10,v);
 
 
@@ -765,6 +784,24 @@ begin
   AssertEqualUS('Bird.EchoUnicodeString(''😄'',...)','😄',v);
   AssertEqualUS('Bird.EchoUnicodeString(''😄'',...)','😄',v);
 end;
 end;
 
 
+procedure TWasmApp.TestFuncArgMethod_Object;
+var
+  v, Lisa: IJSBird;
+begin
+  Prefix:='TWasmApp.TestFuncArgMethod_Object';
+  Bird.Name:='TestFuncArgMethod_Object';
+
+  v:=Bird.EchoBird(nil,@OnBirdCallBird);
+  AssertEqual('Bird.EchoBird(nil,...)',nil,v);
+
+  v:=Bird.EchoBird(Bird,@OnBirdCallBird);
+  AssertEqual('Bird.EchoBird(Bird,...)',Bird,v);
+
+  Lisa:=Bird.CreateBird('Lisa');
+  v:=Bird.EchoBird(Lisa,@OnBirdCallBird);
+  AssertEqual('Bird.EchoBird(Lisa,...)',Lisa,v);
+end;
+
 procedure TWasmApp.TestFuncArgMethod_Variant;
 procedure TWasmApp.TestFuncArgMethod_Variant;
 var
 var
   v: Variant;
   v: Variant;
@@ -772,6 +809,15 @@ begin
   Prefix:='TWasmApp.TestFuncArgMethod_Variant;';
   Prefix:='TWasmApp.TestFuncArgMethod_Variant;';
   Bird.Name:='TestFuncArgMethod_Variant;';
   Bird.Name:='TestFuncArgMethod_Variant;';
 
 
+  v:=Bird.EchoVariant(true,@OnBirdCallVariant);
+  AssertEqual('Bird.EchoVariant(true,...)',true,v);
+
+  v:=Bird.EchoVariant(false,@OnBirdCallVariant);
+  AssertEqual('Bird.EchoVariant(false,...)',false,v);
+
+//  v:=Bird.EchoVariant(Variants.Null,@OnBirdCallVariant);
+//  AssertEqual('Bird.EchoVariant(Variants.Null,...)',Variants.Null,v);
+
   v:=Bird.EchoVariant(0.5,@OnBirdCallVariant);
   v:=Bird.EchoVariant(0.5,@OnBirdCallVariant);
   AssertEqual('Bird.EchoVariant(0.5,...)',0.5,v);
   AssertEqual('Bird.EchoVariant(0.5,...)',0.5,v);
 end;
 end;
@@ -944,6 +990,18 @@ begin
   end;
   end;
 end;
 end;
 
 
+function TJSBird.EchoBird(const v: IJSBird; const Call: TBirdCallBird): IJSBird;
+var
+  m: TJOB_Method;
+begin
+  m:=TJOB_Method.Create(TMethod(Call),@JOBCallTBirdCallBird);
+  try
+    Result:=InvokeJSObjectResult('EchoCall',[v,m],TJSBird) as IJSBird;
+  finally
+    m.Free;
+  end;
+end;
+
 function TJSBird.EchoVariant(const v: Variant; const Call: TBirdCallVariant
 function TJSBird.EchoVariant(const v: Variant; const Call: TBirdCallVariant
   ): Variant;
   ): Variant;
 var
 var

+ 15 - 3
demo/wasienv/dom/job_js.pas

@@ -264,6 +264,7 @@ type
   private
   private
     FJOBObjectID: TJOBObjectID;
     FJOBObjectID: TJOBObjectID;
     FJOBCastSrc: IJSObject;
     FJOBCastSrc: IJSObject;
+    FJOBObjectIDOwner: boolean;
   protected
   protected
     type
     type
       TJOBInvokeNoResultFunc = function(
       TJOBInvokeNoResultFunc = function(
@@ -302,7 +303,8 @@ type
     class function Cast(Intf: IJSObject): IJSObject; overload;
     class function Cast(Intf: IJSObject): IJSObject; overload;
     destructor Destroy; override;
     destructor Destroy; override;
     property JOBObjectID: TJOBObjectID read FJOBObjectID;
     property JOBObjectID: TJOBObjectID read FJOBObjectID;
-    property JOBCastSrc: IJSObject read FJOBCastSrc; // nil means it is the owner, otherwise it is a typecast
+    property JOBObjectIDOwner: boolean read FJOBObjectIDOwner write FJOBObjectIDOwner;
+    property JOBCastSrc: IJSObject read FJOBCastSrc; // nil means it is the original, otherwise it is a typecast
     // call a function
     // call a function
     procedure InvokeJSNoResult(const aName: string; Const Args: Array of const; Invoke: TJOBInvokeType = jiCall); virtual;
     procedure InvokeJSNoResult(const aName: string; Const Args: Array of const; Invoke: TJOBInvokeType = jiCall); virtual;
     function InvokeJSBooleanResult(const aName: string; Const Args: Array of const; Invoke: TJOBInvokeType = jiCall): Boolean; virtual;
     function InvokeJSBooleanResult(const aName: string; Const Args: Array of const; Invoke: TJOBInvokeType = jiCall): Boolean; virtual;
@@ -1859,6 +1861,7 @@ begin
       ObjId:=PLongWord(p)^;
       ObjId:=PLongWord(p)^;
       inc(p,4);
       inc(p,4);
       Result:=aResultClass.JOBCreateFromID(ObjId);
       Result:=aResultClass.JOBCreateFromID(ObjId);
+      Result.JOBObjectIDOwner:=false; // owned by caller (JS code in browser)
     end
     end
   else
   else
     raise EJSArgParse.Create(JOBArgNames[p^]);
     raise EJSArgParse.Create(JOBArgNames[p^]);
@@ -1934,12 +1937,17 @@ var
   Obj: TJSObject;
   Obj: TJSObject;
   S: UnicodeString;
   S: UnicodeString;
 begin
 begin
-  if (Index=Count) or (p^=JOBArgUndefined) then
+  if Index=Count then
   begin
   begin
     Result:=Variants.Unassigned;
     Result:=Variants.Unassigned;
     exit;
     exit;
   end;
   end;
   case p^ of
   case p^ of
+  JOBArgUndefined:
+    begin
+      Result:=Variants.Unassigned;
+      inc(p);
+    end;
   JOBArgTrue:
   JOBArgTrue:
     begin
     begin
       Result:=true;
       Result:=true;
@@ -1981,6 +1989,7 @@ begin
       ObjId:=PLongWord(p)^;
       ObjId:=PLongWord(p)^;
       inc(p,4);
       inc(p,4);
       Obj:=TJSObject.JOBCreateFromID(ObjId);
       Obj:=TJSObject.JOBCreateFromID(ObjId);
+      Obj.JOBObjectIDOwner:=false;
       Result:=Obj as IJSObject;
       Result:=Obj as IJSObject;
     end;
     end;
   else
   else
@@ -2076,6 +2085,7 @@ end;
 
 
 function TJOBCallbackHelper.AllocObjId(ObjId: TJOBObjectID): PByte;
 function TJOBCallbackHelper.AllocObjId(ObjId: TJOBObjectID): PByte;
 begin
 begin
+  //writeln('TJOBCallbackHelper.AllocObjId ObjID=',ObjId);
   GetMem(Result,1+SizeOf(TJOBObjectID));
   GetMem(Result,1+SizeOf(TJOBObjectID));
   Result^:=JOBArgObject;
   Result^:=JOBArgObject;
   PJOBObjectID(Result+1)^:=ObjId;
   PJOBObjectID(Result+1)^:=ObjId;
@@ -2889,6 +2899,7 @@ end;
 constructor TJSObject.JOBCreateFromID(aID: TJOBObjectID);
 constructor TJSObject.JOBCreateFromID(aID: TJOBObjectID);
 begin
 begin
   FJOBObjectID:=aID;
   FJOBObjectID:=aID;
+  FJOBObjectIDOwner:=true;
 end;
 end;
 
 
 constructor TJSObject.JOBCreateGlobal(const aID: UnicodeString);
 constructor TJSObject.JOBCreateGlobal(const aID: UnicodeString);
@@ -2896,6 +2907,7 @@ begin
   FJOBObjectID:=__job_get_global(PWideChar(aID),length(aID));
   FJOBObjectID:=__job_get_global(PWideChar(aID),length(aID));
   if FJOBObjectID=0 then
   if FJOBObjectID=0 then
     raise EJSObject.Create('JS object "'+String(aID)+'" is not registered');
     raise EJSObject.Create('JS object "'+String(aID)+'" is not registered');
+  FJOBObjectIDOwner:=true;
 end;
 end;
 
 
 class function TJSObject.Cast(Intf: IJSObject): IJSObject;
 class function TJSObject.Cast(Intf: IJSObject): IJSObject;
@@ -2907,7 +2919,7 @@ destructor TJSObject.Destroy;
 begin
 begin
   if FJOBCastSrc<>nil then
   if FJOBCastSrc<>nil then
     FJOBCastSrc:=nil
     FJOBCastSrc:=nil
-  else if JOBObjectID>=0 then
+  else if (JOBObjectID>=0) and JOBObjectIDOwner then
     __job_release_object(JOBObjectID);
     __job_release_object(JOBObjectID);
   FJOBObjectID:=0;
   FJOBObjectID:=0;
   inherited Destroy;
   inherited Destroy;

+ 23 - 11
packages/job/job_browser.pp

@@ -31,7 +31,7 @@ Type
   Protected
   Protected
     function Invoke_JSResult(ObjId: TJOBObjectID; NameP, NameLen, Invoke, ArgsP: NativeInt; out JSResult: JSValue): TJOBResult; virtual;
     function Invoke_JSResult(ObjId: TJOBObjectID; NameP, NameLen, Invoke, ArgsP: NativeInt; out JSResult: JSValue): TJOBResult; virtual;
     function GetInvokeArguments(View: TJSDataView; ArgsP: NativeInt): TJSValueDynArray; virtual;
     function GetInvokeArguments(View: TJSDataView; ArgsP: NativeInt): TJSValueDynArray; virtual;
-    function CreateCallbackArgs(View: TJSDataView; const Args: TJSFunctionArguments): TWasmNativeInt; virtual;
+    function CreateCallbackArgs(View: TJSDataView; const Args: TJSFunctionArguments; TempObjIds: TJOBObjectIDArray): TWasmNativeInt; virtual;
     function EatCallbackResult(View: TJSDataView; ResultP: TWasmNativeInt): jsvalue; virtual;
     function EatCallbackResult(View: TJSDataView; ResultP: TWasmNativeInt): jsvalue; virtual;
     // exports
     // exports
     function Get_GlobalID(NameP, NameLen: NativeInt): TJOBObjectID; virtual;
     function Get_GlobalID(NameP, NameLen: NativeInt): TJOBObjectID; virtual;
@@ -487,13 +487,14 @@ var
 
 
   function ReadWasmNativeInt: TWasmNativeInt;
   function ReadWasmNativeInt: TWasmNativeInt;
   begin
   begin
-    Result:=View.getUint32(p,env.IsLittleEndian);
+    Result:=View.getInt32(p,env.IsLittleEndian);
     inc(p,4);
     inc(p,4);
   end;
   end;
 
 
   function ReadArgMethod: TProxyFunc;
   function ReadArgMethod: TProxyFunc;
   var
   var
     aCall, aData, aCode: TWasmNativeInt;
     aCall, aData, aCode: TWasmNativeInt;
+    i: Integer;
   begin
   begin
     aCall:=ReadWasmNativeInt;
     aCall:=ReadWasmNativeInt;
     aData:=ReadWasmNativeInt;
     aData:=ReadWasmNativeInt;
@@ -502,14 +503,21 @@ var
     Result:=function: jsvalue
     Result:=function: jsvalue
       var
       var
         Args, ResultP: TWasmNativeInt;
         Args, ResultP: TWasmNativeInt;
+        TempObjIds: TJOBObjectIDArray;
       begin
       begin
         //writeln('TJSObjectBridge called JS Method Call=',aCall,' Data=',aData,' Code=',aCode,' Args=',JSArguments.length);
         //writeln('TJSObjectBridge called JS Method Call=',aCall,' Data=',aData,' Code=',aCode,' Args=',JSArguments.length);
-        Args:=CreateCallbackArgs(View,JSArguments);
-        ResultP:=CallbackHandler(aCall,aData,aCode,Args); // this frees Args, and may detach View
-        View:=getModuleMemoryDataView();
-        //writeln('TJSObjectBridge called Wasm Call=',aCall,' Data=',aData,' Code=',aCode,' ResultP=',ResultP);
-        Result:=EatCallbackResult(View,ResultP); // this frees ResultP
-        //writeln('TJSObjectBridge Result=',Result);
+        Args:=CreateCallbackArgs(View,JSArguments,TempObjIds);
+        try
+          ResultP:=CallbackHandler(aCall,aData,aCode,Args); // this frees Args, and may detach View
+          View:=getModuleMemoryDataView();
+          //writeln('TJSObjectBridge called Wasm Call=',aCall,' Data=',aData,' Code=',aCode,' ResultP=',ResultP);
+          Result:=EatCallbackResult(View,ResultP); // this frees ResultP
+          //writeln('TJSObjectBridge Result=',Result);
+        finally
+          //writeln('After CallbackHandler: TempObjIds=',length(TempObjIds),' ',TempObjIds);
+          for i:=0 to length(TempObjIds)-1 do
+            ReleaseObject(TempObjIds[i]);
+        end;
       end;
       end;
   end;
   end;
 
 
@@ -653,7 +661,8 @@ begin
 end;
 end;
 
 
 function TJSObjectBridge.CreateCallbackArgs(View: TJSDataView;
 function TJSObjectBridge.CreateCallbackArgs(View: TJSDataView;
-  const Args: TJSFunctionArguments): TWasmNativeInt;
+  const Args: TJSFunctionArguments; TempObjIds: TJOBObjectIDArray
+  ): TWasmNativeInt;
 var
 var
   i, Len, j: Integer;
   i, Len, j: Integer;
   Arg: JSValue;
   Arg: JSValue;
@@ -694,7 +703,7 @@ begin
   begin
   begin
     Arg:=Args[i];
     Arg:=Args[i];
     r:=GetJOBResult(Arg);
     r:=GetJOBResult(Arg);
-    //writeln('TJSObjectBridge.CreateCallbackArgs ',i,'/',Args.Length,' r=',r);
+    writeln('TJSObjectBridge.CreateCallbackArgs ',i,'/',Args.Length,' r=',r);
     case r of
     case r of
     JOBResult_Null:
     JOBResult_Null:
       begin
       begin
@@ -735,7 +744,9 @@ begin
         View.setUint8(p,JOBArgObject);
         View.setUint8(p,JOBArgObject);
         inc(p);
         inc(p);
         NewId:=RegisterLocalObject(TJSObject(Arg));
         NewId:=RegisterLocalObject(TJSObject(Arg));
-        View.setUint32(p, longword(NewId), env.IsLittleEndian);
+        TJSArray(TempObjIds).push(NewId);
+        writeln('TJSObjectBridge.CreateCallbackArgs Object ID=',NewID);
+        View.setInt32(p, NewId, env.IsLittleEndian);
         inc(p,4);
         inc(p,4);
       end;
       end;
     else
     else
@@ -788,6 +799,7 @@ begin
       begin
       begin
         ObjId:=View.getInt32(p,env.IsLittleEndian);
         ObjId:=View.getInt32(p,env.IsLittleEndian);
         Result:=FindObject(ObjId);
         Result:=FindObject(ObjId);
+        writeln('TJSObjectBridge.EatCallbackResult ObjID=',ObjId,' Result=',Result<>nil);
       end;
       end;
     else
     else
       Result:=Undefined;
       Result:=Undefined;

+ 1 - 0
packages/job/job_shared.pp

@@ -9,6 +9,7 @@ interface
 
 
 type
 type
   TJOBObjectID = NativeInt;
   TJOBObjectID = NativeInt;
+  TJOBObjectIDArray = array of TJOBObjectID;
 
 
 // invoke results
 // invoke results
 type
 type