* 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 -
This commit is contained in:
Jonas Maebe 2015-05-31 16:50:47 +00:00
parent 822b943d08
commit 3f736f6114
14 changed files with 299 additions and 149 deletions

View File

@ -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
*****************************************************************************} *****************************************************************************}

View File

@ -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;

View File

@ -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}

View File

@ -890,8 +890,7 @@ implementation
href : treference; href : treference;
pop_size : longint; pop_size : longint;
vmtoffset : aint; vmtoffset : aint;
pvreg, pvreg : tregister;
vmtreg : 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

View File

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

View File

@ -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 }

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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 }

View File

@ -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;

View File

@ -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)
****************************************************************************} ****************************************************************************}

View File

@ -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;

View File

@ -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