* generalized handling of pointers to non-implicit pointer types:

as far as Java is concerned, they're now all arrays of JLObject.
    When loading a value from them, we typecast the loaded value
    to the appropriate type. This allows typecasting one pointer
    type to another without getting verification errors (since an
    "array of JLObject" is not compatible with "array of JLString")
  - no longer allow dereferencing untyped pointers on the JVM
    target, since that always results in invalid bytecode

git-svn-id: branches/jvmbackend@18819 -
This commit is contained in:
Jonas Maebe 2011-08-23 17:44:55 +00:00
parent 0364b7acf9
commit 992cc352c6
5 changed files with 75 additions and 35 deletions

View File

@ -69,6 +69,7 @@ unit cgutils;
indexbase: tregister;
indexsymbol: tasmsymbol;
indexoffset: aint;
checkcast: boolean;
{$endif jvm}
alignment : byte;
end;

View File

@ -154,6 +154,8 @@ uses
property maxevalstackheight: longint read fmaxevalstackheight;
procedure gen_initialize_fields_code(list:TAsmList);
procedure gen_typecheck(list: TAsmList; checkop: tasmop; checkdef: tdef);
protected
function get_enum_init_val_ref(def: tdef; out ref: treference): boolean;
@ -1778,6 +1780,8 @@ implementation
incstack(list,1+ord(size.size>4)-extra_slots);
if finishandval<>-1 then
a_op_const_stack(list,OP_AND,size,finishandval);
if ref.checkcast then
gen_typecheck(list,a_checkcast,size);
end;
function thlcgjvm.loadstoreopcref(def: tdef; isload: boolean; const ref: treference; out finishandval: aint): tasmop;
@ -2089,6 +2093,40 @@ implementation
allocate_implicit_structs_for_st_with_base_ref(list,obj.symtable,ref,fieldvarsym);
end;
procedure thlcgjvm.gen_typecheck(list: TAsmList; checkop: tasmop; checkdef: tdef);
begin
{ replace special types with their equivalent class type }
if (checkdef.typ=pointerdef) and
jvmimplicitpointertype(tpointerdef(checkdef).pointeddef) then
checkdef:=tpointerdef(checkdef).pointeddef;
if (checkdef=voidpointertype) or
(checkdef.typ=formaldef) then
checkdef:=java_jlobject
else if checkdef.typ=enumdef then
checkdef:=tenumdef(checkdef).classdef
else if checkdef.typ=setdef then
begin
if tsetdef(checkdef).elementdef.typ=enumdef then
checkdef:=java_juenumset
else
checkdef:=java_jubitset;
end
else if checkdef.typ=procvardef then
checkdef:=tprocvardef(checkdef).classdef
else if is_wide_or_unicode_string(checkdef) then
checkdef:=java_jlstring
else if is_ansistring(checkdef) then
checkdef:=java_ansistring
else if is_shortstring(checkdef) then
checkdef:=java_shortstring;
if checkdef.typ in [objectdef,recorddef] then
list.concat(taicpu.op_sym(checkop,current_asmdata.RefAsmSymbol(tabstractrecorddef(checkdef).jvm_full_typename(true))))
else if checkdef.typ=classrefdef then
list.concat(taicpu.op_sym(checkop,current_asmdata.RefAsmSymbol('java/lang/Class')))
else
list.concat(taicpu.op_sym(checkop,current_asmdata.RefAsmSymbol(jvmencodetype(checkdef,false))));
end;
procedure thlcgjvm.resizestackfpuval(list: TAsmList; fromsize, tosize: tcgsize);
begin
if (fromsize=OS_F32) and

View File

@ -253,15 +253,24 @@ implementation
end;
pointerdef :
begin
if def=voidpointertype then
if is_voidpointer(def) then
result:=jvmaddencodedtype(java_jlobject,false,encodedstr,forcesignature,founderror)
else if tpointerdef(def).pointeddef.typ in [orddef,floatdef] then
begin
encodedstr:=encodedstr+'[';
result:=jvmaddencodedtype(tpointerdef(def).pointeddef,false,encodedstr,forcesignature,founderror);
end
else if jvmimplicitpointertype(tpointerdef(def).pointeddef) then
result:=jvmaddencodedtype(tpointerdef(def).pointeddef,false,encodedstr,forcesignature,founderror)
else
begin
{ used for internal pointer constructs }
{ Semantically, these are pointers to types that are
pointer-based themselves (or typecastable to pointer).
Internally, we represent them all as array of JLObject so that
they are assignment-compatible. We will perform the type
checks when actually loading a value from them }
encodedstr:=encodedstr+'[';
result:=jvmaddencodedtype(tpointerdef(def).pointeddef,false,encodedstr,forcesignature,founderror);
result:=jvmaddencodedtype(java_jlobject,false,encodedstr,forcesignature,founderror)
end;
end;
floatdef :

