mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-11-04 10:39:40 +01:00 
			
		
		
		
	* implemented declaring and calling constructors for Java classes
o handle them like for regular classes (return a class instance,
     although this is technically not true since they don't return
     anything; will be changed in the future)
   o because of the previous point, make sure that we handle the
     "function result" properly and don't pop too many values from
     the evaluation stack when calling one constructor from another
   o added "extra_pre_call_code" method used by njvmcal to insert
     the "new" opcode to create the new class instance before
     calling a constructor
   o when a constructor does not call any other constructor (inherited
     or otherwise), automatically insert a call to the inherited
     parameterless constructor as required by the jvm standard)
   TODO: check that *if* an inherited or other constructor is called
     from another constructor, that it does so as the first statement/
     call
git-svn-id: branches/jvmbackend@18328 -
			
			
This commit is contained in:
		
							parent
							
								
									e2e32fbbe9
								
							
						
					
					
						commit
						eb5814a868
					
				@ -81,6 +81,7 @@ uses
 | 
			
		||||
      procedure g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean); override;
 | 
			
		||||
      procedure g_proc_exit(list : TAsmList;parasize:longint;nostackframe:boolean); override;
 | 
			
		||||
 | 
			
		||||
      procedure gen_load_return_value(list:TAsmList);override;
 | 
			
		||||
      procedure record_generated_code_for_procdef(pd: tprocdef; code, data: TAsmList); override;
 | 
			
		||||
 | 
			
		||||
      { JVM-specific routines }
 | 
			
		||||
@ -788,11 +789,16 @@ implementation
 | 
			
		||||
 | 
			
		||||
  procedure thlcgjvm.g_proc_exit(list: TAsmList; parasize: longint; nostackframe: boolean);
 | 
			
		||||
    var
 | 
			
		||||
      retdef: tdef;
 | 
			
		||||
      opc: tasmop;
 | 
			
		||||
    begin
 | 
			
		||||
      case current_procinfo.procdef.returndef.typ of
 | 
			
		||||
      if current_procinfo.procdef.proctypeoption=potype_constructor then
 | 
			
		||||
        retdef:=voidtype
 | 
			
		||||
      else
 | 
			
		||||
        retdef:=current_procinfo.procdef.returndef;
 | 
			
		||||
      case retdef.typ of
 | 
			
		||||
        orddef:
 | 
			
		||||
          case torddef(current_procinfo.procdef.returndef).ordtype of
 | 
			
		||||
          case torddef(retdef).ordtype of
 | 
			
		||||
            uvoid:
 | 
			
		||||
              opc:=a_return;
 | 
			
		||||
            s64bit,
 | 
			
		||||
@ -803,7 +809,7 @@ implementation
 | 
			
		||||
              opc:=a_ireturn;
 | 
			
		||||
          end;
 | 
			
		||||
        floatdef:
 | 
			
		||||
          case tfloatdef(current_procinfo.procdef.returndef).floattype of
 | 
			
		||||
          case tfloatdef(retdef).floattype of
 | 
			
		||||
            s32real:
 | 
			
		||||
              opc:=a_freturn;
 | 
			
		||||
            s64real:
 | 
			
		||||
