ソースを参照

* cleaner fix for tb0496 (r1185)

git-svn-id: trunk@1196 -
peter 20 年 前
コミット
2f0fdd1847
6 ファイル変更85 行追加95 行削除
  1. 0 16
      compiler/ncal.pas
  2. 13 8
      compiler/ncgcal.pas
  3. 12 53
      compiler/ncgmem.pas
  4. 50 0
      compiler/ncgutil.pas
  5. 1 17
      compiler/ncnv.pas
  6. 9 1
      tests/webtbs/tw3499.pp

+ 0 - 16
compiler/ncal.pas

@@ -1906,22 +1906,6 @@ type
          { bind parasyms to the callparanodes and insert hidden parameters }
          bind_parasym;
 
-         { methodpointer needs to be a pointer to the VMT for virtual calls.
-           Note: We need to keep the methodpointer in the callnode for TP
-           procvar support, because this calln still maybe converted to a loadn,
-           see tw3499 }
-         if (po_virtualmethod in procdefinition.procoptions) then
-          begin
-            if not assigned(methodpointer) then
-              internalerror(200305063);
-            if (methodpointer.nodetype<>typen) and
-               (methodpointer.resulttype.def.deftype<>classrefdef) then
-              begin
-                methodpointer:=cloadvmtaddrnode.create(methodpointer);
-                resulttypepass(methodpointer);
-              end;
-          end;
-
          { insert type conversions for parameters }
          if assigned(left) then
            tcallparanode(left).insert_typeconv(true);

+ 13 - 8
compiler/ncgcal.pas

@@ -855,22 +855,27 @@ implementation
                 assigned(methodpointer) and
                 (methodpointer.nodetype<>typen) then
                begin
-                 secondpass(methodpointer);
-                 location_force_reg(exprasmlist,methodpointer.location,OS_ADDR,false);
-
                  { virtual methods require an index }
                  if tprocdef(procdefinition).extnumber=$ffff then
                    internalerror(200304021);
-                 { VMT should already be loaded in a register }
-                 if methodpointer.location.register=NR_NO then
-                   internalerror(200304022);
+
+                 secondpass(methodpointer);
+
+                 { Load VMT from self }
+                 if methodpointer.resulttype.def.deftype=objectdef then
+                   gen_load_vmt_register(exprasmlist,tobjectdef(methodpointer.resulttype.def),methodpointer.location,vmtreg)
+                 else
+                   begin
+                     { Load VMT value in register }
+                     location_force_reg(exprasmlist,methodpointer.location,OS_ADDR,false);
+                     vmtreg:=methodpointer.location.register;
+                   end;
 
                  { test validity of VMT }
                  if not(is_interface(tprocdef(procdefinition)._class)) and
                     not(is_cppclass(tprocdef(procdefinition)._class)) then
-                   cg.g_maybe_testvmt(exprasmlist,methodpointer.location.register,tprocdef(procdefinition)._class);
+                   cg.g_maybe_testvmt(exprasmlist,vmtreg,tprocdef(procdefinition)._class);
 
-                 vmtreg:=methodpointer.location.register;
                  pvreg:=cg.getintregister(exprasmlist,OS_ADDR);
                  reference_reset_base(href,vmtreg,
                     tprocdef(procdefinition)._class.vmtmethodoffset(tprocdef(procdefinition).extnumber));

+ 12 - 53
compiler/ncgmem.pas

@@ -98,60 +98,19 @@ implementation
 
       begin
          location_reset(location,LOC_REGISTER,OS_ADDR);
-         if (left.nodetype<>typen) then
-          begin
-            { left contains self, load vmt from self }
-            secondpass(left);
-            if is_object(left.resulttype.def) then
-             begin
-               case left.location.loc of
-                  LOC_CREFERENCE,
-                  LOC_REFERENCE:
-                    begin
-                       reference_reset_base(href,cg.getaddressregister(exprasmlist),tobjectdef(left.resulttype.def).vmt_offset);
-                       cg.a_loadaddr_ref_reg(exprasmlist,left.location.reference,href.base);
-                    end;
-                  else
-                    internalerror(200305056);
-               end;
-             end
-            else
-             begin
-               case left.location.loc of
-                  LOC_REGISTER:
-                    begin
-                    {$ifdef cpu_uses_separate_address_registers}
-                      if getregtype(left.location.register)<>R_ADDRESSREGISTER then
-                        begin
-                          reference_reset_base(href,cg.getaddressregister(exprasmlist),tobjectdef(left.resulttype.def).vmt_offset);
-                          cg.a_load_reg_reg(exprasmlist,OS_ADDR,OS_ADDR,left.location.register,href.base);
-                        end
-                      else
-                    {$endif}
-                        reference_reset_base(href,left.location.register,tobjectdef(left.resulttype.def).vmt_offset);
-                    end;
-                  LOC_CREGISTER,
-                  LOC_CREFERENCE,
-                  LOC_REFERENCE:
-                    begin
-                       reference_reset_base(href,cg.getaddressregister(exprasmlist),tobjectdef(left.resulttype.def).vmt_offset);
-                       cg.a_load_loc_reg(exprasmlist,OS_ADDR,left.location,href.base);
-                    end;
-                  else
-                    internalerror(200305057);
-               end;
-             end;
-            location.register:=cg.getaddressregister(exprasmlist);
-            cg.g_maybe_testself(exprasmlist,href.base);
-            cg.a_load_ref_reg(exprasmlist,OS_ADDR,OS_ADDR,href,location.register);
-          end
+         if (left.nodetype=typen) then
+           begin
+             reference_reset_symbol(href,
+               objectlibrary.newasmsymbol(tobjectdef(tclassrefdef(resulttype.def).pointertype.def).vmt_mangledname,AB_EXTERNAL,AT_DATA),0);
+             location.register:=cg.getaddressregister(exprasmlist);
+             cg.a_loadaddr_ref_reg(exprasmlist,href,location.register);
+           end
          else
