ソースを参照

+ support for class constructors for the JVM target
o initialise class vars that need initialisations (records, arrays) in
class constructors
o treat class constructors as having a "void" resultdef rather than the
class type for JVM (maybe has to be done in general?)
o make it possible to specify pno_noleadingdollar to
tprocdef.customprocname() so it can be used for class constructors
(their name is lower cased because it mustn't conflict with other
identifiers, since their name doesn't matter anyway)
o added tsk_empty synthetic procdef kind which, as the name implies,
generates an empty body (for class generated constructors)
+ auto-generate class constructors in case a class has class vars that
need initialisation

git-svn-id: branches/jvmbackend@18462 -

Jonas Maebe 14 年 前
コミット
e663f0f31f
5 ファイル変更160 行追加95 行削除
  1. 12 2
      compiler/jvm/hlcgcpu.pas
  2. 1 1
      compiler/pdecvar.pas
  3. 113 76
      compiler/pjvm.pas
  4. 21 4
      compiler/symcreat.pas
  5. 13 12
      compiler/symdef.pas

+ 12 - 2
compiler/jvm/hlcgcpu.pas

@@ -1222,7 +1222,7 @@ implementation
       retdef: tdef;
       opc: tasmop;
     begin
-      if current_procinfo.procdef.proctypeoption=potype_constructor then
+      if current_procinfo.procdef.proctypeoption in [potype_constructor,potype_class_constructor] then
         retdef:=voidtype
       else
         retdef:=current_procinfo.procdef.returndef;
@@ -1256,7 +1256,7 @@ implementation
   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
+      if current_procinfo.procdef.proctypeoption in [potype_constructor,potype_class_constructor] then
         exit;
       inherited gen_load_return_value(list);
     end;
@@ -1447,6 +1447,14 @@ implementation
               allocate_implicit_structs_for_st_with_base_ref(list,current_module.globalsymtable,ref,staticvarsym);
             allocate_implicit_structs_for_st_with_base_ref(list,current_module.localsymtable,ref,staticvarsym);
           end;
+        potype_class_constructor:
+          begin
+            { also initialise local variables, if any }
+            inherited;
+            { initialise class fields }
+            reference_reset_base(ref,NR_NO,0,1);
+            allocate_implicit_structs_for_st_with_base_ref(list,tabstractrecorddef(current_procinfo.procdef.owner.defowner).symtable,ref,staticvarsym);
+          end
         else
           inherited
       end;
@@ -1721,6 +1729,8 @@ implementation
           if (tsym(st.symlist[i]).typ<>allocvartyp) then
             continue;
           vs:=tabstractvarsym(st.symlist[i]);
+          if sp_internal in vs.symoptions then
+            continue;
           if not jvmimplicitpointertype(vs.vardef) then
             continue;
           allocate_implicit_struct_with_base_ref(list,vs,ref);

+ 1 - 1
compiler/pdecvar.pas

@@ -1715,10 +1715,10 @@ implementation
                        there is nothing in this case (class+field name will be
                        encoded in the mangled symbol name) }
                      hstaticvs:=tstaticvarsym.create(fieldvs.realname,vs_value,hdef,[]);
-                     include(hstaticvs.symoptions,sp_internal);
                      { rename the original field to prevent a name clash when
                        inserting the new one }
                      fieldvs.Rename(internal_static_field_name(fieldvs.name));
+                     include(fieldvs.symoptions,sp_internal);
                      recst.insert(hstaticvs);
                      { has to be delayed until now, because the calculated
                        mangled name depends on the owner }

+ 113 - 76
compiler/pjvm.pas

