From d456ec2ffe5d95c0560fb631d29935d3e8c6d74b Mon Sep 17 00:00:00 2001
From: Jonas Maebe <jonas@freepascal.org>
Date: Sat, 20 Aug 2011 07:50:41 +0000
Subject: [PATCH]   + support for JVM local variable and parameter debug
 information    o self is encoded as "this" for javac compatibility   +
 ait_jvar (for the above) and ait_jcatch (similar, for future try/catch    
 support) classes   + support for smallset JVM type encoding (as int)

git-svn-id: branches/jvmbackend@18354 -
---
 .gitattributes             |   1 +
 compiler/aasmtai.pas       | 116 ++++++++++++++++++++++++++--
 compiler/agjasmin.pas      |  23 ++++++
 compiler/jvm/cputarg.pas   |   4 +-
 compiler/jvm/dbgjasm.pas   | 150 +++++++++++++++++++++++++++++++++++++
 compiler/jvmdef.pas        |   3 +
 compiler/psystem.pas       |   2 +
 compiler/symsym.pas        |   9 ++-
 compiler/systems.inc       |   2 +-
 compiler/systems/i_jvm.pas |   2 +-
 10 files changed, 301 insertions(+), 11 deletions(-)
 create mode 100644 compiler/jvm/dbgjasm.pas

diff --git a/.gitattributes b/.gitattributes
index 2a53a5cc17..0ae37537f4 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -215,6 +215,7 @@ compiler/jvm/cpunode.pas svneol=native#text/plain
 compiler/jvm/cpupara.pas svneol=native#text/plain
 compiler/jvm/cpupi.pas svneol=native#text/plain
 compiler/jvm/cputarg.pas svneol=native#text/plain
+compiler/jvm/dbgjasm.pas svneol=native#text/plain
 compiler/jvm/hlcgcpu.pas svneol=native#text/plain
 compiler/jvm/itcpujas.pas svneol=native#text/plain
 compiler/jvm/jvmreg.dat svneol=native#text/plain
diff --git a/compiler/aasmtai.pas b/compiler/aasmtai.pas
index f9d8ffec23..df1380be5f 100644
--- a/compiler/aasmtai.pas
+++ b/compiler/aasmtai.pas
@@ -88,7 +88,10 @@ interface
           ait_regalloc,
           ait_tempalloc,
           { used to mark assembler blocks and inlined functions }
-          ait_marker
+          ait_marker,
+          { JVM only }
+          ait_jvar,    { debug information for a local variable }
+          ait_jcatch   { exception catch clause }
           );
 
         taiconst_type = (
@@ -174,7 +177,9 @@ interface
           'cut',
           'regalloc',
           'tempalloc',
-          'marker'
+          'marker',
+          'jvar',
+          'jcatch'
           );
 
     type
@@ -250,7 +255,8 @@ interface
         a new ait type!                                                              }
       SkipInstr = [ait_comment, ait_symbol,ait_section
                    ,ait_stab, ait_function_name, ait_force_line
-                   ,ait_regalloc, ait_tempalloc, ait_symbol_end, ait_directive];
+                   ,ait_regalloc, ait_tempalloc, ait_symbol_end, ait_directive
+                   ,ait_jvar, ait_jcatch];
 
       { ait_* types which do not have line information (and hence which are of type
         tai, otherwise, they are of type tailineinfo }
@@ -258,12 +264,13 @@ interface
                      ait_regalloc,ait_tempalloc,
                      ait_stab,ait_function_name,
                      ait_cutobject,ait_marker,ait_align,ait_section,ait_comment,
-                     ait_const,
+                     ait_const,ait_directive,
 {$ifdef arm}
                      ait_thumb_func,
 {$endif arm}
                      ait_real_32bit,ait_real_64bit,ait_real_80bit,ait_comp_64bit,ait_real_128bit,
-                     ait_symbol
+                     ait_symbol,
+                     ait_jvar,ait_jcatch
                     ];
 
 
@@ -666,6 +673,29 @@ interface
         end;
         tai_align_class = class of tai_align_abstract;
 
