* converted all enum handling for the JVM target so that it uses the

JDK class-style enums rather than plain ordinals like in Pascal
   o for Pascal code, nothing changes, except that for the JVM target
     you can always typecast any enum into a class instance (to interface
     with the JDK)
   o to Java programs, FPC enums look exactly like Java enum types

git-svn-id: branches/jvmbackend@18620 -
This commit is contained in:
Jonas Maebe 2011-08-20 08:15:54 +00:00
parent d64f5d14d6
commit 569228447d
18 changed files with 474 additions and 24 deletions

1
.gitattributes vendored
View File

@ -228,6 +228,7 @@ compiler/jvm/njvminl.pas svneol=native#text/plain
compiler/jvm/njvmld.pas svneol=native#text/plain compiler/jvm/njvmld.pas svneol=native#text/plain
compiler/jvm/njvmmat.pas svneol=native#text/plain compiler/jvm/njvmmat.pas svneol=native#text/plain
compiler/jvm/njvmmem.pas svneol=native#text/plain compiler/jvm/njvmmem.pas svneol=native#text/plain
compiler/jvm/njvmset.pas svneol=native#text/plain
compiler/jvm/njvmutil.pas svneol=native#text/plain compiler/jvm/njvmutil.pas svneol=native#text/plain
compiler/jvm/rgcpu.pas svneol=native#text/plain compiler/jvm/rgcpu.pas svneol=native#text/plain
compiler/jvm/rjvmcon.inc svneol=native#text/plain compiler/jvm/rjvmcon.inc svneol=native#text/plain

View File

@ -776,9 +776,14 @@ implementation
constnil: constnil:
result:=''; result:='';
else else
begin
{ enums are initialized as typed constants }
if not assigned(csym.constdef) or
(csym.constdef.typ<>enumdef) then
result:=' = '+ConstValue(csym) result:=' = '+ConstValue(csym)
end; end;
end; end;
end;
function TJasminAssembler.ConstDefinition(sym: tconstsym): ansistring; function TJasminAssembler.ConstDefinition(sym: tconstsym): ansistring;

View File

@ -32,7 +32,8 @@ implementation
uses uses
ncgbas,ncgflw,ncgcnv,ncgld,ncgmem,ncgcon,ncgset, ncgbas,ncgflw,ncgcnv,ncgld,ncgmem,ncgcon,ncgset,
ncgadd, ncgcal,ncgmat,ncginl, ncgadd, ncgcal,ncgmat,ncginl,
njvmadd,njvmcal,njvmmat,njvmcnv,njvmcon,njvminl,njvmmem,njvmflw,njvmld njvmadd,njvmcal,njvmmat,njvmcnv,njvmcon,njvminl,njvmmem,njvmflw,njvmld,
njvmset
{ these are not really nodes } { these are not really nodes }
,rgcpu,tgcpu,njvmutil; ,rgcpu,tgcpu,njvmutil;

View File

@ -250,8 +250,9 @@ implementation
function thlcgjvm.def2regtyp(def: tdef): tregistertype; function thlcgjvm.def2regtyp(def: tdef): tregistertype;
begin begin
case def.typ of case def.typ of
{ records are implemented via classes } { records and enums are implemented via classes }
recorddef: recorddef,
enumdef:
result:=R_ADDRESSREGISTER; result:=R_ADDRESSREGISTER;
setdef: setdef:
if is_smallset(def) then if is_smallset(def) then

View File