View File

@ -1485,36 +1485,7 @@ implementation
checkdef:=tclassrefdef(node.right.resultdef).pointeddef
else
checkdef:=node.right.resultdef;
{ replace special types with their equivalent class type }
if (checkdef.typ=pointerdef) and
jvmimplicitpointertype(tpointerdef(checkdef).pointeddef) then
checkdef:=tpointerdef(checkdef).pointeddef;
if (checkdef=voidpointertype) or
(checkdef.typ=formaldef) then
checkdef:=java_jlobject
else if checkdef.typ=enumdef then
checkdef:=tenumdef(checkdef).classdef
else if checkdef.typ=setdef then
begin
if tsetdef(checkdef).elementdef.typ=enumdef then
checkdef:=java_juenumset
else
checkdef:=java_jubitset;
end
else if checkdef.typ=procvardef then
checkdef:=tprocvardef(checkdef).classdef
else if is_wide_or_unicode_string(checkdef) then
checkdef:=java_jlstring
else if is_ansistring(checkdef) then
checkdef:=java_ansistring
else if is_shortstring(checkdef) then
checkdef:=java_shortstring;
if checkdef.typ in [objectdef,recorddef] then
current_asmdata.CurrAsmList.concat(taicpu.op_sym(opcode,current_asmdata.RefAsmSymbol(tabstractrecorddef(checkdef).jvm_full_typename(true))))
else if checkdef.typ=classrefdef then
current_asmdata.CurrAsmList.concat(taicpu.op_sym(opcode,current_asmdata.RefAsmSymbol('java/lang/Class')))
else
current_asmdata.CurrAsmList.concat(taicpu.op_sym(opcode,current_asmdata.RefAsmSymbol(jvmencodetype(checkdef,false))));
thlcgjvm(hlcg).gen_typecheck(current_asmdata.CurrAsmList,opcode,checkdef);
location_reset(node.location,LOC_REGISTER,OS_ADDR);
node.location.register:=hlcg.getaddressregister(current_asmdata.CurrAsmList,node.resultdef);
thlcgjvm(hlcg).a_load_stack_reg(current_asmdata.CurrAsmList,node.resultdef,node.location.register);

View File

@ -41,6 +41,7 @@ interface
end;
tjvmderefnode = class(tcgderefnode)
function pass_typecheck: tnode; override;
procedure pass_generate_code; override;
end;
@ -68,12 +69,25 @@ implementation
TJVMDEREFNODE
*****************************************************************************}
function tjvmderefnode.pass_typecheck: tnode;
begin
result:=inherited pass_typecheck;
if assigned(result) then
exit;
{ don't allow dereferencing untyped pointers, because how this has to
be done depends on whether it's a pointer to an implicit pointer type
or not }
if is_voidpointer(left.resultdef) then
CGMessage(parser_e_illegal_expression);
end;
procedure tjvmderefnode.pass_generate_code;
var
implicitptr: boolean;
begin
secondpass(left);
implicitptr:=jvmimplicitpointertype(tpointerdef(left.resultdef).pointeddef);
implicitptr:=jvmimplicitpointertype(resultdef);
if implicitptr then
begin
{ this is basically a typecast: the left node is a regular
@ -91,11 +105,18 @@ implementation
else
begin
{ these are always arrays (used internally for pointers to var
parameters stored in nestedfpstructs) }
parameters stored in nestedfpstructs, and by programmers for any
kind of pointers) }
hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,true);
location_reset_ref(location,LOC_REFERENCE,def_cgsize(resultdef),4);
reference_reset_base(location.reference,left.location.register,0,4);
location.reference.arrayreftype:=art_indexconst;
if (left.nodetype<>addrn) and
not(resultdef.typ in [orddef,floatdef]) and
not is_voidpointer(resultdef) and
((resultdef.typ<>objectdef) or
(find_real_class_definition(tobjectdef(resultdef),false)<>java_jlobject)) then
location.reference.checkcast:=true;
end
end;