+        { JVM variable live range description }
+        tai_jvar = class(tai)
+          stackslot: longint;
+          desc: pshortstring;
+          startlab,stoplab: tasmsymbol;
+
+          constructor Create(_stackslot: longint; const _desc: shortstring; _startlab, _stoplab: TAsmSymbol);
+          constructor ppuload(t:taitype;ppufile:tcompilerppufile);override;
+          procedure ppuwrite(ppufile:tcompilerppufile);override;
+        end;
+        tai_jvar_class = class of tai_jvar;
+
+        { JVM exception catch description }
+        tai_jcatch = class(tai)
+          name: pshortstring;
+          startlab,stoplab,handlerlab: tasmsymbol;
+
+          constructor Create(const _name: shortstring; _startlab, _stoplab, _handlerlab: TAsmSymbol);
+          constructor ppuload(t:taitype;ppufile:tcompilerppufile);override;
+          procedure ppuwrite(ppufile:tcompilerppufile);override;
+        end;
+        tai_jcatch_class = class of tai_jcatch;
+
     var
       { array with all class types for tais }
       aiclass : taiclassarray;
@@ -2454,4 +2484,80 @@ implementation
         ppufile.putbyte(byte(use_op));
       end;
 
+
+{****************************************************************************
+                              tai_jvar
+ ****************************************************************************}
+
+    constructor tai_jvar.Create(_stackslot: longint; const _desc: shortstring; _startlab, _stoplab: TAsmSymbol);
+      begin
+        Inherited create;
+        typ:=ait_jvar;
+        stackslot:=_stackslot;
+        desc:=stringdup(_desc);
+        startlab:=_startlab;
+        stoplab:=_stoplab;
+      end;
+
+
+    constructor tai_jvar.ppuload(t: taitype; ppufile: tcompilerppufile);
+      begin
+        inherited ppuload(t, ppufile);
+        stackslot:=ppufile.getlongint;
+        desc:=stringdup(ppufile.getstring);
+        startlab:=ppufile.getasmsymbol;
+        stoplab:=ppufile.getasmsymbol;
+      end;
+
+
+    procedure tai_jvar.ppuwrite(ppufile: tcompilerppufile);
+      begin
+        inherited ppuwrite(ppufile);
+        ppufile.putlongint(stackslot);
+        ppufile.putstring(desc^);
+        ppufile.putasmsymbol(startlab);
+        ppufile.putasmsymbol(stoplab);
+      end;
+
+
+    {****************************************************************************
+                                  tai_jvar
+     ****************************************************************************}
+
+    constructor tai_jcatch.Create(const _name: shortstring; _startlab, _stoplab, _handlerlab: TAsmSymbol);
+      begin
+        Inherited create;
+        typ:=ait_jcatch;
+        name:=stringdup(_name);
+        startlab:=_startlab;
+        startlab.increfs;
+        stoplab:=_stoplab;
+        stoplab.increfs;
+        handlerlab:=_handlerlab;
+        handlerlab.increfs;
+      end;
+
+
+    constructor tai_jcatch.ppuload(t: taitype; ppufile: tcompilerppufile);
+      begin
+        inherited ppuload(t, ppufile);
+        name:=stringdup(ppufile.getstring);
+        startlab:=ppufile.getasmsymbol;
+        startlab.increfs;
+        stoplab:=ppufile.getasmsymbol;
+        stoplab.increfs;
+        handlerlab:=ppufile.getasmsymbol;
+        handlerlab.increfs;
+      end;
+
+
+    procedure tai_jcatch.ppuwrite(ppufile: tcompilerppufile);
+      begin
+        inherited ppuwrite(ppufile);
+        ppufile.putstring(name^);
+        ppufile.putasmsymbol(startlab);
+        ppufile.putasmsymbol(stoplab);
+        ppufile.putasmsymbol(handlerlab);
+      end;
+
 end.
diff --git a/compiler/agjasmin.pas b/compiler/agjasmin.pas
index a22315972e..e4384b8191 100644
--- a/compiler/agjasmin.pas
+++ b/compiler/agjasmin.pas
@@ -381,6 +381,29 @@ implementation
                  AsmLn;
                end;
 
+             ait_jvar:
+               begin
+                 AsmWrite('.var ');
+                 AsmWrite(tostr(tai_jvar(hp).stackslot));
+                 AsmWrite(' is ');
+                 AsmWrite(tai_jvar(hp).desc^);
+                 AsmWrite(' from ');
+                 AsmWrite(tai_jvar(hp).startlab.name);
+                 AsmWrite(' to ');
+                 AsmWriteLn(tai_jvar(hp).stoplab.name);
+               end;
+
+             ait_jcatch:
+               begin
+                 AsmWrite('.catch ');
+                 AsmWrite(tai_jcatch(hp).name^);
+                 AsmWrite(' from ');
+                 AsmWrite(tai_jcatch(hp).startlab.name);
+                 AsmWrite(' to ');
+                 AsmWrite(tai_jcatch(hp).stoplab.name);
+                 AsmWrite(' using ');
+                 AsmWriteLn(tai_jcatch(hp).handlerlab.name);
+               end;
              else
                internalerror(2010122707);
            end;