@@ -54,102 +54,139 @@ implementation
     { the JVM specs require that you add a default parameterless
       constructor in case the programmer hasn't specified any }
     procedure maybe_add_public_default_java_constructor(obj: tabstractrecorddef);
-
-      function find_parameterless_def(psym: tprocsym): tprocdef;
-        var
-          paras: tparalist;
-        begin
-          paras:=tparalist.create;
-          result:=psym.find_procdef_bypara_no_rettype(paras,[cpo_ignorehidden,cpo_openequalisexact]);
-          paras.free;
-        end;
-
       var
         sym: tsym;
         ps: tprocsym;
         pd: tprocdef;
         topowner: tdefentry;
+        i: longint;
+        needclassconstructor: boolean;
       begin
         { if there is at least one constructor for a class, do nothing (for
            records, we'll always also need a parameterless constructor) }
-        if is_javaclass(obj) and
-           (oo_has_constructor in obj.objectoptions) then
-          exit;
-        { check whether the parent has a parameterless constructor that we can
-          call (in case of a class; all records will derive from
-          java.lang.Object or a shim on top of that with a parameterless
-          constructor) }
-        if is_javaclass(obj) then
+        if not is_javaclass(obj) or
+           not (oo_has_constructor in obj.objectoptions) then
           begin
-            pd:=nil;
-            sym:=tsym(tobjectdef(obj).childof.symtable.find('CREATE'));
-            if assigned(sym) and
-               (sym.typ=procsym) then
+            { check whether the parent has a parameterless constructor that we can
+              call (in case of a class; all records will derive from
+              java.lang.Object or a shim on top of that with a parameterless
+              constructor) }
+            if is_javaclass(obj) then
+              begin
+                pd:=nil;
+                sym:=tsym(tobjectdef(obj).childof.symtable.find('CREATE'));
+                if assigned(sym) and
+                   (sym.typ=procsym) then
+                  pd:=tprocsym(sym).find_bytype_parameterless(potype_constructor);
+                if not assigned(pd) then
+                  begin
+                    Message(sym_e_no_matching_inherited_parameterless_constructor);
+                    exit
+                  end;
+              end;
+            { we call all constructors CREATE, because they don't have a name in
+              Java and otherwise we can't determine whether multiple overloads
+              are created with the same parameters }
+            sym:=tsym(obj.symtable.find('CREATE'));
+            if assigned(sym) then
               begin
-                pd:=find_parameterless_def(tprocsym(sym));
-                { make sure it's a constructor }
-                if assigned(pd) and
-                   (pd.proctypeoption<>potype_constructor) then
-                  pd:=nil;
+                { does another, non-procsym, symbol already exist with that name? }
+                if (sym.typ<>procsym) then
+                  begin
+                    Message1(sym_e_duplicate_id_create_java_constructor,sym.realname);
+                    exit;
+                  end;
+                ps:=tprocsym(sym);
+                { is there already a parameterless function/procedure create? }
+                pd:=ps.find_bytype_parameterless(potype_function);
+                if not assigned(pd) then
+                  pd:=ps.find_bytype_parameterless(potype_procedure);
+                if assigned(pd) then
+                  begin
+                    Message1(sym_e_duplicate_id_create_java_constructor,pd.fullprocname(false));
+                    exit;
+                  end;
               end;
-            if not assigned(pd) then
+            if not assigned(sym) then
               begin
-                Message(sym_e_no_matching_inherited_parameterless_constructor);
-                exit
+                ps:=tprocsym.create('Create');
+                obj.symtable.insert(ps);
               end;
+            { determine symtable level }
+            topowner:=obj;
+            while not(topowner.owner.symtabletype in [staticsymtable,globalsymtable,localsymtable]) do
+              topowner:=topowner.owner.defowner;
+            { create procdef }
+            pd:=tprocdef.create(topowner.owner.symtablelevel+1);
+            { method of this objectdef }
+            pd.struct:=obj;
+            { associated procsym }
+            pd.procsym:=ps;
+            { constructor }
+            pd.proctypeoption:=potype_constructor;
+            { needs to be exported }
+            include(pd.procoptions,po_global);
+            { for Delphi mode }
+            include(pd.procoptions,po_overload);
+            { generate anonymous inherited call in the implementation }
+            pd.synthetickind:=tsk_anon_inherited;
+            { public }
+            pd.visibility:=vis_public;
+            { result type }
+            pd.returndef:=obj;
+            { calling convention, self, ... }
+            handle_calling_convention(pd);
+            { register forward declaration with procsym }
+            proc_add_definition(pd);
           end;
-        { we call all constructors CREATE, because they don't have a name in
-          Java and otherwise we can't determine whether multiple overloads
-          are created with the same parameters }
-        sym:=tsym(obj.symtable.find('CREATE'));
-        if assigned(sym) then
+
+        { also add class constructor if class fields that need wrapping, and
+          if none was defined }
+        if obj.find_procdef_bytype(potype_class_constructor)=nil then
           begin
-            { does another, non-procsym, symbol already exist with that name? }
-            if (sym.typ<>procsym) then
+            needclassconstructor:=false;
+            for i:=0 to obj.symtable.symlist.count-1 do
               begin
-                Message1(sym_e_duplicate_id_create_java_constructor,sym.realname);
-                exit;
+                if (tsym(obj.symtable.symlist[i]).typ=staticvarsym) and
+                   jvmimplicitpointertype(tstaticvarsym(obj.symtable.symlist[i]).vardef) then
+                  begin
+                    needclassconstructor:=true;
+                    break;
+                  end;
               end;
-            ps:=tprocsym(sym);
-            { is there already a parameterless function/procedure create? }
-            pd:=find_parameterless_def(ps);
-            if assigned(pd) then
+            if needclassconstructor then
               begin
-                Message1(sym_e_duplicate_id_create_java_constructor,pd.fullprocname(false));
-                exit;
+                { determine symtable level }
+                topowner:=obj;
+                while not(topowner.owner.symtabletype in [staticsymtable,globalsymtable,localsymtable]) do
+                  topowner:=topowner.owner.defowner;
+                { name doesn't matter, so pick something that hopefully conflict }
+                ps:=tprocsym.create('$fpc_jvm_class_constructor');
+                obj.symtable.insert(ps);
+                { create procdef }
+                pd:=tprocdef.create(topowner.owner.symtablelevel+1);
+                { method of this objectdef }
+                pd.struct:=obj;
+                { associated procsym }
+                pd.procsym:=ps;
+                { constructor }
+                pd.proctypeoption:=potype_class_constructor;
+                { needs to be exported }
+                include(pd.procoptions,po_global);
+                { class constructor is a class method }
+                include(pd.procoptions,po_classmethod);
+                { empty body; proc entry code will add inits for class fields }
+                pd.synthetickind:=tsk_empty;
+                { private (= package visibility) }
+                pd.visibility:=vis_private;
+                { result type }
+                pd.returndef:=obj;
+                { calling convention, self, ... }
+                handle_calling_convention(pd);
+                { register forward declaration with procsym }
+                proc_add_definition(pd);
               end;
           end;
-        if not assigned(sym) then
-          begin
-            ps:=tprocsym.create('Create');
-            obj.symtable.insert(ps);
-          end;
-        { determine symtable level }
-        topowner:=obj;
-        while not(topowner.owner.symtabletype in [staticsymtable,globalsymtable,localsymtable]) do
-          topowner:=topowner.owner.defowner;
-        { create procdef }
-        pd:=tprocdef.create(topowner.owner.symtablelevel+1);
-        { method of this objectdef }
-        pd.struct:=obj;
-        { associated procsym }
-        pd.procsym:=ps;
-        { constructor }
-        pd.proctypeoption:=potype_constructor;
-        { needs to be exported }
-        include(pd.procoptions,po_global);
-        { for Delphi mode }
-        include(pd.procoptions,po_overload);
-        { generate anonymous inherited call in the implementation }
-        pd.synthetickind:=tsk_anon_inherited;
-        { public }
-        pd.visibility:=vis_public;
-        { result type }
-        pd.returndef:=obj;
-        { calling convention, self, ... }
-        handle_calling_convention(pd);
-        { register forward declaration with procsym }
-        proc_add_definition(pd);
       end;
 
 

+ 21 - 4
compiler/symcreat.pas

@@ -190,7 +190,7 @@ implementation
             (po_classmethod in tprocdef(pd).procoptions) and
             not(tprocdef(pd).proctypeoption in [potype_constructor,potype_destructor]);
           { + 'overload' for Delphi modes }
-          str:=tprocdef(pd).customprocname([pno_proctypeoption,pno_paranames,pno_noclassmarker])+'overload;';
+          str:=tprocdef(pd).customprocname([pno_proctypeoption,pno_paranames,pno_noclassmarker,pno_noleadingdollar])+'overload;';
           if not str_parse_method_dec(str,isclassmethod,obj,newpd) then
             internalerror(2011032001);
           newpd.synthetickind:=tsk_anon_inherited;
@@ -207,7 +207,7 @@ implementation
       isclassmethod:=
         (po_classmethod in pd.procoptions) and
         not(pd.proctypeoption in [potype_constructor,potype_destructor]);
-      str:=pd.customprocname([pno_proctypeoption,pno_paranames,pno_ownername,pno_noclassmarker]);
+      str:=pd.customprocname([pno_proctypeoption,pno_paranames,pno_ownername,pno_noclassmarker,pno_noleadingdollar]);
       str:=str+'begin inherited end;';
       str_parse_method_impl(str,isclassmethod);
     end;
@@ -229,7 +229,7 @@ implementation
       if (struct.typ=recorddef) and
          not assigned(struct.typesym) then
         internalerror(2011032812);
-      str:=pd.customprocname([pno_proctypeoption,pno_paranames,pno_ownername,pno_noclassmarker]);
+      str:=pd.customprocname([pno_proctypeoption,pno_paranames,pno_ownername,pno_noclassmarker,pno_noleadingdollar]);
       { the inherited clone will already copy all fields in a shallow way ->
         copy records/regular arrays in a regular way }
       str:=str+'begin result:=inherited;';
@@ -268,7 +268,7 @@ implementation
       if (struct.typ=recorddef) and
          not assigned(struct.typesym) then
         internalerror(2011032811);
-      str:=pd.customprocname([pno_proctypeoption,pno_paranames,pno_ownername,pno_noclassmarker]);
+      str:=pd.customprocname([pno_proctypeoption,pno_paranames,pno_ownername,pno_noclassmarker,pno_noleadingdollar]);
       { copy all fields }
       str:=str+'begin ';
       for i:=0 to struct.symtable.symlist.count-1 do
@@ -285,6 +285,21 @@ implementation
     end;
 
 
+  procedure implement_empty(pd: tprocdef);
+    var
+      str: ansistring;
+      isclassmethod: boolean;
+    begin
+      isclassmethod:=
+        (po_classmethod in pd.procoptions) and
+        not(pd.proctypeoption in [potype_constructor,potype_destructor]);
+      str:=pd.customprocname([pno_proctypeoption,pno_paranames,pno_ownername,pno_noclassmarker,pno_noleadingdollar]);
+      str:=str+'begin end;';
+      str_parse_method_impl(str,isclassmethod);
+    end;
+
+
+
   procedure add_synthetic_method_implementations_for_struct(struct: tabstractrecorddef);
     var
       i   : longint;
@@ -306,6 +321,8 @@ implementation
               implement_jvm_clone(pd);
             tsk_record_deepcopy:
               implement_record_deepcopy(pd);
+            tsk_empty:
+              implement_empty(pd);
             else
               internalerror(2011032801);
           end;

+ 13 - 12
compiler/symdef.pas

@@ -418,7 +418,7 @@ interface
        { tabstractprocdef }
 
        tprocnameoption = (pno_showhidden, pno_proctypeoption, pno_paranames,
-         pno_ownername, pno_noclassmarker);
+         pno_ownername, pno_noclassmarker, pno_noleadingdollar);
        tprocnameoptions = set of tprocnameoption;
 
        tabstractprocdef = class(tstoreddef)
@@ -3869,7 +3869,7 @@ implementation
 
     function tprocdef.customprocname(pno: tprocnameoptions):ansistring;
       var
-        s : ansistring;
+        s, rn : ansistring;
         t : ttoken;
       begin
 {$ifdef EXTDEBUG}
@@ -3892,18 +3892,15 @@ implementation
         else
           begin
             if (po_classmethod in procoptions) and
-               not(pno_noclassmarker in pno) and
-               not (proctypeoption in [potype_class_constructor,potype_class_destructor]) then
+               not(pno_noclassmarker in pno) then
               s:='class ';
             case proctypeoption of
-              potype_constructor:
+              potype_constructor,
+              potype_class_constructor:
                 s:=s+'constructor ';
+              potype_class_destructor,
               potype_destructor:
-                s:=s+'destructor '+s;
-              potype_class_constructor:
-                s:=s+'class constructor ';
-              potype_class_destructor:
-                s:=s+'class destructor ';
+                s:=s+'destructor ';
               else
                 if (pno_proctypeoption in pno) and
                    assigned(returndef) and
@@ -3915,7 +3912,11 @@ implementation
             if (pno_ownername in pno) and
                (owner.symtabletype in [recordsymtable,objectsymtable]) then
               s:=s+tabstractrecorddef(owner.defowner).RttiName+'.';
-            s:=s+procsym.realname+typename_paras(pno);
+            rn:=procsym.realname;
+            if (pno_noleadingdollar in pno) and
+               (rn[1]='$') then
+              delete(rn,1,1);
+            s:=s+rn+typename_paras(pno);
           end;
         if not(proctypeoption in [potype_constructor,potype_destructor,
              potype_class_constructor,potype_class_destructor]) and
@@ -4383,7 +4384,7 @@ implementation
         tmpresult:=tmpresult+')';
         { And the type of the function result (void in case of a procedure and
           constructor). }
-        if (proctypeoption=potype_constructor) then
+        if (proctypeoption in [potype_constructor,potype_class_constructor]) then
           jvmaddencodedtype(voidtype,false,tmpresult,founderror)
         else if not jvmaddencodedtype(returndef,false,tmpresult,founderror) then
           internalerror(2010122610);