mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-11-07 07:59:40 +01:00
+ support for range checking calculations with hlcgobj
* added runerror number to JVM FpcRunTimeError exceptions
* enabled calling errorproc when a run time error occurs on the
JVM target
git-svn-id: branches/jvmbackend@18749 -
This commit is contained in:
parent
851cb65021
commit
7f22a2f223
@ -779,7 +779,7 @@ unit cg64f32;
|
|||||||
cg.a_cmp_const_reg_label(list,OS_32,OC_EQ,-1,hreg,neglabel);
|
cg.a_cmp_const_reg_label(list,OS_32,OC_EQ,-1,hreg,neglabel);
|
||||||
end;
|
end;
|
||||||
{ For all other values we have a range check error }
|
{ For all other values we have a range check error }
|
||||||
cg.a_call_name(list,'FPC_RANGEERROR',false);
|
cg.a_call_name(list,'fpc_rangeerror',false);
|
||||||
|
|
||||||
{ if the high dword = 0, the low dword can be considered a }
|
{ if the high dword = 0, the low dword can be considered a }
|
||||||
{ simple cardinal }
|
{ simple cardinal }
|
||||||
@ -819,7 +819,7 @@ unit cg64f32;
|
|||||||
current_asmdata.getjumplabel(neglabel);
|
current_asmdata.getjumplabel(neglabel);
|
||||||
cg.a_cmp_const_reg_label(list,OS_32,OC_LT,0,hreg,neglabel);
|
cg.a_cmp_const_reg_label(list,OS_32,OC_LT,0,hreg,neglabel);
|
||||||
|
|
||||||
cg.a_call_name(list,'FPC_RANGEERROR',false);
|
cg.a_call_name(list,'fpc_rangeerror',false);
|
||||||
|
|
||||||
{ if we get here, the 64bit value lies between }
|
{ if we get here, the 64bit value lies between }
|
||||||
{ longint($80000000) and -1 (JM) }
|
{ longint($80000000) and -1 (JM) }
|
||||||
@ -870,7 +870,7 @@ unit cg64f32;
|
|||||||
current_asmdata.getjumplabel(poslabel);
|
current_asmdata.getjumplabel(poslabel);
|
||||||
cg.a_cmp_const_reg_label(list,opsize,OC_GTE,0,hreg,poslabel);
|
cg.a_cmp_const_reg_label(list,opsize,OC_GTE,0,hreg,poslabel);
|
||||||
|
|
||||||
cg.a_call_name(list,'FPC_RANGEERROR',false);
|
cg.a_call_name(list,'fpc_rangeerror',false);
|
||||||
cg.a_label(list,poslabel);
|
cg.a_label(list,poslabel);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|||||||
@ -463,6 +463,8 @@ unit cgobj;
|
|||||||
@param(p Node which contains the value to check)
|
@param(p Node which contains the value to check)
|
||||||
@param(todef Type definition of node to range check)
|
@param(todef Type definition of node to range check)
|
||||||
}
|
}
|
||||||
|
{ only left here because used by cg64f32; normally, the code in
|
||||||
|
hlcgobj is used }
|
||||||
procedure g_rangecheck(list: TAsmList; const l:tlocation; fromdef,todef: tdef); virtual;
|
procedure g_rangecheck(list: TAsmList; const l:tlocation; fromdef,todef: tdef); virtual;
|
||||||
|
|
||||||
{# Generates overflow checking code for a node }
|
{# Generates overflow checking code for a node }
|
||||||
|
|||||||
@ -496,6 +496,8 @@ unit hlcgobj;
|
|||||||
the assembler/object file }
|
the assembler/object file }
|
||||||
procedure record_generated_code_for_procdef(pd: tprocdef; code, data: TAsmList); virtual;
|
procedure record_generated_code_for_procdef(pd: tprocdef; code, data: TAsmList); virtual;
|
||||||
|
|
||||||
|
{ generate a call to a routine in the system unit }
|
||||||
|
procedure g_call_system_proc(list: TAsmList; const procname: string);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
var
|
var
|
||||||
@ -510,7 +512,7 @@ implementation
|
|||||||
globals,options,systems,
|
globals,options,systems,
|
||||||
fmodule,export,
|
fmodule,export,
|
||||||
verbose,defutil,paramgr,
|
verbose,defutil,paramgr,
|
||||||
symbase,symsym,
|
symbase,symsym,symtable,
|
||||||
ncon,nld,pass_1,pass_2,
|
ncon,nld,pass_1,pass_2,
|
||||||
cpuinfo,cgobj,tgobj,cutils,procinfo,
|
cpuinfo,cgobj,tgobj,cutils,procinfo,
|
||||||
ncgutil,ngenutil;
|
ncgutil,ngenutil;
|
||||||
@ -1662,10 +1664,195 @@ implementation
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
procedure thlcgobj.g_rangecheck(list: TAsmList; const l: tlocation; fromdef, todef: tdef);
|
procedure thlcgobj.g_rangecheck(list: TAsmList; const l: tlocation; fromdef, todef: tdef);
|
||||||
|
var
|
||||||
|
aintmax: aint;
|
||||||
|
neglabel : tasmlabel;
|
||||||
|
hreg : tregister;
|
||||||
|
lto,hto,
|
||||||
|
lfrom,hfrom : TConstExprInt;
|
||||||
|
fromsize, tosize: cardinal;
|
||||||
|
maxdef: tdef;
|
||||||
|
from_signed, to_signed: boolean;
|
||||||
begin
|
begin
|
||||||
if not(cs_check_range in current_settings.localswitches) then
|
{ range checking on and range checkable value? }
|
||||||
|
if not(cs_check_range in current_settings.localswitches) or
|
||||||
|
not(fromdef.typ in [orddef,enumdef]) or
|
||||||
|
{ C-style booleans can't really fail range checks, }
|
||||||
|
{ all values are always valid }
|
||||||
|
is_cbool(todef) then
|
||||||
exit;
|
exit;
|
||||||
internalerror(2011010610);
|
{ only check when assigning to scalar, subranges are different, }
|
||||||
|
{ when todef=fromdef then the check is always generated }
|
||||||
|
getrange(fromdef,lfrom,hfrom);
|
||||||
|
getrange(todef,lto,hto);
|
||||||
|
from_signed := is_signed(fromdef);
|
||||||
|
to_signed := is_signed(todef);
|
||||||
|
{ check the rangedef of the array, not the array itself }
|
||||||
|
{ (only change now, since getrange needs the arraydef) }
|
||||||
|
if (todef.typ = arraydef) then
|
||||||
|
todef := tarraydef(todef).rangedef;
|
||||||
|
{ no range check if from and to are equal and are both longint/dword }
|
||||||
|
{ (if we have a 32bit processor) or int64/qword, since such }
|
||||||
|
{ operations can at most cause overflows (JM) }
|
||||||
|
{ Note that these checks are mostly processor independent, they only }
|
||||||
|
{ have to be changed once we introduce 64bit subrange types }
|
||||||
|
if (fromdef = todef) and
|
||||||
|
(fromdef.typ=orddef) and
|
||||||
|
(((((torddef(fromdef).ordtype = s64bit) and
|
||||||
|
(lfrom = low(int64)) and
|
||||||
|
(hfrom = high(int64))) or
|
||||||
|
((torddef(fromdef).ordtype = u64bit) and
|
||||||
|
(lfrom = low(qword)) and
|
||||||
|
(hfrom = high(qword))) or
|
||||||
|
((torddef(fromdef).ordtype = scurrency) and
|
||||||
|
(lfrom = low(int64)) and
|
||||||
|
(hfrom = high(int64)))))) then
|
||||||
|
exit;
|
||||||
|
{ 32 bit operations are automatically widened to 64 bit on 64 bit addr
|
||||||
|
targets }
|
||||||
|
{$ifdef cpu32bitaddr}
|
||||||
|
if (fromdef = todef) and
|
||||||
|
(fromdef.typ=orddef) and
|
||||||
|
(((((torddef(fromdef).ordtype = s32bit) and
|
||||||
|
(lfrom = int64(low(longint))) and
|
||||||
|
(hfrom = int64(high(longint)))) or
|
||||||
|
((torddef(fromdef).ordtype = u32bit) and
|
||||||
|
(lfrom = low(cardinal)) and
|
||||||
|
(hfrom = high(cardinal)))))) then
|
||||||
|
exit;
|
||||||
|
{$endif cpu32bitaddr}
|
||||||
|
|
||||||
|
{ optimize some range checks away in safe cases }
|
||||||
|
fromsize := fromdef.size;
|
||||||
|
tosize := todef.size;
|
||||||
|
if ((from_signed = to_signed) or
|
||||||
|
(not from_signed)) and
|
||||||
|
(lto<=lfrom) and (hto>=hfrom) and
|
||||||
|
(fromsize <= tosize) then
|
||||||
|
begin
|
||||||
|
{ if fromsize < tosize, and both have the same signed-ness or }
|
||||||
|
{ fromdef is unsigned, then all bit patterns from fromdef are }
|
||||||
|
{ valid for todef as well }
|
||||||
|
if (fromsize < tosize) then
|
||||||
|
exit;
|
||||||
|
if (fromsize = tosize) and
|
||||||
|
(from_signed = to_signed) then
|
||||||
|
{ only optimize away if all bit patterns which fit in fromsize }
|
||||||
|
{ are valid for the todef }
|
||||||
|
begin
|
||||||
|
{$ifopt Q+}
|
||||||
|
{$define overflowon}
|
||||||
|
{$Q-}
|
||||||
|
{$endif}
|
||||||
|
{$ifopt R+}
|
||||||
|
{$define rangeon}
|
||||||
|
{$R-}
|
||||||
|
{$endif}
|
||||||
|
if to_signed then
|
||||||
|
begin
|
||||||
|
{ calculation of the low/high ranges must not overflow 64 bit
|
||||||
|
otherwise we end up comparing with zero for 64 bit data types on
|
||||||
|
64 bit processors }
|
||||||
|
if (lto = (int64(-1) << (tosize * 8 - 1))) and
|
||||||
|
(hto = (-((int64(-1) << (tosize * 8 - 1))+1))) then
|
||||||
|
exit
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
{ calculation of the low/high ranges must not overflow 64 bit
|
||||||
|
otherwise we end up having all zeros for 64 bit data types on
|
||||||
|
64 bit processors }
|
||||||
|
if (lto = 0) and
|
||||||
|
(qword(hto) = (qword(-1) >> (64-(tosize * 8))) ) then
|
||||||
|
exit
|
||||||
|
end;
|
||||||
|
{$ifdef overflowon}
|
||||||
|
{$Q+}
|
||||||
|
{$undef overflowon}
|
||||||
|
{$endif}
|
||||||
|
{$ifdef rangeon}
|
||||||
|
{$R+}
|
||||||
|
{$undef rangeon}
|
||||||
|
{$endif}
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ depending on the types involved, we perform the range check for 64 or
|
||||||
|
for 32 bit }
|
||||||
|
if fromsize=8 then
|
||||||
|
maxdef:=fromdef
|
||||||
|
else
|
||||||
|
maxdef:=todef;
|
||||||
|
{$if sizeof(aintmax) = 8}
|
||||||
|
if maxdef.size=8 then
|
||||||
|
aintmax:=high(int64)
|
||||||
|
else
|
||||||
|
{$endif}
|
||||||
|
begin
|
||||||
|
aintmax:=high(longint);
|
||||||
|
maxdef:=u32inttype;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ generate the rangecheck code for the def where we are going to }
|
||||||
|
{ store the result }
|
||||||
|
|
||||||
|
{ use the trick that }
|
||||||
|
{ a <= x <= b <=> 0 <= x-a <= b-a <=> unsigned(x-a) <= unsigned(b-a) }
|
||||||
|
|
||||||
|
{ To be able to do that, we have to make sure however that either }
|
||||||
|
{ fromdef and todef are both signed or unsigned, or that we leave }
|
||||||
|
{ the parts < 0 and > maxlongint out }
|
||||||
|
|
||||||
|
if from_signed xor to_signed then
|
||||||
|
begin
|
||||||
|
if from_signed then
|
||||||
|
{ from is signed, to is unsigned }
|
||||||
|
begin
|
||||||
|
{ if high(from) < 0 -> always range error }
|
||||||
|
if (hfrom < 0) or
|
||||||
|
{ if low(to) > maxlongint also range error }
|
||||||
|
(lto > aintmax) then
|
||||||
|
begin
|
||||||
|
g_call_system_proc(list,'fpc_rangeerror');
|
||||||
|
exit
|
||||||
|
end;
|
||||||
|
{ from is signed and to is unsigned -> when looking at to }
|
||||||
|
{ as an signed value, it must be < maxaint (otherwise }
|
||||||
|
{ it will become negative, which is invalid since "to" is unsigned) }
|
||||||
|
if hto > aintmax then
|
||||||
|
hto := aintmax;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
{ from is unsigned, to is signed }
|
||||||
|
begin
|
||||||
|
if (lfrom > aintmax) or
|
||||||
|
(hto < 0) then
|
||||||
|
begin
|
||||||
|
g_call_system_proc(list,'fpc_rangeerror');
|
||||||
|
exit
|
||||||
|
end;
|
||||||
|
{ from is unsigned and to is signed -> when looking at to }
|
||||||
|
{ as an unsigned value, it must be >= 0 (since negative }
|
||||||
|
{ values are the same as values > maxlongint) }
|
||||||
|
if lto < 0 then
|
||||||
|
lto := 0;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
hreg:=getintregister(list,maxdef);
|
||||||
|
a_load_loc_reg(list,fromdef,maxdef,l,hreg);
|
||||||
|
a_op_const_reg(list,OP_SUB,maxdef,tcgint(int64(lto)),hreg);
|
||||||
|
current_asmdata.getjumplabel(neglabel);
|
||||||
|
{
|
||||||
|
if from_signed then
|
||||||
|
a_cmp_const_reg_label(list,OS_INT,OC_GTE,aint(hto-lto),hreg,neglabel)
|
||||||
|
else
|
||||||
|
}
|
||||||
|
if qword(hto-lto)>qword(aintmax) then
|
||||||
|
a_cmp_const_reg_label(list,maxdef,OC_BE,aintmax,hreg,neglabel)
|
||||||
|
else
|
||||||
|
a_cmp_const_reg_label(list,maxdef,OC_BE,tcgint(int64(hto-lto)),hreg,neglabel);
|
||||||
|
g_call_system_proc(list,'fpc_rangeerror');
|
||||||
|
a_label(list,neglabel);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure thlcgobj.g_profilecode(list: TAsmList);
|
procedure thlcgobj.g_profilecode(list: TAsmList);
|
||||||
@ -2723,4 +2910,19 @@ implementation
|
|||||||
current_asmdata.asmlists[al_procedures].concatlist(data);
|
current_asmdata.asmlists[al_procedures].concatlist(data);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure thlcgobj.g_call_system_proc(list: TAsmList; const procname: string);
|
||||||
|
var
|
||||||
|
srsym: tsym;
|
||||||
|
pd: tprocdef;
|
||||||
|
begin
|
||||||
|
srsym:=tsym(systemunit.find(procname));
|
||||||
|
if not assigned(srsym) or
|
||||||
|
(srsym.typ<>procsym) then
|
||||||
|
Message1(cg_f_unknown_compilerproc,procname);
|
||||||
|
pd:=tprocdef(tprocsym(srsym).procdeflist[0]);
|
||||||
|
a_call_name(list,pd,pd.mangledname,false);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|||||||
@ -192,8 +192,6 @@ uses
|
|||||||
procedure concatcopy_set(list: TAsmList; size: tdef; const source, dest: treference);
|
procedure concatcopy_set(list: TAsmList; size: tdef; const source, dest: treference);
|
||||||
procedure concatcopy_shortstring(list: TAsmList; size: tdef; const source, dest: treference);
|
procedure concatcopy_shortstring(list: TAsmList; size: tdef; const source, dest: treference);
|
||||||
|
|
||||||
{ generate a call to a routine in the system unit }
|
|
||||||
procedure g_call_system_proc(list: TAsmList; const procname: string);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure create_hlcodegen;
|
procedure create_hlcodegen;
|
||||||
@ -2102,19 +2100,6 @@ implementation
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure thlcgjvm.g_call_system_proc(list: TAsmList; const procname: string);
|
|
||||||
var
|
|
||||||
srsym: tsym;
|
|
||||||
pd: tprocdef;
|
|
||||||
begin
|
|
||||||
srsym:=tsym(systemunit.find(procname));
|
|
||||||
if not assigned(srsym) or
|
|
||||||
(srsym.typ<>procsym) then
|
|
||||||
Message1(cg_f_unknown_compilerproc,procname);
|
|
||||||
pd:=tprocdef(tprocsym(srsym).procdeflist[0]);
|
|
||||||
a_call_name(list,pd,pd.mangledname,false);
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure create_hlcodegen;
|
procedure create_hlcodegen;
|
||||||
begin
|
begin
|
||||||
hlcg:=thlcgjvm.create;
|
hlcg:=thlcgjvm.create;
|
||||||
|
|||||||
@ -89,7 +89,7 @@ interface
|
|||||||
|
|
||||||
{ insert range check if not explicit conversion }
|
{ insert range check if not explicit conversion }
|
||||||
if not(nf_explicit in flags) then
|
if not(nf_explicit in flags) then
|
||||||
cg.g_rangecheck(current_asmdata.CurrAsmList,left.location,left.resultdef,resultdef);
|
hlcg.g_rangecheck(current_asmdata.CurrAsmList,left.location,left.resultdef,resultdef);
|
||||||
|
|
||||||
{ is the result size smaller? when typecasting from void
|
{ is the result size smaller? when typecasting from void
|
||||||
we always reuse the current location, because there is
|
we always reuse the current location, because there is
|
||||||
|
|||||||
@ -685,10 +685,11 @@ procedure fpc_largeset_symdif_sets(set1,set2,dest : pointer;size : longint); com
|
|||||||
procedure fpc_largeset_comp_sets(set1,set2 : pointer;size : longint); compilerproc;
|
procedure fpc_largeset_comp_sets(set1,set2 : pointer;size : longint); compilerproc;
|
||||||
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_rangeerror; compilerproc;
|
procedure fpc_rangeerror; compilerproc;
|
||||||
procedure fpc_divbyzero; compilerproc;
|
procedure fpc_divbyzero; compilerproc;
|
||||||
procedure fpc_overflow; compilerproc;
|
procedure fpc_overflow; compilerproc;
|
||||||
|
(*
|
||||||
procedure fpc_iocheck; compilerproc;
|
procedure fpc_iocheck; compilerproc;
|
||||||
|
|
||||||
procedure fpc_InitializeUnits; compilerproc;
|
procedure fpc_InitializeUnits; compilerproc;
|
||||||
|
|||||||
@ -983,10 +983,10 @@ end;
|
|||||||
|
|
||||||
Procedure HandleErrorAddrFrame (Errno : longint;addr,frame : Pointer);[public,alias:'FPC_BREAK_ERROR']; {$ifdef CPU86} register; {$endif}
|
Procedure HandleErrorAddrFrame (Errno : longint;addr,frame : Pointer);[public,alias:'FPC_BREAK_ERROR']; {$ifdef CPU86} register; {$endif}
|
||||||
begin
|
begin
|
||||||
raise FpcRunTimeError.Create(Errno);
|
|
||||||
(*
|
|
||||||
If pointer(ErrorProc)<>Nil then
|
If pointer(ErrorProc)<>Nil then
|
||||||
ErrorProc(Errno,addr,frame);
|
ErrorProc(Errno,addr,frame);
|
||||||
|
raise FpcRunTimeError.Create(Errno);
|
||||||
|
(*
|
||||||
errorcode:=word(Errno);
|
errorcode:=word(Errno);
|
||||||
erroraddr:=addr;
|
erroraddr:=addr;
|
||||||
errorbase:=frame;
|
errorbase:=frame;
|
||||||
|
|||||||
@ -648,17 +648,22 @@ function SysSetCtrlBreakHandler (Handler: TCtrlBreakHandler): TCtrlBreakHandler;
|
|||||||
*)
|
*)
|
||||||
|
|
||||||
{ Error handlers }
|
{ Error handlers }
|
||||||
(*
|
|
||||||
Type
|
Type
|
||||||
|
(*
|
||||||
TBackTraceStrFunc = Function (Addr: Pointer): ShortString;
|
TBackTraceStrFunc = Function (Addr: Pointer): ShortString;
|
||||||
|
*)
|
||||||
TErrorProc = Procedure (ErrNo : Longint; Address,Frame : Pointer);
|
TErrorProc = Procedure (ErrNo : Longint; Address,Frame : Pointer);
|
||||||
|
(*
|
||||||
TAbstractErrorProc = Procedure;
|
TAbstractErrorProc = Procedure;
|
||||||
TAssertErrorProc = Procedure(const msg,fname:ShortString;lineno:longint;erroraddr:pointer);
|
TAssertErrorProc = Procedure(const msg,fname:ShortString;lineno:longint;erroraddr:pointer);
|
||||||
TSafeCallErrorProc = Procedure(error : HResult;addr : pointer);
|
TSafeCallErrorProc = Procedure(error : HResult;addr : pointer);
|
||||||
|
*)
|
||||||
const
|
const
|
||||||
|
(*
|
||||||
BackTraceStrFunc : TBackTraceStrFunc = @SysBackTraceStr;
|
BackTraceStrFunc : TBackTraceStrFunc = @SysBackTraceStr;
|
||||||
|
*)
|
||||||
ErrorProc : TErrorProc = nil;
|
ErrorProc : TErrorProc = nil;
|
||||||
|
(*
|
||||||
AbstractErrorProc : TAbstractErrorProc = nil;
|
AbstractErrorProc : TAbstractErrorProc = nil;
|
||||||
AssertErrorProc : TAssertErrorProc = @SysAssert;
|
AssertErrorProc : TAssertErrorProc = @SysAssert;
|
||||||
SafeCallErrorProc : TSafeCallErrorProc = nil;
|
SafeCallErrorProc : TSafeCallErrorProc = nil;
|
||||||
|
|||||||
@ -18,5 +18,6 @@
|
|||||||
constructor FpcRunTimeError.create(l: longint);
|
constructor FpcRunTimeError.create(l: longint);
|
||||||
begin
|
begin
|
||||||
inherited Create('Run time error '+unicodestring(JLInteger.valueOf(l).toString));
|
inherited Create('Run time error '+unicodestring(JLInteger.valueOf(l).toString));
|
||||||
|
errornr:=l;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|||||||
@ -17,5 +17,6 @@
|
|||||||
|
|
||||||
type
|
type
|
||||||
FpcRunTimeError = class(JLException)
|
FpcRunTimeError = class(JLException)
|
||||||
|
errornr: longint;
|
||||||
constructor create(l: longint);
|
constructor create(l: longint);
|
||||||
end;
|
end;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user