diff --git a/compiler/jvm/cputarg.pas b/compiler/jvm/cputarg.pas
index 6ec20996c4..2cb543c6d4 100644
--- a/compiler/jvm/cputarg.pas
+++ b/compiler/jvm/cputarg.pas
@@ -57,9 +57,7 @@ implementation
              Debuginfo
 **************************************}
 
-  {$ifdef Dbgjvm}
-      ,dbgjvm
-  {$endif Dbgjvm}
+      ,dbgjasm
 
       ;
 
diff --git a/compiler/jvm/dbgjasm.pas b/compiler/jvm/dbgjasm.pas
new file mode 100644
index 0000000000..5156ce28f5
--- /dev/null
+++ b/compiler/jvm/dbgjasm.pas
@@ -0,0 +1,150 @@
+{
+    Copyright (c) 2003-2006 by Peter Vreman, Florian Klaempfl, and Jonas Maebe
+
+    This units contains support for Jasmin debug info generation
+
+    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 dbgjasm;
+
+{$i fpcdefs.inc}
+
+interface
+
+    uses
+      cclasses,globtype,
+      aasmbase,aasmtai,aasmdata,
+      symbase,symconst,symtype,symdef,symsym,
+      finput,
+      DbgBase;
+
+    type
+      { TDebugInfoJasmin }
+
+      TDebugInfoJasmin=class(TDebugInfo)
+      protected
+        fcurrprocstart,
+        fcurrprocend: tasmsymbol;
+
+        procedure appendsym_localsym(list: TAsmList; sym: tabstractnormalvarsym);
+
+        procedure appendsym_paravar(list:TAsmList;sym:tparavarsym);override;
+        procedure appendsym_localvar(list:TAsmList;sym:tlocalvarsym);override;
+        procedure beforeappenddef(list:TAsmList;def:tdef);override;
+        procedure appendprocdef(list:TAsmList;def:tprocdef);override;
+      public
+        procedure inserttypeinfo;override;
+        procedure insertlineinfo(list:TAsmList);override;
+      end;
+
+implementation
+
+    uses
+      sysutils,cutils,cfileutl,constexp,
+      version,globals,verbose,systems,
+      cpubase,cpuinfo,cgbase,paramgr,
+      fmodule,
+      defutil,symtable,ppu
+      ;
+
+{****************************************************************************
+                              TDebugInfoJasmin
+****************************************************************************}
+
+  procedure TDebugInfoJasmin.appendsym_localsym(list: TAsmList; sym: tabstractnormalvarsym);
+    var
+      jvar: tai_jvar;
+      proc: tprocdef;
+    begin
+      if tdef(sym.owner.defowner).typ<>procdef then
+        exit;
+      if not(sym.localloc.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
+        exit;
+      proc:=tprocdef(sym.owner.defowner);
+      jvar:=tai_jvar.create(sym.localloc.reference.offset,sym.jvmmangledbasename,fcurrprocstart,fcurrprocend);
+      proc.exprasmlist.InsertAfter(jvar,proc.procstarttai);
+    end;
+
+
+  procedure TDebugInfoJasmin.appendsym_paravar(list: TAsmList; sym: tparavarsym);
+    begin
+      appendsym_localsym(list,sym);
+    end;
+
+
+  procedure TDebugInfoJasmin.appendsym_localvar(list: TAsmList; sym: tlocalvarsym);
+    begin
+      appendsym_localsym(list,sym);
+    end;
+
+
+  procedure TDebugInfoJasmin.beforeappenddef(list: TAsmList; def: tdef);
+    begin
+    end;
+
+
+  procedure TDebugInfoJasmin.appendprocdef(list: TAsmList; def: tprocdef);
+    var
+      procstartlabel,
+      procendlabel    : tasmlabel;
+    begin
+      { insert debug information for local variables and parameters, but only
+        for routines implemented in the Pascal code }
+      if not assigned(def.procstarttai) then
+        exit;
+
+      current_asmdata.getlabel(procstartlabel,alt_dbgtype);
+      current_asmdata.getlabel(procendlabel,alt_dbgtype);
+      def.exprasmlist.insertafter(tai_label.create(procstartlabel),def.procstarttai);
+      def.exprasmlist.insertbefore(tai_label.create(procendlabel),def.procendtai);
+
+      fcurrprocstart:=procstartlabel;
+      fcurrprocend:=procendlabel;
+
+      write_symtable_parasyms(list,def.paras);
+      write_symtable_syms(list,def.localst);
+    end;
+
+
+  procedure TDebugInfoJasmin.inserttypeinfo;
+    begin
+      { write all procedures and methods }
+      if assigned(current_module.globalsymtable) then
+        write_symtable_procdefs(nil,current_module.globalsymtable);
+      if assigned(current_module.localsymtable) then
+        write_symtable_procdefs(nil,current_module.localsymtable);
+    end;
+
+  procedure TDebugInfoJasmin.insertlineinfo(list: TAsmList);
+    begin
+    end;
+
+
+{****************************************************************************
+****************************************************************************}
+    const
+      dbg_jasmin_info : tdbginfo =
+         (
+           id     : dbg_jasmin;
+           idtxt  : 'JASMIN';
+         );
+
+
+initialization
+  RegisterDebugInfo(dbg_jasmin_info,TDebugInfoJasmin);
+
+end.
diff --git a/compiler/jvmdef.pas b/compiler/jvmdef.pas
index cec6b267ed..29440b72fd 100644
--- a/compiler/jvmdef.pas
+++ b/compiler/jvmdef.pas
@@ -148,6 +148,9 @@ implementation
             end;
           setdef :
             begin
+              if is_smallset(def) then
+                encodedstr:=encodedstr+'I'
+              else
               { will be hanlded via wrapping later, although wrapping may
                 happen at higher level }
               result:=false;
diff --git a/compiler/psystem.pas b/compiler/psystem.pas
index 8eafbd9ef8..d76ae3df70 100644
--- a/compiler/psystem.pas
+++ b/compiler/psystem.pas
@@ -625,6 +625,8 @@ implementation
         aiclass[ait_regalloc]:=tai_regalloc;
         aiclass[ait_tempalloc]:=tai_tempalloc;
         aiclass[ait_marker]:=tai_marker;
+        aiclass[ait_jvar]:=tai_jvar;
+        aiclass[ait_jcatch]:=tai_jcatch;
       end;
 
 end.
diff --git a/compiler/symsym.pas b/compiler/symsym.pas
index b5ee8c0262..bb8a7e9520 100644
--- a/compiler/symsym.pas
+++ b/compiler/symsym.pas
@@ -1154,7 +1154,14 @@ implementation
       begin
         if not jvmtryencodetype(vardef,result,founderror) then
           internalerror(2011011203);
-        result:=realname+' '+result;
+        if (typ=paravarsym) and
+           (vo_is_self in tparavarsym(self).varoptions) then
+          result:='this ' +result
+        else if (typ in [paravarsym,localvarsym]) and
+                ([vo_is_funcret,vo_is_result] * tabstractnormalvarsym(self).varoptions <> []) then
+          result:='result '+result
+        else
+          result:=realname+' '+result;
       end;
 
 
diff --git a/compiler/systems.inc b/compiler/systems.inc
index c7b6ec0052..990ad234a2 100644
--- a/compiler/systems.inc
+++ b/compiler/systems.inc
@@ -203,7 +203,7 @@
             ,res_single_file);
 
        tdbg = (dbg_none
-            ,dbg_stabs,dbg_dwarf2,dbg_dwarf3,dbg_dwarf4
+            ,dbg_stabs,dbg_dwarf2,dbg_dwarf3,dbg_dwarf4,dbg_jasmin
        );
 
        tscripttype = (script_none
diff --git a/compiler/systems/i_jvm.pas b/compiler/systems/i_jvm.pas
index 502f5bd255..b66020cb5f 100644
--- a/compiler/systems/i_jvm.pas
+++ b/compiler/systems/i_jvm.pas
@@ -74,7 +74,7 @@ unit i_jvm;
             linkextern   : nil;
             ar           : ar_none;
             res          : res_none;
-            dbg          : dbg_none;
+            dbg          : dbg_jasmin;
             script       : script_unix;
             endian       : endian_big;
             alignment    :