@ -57,12 +57,12 @@ interface
uses uses
systems, systems,
cutils,verbose,constexp, cutils,verbose,constexp,
symtable,symdef, symconst,symtable,symdef,
paramgr,procinfo, paramgr,procinfo,
aasmtai,aasmdata,aasmcpu,defutil, aasmtai,aasmdata,aasmcpu,defutil,
hlcgobj,hlcgcpu,cgutils, hlcgobj,hlcgcpu,cgutils,
cpupara, cpupara,
ncon,nset,nadd,ncal, ncon,nset,nadd,ncal,ncnv,
cgobj; cgobj;
{***************************************************************************** {*****************************************************************************
@ -71,6 +71,20 @@ interface
function tjvmaddnode.pass_1: tnode; function tjvmaddnode.pass_1: tnode;
begin begin
{ special handling for enums: they're classes in the JVM -> get their
ordinal value to compare them (do before calling inherited pass_1,
because pass_1 will convert enum constants from ordinals into class
instances) }
if (left.resultdef.typ=enumdef) and
(right.resultdef.typ=enumdef) then
begin
{ enums can only be compared at this stage (add/sub is only allowed
in constant expressions) }
if not is_boolean(resultdef) then
internalerror(2011062603);
inserttypeconv_explicit(left,s32inttype);
inserttypeconv_explicit(right,s32inttype);
end;
result:=inherited pass_1; result:=inherited pass_1;
if expectloc=LOC_FLAGS then if expectloc=LOC_FLAGS then
expectloc:=LOC_JUMP; expectloc:=LOC_JUMP;

View File

@ -534,6 +534,42 @@ implementation
left:=nil; left:=nil;
end; end;
function ord_enum_explicit_typecast(fdef: torddef; todef: tenumdef): tnode;
var
psym: tsym;
begin
{ we only create a class for the basedefs }
todef:=todef.getbasedef;
psym:=search_struct_member(todef.classdef,'FPCVALUEOF');
if not assigned(psym) or
(psym.typ<>procsym) then
internalerror(2011062601);
result:=ccallnode.create(ccallparanode.create(left,nil),
tprocsym(psym),psym.owner,
cloadvmtaddrnode.create(ctypenode.create(todef.classdef)),[]);
{ convert the result to the result type of this type conversion node }
inserttypeconv_explicit(result,resultdef);
{ left is reused }
left:=nil;
end;
function enum_ord_explicit_typecast(fdef: tenumdef; todef: torddef): tnode;
var
psym: tsym;
begin
{ we only create a class for the basedef }
fdef:=fdef.getbasedef;
psym:=search_struct_member(fdef.classdef,'FPCORDINAL');
if not assigned(psym) or
(psym.typ<>procsym) then
internalerror(2011062602);
result:=ccallnode.create(nil,tprocsym(psym),psym.owner,left,[]);
{ convert the result to the result type of this type conversion node }
inserttypeconv_explicit(result,resultdef);
{ left is reused }
left:=nil;
end;
function ptr_no_typecheck_required(fromdef, todef: tdef): boolean; function ptr_no_typecheck_required(fromdef, todef: tdef): boolean;
function check_type_equality(def1,def2: tdef): boolean; function check_type_equality(def1,def2: tdef): boolean;
@ -635,6 +671,7 @@ implementation
is_dynamic_array(left.resultdef) or is_dynamic_array(left.resultdef) or
((left.resultdef.typ in [stringdef,classrefdef]) and ((left.resultdef.typ in [stringdef,classrefdef]) and
not is_shortstring(left.resultdef)) or not is_shortstring(left.resultdef)) or
(left.resultdef.typ=enumdef) or
procvarconv; procvarconv;
toclasscompatible:= toclasscompatible:=
(resultdef.typ=pointerdef) or (resultdef.typ=pointerdef) or
@ -642,6 +679,7 @@ implementation
is_dynamic_array(resultdef) or is_dynamic_array(resultdef) or
((resultdef.typ in [stringdef,classrefdef]) and ((resultdef.typ in [stringdef,classrefdef]) and
not is_shortstring(resultdef)) or not is_shortstring(resultdef)) or
(resultdef.typ=enumdef) or
procvarconv; procvarconv;
{ typescasts from void (the result of untyped_ptr^) to an implicit { typescasts from void (the result of untyped_ptr^) to an implicit
pointertype (record, array, ...) also needs a typecheck } pointertype (record, array, ...) also needs a typecheck }
@ -668,6 +706,11 @@ implementation
fromdef:=left.resultdef; fromdef:=left.resultdef;
todef:=resultdef; todef:=resultdef;
get_most_nested_types(fromdef,todef); get_most_nested_types(fromdef,todef);
{ in case of enums, get the equivalent class definitions }
if (fromdef.typ=enumdef) then
fromdef:=tenumdef(fromdef).getbasedef;
if (todef.typ=enumdef) then
todef:=tenumdef(todef).getbasedef;
fromarrtype:=jvmarrtype_setlength(fromdef); fromarrtype:=jvmarrtype_setlength(fromdef);
toarrtype:=jvmarrtype_setlength(todef); toarrtype:=jvmarrtype_setlength(todef);
if not ptr_no_typecheck_required(fromdef,todef) then if not ptr_no_typecheck_required(fromdef,todef) then
@ -723,6 +766,8 @@ implementation
begin begin
if (convtype<>tc_int_2_real) then if (convtype<>tc_int_2_real) then
begin begin
if (left.resultdef.typ=enumdef) then
inserttypeconv_explicit(left,s32inttype);
if not check_only then if not check_only then
resnode:=int_real_explicit_typecast(tfloatdef(resultdef),'INTBITSTOFLOAT','LONGBITSTODOUBLE'); resnode:=int_real_explicit_typecast(tfloatdef(resultdef),'INTBITSTOFLOAT','LONGBITSTODOUBLE');
result:=true; result:=true;
@ -731,13 +776,49 @@ implementation
result:=false; result:=false;
exit; exit;
end; end;
{ nothing special required when going between ordinals and enums }
if (left.resultdef.typ in [orddef,enumdef]) and { enums }
(resultdef.typ in [orddef,enumdef]) then if (left.resultdef.typ=enumdef) or
(resultdef.typ=enumdef) then
begin
{ both enum? }
if (resultdef.typ=left.resultdef.typ) then
begin
{ same base type -> nothing special }
fromdef:=tenumdef(left.resultdef).getbasedef;
todef:=tenumdef(resultdef).getbasedef;
if fromdef=todef then
begin begin
result:=false; result:=false;
exit; exit;
end; end;
{ convert via ordinal intermediate }
if not check_only then
begin;
inserttypeconv_explicit(left,s32inttype);
inserttypeconv_explicit(left,resultdef);
resnode:=left;
left:=nil
end;
result:=true;
exit;
end;
{ enum to orddef & vice versa }
if left.resultdef.typ=orddef then
begin
if not check_only then
resnode:=ord_enum_explicit_typecast(torddef(left.resultdef),tenumdef(resultdef));
result:=true;
exit;
end
else if resultdef.typ=orddef then
begin
if not check_only then
resnode:=enum_ord_explicit_typecast(tenumdef(left.resultdef),torddef(resultdef));
result:=true;
exit;
end
end;
{$ifndef nounsupported} {$ifndef nounsupported}
if (left.resultdef.typ in [orddef,enumdef,setdef]) and if (left.resultdef.typ in [orddef,enumdef,setdef]) and
@ -792,6 +873,16 @@ implementation
function tjvmtypeconvnode.target_specific_general_typeconv: boolean; function tjvmtypeconvnode.target_specific_general_typeconv: boolean;
begin begin
result:=false; result:=false;
{ on the JVM platform, enums can always be converted to class instances,
because enums /are/ class instances there. To prevent the
typechecking/conversion code from assuming it can treat it like any
ordinal constant, firstpass() it so that the ordinal constant gets
replaced with a load of a staticvarsym. This is not done in
pass_typecheck, because that would prevent many optimizations }
if (left.nodetype=ordconstn) and
(left.resultdef.typ=enumdef) and
(resultdef.typ=objectdef) then
firstpass(left);
{$ifndef nounsupported} {$ifndef nounsupported}
{ generated in nmem; replace voidpointertype with java_jlobject } { generated in nmem; replace voidpointertype with java_jlobject }
if nf_load_procvar in flags then if nf_load_procvar in flags then
@ -913,7 +1004,9 @@ implementation
if checkdef=voidpointertype then if checkdef=voidpointertype then
checkdef:=java_jlobject checkdef:=java_jlobject
else if checkdef.typ=pointerdef then else if checkdef.typ=pointerdef then
checkdef:=tpointerdef(checkdef).pointeddef; checkdef:=tpointerdef(checkdef).pointeddef
else if checkdef.typ=enumdef then
checkdef:=tenumdef(checkdef).classdef;
{$ifndef nounsupported} {$ifndef nounsupported}
if checkdef.typ=procvardef then if checkdef.typ=procvardef then
checkdef:=java_jlobject checkdef:=java_jlobject

View File

@ -30,6 +30,16 @@ interface
node,ncon,ncgcon; node,ncon,ncgcon;
type type
tjvmordconstnode = class(tcgordconstnode)
{ normally, we convert the enum constant into a load of the
appropriate enum class field in pass_1. In some cases (array index),
we want to keep it as an enum constant however }
enumconstok: boolean;
function pass_1: tnode; override;
function docompare(p: tnode): boolean; override;
function dogetcopy: tnode; override;
end;
tjvmrealconstnode = class(tcgrealconstnode) tjvmrealconstnode = class(tcgrealconstnode)
procedure pass_generate_code;override; procedure pass_generate_code;override;
end; end;
@ -43,14 +53,73 @@ interface
implementation implementation
uses uses
globtype,cutils,widestr,verbose, globtype,cutils,widestr,verbose,constexp,
symdef,symsym,symtable,symconst, symdef,symsym,symtable,symconst,
aasmdata,aasmcpu,defutil, aasmdata,aasmcpu,defutil,
ncal, ncal,nld,
cgbase,hlcgobj,hlcgcpu,cgutils,cpubase cgbase,hlcgobj,hlcgcpu,cgutils,cpubase
; ;
{*****************************************************************************
TJVMORDCONSTNODE
*****************************************************************************}
function tjvmordconstnode.pass_1: tnode;
var
basedef: tenumdef;
sym: tenumsym;
classfield: tsym;
i: longint;
begin
if (resultdef.typ<>enumdef) or
enumconstok then
begin
result:=inherited pass_1;
exit;
end;
{ convert into JVM class instance }
{ a) find the enumsym corresponding to the value (may not exist in case
of an explicit typecast of an integer -> error) }
sym:=nil;
basedef:=tenumdef(resultdef).getbasedef;
for i:=0 to tenumdef(resultdef).symtable.symlist.count-1 do
begin
sym:=tenumsym(basedef.symtable.symlist[i]);
if sym.value=value then
break;
sym:=nil;
end;
if not assigned(sym) then
begin
Message(parser_e_range_check_error);
exit;
end;
{ b) find the corresponding class field }
classfield:=search_struct_member(basedef.classdef,sym.name);
if not assigned(classfield) or
(classfield.typ<>staticvarsym) then
internalerror(2011062606);
{ c) create loadnode of the field }
result:=cloadnode.create(classfield,classfield.owner);
end;
function tjvmordconstnode.docompare(p: tnode): boolean;
begin
result:=inherited docompare(p);
if result then
result:=(enumconstok=tjvmordconstnode(p).enumconstok);
end;
function tjvmordconstnode.dogetcopy: tnode;
begin
result:=inherited dogetcopy;
tjvmordconstnode(result).enumconstok:=enumconstok;
end;
{***************************************************************************** {*****************************************************************************
TJVMREALCONSTNODE TJVMREALCONSTNODE
*****************************************************************************} *****************************************************************************}
@ -136,6 +205,7 @@ implementation
begin begin
cordconstnode:=tjvmordconstnode;
crealconstnode:=tjvmrealconstnode; crealconstnode:=tjvmrealconstnode;
cstringconstnode:=tjvmstringconstnode; cstringconstnode:=tjvmstringconstnode;
end. end.