-          begin
-            reference_reset_symbol(href,
-              objectlibrary.newasmsymbol(tobjectdef(tclassrefdef(resulttype.def).pointertype.def).vmt_mangledname,AB_EXTERNAL,AT_DATA),0);
-            location.register:=cg.getaddressregister(exprasmlist);
-            cg.a_loadaddr_ref_reg(exprasmlist,href,location.register);
-          end;
+           begin
+             { left contains self, load vmt from self }
+             secondpass(left);
+             gen_load_vmt_register(exprasmlist,tobjectdef(left.resulttype.def),left.location,location.register);
+           end;
       end;
 
 

+ 50 - 0
compiler/ncgutil.pas

@@ -71,6 +71,7 @@ interface
 
     procedure gen_external_stub(list:taasmoutput;pd:tprocdef;const externalname:string);
     procedure gen_intf_wrappers(list:taasmoutput;st:tsymtable);
+    procedure gen_load_vmt_register(list:taasmoutput;objdef:tobjectdef;selfloc:tlocation;var vmtreg:tregister);
 
    {#
       Allocate the buffers for exception management and setjmp environment.
@@ -2390,4 +2391,53 @@ implementation
           end;
       end;
 
+
+    procedure gen_load_vmt_register(list:taasmoutput;objdef:tobjectdef;selfloc:tlocation;var vmtreg:tregister);
+      var
+        href : treference;
+      begin
+        if is_object(objdef) then
+          begin
+            case selfloc.loc of
+              LOC_CREFERENCE,
+              LOC_REFERENCE:
+                begin
+                  reference_reset_base(href,cg.getaddressregister(list),objdef.vmt_offset);
+                  cg.a_loadaddr_ref_reg(list,selfloc.reference,href.base);
+                end;
+              else
+                internalerror(200305056);
+            end;
+          end
+        else
+          begin
+            case selfloc.loc of
+              LOC_REGISTER:
+                begin
+{$ifdef cpu_uses_separate_address_registers}
+                  if getregtype(left.location.register)<>R_ADDRESSREGISTER then
+                    begin
+                      reference_reset_base(href,cg.getaddressregister(list),objdef.vmt_offset);
+                      cg.a_load_reg_reg(list,OS_ADDR,OS_ADDR,selfloc.register,href.base);
+                    end
+                  else
+{$endif cpu_uses_separate_address_registers}
+                    reference_reset_base(href,selfloc.register,objdef.vmt_offset);
+                end;
+              LOC_CREGISTER,
+              LOC_CREFERENCE,
+              LOC_REFERENCE:
+                begin
+                    reference_reset_base(href,cg.getaddressregister(list),objdef.vmt_offset);
+                    cg.a_load_loc_reg(list,OS_ADDR,selfloc,href.base);
+                end;
+              else
+                internalerror(200305057);
+            end;
+          end;
+        vmtreg:=cg.getaddressregister(list);
+        cg.g_maybe_testself(list,href.base);
+        cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,vmtreg);
+      end;
+
 end.

+ 1 - 17
compiler/ncnv.pas

@@ -1518,23 +1518,7 @@ implementation
                             if (tcallnode(left).symtableprocentry.owner.symtabletype=objectsymtable) then
                              begin
                                if assigned(tcallnode(left).methodpointer) then
-                                 begin
-                                   { kick the loadvmtaddrnode we added in ncal.pas around line 1920?
-                                     if you mess around here, check tbs/tb0496.pp (FK)
-                                   }
-                                   if (po_virtualmethod in tcallnode(left).procdefinition.procoptions) and
-                                     (tcallnode(left).methodpointer.nodetype=loadvmtaddrn) and
-                                     assigned(tloadvmtaddrnode(tcallnode(left).methodpointer).left) and
-                                     (tloadvmtaddrnode(tcallnode(left).methodpointer).left.nodetype<>typen) and
-                                     (tloadvmtaddrnode(tcallnode(left).methodpointer).left.resulttype.def.deftype<>classrefdef) then
-                                     begin
-                                       hp2:=tcallnode(left).methodpointer;
-                                       tcallnode(left).methodpointer:=tloadvmtaddrnode(tcallnode(left).methodpointer).left;
-                                       tloadvmtaddrnode(hp2).left:=nil;
-                                       hp2.free;
-                                     end;
-                                   tloadnode(hp).set_mp(tcallnode(left).get_load_methodpointer)
-                                 end
+                                 tloadnode(hp).set_mp(tcallnode(left).get_load_methodpointer)
                                else
                                  tloadnode(hp).set_mp(load_self_node);
                              end;

+ 9 - 1
tests/webtbs/tw3499.pp

@@ -3,10 +3,13 @@
 { e-mail: [email protected] }
 program test;
 
-{$mode delphi}
+{$ifdef fpc}{$mode delphi}{$endif}
 
 uses SysUtils;
 
+var
+  err : boolean;
+
 type
   TProcedure = procedure of object;
   Class1 = class
@@ -27,13 +30,18 @@ end;
 procedure Class2.d();
 begin
   writeLn('procedure called');
+  err:=false;
 end;
 
 var
   c: Class1;
   e: Class2;
 begin
+  err:=true;
   c := Class1.create();
   e := Class2.create();
   c.p(e.d);
+  c.proc;
+  if err then
+    halt(1);
 end.