Browse Source

* handle the loading of VMT entries at the node level, so it's done in a
type-safe way (for LLVM, and also internal consistency checking between
the VMT as generated in nobj.pas and ncgvmt.pas)
o also converted the VMT validity checking to the node level

git-svn-id: trunk@30950 -

Jonas Maebe 10 years ago
parent
commit
3f736f6114

+ 0 - 47
compiler/cgobj.pas

@@ -348,7 +348,6 @@ unit cgobj;
           procedure optimize_op_const(size: TCGSize; var op: topcg; var a : tcgint);virtual;
           procedure optimize_op_const(size: TCGSize; var op: topcg; var a : tcgint);virtual;
 
 
 
 
-          procedure g_maybe_testvmt(list : TAsmList;reg:tregister;objdef:tobjectdef);
           {# This should emit the opcode to copy len bytes from the source
           {# This should emit the opcode to copy len bytes from the source
              to destination.
              to destination.
 
 
@@ -2185,52 +2184,6 @@ implementation
 {$endif cpuflags}
 {$endif cpuflags}
 
 
 
 
-    procedure tcg.g_maybe_testvmt(list : TAsmList;reg:tregister;objdef:tobjectdef);
-      var
-        hrefvmt : treference;
-        cgpara1,cgpara2 : TCGPara;
-        pd: tprocdef;
-      begin
-        cgpara1.init;
-        cgpara2.init;
-        if (cs_check_object in current_settings.localswitches) then
-         begin
-           pd:=search_system_proc('fpc_check_object_ext');
-           paramanager.getintparaloc(list,pd,1,cgpara1);
-           paramanager.getintparaloc(list,pd,2,cgpara2);
-           reference_reset_symbol(hrefvmt,current_asmdata.RefAsmSymbol(objdef.vmt_mangledname,AT_DATA),0,sizeof(pint));
-           if pd.is_pushleftright then
-             begin
-               a_load_reg_cgpara(list,OS_ADDR,reg,cgpara1);
-               a_loadaddr_ref_cgpara(list,hrefvmt,cgpara2);
-             end
-           else
-             begin
-               a_loadaddr_ref_cgpara(list,hrefvmt,cgpara2);
-               a_load_reg_cgpara(list,OS_ADDR,reg,cgpara1);
-             end;
-           paramanager.freecgpara(list,cgpara1);
-           paramanager.freecgpara(list,cgpara2);
-           allocallcpuregisters(list);
-           a_call_name(list,'fpc_check_object_ext',false);
-           deallocallcpuregisters(list);
-         end
-        else
-         if (cs_check_range in current_settings.localswitches) then
-          begin
-            pd:=search_system_proc('fpc_check_object');
-            paramanager.getintparaloc(list,pd,1,cgpara1);
-            a_load_reg_cgpara(list,OS_ADDR,reg,cgpara1);
-            paramanager.freecgpara(list,cgpara1);
-            allocallcpuregisters(list);
-            a_call_name(list,'fpc_check_object',false);
-            deallocallcpuregisters(list);
-          end;
-        cgpara1.done;
-        cgpara2.done;
-      end;
-
-
 {*****************************************************************************
 {*****************************************************************************
                             Entry/Exit Code Functions
                             Entry/Exit Code Functions
 *****************************************************************************}
 *****************************************************************************}

+ 7 - 0
compiler/jvm/njvmcal.pas

@@ -50,6 +50,7 @@ interface
          procedure extra_post_call_code; override;
          procedure extra_post_call_code; override;
          function dispatch_procvar: tnode;
          function dispatch_procvar: tnode;
          procedure remove_hidden_paras;
          procedure remove_hidden_paras;
+         procedure gen_vmt_entry_load; override;
         public
         public
          function pass_typecheck: tnode; override;
          function pass_typecheck: tnode; override;
          function pass_1: tnode; override;
          function pass_1: tnode; override;
@@ -492,6 +493,12 @@ implementation
     end;
     end;
 
 
 
 
+  procedure tjvmcallnode.gen_vmt_entry_load;
+    begin
+      { nothing to do }
+    end;
+
+
   function tjvmcallnode.pass_typecheck: tnode;
   function tjvmcallnode.pass_typecheck: tnode;
     begin
     begin
       result:=inherited pass_typecheck;
       result:=inherited pass_typecheck;

+ 37 - 0
compiler/ncal.pas

@@ -84,6 +84,7 @@ interface
           procedure register_created_object_types;
           procedure register_created_object_types;
           function get_expect_loc: tcgloc;
           function get_expect_loc: tcgloc;
        protected
        protected
+          procedure gen_vmt_entry_load; virtual;
           procedure gen_syscall_para(para: tcallparanode); virtual;
           procedure gen_syscall_para(para: tcallparanode); virtual;
           procedure objc_convert_to_message_send;virtual;
           procedure objc_convert_to_message_send;virtual;
 
 
@@ -123,6 +124,8 @@ interface
           procdefinitionderef : tderef;
           procdefinitionderef : tderef;
           { tree that contains the pointer to the object for this method }
           { tree that contains the pointer to the object for this method }
           methodpointer  : tnode;
           methodpointer  : tnode;
+          { tree representing the VMT entry to call (if any) }
+          vmt_entry      : tnode;
           { tree that contains the self/vmt parameter when this node was created
           { tree that contains the self/vmt parameter when this node was created
             (so it's still valid when this node is processed in an inline
             (so it's still valid when this node is processed in an inline
              context)
              context)
@@ -1484,6 +1487,7 @@ implementation
            varargsparas.free;
            varargsparas.free;
          call_self_node.free;
          call_self_node.free;
          call_vmt_node.free;
          call_vmt_node.free;
+         vmt_entry.free;
 {$ifndef symansistr}
 {$ifndef symansistr}
          stringdispose(fforcedprocname);
          stringdispose(fforcedprocname);
 {$endif symansistr}
 {$endif symansistr}
@@ -2323,6 +2327,36 @@ implementation
       end;
       end;
 
 
 
 
+    procedure tcallnode.gen_vmt_entry_load;
+      var
+        vmt_def: trecorddef;
+      begin
+        if not assigned(right) and
+           (forcedprocname='') and
+           (po_virtualmethod in procdefinition.procoptions) and
+           not is_objectpascal_helper(tprocdef(procdefinition).struct) and
+           assigned(methodpointer) and
+           (methodpointer.nodetype<>typen) then
+          begin
+            vmt_entry:=load_vmt_for_self_node(methodpointer.getcopy);
+            { get the right entry in the VMT }
+            vmt_entry:=cderefnode.create(vmt_entry);
+            typecheckpass(vmt_entry);
+            vmt_def:=trecorddef(vmt_entry.resultdef);
+            { tobjectdef(tprocdef(procdefinition).struct) can be a parent of the
+              methodpointer's resultdef, but the vmtmethodoffset of the method
+              in that objectdef is obviously the same as in any child class }
+            vmt_entry:=csubscriptnode.create(
+                trecordsymtable(vmt_def.symtable).findfieldbyoffset(
+                  tobjectdef(tprocdef(procdefinition).struct).vmtmethodoffset(tprocdef(procdefinition).extnumber)
+                ),
+               vmt_entry
+              );
+            firstpass(vmt_entry);
+          end;
+      end;
+
+
     procedure tcallnode.gen_syscall_para(para: tcallparanode);
     procedure tcallnode.gen_syscall_para(para: tcallparanode);
       begin
       begin
         { unsupported }
         { unsupported }
@@ -4093,6 +4127,9 @@ implementation
            end
            end
          else
          else
            expectloc:=LOC_VOID;
            expectloc:=LOC_VOID;
+
+         { create tree for VMT entry if required }
+         gen_vmt_entry_load;
       end;
       end;
 
 
 {$ifdef state_tracking}
 {$ifdef state_tracking}

+ 9 - 21
compiler/ncgcal.pas

@@ -890,8 +890,7 @@ implementation
         href : treference;
         href : treference;
         pop_size : longint;
         pop_size : longint;
         vmtoffset : aint;
         vmtoffset : aint;
-        pvreg,
-        vmtreg : tregister;
+        pvreg : tregister;
         oldaktcallnode : tcallnode;
         oldaktcallnode : tcallnode;
         retlocitem: pcgparalocation;
         retlocitem: pcgparalocation;
         pd : tprocdef;
         pd : tprocdef;
@@ -1001,37 +1000,26 @@ implementation
                  if tprocdef(procdefinition).extnumber=$ffff then
                  if tprocdef(procdefinition).extnumber=$ffff then
                    internalerror(200304021);
                    internalerror(200304021);
 
 
-                 secondpass(methodpointer);
+                 { load the VMT entry (address of the virtual method) }
+                 secondpass(vmt_entry);
 
 
-                 { Load VMT from self }
-                 if methodpointer.resultdef.typ=objectdef then
-                   gen_load_vmt_register(current_asmdata.CurrAsmList,tobjectdef(methodpointer.resultdef),methodpointer.location,vmtreg)
-                 else
-                   begin
-                     { Load VMT value in register }
-                     hlcg.location_force_reg(current_asmdata.CurrAsmList,methodpointer.location,methodpointer.resultdef,methodpointer.resultdef,false);
-                     vmtreg:=methodpointer.location.register;
-                     { test validity of VMT }
-                     if not(is_interface(tprocdef(procdefinition).struct)) and
-                        not(is_cppclass(tprocdef(procdefinition).struct)) then
-                       cg.g_maybe_testvmt(current_asmdata.CurrAsmList,vmtreg,tobjectdef(tprocdef(procdefinition).struct));
-                   end;
-
-                 { Call through VMT, generate a VTREF symbol to notify the linker }
-                 vmtoffset:=tobjectdef(tprocdef(procdefinition).struct).vmtmethodoffset(tprocdef(procdefinition).extnumber);
                  { register call for WPO }
                  { register call for WPO }
                  if (not assigned(current_procinfo) or
                  if (not assigned(current_procinfo) or
                      wpoinfomanager.symbol_live(current_procinfo.procdef.mangledname)) then
                      wpoinfomanager.symbol_live(current_procinfo.procdef.mangledname)) then
                    tobjectdef(tprocdef(procdefinition).struct).register_vmt_call(tprocdef(procdefinition).extnumber);
                    tobjectdef(tprocdef(procdefinition).struct).register_vmt_call(tprocdef(procdefinition).extnumber);
 
 
-                 reference_reset_base(href,vmtreg,vmtoffset,proc_addr_voidptrdef.alignment);
+                 if not(vmt_entry.location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
+                   internalerror(2015052502);
+                 href:=vmt_entry.location.reference;
                  pvreg:=NR_NO;
                  pvreg:=NR_NO;
 
 
                  callref:=can_call_ref(href);
                  callref:=can_call_ref(href);
                  if not callref then
                  if not callref then
                    begin
                    begin
                      pvreg:=get_call_reg(current_asmdata.CurrAsmList);
                      pvreg:=get_call_reg(current_asmdata.CurrAsmList);
-                     cg.a_load_ref_reg(current_asmdata.CurrAsmList,proc_addr_size,proc_addr_size,href,pvreg);
+                     hlcg.a_load_ref_reg(current_asmdata.CurrAsmList,
+                       vmt_entry.resultdef,vmt_entry.resultdef,
+                       href,pvreg);
                    end;
                    end;
 
 
                  { Load parameters that are in temporary registers in the
                  { Load parameters that are in temporary registers in the

+ 2 - 5
compiler/ncgmem.pas

@@ -138,11 +138,8 @@ implementation
                end;
                end;
            end
            end
          else
          else
-           begin
-             { left contains self, load vmt from self }
-             secondpass(left);
-             gen_load_vmt_register(current_asmdata.CurrAsmList,tobjectdef(left.resultdef),left.location,location.register);
-           end;
+           { should be handled in pass 1 }
+           internalerror(2015052801);
       end;
       end;
 
 
 
 

+ 0 - 68
compiler/ncgutil.pas

@@ -85,7 +85,6 @@ interface
     procedure gen_load_para_value(list:TAsmList);
     procedure gen_load_para_value(list:TAsmList);
 
 
     procedure gen_external_stub(list:TAsmList;pd:tprocdef;const externalname:string);
     procedure gen_external_stub(list:TAsmList;pd:tprocdef;const externalname:string);
-    procedure gen_load_vmt_register(list:TAsmList;objdef:tobjectdef;selfloc:tlocation;var vmtreg:tregister);
 
 
     procedure get_used_regvars(n: tnode; var rv: tusedregvars);
     procedure get_used_regvars(n: tnode; var rv: tusedregvars);
     { adds the regvars used in n and its children to rv.allregvars,
     { adds the regvars used in n and its children to rv.allregvars,
@@ -1899,73 +1898,6 @@ implementation
       end;
       end;
 
 
 
 
-    procedure gen_load_vmt_register(list:TAsmList;objdef:tobjectdef;selfloc:tlocation;var vmtreg:tregister);
-      var
-        href : treference;
-        selfdef: tdef;
-      begin
-        if is_object(objdef) then
-          begin
-            case selfloc.loc of
-              LOC_CREFERENCE,
-              LOC_REFERENCE:
-                begin
-                  hlcg.reference_reset_base(href,voidpointertype,hlcg.getaddressregister(list,voidpointertype),objdef.vmt_offset,voidpointertype.size);
-                  hlcg.a_loadaddr_ref_reg(list,voidpointertype,voidpointertype,selfloc.reference,href.base);
-                  selfdef:=getpointerdef(objdef);
-                end;
-              else
-                internalerror(200305056);
-            end;
-          end
-        else
-          { This is also valid for Objective-C classes: vmt_offset is 0 there,
-            and the first "field" of an Objective-C class instance is a pointer
-            to its "meta-class".  }
-          begin
-            selfdef:=objdef;
-            case selfloc.loc of
-              LOC_REGISTER:
-                begin
-{$ifdef cpu_uses_separate_address_registers}
-                  if getregtype(selfloc.register)<>R_ADDRESSREGISTER then
-                    begin
-                      reference_reset_base(href,cg.getaddressregister(list),objdef.vmt_offset,sizeof(pint));
-                      cg.a_load_reg_reg(list,OS_ADDR,OS_ADDR,selfloc.register,href.base);
-                    end
-                  else
-{$endif cpu_uses_separate_address_registers}
-                    hlcg.reference_reset_base(href,voidpointertype,selfloc.register,objdef.vmt_offset,voidpointertype.size);
-                end;
-              LOC_CONSTANT,
-              LOC_CREGISTER,
-              LOC_CREFERENCE,
-              LOC_REFERENCE,
-              LOC_CSUBSETREG,
-              LOC_SUBSETREG,
-              LOC_CSUBSETREF,
-              LOC_SUBSETREF:
-                begin
-                  hlcg.reference_reset_base(href,voidpointertype,hlcg.getaddressregister(list,voidpointertype),objdef.vmt_offset,voidpointertype.size);
-                  { todo: pass actual vmt pointer type to hlcg }
-                  hlcg.a_load_loc_reg(list,voidpointertype,voidpointertype,selfloc,href.base);
-                end;
-              else
-                internalerror(200305057);
-            end;
-          end;
-        vmtreg:=hlcg.getaddressregister(list,voidpointertype);
-        hlcg.g_maybe_testself(list,selfdef,href.base);
-        hlcg.a_load_ref_reg(list,voidpointertype,voidpointertype,href,vmtreg);
-
-        { test validity of VMT }
-        if not(is_interface(objdef)) and
-           not(is_cppclass(objdef)) and
-           not(is_objc_class_or_protocol(objdef)) then
-           cg.g_maybe_testvmt(list,vmtreg,objdef);
-      end;
-
-
     function getprocalign : shortint;
     function getprocalign : shortint;
       begin
       begin
         { gprof uses 16 byte granularity }
         { gprof uses 16 byte granularity }

+ 3 - 1
compiler/ncgvmt.pas

@@ -1086,7 +1086,9 @@ implementation
               genintmsgtab(tcb,intmessagetable,intmessagetabledef);
               genintmsgtab(tcb,intmessagetable,intmessagetabledef);
           end;
           end;
 
 
-         tcb.begin_anonymous_record('',voidpointertype.alignment,
+         { reuse the type created in nobj, so we get internal consistency
+           checking for free }
+         tcb.begin_anonymous_record('$vmtdef$'+_class.mangledparaname,voidpointertype.alignment,
            targetinfos[target_info.system]^.alignment.recordalignmin,
            targetinfos[target_info.system]^.alignment.recordalignmin,
            targetinfos[target_info.system]^.alignment.maxCrecordalign);
            targetinfos[target_info.system]^.alignment.maxCrecordalign);
 
 

+ 3 - 3
compiler/nmem.pas

@@ -260,11 +260,11 @@ implementation
                    end
                    end
                  else
                  else
                    result:=objcloadbasefield(left,'ISA');
                    result:=objcloadbasefield(left,'ISA');
-                 { reused }
-                 left:=nil;
                end
                end
              else
              else
-               firstpass(left);
+               result:=ctypeconvnode.create_internal(load_vmt_for_self_node(left),resultdef);
+             { reused }
+             left:=nil;
            end
            end
          else if not is_objcclass(left.resultdef) and
          else if not is_objcclass(left.resultdef) and
                  not is_objcclassref(left.resultdef) then
                  not is_objcclassref(left.resultdef) then

+ 88 - 3
compiler/nobj.pas

@@ -46,6 +46,7 @@ interface
         procedure prot_get_procdefs_recursive(ImplProt:TImplementedInterface;ProtDef:TObjectDef);
         procedure prot_get_procdefs_recursive(ImplProt:TImplementedInterface;ProtDef:TObjectDef);
         procedure intf_optimize_vtbls;
         procedure intf_optimize_vtbls;
         procedure intf_allocate_vtbls;
         procedure intf_allocate_vtbls;
+        procedure generate_vmt_def;
       public
       public
         constructor create(c:tobjectdef);
         constructor create(c:tobjectdef);
         procedure  generate_vmt;
         procedure  generate_vmt;
@@ -57,9 +58,9 @@ implementation
 
 
     uses
     uses
        SysUtils,
        SysUtils,
-       globals,verbose,systems,
+       globals,verbose,systems,fmodule,
        node,
        node,
-       symbase,symtable,symconst,symtype,defcmp,
+       symbase,symtable,symconst,symtype,defcmp,defutil,
        symcpu,
        symcpu,
        dbgbase,
        dbgbase,
        wpobase
        wpobase
@@ -786,6 +787,90 @@ implementation
       end;
       end;
 
 
 
 
+    procedure TVMTBuilder.generate_vmt_def;
+      var
+        i: longint;
+        vmtdef: trecorddef;
+        systemvmt: tdef;
+        sym: tsym;
+        symtab: tsymtable;
+      begin
+        { these types don't have an actual VMT, we only use the other methods
+          in TVMTBuilder to determine duplicates/overrides }
+        if _class.objecttype in [
+           odt_helper,
+           odt_objcclass,
+           odt_objccategory,
+           odt_objcprotocol,
+           odt_javaclass,
+           odt_interfacecom_property,
+           odt_interfacecom_function,
+           odt_interfacejava] then
+         exit;
+
+        { todo in the future }
+        if _class.objecttype = odt_cppclass then
+          exit;
+
+        { the VMT definition may already exist in case of generics }
+        if searchsym_in_module(current_module,'vmtdef$'+_class.mangledparaname,sym,symtab) then
+          exit;
+        { create VMT type definition }
+        vmtdef:=crecorddef.create_global_internal(
+          '$vmtdef$'+_class.mangledparaname,
+          0,
+          target_info.alignment.recordalignmin,
+          target_info.alignment.maxCrecordalign);
+        { standard VMT fields }
+        case _Class.objecttype of
+          odt_class:
+            begin
+              systemvmt:=search_system_type('TVMT').typedef;
+              { does the TVMT type look like we expect? (so that this code is
+                easily triggered in case the definition of the VMT would
+                change) }
+              if (systemvmt.typ<>recorddef) or
+                 (trecorddef(systemvmt).symtable.SymList.count<>25) then
+                internalerror(2015052601);
+              { system.tvmt is a record that represents the VMT of TObject,
+                including its virtual methods. We only want the non-method
+                fields, as the methods will be added automatically based on
+                the VMT we generated here only add the 12 first fields }
+              for i:=0 to 11 do
+                begin
+                  sym:=tsym(trecorddef(systemvmt).symtable.SymList[i]);
+                  if sym.typ<>fieldvarsym then
+                    internalerror(2015052602);
+                  vmtdef.add_field_by_def(tfieldvarsym(sym).vardef);
+                end;
+            end;
+           odt_interfacecom,odt_interfacecorba,odt_dispinterface:
+             { nothing }
+             ;
+          odt_object:
+            begin
+              { size, -size, parent vmt [, dmt ] }
+              vmtdef.add_field_by_def(ptrsinttype);
+              vmtdef.add_field_by_def(ptrsinttype);
+              vmtdef.add_field_by_def(voidpointertype);
+{$ifdef WITHDMT}
+              vmtdef.add_field_by_def(voidpointertype);
+{$endif WITHDMT}
+            end;
+          else
+            internalerror(2015052605);
+        end;
+
+        { now add the methods }
+        for i:=0 to _class.vmtentries.count-1 do
+          vmtdef.add_field_by_def(
+            getprocaddressprocvar(pvmtentry(_class.vmtentries[i])^.procdef)
+          );
+        { the VMT ends with a nil pointer }
+        vmtdef.add_field_by_def(voidcodepointertype);
+      end;
+
+
     procedure TVMTBuilder.generate_vmt;
     procedure TVMTBuilder.generate_vmt;
       var
       var
         i : longint;
         i : longint;
@@ -829,7 +914,7 @@ implementation
             { Allocate interface tables }
             { Allocate interface tables }
             intf_allocate_vtbls;
             intf_allocate_vtbls;
           end;
           end;
-
+        generate_vmt_def;
         current_structdef:=old_current_structdef;
         current_structdef:=old_current_structdef;
       end;
       end;
 
 

+ 121 - 1
compiler/nutils.pas

@@ -76,6 +76,9 @@ interface
     function load_self_pointer_node:tnode;
     function load_self_pointer_node:tnode;
     function load_vmt_pointer_node:tnode;
     function load_vmt_pointer_node:tnode;
     function is_self_node(p:tnode):boolean;
     function is_self_node(p:tnode):boolean;
+    { create a tree that loads the VMT based on a self-node of an object/class/
+      interface }
+    function load_vmt_for_self_node(self_node: tnode): tnode;
 
 
     function node_complexity(p: tnode): cardinal;
     function node_complexity(p: tnode): cardinal;
     function node_resources_fpu(p: tnode): cardinal;
     function node_resources_fpu(p: tnode): cardinal;
@@ -150,7 +153,7 @@ implementation
     uses
     uses
       cutils,verbose,globals,
       cutils,verbose,globals,
       symconst,symdef,
       symconst,symdef,
-      defutil,defcmp,
+      defutil,defcmp,htypechk,
       nbas,ncon,ncnv,nld,nflw,nset,ncal,nadd,nmem,ninl,
       nbas,ncon,ncnv,nld,nflw,nset,ncal,nadd,nmem,ninl,
       cpubase,cgbase,procinfo,
       cpubase,cgbase,procinfo,
       pass_1;
       pass_1;
@@ -554,6 +557,123 @@ implementation
       end;
       end;
 
 
 
 
+    function load_vmt_for_self_node(self_node: tnode): tnode;
+      var
+        self_resultdef: tdef;
+        obj_def: tobjectdef;
+        self_temp,
+        vmt_temp: ttempcreatenode;
+        check_self: tnode;
+        stat: tstatementnode;
+        block: tblocknode;
+        paras: tcallparanode;
+        docheck: boolean;
+      begin
+        self_resultdef:=self_node.resultdef;
+        case self_resultdef.typ of
+          classrefdef:
+            obj_def:=tobjectdef(tclassrefdef(self_resultdef).pointeddef);
+          objectdef:
+            obj_def:=tobjectdef(self_resultdef);
+          else
+            internalerror(2015052701);
+        end;
+        if is_classhelper(obj_def) then
+          obj_def:=tobjectdef(tobjectdef(obj_def).extendeddef);
+        docheck:=
+          not(is_interface(obj_def)) and
+          not(is_cppclass(obj_def)) and
+          not(is_objc_class_or_protocol(obj_def)) and
+          (([cs_check_object,cs_check_range]*current_settings.localswitches)<>[]);
+
+        block:=nil;
+        stat:=nil;
+        if docheck then
+          begin
+            { check for nil self-pointer }
+            block:=internalstatements(stat);
+            self_temp:=ctempcreatenode.create_value(
+              self_resultdef,self_resultdef.size,tt_persistent,true,
+              self_node);
+            addstatement(stat,self_temp);
+
+            { in case of an object, self can only be nil if it's a dereferenced
+              node somehow
+            }
+            if not is_object(self_resultdef) or
+               (actualtargetnode(@self_node)^.nodetype=derefn) then
+              begin
+                check_self:=ctemprefnode.create(self_temp);
+                if is_object(self_resultdef) then
+                  check_self:=caddrnode.create(check_self);
+                addstatement(stat,cifnode.create(
+                  caddnode.create(equaln,
+                    ctypeconvnode.create_explicit(
+                      check_self,
+                      voidpointertype
+                    ),
+                    cnilnode.create),
+                  ccallnode.createintern('fpc_objecterror',nil),
+                  nil)
+                );
+              end;
+            addstatement(stat,ctempdeletenode.create_normal_temp(self_temp));
+            self_node:=ctemprefnode.create(self_temp);
+          end;
+        { get the VMT field in case of a class/object }
+        if (self_resultdef.typ=objectdef) and
+           assigned(tobjectdef(self_resultdef).vmt_field) then
+          result:=csubscriptnode.create(tobjectdef(self_resultdef).vmt_field,self_node)
+        { in case of a classref, the "instance" is a pointer
+          to pointer to a VMT and there is no vmt field }
+        else if self_resultdef.typ=classrefdef then
+          result:=self_node
+        { in case of an interface, the "instance" is a pointer to a pointer
+          to a VMT -> dereference once already }
+        else
+          { in case of an interface/classref, the "instance" is a pointer
+            to pointer to a VMT and there is no vmt field }
+          result:=cderefnode.create(
+            ctypeconvnode.create_explicit(
+              self_node,
+              getpointerdef(voidpointertype)
+            )
+          );
+        result:=ctypeconvnode.create_explicit(
+          result,
+          getpointerdef(obj_def.vmt_def));
+        typecheckpass(result);
+        if docheck then
+          begin
+            { add a vmt validity check }
+            vmt_temp:=ctempcreatenode.create_value(result.resultdef,result.resultdef.size,tt_persistent,true,result);
+            addstatement(stat,vmt_temp);
+            paras:=ccallparanode.create(ctemprefnode.create(vmt_temp),nil);
+            if cs_check_object in current_settings.localswitches then
+              begin
+                paras:=ccallparanode.create(
+                  cloadvmtaddrnode.create(ctypenode.create(obj_def)),
+                  paras
+                );
+                addstatement(stat,
+                  ccallnode.createintern(
+                    'fpc_check_object_ext',paras
+                  )
+                );
+              end
+            else
+              addstatement(stat,
+                ccallnode.createintern(
+                  'fpc_check_object',paras
+                )
+              );
+            addstatement(stat,ctempdeletenode.create_normal_temp(vmt_temp));
+            addstatement(stat,ctemprefnode.create(vmt_temp));
+            result:=block;
+          end
+      end;
+
+
     { this function must return a very high value ("infinity") for   }
     { this function must return a very high value ("infinity") for   }
     { trees containing a call, the rest can be balanced more or less }
     { trees containing a call, the rest can be balanced more or less }
     { at will, probably best mainly in terms of required memory      }
     { at will, probably best mainly in terms of required memory      }

+ 14 - 0
compiler/symdef.pas

@@ -430,6 +430,7 @@ interface
           function  needs_separate_initrtti : boolean;override;
           function  needs_separate_initrtti : boolean;override;
           function  rtti_mangledname(rt:trttitype):string;override;
           function  rtti_mangledname(rt:trttitype):string;override;
           function  vmt_mangledname : TSymStr;
           function  vmt_mangledname : TSymStr;
+          function  vmt_def: trecorddef;
           procedure check_forwards; override;
           procedure check_forwards; override;
           procedure insertvmt;
           procedure insertvmt;
           function  vmt_offset: asizeint;
           function  vmt_offset: asizeint;
@@ -6644,6 +6645,19 @@ implementation
       end;
       end;
 
 
 
 
+    function tobjectdef.vmt_def: trecorddef;
+      var
+        vmttypesym: tsym;
+      begin
+        vmttypesym:=tsym(get_top_level_symtable.Find('vmtdef$'+mangledparaname));
+        if not assigned(vmttypesym) or
+           (vmttypesym.typ<>symconst.typesym) or
+           (ttypesym(vmttypesym).typedef.typ<>recorddef) then
+          internalerror(2015052501);
+        result:=trecorddef(ttypesym(vmttypesym).typedef);
+      end;
+
+
     function tobjectdef.needs_inittable : boolean;
     function tobjectdef.needs_inittable : boolean;
       var
       var
         hp : tobjectdef;
         hp : tobjectdef;

+ 10 - 0
compiler/symtype.pas

@@ -89,6 +89,7 @@ interface
          function  needs_separate_initrtti:boolean;virtual;abstract;
          function  needs_separate_initrtti:boolean;virtual;abstract;
          procedure ChangeOwner(st:TSymtable);
          procedure ChangeOwner(st:TSymtable);
          procedure register_created_object_type;virtual;
          procedure register_created_object_type;virtual;
+         function  get_top_level_symtable: tsymtable;
       end;
       end;
 
 
 {************************************************
 {************************************************
@@ -356,6 +357,15 @@ implementation
       begin
       begin
       end;
       end;
 
 
+
+    function tdef.get_top_level_symtable: tsymtable;
+      begin
+        result:=owner;
+        while assigned(result) and
+              assigned(result.defowner) do
+          result:=tdef(result.defowner).owner;
+      end;
+
 {****************************************************************************
 {****************************************************************************
                           TSYM (base for all symtypes)
                           TSYM (base for all symtypes)
 ****************************************************************************}
 ****************************************************************************}

+ 1 - 0
rtl/inc/compproc.inc

@@ -711,6 +711,7 @@ procedure fpc_largeset_comp_sets(set1,set2 : pointer;size : longint); compilerpr
 procedure fpc_largeset_contains_sets(set1,set2 : pointer; size: longint); compilerproc;
 procedure fpc_largeset_contains_sets(set1,set2 : pointer; size: longint); compilerproc;
 {$endif LARGESETS}
 {$endif LARGESETS}
 
 
+procedure fpc_objecterror; compilerproc;
 procedure fpc_rangeerror; compilerproc;
 procedure fpc_rangeerror; compilerproc;
 procedure fpc_divbyzero; compilerproc;
 procedure fpc_divbyzero; compilerproc;
 procedure fpc_overflow; compilerproc;
 procedure fpc_overflow; compilerproc;

+ 4 - 0
rtl/inc/system.inc

@@ -736,6 +736,10 @@ begin
 end;
 end;
 {$endif ndef FPC_SYSTEM_HAS_GET_CALLER_STACKINFO}
 {$endif ndef FPC_SYSTEM_HAS_GET_CALLER_STACKINFO}
 
 
+procedure fpc_objecterror; compilerproc;
+begin
+  HandleErrorAddrFrameInd(210,get_pc_addr,get_frame);
+end;
 
 
 procedure fpc_rangeerror;[public,alias:'FPC_RANGEERROR']; compilerproc;
 procedure fpc_rangeerror;[public,alias:'FPC_RANGEERROR']; compilerproc;
 begin
 begin