View File

@ -26,9 +26,13 @@ unit njvmflw;
interface interface
uses uses
aasmbase,node,nflw; aasmbase,node,nflw,ncgflw;
type type
tjvmfornode = class(tcgfornode)
function pass_1: tnode; override;
end;
tjvmraisenode = class(traisenode) tjvmraisenode = class(traisenode)
function pass_typecheck: tnode; override; function pass_typecheck: tnode; override;
procedure pass_generate_code;override; procedure pass_generate_code;override;
@ -53,11 +57,61 @@ implementation
symconst,symdef,symsym,aasmtai,aasmdata,aasmcpu,defutil,jvmdef, symconst,symdef,symsym,aasmtai,aasmdata,aasmcpu,defutil,jvmdef,
procinfo,cgbase,pass_2,parabase, procinfo,cgbase,pass_2,parabase,
cpubase,cpuinfo, cpubase,cpuinfo,
nld,ncon, nbas,nld,ncon,ncnv,
tgobj,paramgr, tgobj,paramgr,
cgutils,hlcgobj,hlcgcpu cgutils,hlcgobj,hlcgcpu
; ;
{*****************************************************************************
TFJVMFORNODE
*****************************************************************************}
function tjvmfornode.pass_1: tnode;
var
iteratortmp: ttempcreatenode;
olditerator: tnode;
block,
newbody: tblocknode;
stat,
newbodystat: tstatementnode;
begin
{ transform for-loops with enums to:
for tempint:=ord(lowval) to ord(upperval) do
begin
originalctr:=tenum(tempint);
<original loop body>
end;
enums are class instances in Java and hence can't be increased or so.
The type conversion consists of an array lookup in a final method,
so it shouldn't be too expensive.
}
if left.resultdef.typ=enumdef then
begin
block:=internalstatements(stat);
iteratortmp:=ctempcreatenode.create(s32inttype,left.resultdef.size,tt_persistent,true);
addstatement(stat,iteratortmp);
olditerator:=left;
left:=ctemprefnode.create(iteratortmp);
inserttypeconv_explicit(right,s32inttype);
inserttypeconv_explicit(t1,s32inttype);
newbody:=internalstatements(newbodystat);
addstatement(newbodystat,cassignmentnode.create(olditerator,
ctypeconvnode.create_explicit(ctemprefnode.create(iteratortmp),
olditerator.resultdef)));
addstatement(newbodystat,t2);
addstatement(stat,cfornode.create(left,right,t1,newbody,lnf_backward in loopflags));
addstatement(stat,ctempdeletenode.create(iteratortmp));
left:=nil;
right:=nil;
t1:=nil;
t2:=nil;
result:=block
end
else
result:=inherited pass_1;
end;
{***************************************************************************** {*****************************************************************************
SecondRaise SecondRaise
*****************************************************************************} *****************************************************************************}
@ -425,6 +479,7 @@ implementation
end; end;
begin begin
cfornode:=tjvmfornode;
craisenode:=tjvmraisenode; craisenode:=tjvmraisenode;
ctryexceptnode:=tjvmtryexceptnode; ctryexceptnode:=tjvmtryexceptnode;
ctryfinallynode:=tjvmtryfinallynode; ctryfinallynode:=tjvmtryfinallynode;

