From 181804e4b99392e09cd134bbd1379a419a2e5fd2 Mon Sep 17 00:00:00 2001
From: joost <joost@cnoc.nl>
Date: Sun, 8 Aug 2010 13:27:54 +0000
Subject: [PATCH]  * Fixed passing parameters on the stack to cdecl
 interface-methods. The 'call'    shifted all the parameters on the stack. Now
 the 'self' parameter is    declared as var, not const, restoring its original
 value is not necessary    anymore

git-svn-id: trunk@15744 -
---
 .gitattributes            |  2 ++
 compiler/i386/cgcpu.pas   | 51 ++++++---------------------------------
 tests/test/tintfcdecl1.pp | 42 ++++++++++++++++++++++++++++++++
 tests/test/tintfcdecl2.pp | 42 ++++++++++++++++++++++++++++++++
 4 files changed, 93 insertions(+), 44 deletions(-)
 create mode 100644 tests/test/tintfcdecl1.pp
 create mode 100644 tests/test/tintfcdecl2.pp

diff --git a/.gitattributes b/.gitattributes
index 027b677f58..70213ac393 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -9235,6 +9235,8 @@ tests/test/tinterface4.pp svneol=native#text/plain
 tests/test/tinterface5.pp svneol=native#text/plain
 tests/test/tinterface6.pp svneol=native#text/plain
 tests/test/tinterrupt.pp svneol=native#text/plain
+tests/test/tintfcdecl1.pp svneol=native#text/plain
+tests/test/tintfcdecl2.pp svneol=native#text/plain
 tests/test/tintfdef.pp svneol=native#text/plain
 tests/test/tintuint.pp svneol=native#text/plain
 tests/test/tisogoto1.pp svneol=native#text/pascal
diff --git a/compiler/i386/cgcpu.pas b/compiler/i386/cgcpu.pas
index faeedca2e6..94c840a5bb 100644
--- a/compiler/i386/cgcpu.pas
+++ b/compiler/i386/cgcpu.pas
@@ -552,38 +552,20 @@ unit cgcpu;
       {
       possible calling conventions:
                     default stdcall cdecl pascal register
-      default(0):      OK     OK    OK(1)  OK       OK
-      virtual(2):      OK     OK    OK(3)  OK       OK
+      default(0):      OK     OK    OK     OK       OK
+      virtual(1):      OK     OK    OK     OK       OK(2)
 
       (0):
           set self parameter to correct value
           jmp mangledname
 
-      (1): The code is the following
-           set self parameter to correct value
-           call mangledname
-           set self parameter to interface value
-           ret
-
-           This is different to case (0) because in theory, the caller
-           could reuse the data pushed on the stack so we've to return
-           it unmodified because self is const.
-
-      (2): The wrapper code use %eax to reach the virtual method address
+      (1): The wrapper code use %eax to reach the virtual method address
            set self to correct value
            move self,%eax
            mov  0(%eax),%eax ; load vmt
            jmp  vmtoffs(%eax) ; method offs
 
-      (3): The wrapper code use %eax to reach the virtual method address
-           set self to correct value
-           move self,%eax
-           mov  0(%eax),%eax ; load vmt
-           jmp  vmtoffs(%eax) ; method offs
-           set self parameter to interface value
-
-
-      (4): Virtual use values pushed on stack to reach the method address
+      (2): Virtual use values pushed on stack to reach the method address
            so the following code be generated:
            set self to correct value
            push %ebx ; allocate space for function address
@@ -676,30 +658,11 @@ unit cgcpu;
         { set param1 interface to self  }
         g_adjust_self_value(list,procdef,ioffset);
 
-        { case 1 or 2 }
-        if (procdef.proccalloption in clearstack_pocalls) then
-          begin
-            if po_virtualmethod in procdef.procoptions then
-              begin
-                { case 2 }
-                getselftoeax(0);
-                loadvmttoeax;
-                op_oneaxmethodaddr(A_CALL);
-              end
-            else
-              begin
-                { case 1 }
-                cg.a_call_name(list,procdef.mangledname,false);
-              end;
-            { restore param1 value self to interface }
-            g_adjust_self_value(list,procdef,-ioffset);
-            list.concat(taicpu.op_none(A_RET,S_L));
-          end
-        else if po_virtualmethod in procdef.procoptions then
+        if po_virtualmethod in procdef.procoptions then
           begin
             if (procdef.proccalloption=pocall_register) then
               begin
-                { case 4 }
+                { case 2 }
                 list.concat(taicpu.op_reg(A_PUSH,S_L,NR_EBX)); { allocate space for address}
                 list.concat(taicpu.op_reg(A_PUSH,S_L,NR_EAX));
                 getselftoeax(8);
@@ -715,7 +678,7 @@ unit cgcpu;
               end
             else
               begin
-                { case 3 }
+                { case 1 }
                 getselftoeax(0);
                 loadvmttoeax;
                 op_oneaxmethodaddr(A_JMP);
diff --git a/tests/test/tintfcdecl1.pp b/tests/test/tintfcdecl1.pp
new file mode 100644
index 0000000000..75a407cdd8
--- /dev/null
+++ b/tests/test/tintfcdecl1.pp
@@ -0,0 +1,42 @@
+program tinfcdecl1;
+
+{$mode objfpc}{$H+}
+
+type
+  IcdeclIntf = interface
+  ['{3C409C8B-3A15-44B2-B22D-6BAA2071CAAD}']
+    function DoSomething : longint; cdecl;
+  end;
+
+  { TcdeclClass }
+
+  TcdeclClass = class(TInterfacedObject,IcdeclIntf)
+  private
+    FCounter: integer;
+  public
+    function DoSomething : longint; cdecl;
+  end;
+
+{ TcdeclClass }
+
+function TcdeclClass.DoSomething: longint; cdecl;
+begin
+  inc(FCounter);
+  result := FCounter;
+end;
+
+var
+  js: TcdeclClass;
+  ji: IcdeclIntf;
+  i: longint;
+begin
+  js := TcdeclClass.Create;
+
+  i := js.DoSomething;
+
+  ji := IcdeclIntf(js);
+  i := ji.DoSomething;
+
+  if i <> 2 then halt(1);
+end.
+
diff --git a/tests/test/tintfcdecl2.pp b/tests/test/tintfcdecl2.pp
new file mode 100644
index 0000000000..ec9b93607a
--- /dev/null
+++ b/tests/test/tintfcdecl2.pp
@@ -0,0 +1,42 @@
+program tintfcdecl2;
+
+{$mode objfpc}{$H+}
+
+type
+  IcdeclIntf = interface
+  ['{3C409C8B-3A15-44B2-B22D-6BAA2071CAAD}']
+    function DoSomething : longint; cdecl;
+  end;
+
+  { TcdeclClass }
+
+  TcdeclClass = class(TInterfacedObject,IcdeclIntf)
+  private
+    FCounter: integer;
+  public
+    function DoSomething : longint; cdecl; virtual;
+  end;
+
+{ TcdeclClass }
+
+function TcdeclClass.DoSomething: longint; cdecl;
+begin
+  inc(FCounter);
+  result := FCounter;
+end;
+
+var
+  js: TcdeclClass;
+  ji: IcdeclIntf;
+  i: longint;
+begin
+  js := TcdeclClass.Create;
+
+  i := js.DoSomething;
+
+  ji := IcdeclIntf(js);
+  i := ji.DoSomething;
+
+  if i <> 2 then halt(1);
+end.
+