@ -817,6 +823,14 @@ implementation
 | 
			
		||||
      list.concat(taicpu.op_none(opc));
 | 
			
		||||
    end;
 | 
			
		||||
 | 
			
		||||
  procedure thlcgjvm.gen_load_return_value(list: TAsmList);
 | 
			
		||||
    begin
 | 
			
		||||
      { constructors don't return anything in the jvm }
 | 
			
		||||
      if current_procinfo.procdef.proctypeoption=potype_constructor then
 | 
			
		||||
        exit;
 | 
			
		||||
      inherited gen_load_return_value(list);
 | 
			
		||||
    end;
 | 
			
		||||
 | 
			
		||||
  procedure thlcgjvm.record_generated_code_for_procdef(pd: tprocdef; code, data: TAsmList);
 | 
			
		||||
    begin
 | 
			
		||||
      { add something to the al_procedures list as well, because if all al_*
 | 
			
		||||
 | 
			
		||||
@ -35,6 +35,7 @@ interface
 | 
			
		||||
 | 
			
		||||
       tjvmcallnode = class(tcgcallnode)
 | 
			
		||||
        protected
 | 
			
		||||
         procedure extra_pre_call_code; override;
 | 
			
		||||
         procedure set_result_location(realresdef: tstoreddef); override;
 | 
			
		||||
         procedure do_release_unused_return_value;override;
 | 
			
		||||
         procedure extra_post_call_code; override;
 | 
			
		||||
@ -45,16 +46,37 @@ implementation
 | 
			
		||||
 | 
			
		||||
    uses
 | 
			
		||||
      verbose,globtype,
 | 
			
		||||
      symtype,defutil,ncal,
 | 
			
		||||
      cgbase,cgutils,tgobj,
 | 
			
		||||
      symconst,symtype,defutil,ncal,
 | 
			
		||||
      cgbase,cgutils,tgobj,procinfo,
 | 
			
		||||
      cpubase,aasmdata,aasmcpu,
 | 
			
		||||
      hlcgobj,hlcgcpu;
 | 
			
		||||
      hlcgobj,hlcgcpu,
 | 
			
		||||
      jvmdef;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
{*****************************************************************************
 | 
			
		||||
                             TJVMCALLNODE
 | 
			
		||||
*****************************************************************************}
 | 
			
		||||
 | 
			
		||||
    procedure tjvmcallnode.extra_pre_call_code;
 | 
			
		||||
      begin
 | 
			
		||||
        { when calling a constructor, first create a new instance, except
 | 
			
		||||
          when calling it from another constructor (because then this has
 | 
			
		||||
          already been done before calling the current constructor) }
 | 
			
		||||
        if procdefinition.typ<>procdef then
 | 
			
		||||
          exit;
 | 
			
		||||
        if tprocdef(procdefinition).proctypeoption<>potype_constructor then
 | 
			
		||||
          exit;
 | 
			
		||||
        if (methodpointer.resultdef.typ<>classrefdef) then
 | 
			
		||||
          exit;
 | 
			
		||||
        current_asmdata.CurrAsmList.concat(taicpu.op_sym(a_new,current_asmdata.RefAsmSymbol(tobjectdef(tprocdef(procdefinition).owner.defowner).jvm_full_typename)));
 | 
			
		||||
        { the constructor doesn't return anything, so put a duplicate of the
 | 
			
		||||
          self pointer on the evaluation stack for use as function result
 | 
			
		||||
          after the constructor has run }
 | 
			
		||||
        current_asmdata.CurrAsmList.concat(taicpu.op_none(a_dup));
 | 
			
		||||
        thlcgjvm(hlcg).incstack(2);
 | 
			
		||||
      end;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    procedure tjvmcallnode.set_result_location(realresdef: tstoreddef);
 | 
			
		||||
      begin
 | 
			
		||||
        location_reset_ref(location,LOC_REFERENCE,def_cgsize(realresdef),1);
 | 
			
		||||
@ -64,6 +86,9 @@ implementation
 | 
			
		||||
 | 
			
		||||
    procedure tjvmcallnode.do_release_unused_return_value;
 | 
			
		||||
      begin
 | 
			
		||||
        if (tprocdef(procdefinition).proctypeoption=potype_constructor) and
 | 
			
		||||
           (current_procinfo.procdef.proctypeoption=potype_constructor) then
 | 
			
		||||
          exit;
 | 
			
		||||
        case resultdef.size of
 | 
			
		||||
          0:
 | 
			
		||||
            ;
 | 
			
		||||
@ -92,7 +117,11 @@ implementation
 | 
			
		||||
          realresdef:=tstoreddef(resultdef)
 | 
			
		||||
        else
 | 
			
		||||
          realresdef:=tstoreddef(typedef);
 | 
			
		||||
        totalremovesize:=pushedparasize-realresdef.size;
 | 
			
		||||
        { a constructor doesn't actually return a value in the jvm }
 | 
			
		||||
        if (tprocdef(procdefinition).proctypeoption=potype_constructor) then
 | 
			
		||||
          totalremovesize:=pushedparasize
 | 
			
		||||
        else
 | 
			
		||||
          totalremovesize:=pushedparasize-realresdef.size;
 | 
			
		||||
        { remove parameters from internal evaluation stack counter (in case of
 | 
			
		||||
          e.g. no parameters and a result, it can also increase) }
 | 
			
		||||
        if totalremovesize>0 then
 | 
			
		||||
 | 
			
		||||
@ -1670,7 +1670,12 @@ implementation
 | 
			
		||||
              { push 0 as self when allocation is needed }
 | 
			
		||||
              if (methodpointer.resultdef.typ=classrefdef) or
 | 
			
		||||
                 (cnf_new_call in callnodeflags) then
 | 
			
		||||
                selftree:=cpointerconstnode.create(0,voidpointertype)
 | 
			
		||||
                if not is_javaclass(tdef(procdefinition.owner.defowner)) then
 | 
			
		||||
                  selftree:=cpointerconstnode.create(0,voidpointertype)
 | 
			
		||||
                else
 | 
			
		||||
                 { special handling for Java constructors, handled in
 | 
			
		||||
                   tjvmcallnode.extra_pre_call_code }
 | 
			
		||||
                  selftree:=cnothingnode.create
 | 
			
		||||
              else
 | 
			
		||||
                begin
 | 
			
		||||
                  if methodpointer.nodetype=typen then
 | 
			
		||||
@ -3340,6 +3345,15 @@ implementation
 | 
			
		||||
             doinlinesimplify(tnode(callcleanupblock));
 | 
			
		||||
           end;
 | 
			
		||||
 | 
			
		||||
         { If a constructor calls another constructor of the same or of an
 | 
			
		||||
           inherited class, some targets (jvm) have to generate different
 | 
			
		||||
           entry code for the constructor. }
 | 
			
		||||
         if (current_procinfo.procdef.proctypeoption=potype_constructor) and
 | 
			
		||||
            (procdefinition.typ=procdef) and
 | 
			
		||||
            (tprocdef(procdefinition).proctypeoption=potype_constructor) and
 | 
			
		||||
            ([cnf_member_call,cnf_inherited] * callnodeflags <> []) then
 | 
			
		||||
           current_procinfo.ConstructorCallingConstructor:=true;
 | 
			
		||||
 | 
			
		||||
         { Continue with checking a normal call or generate the inlined code }
 | 
			
		||||
         if cnf_do_inline in callnodeflags then
 | 
			
		||||
           result:=pass1_inline
 | 
			
		||||
 | 
			
		||||
@ -68,6 +68,7 @@ interface
 | 
			
		||||
          }
 | 
			
		||||
          procedure pop_parasize(pop_size:longint);virtual;
 | 
			
		||||
          procedure extra_interrupt_code;virtual;
 | 
			
		||||
          procedure extra_pre_call_code;virtual;
 | 
			
		||||
          procedure extra_call_code;virtual;
 | 
			
		||||
          procedure extra_post_call_code;virtual;
 | 
			
		||||
          procedure do_syscall;virtual;abstract;
 | 
			
		||||
@ -285,6 +286,11 @@ implementation
 | 
			
		||||
      end;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    procedure tcgcallnode.extra_pre_call_code;
 | 
			
		||||
      begin
 | 
			
		||||
      end;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    procedure tcgcallnode.extra_call_code;
 | 
			
		||||
      begin
 | 
			
		||||
      end;
 | 
			
		||||
@ -650,6 +656,8 @@ implementation
 | 
			
		||||
            not(procdefinition.has_paraloc_info in [callerside,callbothsides]) then
 | 
			
		||||
           internalerror(200305264);
 | 
			
		||||
 | 
			
		||||
         extra_pre_call_code;
 | 
			
		||||
 | 
			
		||||
         if assigned(callinitblock) then
 | 
			
		||||
           secondpass(tnode(callinitblock));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -102,7 +102,9 @@ implementation
 | 
			
		||||
        include(current_structdef.objectoptions,oo_has_constructor);
 | 
			
		||||
        { Set return type, class and record constructors return the
 | 
			
		||||
          created instance, object constructors return boolean }
 | 
			
		||||
        if is_class(pd.struct) or is_record(pd.struct) then
 | 
			
		||||
        if is_class(pd.struct) or
 | 
			
		||||
           is_record(pd.struct) or
 | 
			
		||||
           is_javaclass(pd.struct) then
 | 
			
		||||
          pd.returndef:=pd.struct
 | 
			
		||||
        else
 | 
			
		||||
{$ifdef CPU64bitaddr}
 | 
			
		||||
 | 
			
		||||
@ -1402,7 +1402,9 @@ implementation
 | 
			
		||||
                begin
 | 
			
		||||
                  { Set return type, class constructors return the
 | 
			
		||||
                    created instance, object constructors return boolean }
 | 
			
		||||
                  if is_class(pd.struct) or is_record(pd.struct) then
 | 
			
		||||
                  if is_class(pd.struct) or
 | 
			
		||||
                     is_record(pd.struct) or
 | 
			
		||||
                     is_javaclass(pd.struct) then
 | 
			
		||||
                    pd.returndef:=pd.struct
 | 
			
		||||
                  else
 | 
			
		||||
{$ifdef CPU64bitaddr}
 | 
			
		||||
@ -2377,7 +2379,7 @@ const
 | 
			
		||||
      mutexclpo     : []
 | 
			
		||||
    ),(
 | 
			
		||||
      idtok:_OVERLOAD;
 | 
			
		||||
      pd_flags : [pd_implemen,pd_interface,pd_body];
 | 
			
		||||
      pd_flags : [pd_implemen,pd_interface,pd_body,pd_javaclass,pd_intfjava];
 | 
			
		||||
      handler  : @pd_overload;
 | 
			
		||||
      pocall   : pocall_none;
 | 
			
		||||
      pooption : [po_overload];
 | 
			
		||||
@ -2386,7 +2388,7 @@ const
 | 
			
		||||
      mutexclpo     : []
 | 
			
		||||
    ),(
 | 
			
		||||
      idtok:_OVERRIDE;
 | 
			
		||||
      pd_flags : [pd_interface,pd_object,pd_notobjintf,pd_objcclass,pd_javaclass,pd_notrecord];
 | 
			
		||||
      pd_flags : [pd_interface,pd_object,pd_notobjintf,pd_objcclass,pd_javaclass,pd_intfjava,pd_notrecord];
 | 
			
		||||
      handler  : @pd_override;
 | 
			
		||||
      pocall   : pocall_none;
 | 
			
		||||
      pooption : [po_overridingmethod,po_virtualmethod];
 | 
			
		||||
 | 
			
		||||
@ -1257,7 +1257,9 @@ implementation
 | 
			
		||||
                     else
 | 
			
		||||
                       begin
 | 
			
		||||
                         p1:=ctypenode.create(ttypesym(sym).typedef);
 | 
			
		||||
                         if (is_class(ttypesym(sym).typedef) or is_objcclass(ttypesym(sym).typedef)) and
 | 
			
		||||
                         if (is_class(ttypesym(sym).typedef) or
 | 
			
		||||
                             is_objcclass(ttypesym(sym).typedef) or
 | 
			
		||||
                             is_javaclass(ttypesym(sym).typedef)) and
 | 
			
		||||
                            not(block_type in [bt_type,bt_const_type,bt_var_type]) then
 | 
			
		||||
                           p1:=cloadvmtaddrnode.create(p1);
 | 
			
		||||
                       end;
 | 
			
		||||
@ -1553,7 +1555,8 @@ implementation
 | 
			
		||||
                            (for "TClassHelper.Something") }
 | 
			
		||||
                          { class reference ? }
 | 
			
		||||
                          if is_class(hdef) or
 | 
			
		||||
                             is_objcclass(hdef) then
 | 
			
		||||
                             is_objcclass(hdef) or
 | 
			
		||||
                             is_javaclass(hdef) then
 | 
			
		||||
                           begin
 | 
			
		||||
                             if getaddr and (token=_POINT) then
 | 
			
		||||
                              begin
 | 
			
		||||
 | 
			
		||||
@ -114,6 +114,11 @@ unit procinfo;
 | 
			
		||||
          { max. of space need for parameters }
 | 
			
		||||
          maxpushedparasize : aint;
 | 
			
		||||
 | 
			
		||||
          { is this a constructor that calls another constructor on itself
 | 
			
		||||
            (either inherited, or another constructor of the same class)?
 | 
			
		||||
            Requires different entry code for some targets. }
 | 
			
		||||
          ConstructorCallingConstructor: boolean;
 | 
			
		||||
 | 
			
		||||
          constructor create(aparent:tprocinfo);virtual;
 | 
			
		||||
          destructor destroy;override;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -292,6 +292,7 @@ implementation
 | 
			
		||||
      var
 | 
			
		||||
        srsym        : tsym;
 | 
			
		||||
        para         : tcallparanode;
 | 
			
		||||
        call         : tcallnode;
 | 
			
		||||
        newstatement : tstatementnode;
 | 
			
		||||
      begin
 | 
			
		||||
        result:=internalstatements(newstatement);
 | 
			
		||||
@ -350,6 +351,25 @@ implementation
 | 
			
		||||
                              voidpointertype),
 | 
			
		||||
                          ccallnode.createintern('fpc_help_constructor',para)));
 | 
			
		||||
                    end
 | 
			
		||||
                else
 | 
			
		||||
                  if is_javaclass(current_structdef) then
 | 
			
		||||
                    begin
 | 
			
		||||
                      if (current_procinfo.procdef.proctypeoption=potype_constructor) and
 | 
			
		||||
                         not current_procinfo.ConstructorCallingConstructor then
 | 
			
		||||
                       begin
 | 
			
		||||
                         { call inherited constructor }
 | 
			
		||||
                         srsym:=search_struct_member(tobjectdef(current_structdef).childof,'CREATE');
 | 
			
		||||
                         if assigned(srsym) and
 | 
			
		||||
                            (srsym.typ=procsym) then
 | 
			
		||||
                           begin
 | 
			
		||||
                             call:=ccallnode.create(nil,tprocsym(srsym),srsym.owner,load_self_node,[cnf_inherited]);
 | 
			
		||||
                             exclude(tcallnode(call).callnodeflags,cnf_return_value_used);
 | 
			
		||||
                             addstatement(newstatement,call);
 | 
			
		||||
                           end
 | 
			
		||||
                         else
 | 
			
		||||
                           internalerror(2011010312);
 | 
			
		||||
                       end;
 | 
			
		||||
                    end
 | 
			
		||||
                else
 | 
			
		||||
                  if not is_record(current_structdef) then
 | 
			
		||||
                  internalerror(200305103);
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user