View File

@ -57,7 +57,7 @@ implementation
cutils,verbose,constexp, cutils,verbose,constexp,
symconst,symtype,symtable,symsym,symdef,defutil,jvmdef, symconst,symtype,symtable,symsym,symdef,defutil,jvmdef,
htypechk, htypechk,
nadd,ncal,ncnv,ncon,pass_1, nadd,ncal,ncnv,ncon,pass_1,njvmcon,
aasmdata,aasmcpu,pass_2, aasmdata,aasmcpu,pass_2,
cgutils,hlcgobj,hlcgcpu; cgutils,hlcgobj,hlcgcpu;
@ -235,12 +235,21 @@ implementation
exit; exit;
end end
else else
begin
{ keep indices that are enum constants that way, rather than
transforming them into a load of the class instance that
represents this constant (since we then would have to extract
the int constant value again at run time anyway) }
if right.nodetype=ordconstn then
tjvmordconstnode(right).enumconstok:=true;
result:=inherited; result:=inherited;
end; end;
end;
procedure tjvmvecnode.pass_generate_code; procedure tjvmvecnode.pass_generate_code;
var var
psym: tsym;
newsize: tcgsize; newsize: tcgsize;
begin begin
if left.resultdef.typ=stringdef then if left.resultdef.typ=stringdef then
@ -269,6 +278,29 @@ implementation
if (right.location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) and if (right.location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) and
(right.location.reference.arrayreftype<>art_none) then (right.location.reference.arrayreftype<>art_none) then
hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,right.resultdef,true); hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,right.resultdef,true);
{ replace enum class instance with the corresponding integer value }
if (right.resultdef.typ=enumdef) then
begin
if (right.location.loc<>LOC_CONSTANT) then
begin
psym:=search_struct_member(tenumdef(right.resultdef).classdef,'FPCORDINAL');
if not assigned(psym) or
(psym.typ<>procsym) or
(tprocsym(psym).ProcdefList.count<>1) then
internalerror(2011062607);
thlcgjvm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,right.resultdef,right.location);
hlcg.a_call_name(current_asmdata.CurrAsmList,tprocdef(tprocsym(psym).procdeflist[0]),tprocdef(tprocsym(psym).procdeflist[0]).mangledname,false);
{ call replaces self parameter with longint result -> no stack
height change }
location_reset(right.location,LOC_REGISTER,OS_S32);
right.location.register:=hlcg.getintregister(current_asmdata.CurrAsmList,s32inttype);
thlcgjvm(hlcg).a_load_stack_reg(current_asmdata.CurrAsmList,s32inttype,right.location.register);
end;
{ always force to integer location, because enums are handled as
object instances (since that's what they are in Java) }
right.resultdef:=s32inttype;
right.location.size:=OS_S32;
end;
{ adjust index if necessary } { adjust index if necessary }
if not is_special_array(left.resultdef) and if not is_special_array(left.resultdef) and

64
compiler/jvm/njvmset.pas Normal file
View File

@ -0,0 +1,64 @@
{
Copyright (c) 2011 by Jonas Maebe
Generate JVM bytecode for in set/case nodes
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
****************************************************************************
}
unit njvmset;
{$i fpcdefs.inc}
interface
uses
globtype,
node,nset,ncgset;
type
tjvmcasenode = class(tcgcasenode)
function pass_1: tnode; override;
end;
implementation
uses
symconst,symdef,
pass_1,
ncnv;
{*****************************************************************************
TJVMCASENODE
*****************************************************************************}
function tjvmcasenode.pass_1: tnode;
begin
{ convert case expression to an integer in case it's an enum, since
enums are class instances in the JVM. All labels are stored as
ordinal values, so it doesn't matter that we change the type }
if left.resultdef.typ=enumdef then
inserttypeconv_explicit(left,s32inttype);
result:=inherited pass_1;
end;
begin
ccasenode:=tjvmcasenode;
end.

View File

@ -204,7 +204,10 @@ implementation
result:=false; result:=false;
end; end;
end; end;
enumdef, enumdef:
begin
result:=jvmaddencodedtype(tenumdef(def).classdef,false,encodedstr,forcesignature,founderror);
end;
orddef : orddef :
begin begin
{ for procedure "results" } { for procedure "results" }

View File

@ -309,6 +309,7 @@ implementation
staticvarsym : staticvarsym :
begin begin
gvs:=tstaticvarsym(symtableentry); gvs:=tstaticvarsym(symtableentry);
{$ifndef jvm}
if ([vo_is_dll_var,vo_is_external] * gvs.varoptions <> []) then if ([vo_is_dll_var,vo_is_external] * gvs.varoptions <> []) then
begin begin
{ assume external variables use the default alignment } { assume external variables use the default alignment }
@ -319,6 +320,7 @@ implementation
exit; exit;
end end
else else
{$endif jvm}
begin begin
location.reference.alignment:=var_align(gvs.vardef.alignment); location.reference.alignment:=var_align(gvs.vardef.alignment);
end; end;

View File

@ -2221,6 +2221,14 @@ implementation
{ structured types } { structured types }
if not( if not(
(left.resultdef.typ=formaldef) or (left.resultdef.typ=formaldef) or
{$ifdef jvm}
{ enums /are/ class instances on the JVM
platform }
(((left.resultdef.typ=enumdef) and
(resultdef.typ=objectdef)) or
((resultdef.typ=enumdef) and
(left.resultdef.typ=objectdef))) or
{$endif}
( (
not(is_open_array(left.resultdef)) and not(is_open_array(left.resultdef)) and
not(is_array_constructor(left.resultdef)) and not(is_array_constructor(left.resultdef)) and

View File

@ -2992,7 +2992,10 @@ implementation
expectloc:=LOC_REGISTER; expectloc:=LOC_REGISTER;
{ in case of range/overflow checking, use a regular addnode { in case of range/overflow checking, use a regular addnode
because it's too complex to handle correctly otherwise } because it's too complex to handle correctly otherwise }
{$ifndef jvm}
{ enums are class instances in the JVM -> always need conversion }
if ([cs_check_overflow,cs_check_range]*current_settings.localswitches)<>[] then if ([cs_check_overflow,cs_check_range]*current_settings.localswitches)<>[] then
{$endif}
begin begin
{ create constant 1 } { create constant 1 }
hp:=cordconstnode.create(1,left.resultdef,false); hp:=cordconstnode.create(1,left.resultdef,false);
@ -3053,11 +3056,16 @@ implementation
{ range/overflow checking doesn't work properly } { range/overflow checking doesn't work properly }
{ with the inc/dec code that's generated (JM) } { with the inc/dec code that's generated (JM) }
if (current_settings.localswitches * [cs_check_overflow,cs_check_range] <> []) and if ((current_settings.localswitches * [cs_check_overflow,cs_check_range] <> []) and
{ No overflow check for pointer operations, because inc(pointer,-1) will always { No overflow check for pointer operations, because inc(pointer,-1) will always
trigger an overflow. For uint32 it works because then the operation is done trigger an overflow. For uint32 it works because then the operation is done
in 64bit. Range checking is not applicable to pointers either } in 64bit. Range checking is not applicable to pointers either }
(tcallparanode(left).left.resultdef.typ<>pointerdef) then (tcallparanode(left).left.resultdef.typ<>pointerdef))
{$ifdef jvm}
{ enums are class instances on the JVM -> special treatment }
or (tcallparanode(left).left.resultdef.typ=enumdef)
{$endif}
then
{ convert to simple add (JM) } { convert to simple add (JM) }
begin begin
newblock := internalstatements(newstatement); newblock := internalstatements(newstatement);

View File

@ -71,6 +71,9 @@ implementation
{ parser } { parser }
scanner, scanner,
pbase,pexpr,ptype,ptconst,pdecsub,pdecvar,pdecobj, pbase,pexpr,ptype,ptconst,pdecsub,pdecvar,pdecobj,
{$ifdef jvm}
pjvm,
{$endif}
{ cpu-information } { cpu-information }
cpuinfo cpuinfo
; ;
@ -204,6 +207,14 @@ implementation
sym.deprecatedmsg:=deprecatedmsg; sym.deprecatedmsg:=deprecatedmsg;
sym.visibility:=symtablestack.top.currentvisibility; sym.visibility:=symtablestack.top.currentvisibility;
symtablestack.top.insert(sym); symtablestack.top.insert(sym);
{$ifdef jvm}
{ for the JVM target, some constants need to be
initialized at run time (enums, sets) -> create fake
typed const to do so }
if assigned(tconstsym(sym).constdef) and
(tconstsym(sym).constdef.typ=enumdef) then
jvm_add_typed_const_initializer(tconstsym(sym));
{$endif}
end end
else else
stringdispose(deprecatedmsg); stringdispose(deprecatedmsg);

View File

@ -28,7 +28,7 @@ interface
uses uses
globtype, globtype,
symtype,symbase,symdef; symtype,symbase,symdef,symsym;
{ the JVM specs require that you add a default parameterless { the JVM specs require that you add a default parameterless
constructor in case the programmer hasn't specified any } constructor in case the programmer hasn't specified any }
@ -41,6 +41,7 @@ interface
procedure jvm_maybe_create_enum_class(const name: TIDString; def: tdef); procedure jvm_maybe_create_enum_class(const name: TIDString; def: tdef);
procedure jvm_add_typed_const_initializer(csym: tconstsym);
implementation implementation
@ -49,9 +50,9 @@ implementation
cutils,cclasses, cutils,cclasses,
verbose,systems, verbose,systems,
fmodule, fmodule,
parabase, parabase,aasmdata,
pdecsub, pdecsub,
symtable,symconst,symsym,symcreat,defcmp,jvmdef, symtable,symconst,symcreat,defcmp,jvmdef,
defutil,paramgr; defutil,paramgr;
@ -329,4 +330,44 @@ implementation
restore_scanner(sstate); restore_scanner(sstate);
end; end;
procedure jvm_add_typed_const_initializer(csym: tconstsym);
var
ssym: tstaticvarsym;
esym: tenumsym;
i: longint;
sstate: symcreat.tscannerstate;
begin
case csym.constdef.typ of
enumdef:
begin
replace_scanner('jvm_enum_const',sstate);
{ make sure we don't emit a definition for this field (we'll do
that for the constsym already) -> mark as external }
ssym:=tstaticvarsym.create(internal_static_field_name(csym.realname),vs_final,csym.constdef,[vo_is_external]);
csym.owner.insert(ssym);
{ alias storage to the constsym }
ssym.set_mangledname(csym.realname);
for i:=0 to tenumdef(csym.constdef).symtable.symlist.count-1 do
begin
esym:=tenumsym(tenumdef(csym.constdef).symtable.symlist[i]);
if esym.value=csym.value.valueord.svalue then
break;
esym:=nil;
end;
{ can happen in case of explicit typecast from integer constant
to enum type }
if not assigned(esym) then
begin
MessagePos(csym.fileinfo,parser_e_range_check_error);
exit;
end;
str_parse_typedconst(current_asmdata.asmlists[al_typedconsts],esym.name+';',ssym);
restore_scanner(sstate);
end
else
internalerror(2011062701);
end;
end;
end. end.

View File

@ -61,6 +61,15 @@ interface
} }
function str_parse_method_impl(str: ansistring; usefwpd: tprocdef; is_classdef: boolean):boolean; function str_parse_method_impl(str: ansistring; usefwpd: tprocdef; is_classdef: boolean):boolean;
{ parses a typed constant assignment to ssym
WARNINGS:
* save the scanner state before calling this routine, and restore when done.
* the code *must* be written in objfpc style
}
procedure str_parse_typedconst(list: TAsmList; str: ansistring; ssym: tstaticvarsym);
{ in the JVM, constructors are not automatically inherited (so you can hide { in the JVM, constructors are not automatically inherited (so you can hide
them). To emulate the Pascal behaviour, we have to automatically add them). To emulate the Pascal behaviour, we have to automatically add
@ -209,6 +218,27 @@ implementation
end; end;
procedure str_parse_typedconst(list: TAsmList; str: ansistring; ssym: tstaticvarsym);
var
old_block_type: tblock_type;
old_parse_only: boolean;
begin
Message1(parser_d_internal_parser_string,str);
{ a string that will be interpreted as the start of a new section ->
typed constant parsing will stop }
str:=str+'type ';
old_parse_only:=parse_only;
old_block_type:=block_type;
parse_only:=true;
block_type:=bt_const;
current_scanner.substitutemacro('typed_const_macro',@str[1],length(str),current_scanner.line_no,current_scanner.inputfile.ref_index);
current_scanner.readtoken(false);
read_typed_const(list,ssym,ssym.owner.symtabletype in [recordsymtable,objectsymtable]);
parse_only:=old_parse_only;
block_type:=old_block_type;
end;
procedure add_missing_parent_constructors_intf(obj: tobjectdef; forcevis: tvisibility); procedure add_missing_parent_constructors_intf(obj: tobjectdef; forcevis: tvisibility);
var var
parent: tobjectdef; parent: tobjectdef;

View File

@ -701,6 +701,8 @@ interface
function min:asizeint; function min:asizeint;
function max:asizeint; function max:asizeint;
function getfirstsym:tsym; function getfirstsym:tsym;
{ returns basedef if assigned, otherwise self }
function getbasedef: tenumdef;
end; end;
tsetdef = class(tstoreddef) tsetdef = class(tstoreddef)
@ -1844,6 +1846,15 @@ implementation
end; end;
function tenumdef.getbasedef: tenumdef;
begin
if not assigned(basedef) then
result:=self
else
result:=basedef;
end;
procedure tenumdef.buildderef; procedure tenumdef.buildderef;
begin begin
inherited buildderef; inherited buildderef;