Преглед на файлове

+ support for formal var/out parameters on the JVM target:
o primitive types are first boxed
o the parameter is passed inside an array of one class instance
o changing the parameter inside the routine (by assigning a value to it
like in Delphi.NET and different from regular Pascal code) will replace
this class instance (again boxing the value if required)
o on return, the class instance is extracted, unboxed if required, and
assigned back to the original location
o formal const parameters are handled without the extra array indirection,
since they cannot be changed

TODO: while writing tjvmcallparanode.handleformalcopyoutpara() I forgot that
calling getcopy on ttemprefnodes whose ttempcreatenode hasn't been copied
yet works fine, so that code is more complex than needed. Still have to
fix.

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

Jonas Maebe преди 14 години
родител
ревизия
d6966e545b
променени са 13 файла, в които са добавени 574 реда и са изтрити 58 реда
  1. 1 0
      compiler/compinnr.inc
  2. 5 2
      compiler/jvm/cpupara.pas
  3. 235 16
      compiler/jvm/njvmcal.pas
  4. 32 3
      compiler/jvm/njvmcnv.pas
  5. 28 23
      compiler/jvm/njvminl.pas
  6. 31 2
      compiler/jvm/njvmld.pas
  7. 123 0
      compiler/jvmdef.pas
  8. 63 10
      compiler/ncal.pas
  9. 22 0
      compiler/ncgcal.pas
  10. 3 0
      compiler/ncgld.pas
  11. 27 1
      compiler/ninl.pas
  12. 2 1
      compiler/symdef.pas
  13. 2 0
      rtl/inc/innr.inc

+ 1 - 0
compiler/compinnr.inc

@@ -84,6 +84,7 @@ const
    in_bsf_x             = 74;
    in_bsf_x             = 74;
    in_bsr_x             = 75;
    in_bsr_x             = 75;
    in_box_x             = 76; { managed platforms: wrap in class instance }
    in_box_x             = 76; { managed platforms: wrap in class instance }
+   in_unbox_x_y         = 77; { manage platforms: extract from class instance }
 
 
 { Internal constant functions }
 { Internal constant functions }
    in_const_sqr        = 100;
    in_const_sqr        = 100;

+ 5 - 2
compiler/jvm/cpupara.pas

@@ -83,7 +83,10 @@ implementation
     { true if a parameter is too large to copy and only the address is pushed }
     { true if a parameter is too large to copy and only the address is pushed }
     function TJVMParaManager.push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
     function TJVMParaManager.push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
       begin
       begin
-        result:=jvmimplicitpointertype(def);
+        result:=
+          jvmimplicitpointertype(def) or
+          ((def.typ=formaldef) and
+           not(varspez in [vs_var,vs_out]));
       end;
       end;
 
 
 
 
@@ -92,7 +95,7 @@ implementation
         { in principle also for vs_constref, but since we can't have real
         { in principle also for vs_constref, but since we can't have real
           references, that won't make a difference }
           references, that won't make a difference }
         result:=
         result:=
-          (varspez in [vs_var,vs_out]) and
+          (varspez in [vs_var,vs_out,vs_constref]) and
           not jvmimplicitpointertype(def);
           not jvmimplicitpointertype(def);
       end;
       end;
 
 

+ 235 - 16
compiler/jvm/njvmcal.pas

@@ -31,13 +31,14 @@ interface
       ncgcal;
       ncgcal;
 
 
     type
     type
-
        tjvmcallparanode = class(tcgcallparanode)
        tjvmcallparanode = class(tcgcallparanode)
         protected
         protected
          outcopybasereg: tregister;
          outcopybasereg: tregister;
          procedure push_formal_para; override;
          procedure push_formal_para; override;
          procedure push_copyout_para; override;
          procedure push_copyout_para; override;
 
 
+         procedure handleformalcopyoutpara(orgparadef: tdef); override;
+
          procedure load_arrayref_para(useparadef: tdef);
          procedure load_arrayref_para(useparadef: tdef);
        end;
        end;
 
 
@@ -55,12 +56,12 @@ interface
 implementation
 implementation
 
 
     uses
     uses
-      verbose,globtype,
+      verbose,globtype,constexp,
       symconst,defutil,ncal,
       symconst,defutil,ncal,
       cgutils,tgobj,procinfo,
       cgutils,tgobj,procinfo,
       cpubase,aasmdata,aasmcpu,
       cpubase,aasmdata,aasmcpu,
       hlcgobj,hlcgcpu,
       hlcgobj,hlcgcpu,
-      node,
+      pass_1,node,nutils,nbas,ncnv,ncon,ninl,nld,nmem,
       jvmdef;
       jvmdef;
 
 
 {*****************************************************************************
 {*****************************************************************************
@@ -95,14 +96,22 @@ implementation
 
 
 
 
     procedure tjvmcallparanode.push_formal_para;
     procedure tjvmcallparanode.push_formal_para;
-      var
-        primitivetype: boolean;
       begin
       begin
-        { create an array with one element of JLObject }
-        thlcgjvm(hlcg).a_load_const_stack(current_asmdata.CurrAsmList,s32inttype,1,R_INTREGISTER);
-        { left is either an object-derived type, or has been boxed into one }
-        current_asmdata.CurrAsmList.concat(taicpu.op_sym(a_anewarray,current_asmdata.RefAsmSymbol(jvmarrtype(java_jlobject,primitivetype))));
-        load_arrayref_para(java_jlobject);
+        { primitive values are boxed, so in all cases this is a pointer to
+          something and since it cannot be changed (or is not supposed to be
+          changed anyway), we don't have to create a temporary array to hold a
+          pointer to this value and can just pass the pointer to this value
+          directly.
+
+          In case the value can be changed (formal var/out), then we have
+          already created a temporary array of one element that holds the boxed
+          (or in case of a non-primitive type: original) value. The reason is
+          that copying it back out may be a complex operation which we don't
+          want to handle at the code generator level.
+
+          -> always push a value parameter (which is either an array of one
+          element, or an object) }
+        push_value_para
       end;
       end;
 
 
 
 
@@ -125,6 +134,220 @@ implementation
       end;
       end;
 
 
 
 
+    procedure getparabasenodes(p: tnode; out basenode: tnode; out parent: tunarynode);
+      begin
+        parent:=nil;
+        while assigned(p) do
+          begin
+            case p.nodetype of
+              inlinen:
+                begin
+                  if tinlinenode(p).inlinenumber=in_box_x then
+                    begin
+                      parent:=tunarynode(p);
+                      p:=parent.left;
+                    end
+                  else
+                    break;
+                end;
+              subscriptn,
+              vecn:
+                begin
+                  break;
+                end;
+              typeconvn:
+                begin
+                  parent:=tunarynode(p);
+                  { skip typeconversions that don't change the node type }
+                  p:=p.actualtargetnode;
+                end;
+              derefn:
+                begin
+                  parent:=tunarynode(p);
+                  p:=tunarynode(p).left;
+                end
+              else
+                break;
+            end;
+          end;
+        basenode:=p;
+      end;
+
+
+    function replacewithtemps(var orgnode, copiednode: tnode): ttempcreatenode;
+      begin
+        result:=ctempcreatenode.create_value(
+          orgnode.resultdef,orgnode.resultdef.size,
+          tt_persistent,true,orgnode);
+        { this right is reused while constructing the temp }
+        orgnode:=ctemprefnode.create(result);
+        typecheckpass(orgnode);
+        { this right is not reused }
+        copiednode.free;
+        copiednode:=ctemprefnode.create(result);
+        typecheckpass(copiednode);
+      end;
+
+
+    procedure tjvmcallparanode.handleformalcopyoutpara(orgparadef: tdef);
+      var
+        paravaltemp,
+        arraytemp,
+        indextemp: ttempcreatenode;
+        arrdef: tarraydef;
+        initstat,
+        finistat: tstatementnode;
+        leftcopy: tnode;
+        realpara, copyrealpara, tempn, assignmenttempn: tnode;
+        realparaparent,copyrealparaparent: tunarynode;
+        derefbasedef: tdef;
+        deref: boolean;
+      begin
+        fparainit:=internalstatements(initstat);
+        { In general, we now create a temp array of one element, assign left
+          (or its address in case of a jvmimplicitpointertype) to it, replace
+          the parameter with this array, and add code to paracopyback that
+          extracts the value from the array again and assigns it to the original
+          variable.
+
+          Complications
+            a) in case the parameter involves calling a function, it must not
+               be called twice, so take the address of the location (since this
+               is a var/out parameter, taking the address is conceptually
+               always possible)
+            b) in case this is an element of a string, we can't take the address
+               in JVM code, so we then have to take the address of the string
+               (which conceptually may not be possible since it can be a
+                property or so) and store the index value into a temp, and
+                reconstruct the vecn in te paracopyback code from this data
+                (it's similar for normal var/out parameters)
+        }
+
+        { we'll replace a bunch of stuff in the parameter with temprefnodes,
+          but we can't take a getcopy for the assignment afterwards of this
+          result since a getcopy will always assume that we are copying the
+          init/deletenodes too and that the temprefnodes have to point to the
+          new temps -> get a copy of the parameter in advance, and then replace
+          the nodes in the copy with temps just like in the original para }
+        leftcopy:=left.getcopy;
+        { get the real parameter source in case of type conversions. This is
+          the same logic as for set_unique(). The parent is where we have to
+          replace realpara with the temp that replaces it. }
+        getparabasenodes(left,realpara,realparaparent);
+        getparabasenodes(leftcopy,copyrealpara,copyrealparaparent);
+        { assign either the parameter's address (in case it's an implicit
+          pointer type) or the parameter itself (in case it's a primitive or
+          actual pointer/object type) to the temp }
+        deref:=false;
+        if jvmimplicitpointertype(realpara.resultdef) then
+          begin
+            derefbasedef:=realpara.resultdef;
+            realpara:=caddrnode.create_internal(realpara);
+            include(realpara.flags,nf_typedaddr);
+            typecheckpass(realpara);
+            { we'll have to reference the parameter again in the expression }
+            deref:=true;
+          end;
+        paravaltemp:=nil;
+        { make sure we don't replace simple loadnodes with a temp, because
+          in case of passing e.g. stringvar[3] to a formal var/out parameter,
+          we add "stringvar[3]:=<result>" afterwards. Because Java strings are
+          immutable, this is translated into "stringvar:=stringvar.setChar(3,
+          <result>)". So if we replace stringvar with a temp, this will change
+          the temp rather than stringvar. }
+        indextemp:=nil;
+        if (realpara.nodetype=vecn) then
+          begin
+            if node_complexity(tvecnode(realpara).left)>1 then
+              begin
+                paravaltemp:=replacewithtemps(tvecnode(realpara).left,
+                  tvecnode(copyrealpara).left);
+                addstatement(initstat,paravaltemp);
+              end;
+            { in case of an array index, also replace the index with a temp if
+              necessary/useful }
+            if (node_complexity(tvecnode(realpara).right)>1) then
+              begin
+                indextemp:=replacewithtemps(tvecnode(realpara).right,
+                  tvecnode(copyrealpara).right);
+                addstatement(initstat,indextemp);
+              end;
+          end
+        else
+          begin
+            paravaltemp:=ctempcreatenode.create_value(
+              realpara.resultdef,java_jlobject.size,tt_persistent,true,realpara);
+            addstatement(initstat,paravaltemp);
+            { replace the parameter in the parameter expression with this temp }
+            tempn:=ctemprefnode.create(paravaltemp);
+            assignmenttempn:=ctemprefnode.create(paravaltemp);
+            { will be spliced in the middle of a tree that has already been
+              typecheckpassed }
+            typecheckpass(tempn);
+            typecheckpass(assignmenttempn);
+            if assigned(realparaparent) then
+              begin
+                { left has been reused in paravaltemp (it's realpara itself) ->
+                  don't free }
+                realparaparent.left:=tempn;
+                { the left's copy is not reused }
+                copyrealparaparent.left.free;
+                copyrealparaparent.left:=assignmenttempn;
+              end
+            else
+              begin
+                { left has been reused in paravaltemp (it's realpara itself) ->
+                  don't free }
+                left:=tempn;
+                { leftcopy can remain the same }
+                assignmenttempn.free;
+              end;
+          end;
+        { create the array temp that and assign the parameter value (typecasted
+          to java_jlobject) }
+        arrdef:=tarraydef.create(0,1,s32inttype);
+        arrdef.elementdef:=java_jlobject;
+        arraytemp:=ctempcreatenode.create(arrdef,java_jlobject.size,
+          tt_persistent,true);
+        addstatement(initstat,arraytemp);
+        { wrap the primitive type in an object container
+          if required }
+        if (left.resultdef.typ in [orddef,floatdef]) then
+          begin
+            left:=cinlinenode.create(in_box_x,false,ccallparanode.create(left,nil));
+            typecheckpass(left);
+          end;
+        addstatement(initstat,cassignmentnode.create(
+          cvecnode.create(ctemprefnode.create(arraytemp),genintconstnode(0)),
+          ctypeconvnode.create_explicit(left,java_jlobject)));
+        { replace the parameter with the array }
+        left:=ctemprefnode.create(arraytemp);
+        { add the extraction of the parameter and assign it back to the
+          original location }
+        fparacopyback:=internalstatements(finistat);
+        tempn:=cvecnode.create(ctemprefnode.create(arraytemp),genintconstnode(0));
+        { unbox if necessary }
+        if orgparadef.typ in [orddef,floatdef] then
+          tempn:=cinlinenode.create(in_unbox_x_y,false,ccallparanode.create(
+            ctypenode.create(orgparadef),ccallparanode.create(tempn,nil)));
+        if (deref) then
+          begin
+            inserttypeconv_explicit(tempn,getpointerdef(derefbasedef));
+            tempn:=cderefnode.create(tempn);
+          end;
+        addstatement(finistat,cassignmentnode.create(leftcopy,
+          ctypeconvnode.create_explicit(tempn,orgparadef)));
+        if assigned(indextemp) then
+          addstatement(finistat,ctempdeletenode.create(indextemp));
+        addstatement(finistat,ctempdeletenode.create(arraytemp));
+        if assigned(paravaltemp) then
+          addstatement(finistat,ctempdeletenode.create(paravaltemp));
+        typecheckpass(fparainit);
+        typecheckpass(left);
+        typecheckpass(fparacopyback);
+      end;
+
+
 {*****************************************************************************
 {*****************************************************************************
                              TJVMCALLNODE
                              TJVMCALLNODE
 *****************************************************************************}
 *****************************************************************************}
@@ -246,12 +469,8 @@ implementation
                       end
                       end
                     else
                     else
                       begin
                       begin
-{$ifndef nounsupported}
-                        { to do: extract value from boxed parameter or load
-                          value back }
-{$else}
-                        internalerror(2011051901);
-{$endif}
+                        { extracting values from foramldef parameters is done
+                          by the generic code }
                       end;
                       end;
                   end;
                   end;
               end;
               end;

+ 32 - 3
compiler/jvm/njvmcnv.pas

@@ -93,7 +93,7 @@ implementation
       symconst,symdef,symsym,symtable,aasmbase,aasmdata,
       symconst,symdef,symsym,symtable,aasmbase,aasmdata,
       defutil,defcmp,jvmdef,
       defutil,defcmp,jvmdef,
       cgbase,cgutils,pass_1,pass_2,
       cgbase,cgutils,pass_1,pass_2,
-      nbas,ncon,ncal,nld,nmem,procinfo,
+      nbas,ncon,ncal,ninl,nld,nmem,procinfo,
       nutils,
       nutils,
       cpubase,aasmcpu,
       cpubase,aasmcpu,
       tgobj,hlcgobj,hlcgcpu;
       tgobj,hlcgobj,hlcgcpu;
@@ -912,7 +912,35 @@ implementation
           side }
           side }
         if (left.resultdef.typ=formaldef) and
         if (left.resultdef.typ=formaldef) and
            not assignment_side then
            not assignment_side then
-          exit;
+          begin
+            if resultdef.typ in [orddef,floatdef] then
+              begin
+                if not check_only then
+                  begin
+                    resnode:=cinlinenode.create(in_unbox_x_y,false,
+                      ccallparanode.create(ctypenode.create(resultdef),
+                        ccallparanode.create(left,nil)));
+                    left:=nil;
+                  end;
+                result:=true;
+                exit;
+              end
+            else if jvmimplicitpointertype(resultdef) then
+              begin
+                { typecast formaldef to pointer to the type, then deref, so that
+                  a proper checkcast is inserted }
+                if not check_only then
+                  begin
+                    resnode:=ctypeconvnode.create_explicit(left,getpointerdef(resultdef));
+                    resnode:=cderefnode.create(resnode);
+                    left:=nil;
+                  end;
+                result:=true;
+                exit;
+              end;
+            result:=false;
+            exit;
+          end;
 
 
         { don't allow conversions between different classes of primitive types,
         { don't allow conversions between different classes of primitive types,
           except for a few special cases }
           except for a few special cases }
@@ -1195,7 +1223,8 @@ implementation
       if (checkdef.typ=pointerdef) and
       if (checkdef.typ=pointerdef) and
          jvmimplicitpointertype(tpointerdef(checkdef).pointeddef) then
          jvmimplicitpointertype(tpointerdef(checkdef).pointeddef) then
         checkdef:=tpointerdef(checkdef).pointeddef;
         checkdef:=tpointerdef(checkdef).pointeddef;
-      if checkdef=voidpointertype then
+      if (checkdef=voidpointertype) or
+         (checkdef.typ=formaldef) then
         checkdef:=java_jlobject
         checkdef:=java_jlobject
       else if checkdef.typ=enumdef then
       else if checkdef.typ=enumdef then
         checkdef:=tenumdef(checkdef).classdef
         checkdef:=tenumdef(checkdef).classdef

+ 28 - 23
compiler/jvm/njvminl.pas

@@ -38,8 +38,8 @@ interface
 
 
           function first_copy: tnode; override;
           function first_copy: tnode; override;
 
 
-          function handle_box: tnode; override;
           function first_box: tnode; override;
           function first_box: tnode; override;
+          function first_unbox: tnode; override;
 
 
           function first_setlength_array: tnode;
           function first_setlength_array: tnode;
           function first_setlength_string: tnode;
           function first_setlength_string: tnode;
@@ -76,7 +76,6 @@ interface
 *)
 *)
           procedure second_new; override;
           procedure second_new; override;
           procedure second_setlength; override;
           procedure second_setlength; override;
-          procedure second_box; override;
        protected
        protected
           procedure load_fpu_location;
           procedure load_fpu_location;
        end;
        end;
@@ -238,20 +237,38 @@ implementation
       end;
       end;
 
 
 
 
-    function tjvminlinenode.handle_box: tnode;
+    function tjvminlinenode.first_box: tnode;
+      var
+        boxdef,
+        boxparadef: tdef;
       begin
       begin
-        Result:=inherited;
-        resultdef:=java_jlobject;
+        { get class wrapper type }
+        jvmgetboxtype(left.resultdef,boxdef,boxparadef);
+        { created wrapped instance }
+        inserttypeconv_explicit(tcallparanode(left).left,boxparadef);
+        result:=ccallnode.createinternmethod(
+          cloadvmtaddrnode.create(ctypenode.create(tobjectdef(boxdef))),'CREATE',left);
+        { reused }
+        left:=nil;
       end;
       end;
 
 
 
 
-    function tjvminlinenode.first_box: tnode;
+    function tjvminlinenode.first_unbox: tnode;
+      var
+        val: tnode;
+        boxdef,
+        boxparadef: tdef;
       begin
       begin
-        result:=nil;
-        expectloc:=LOC_REGISTER;
-{$ifdef nounsupported}
-        internalerror(2011042603);
-{$endif}
+        jvmgetboxtype(resultdef,boxdef,boxparadef);
+        val:=tcallparanode(tcallparanode(left).right).left;
+        tcallparanode(tcallparanode(left).right).left:=nil;
+        { typecast to the boxing type }
+        val:=ctypeconvnode.create_explicit(val,boxdef);
+        { call the unboxing method }
+        val:=ccallnode.createinternmethod(val,jvmgetunboxmethod(resultdef),nil);
+        { add type conversion for shortint -> byte etc }
+        inserttypeconv_explicit(val,resultdef);
+        result:=val;
       end;
       end;
 
 
 
 
@@ -796,18 +813,6 @@ implementation
         thlcgjvm(hlcg).a_load_reg_loc(current_asmdata.CurrAsmList,target.resultdef,target.resultdef,tmpreg,target.location);
         thlcgjvm(hlcg).a_load_reg_loc(current_asmdata.CurrAsmList,target.resultdef,target.resultdef,tmpreg,target.location);
       end;
       end;
 
 
-    procedure tjvminlinenode.second_box;
-      begin
-{$ifndef nounsupported}
-        secondpass(tcallparanode(left).left);
-        location_reset(location,LOC_REGISTER,OS_ADDR);
-        location.register:=hlcg.getaddressregister(current_asmdata.CurrAsmList,java_jlobject);
-        hlcg.a_load_const_reg(current_asmdata.CurrAsmList,java_jlobject,0,location.register);
-{$else}
-        internalerror(2011042606);
-{$endif}
-      end;
-
 
 
 begin
 begin
    cinlinenode:=tjvminlinenode;
    cinlinenode:=tjvminlinenode;

+ 31 - 2
compiler/jvm/njvmld.pas

@@ -55,15 +55,19 @@ implementation
 uses
 uses
   verbose,
   verbose,
   aasmdata,
   aasmdata,
-  nbas,nld,ncal,nmem,ncnv,
+  nbas,nld,ncal,ninl,nmem,ncnv,
   symconst,symsym,symdef,symtable,defutil,jvmdef,
   symconst,symsym,symdef,symtable,defutil,jvmdef,
   paramgr,
   paramgr,
+  pass_1,
   cgbase,hlcgobj;
   cgbase,hlcgobj;
 
 
 { tjvmassignmentnode }
 { tjvmassignmentnode }
 
 
 function tjvmassignmentnode.pass_1: tnode;
 function tjvmassignmentnode.pass_1: tnode;
   var
   var
+    block: tblocknode;
+    tempn: ttempcreatenode;
+    stat: tstatementnode;
     target: tnode;
     target: tnode;
     psym: tsym;
     psym: tsym;
   begin
   begin
@@ -115,6 +119,30 @@ function tjvmassignmentnode.pass_1: tnode;
         tvecnode(target).right:=nil;
         tvecnode(target).right:=nil;
         exit;
         exit;
       end
       end
+    else if target.resultdef.typ=formaldef then
+      begin
+        if right.resultdef.typ in [orddef,floatdef] then
+          right:=cinlinenode.create(in_box_x,false,right)
+        else if jvmimplicitpointertype(right.resultdef) then
+          begin
+            { we have to assign the address of a deep copy of the type to the
+              object in the formalpara -> create a temp, assign the value to
+              the temp, then assign the address in the temp to the para }
+            block:=internalstatements(stat);
+            tempn:=ctempcreatenode.create_value(right.resultdef,right.resultdef.size,
+              tt_persistent,false,right);
+            addstatement(stat,tempn);
+            right:=caddrnode.create(ctemprefnode.create(tempn));
+            inserttypeconv_explicit(right,java_jlobject);
+            addstatement(stat,ctempdeletenode.create_normal_temp(tempn));
+            addstatement(stat,ctypeconvnode.create_explicit(
+              caddrnode.create(ctemprefnode.create(tempn)),java_jlobject));
+            right:=block;
+          end;
+        typecheckpass(right);
+        result:=inherited;
+        exit;
+      end
     else
     else
       result:=inherited;
       result:=inherited;
   end;
   end;
@@ -134,7 +162,8 @@ function tjvmloadnode.is_addr_param_load: boolean;
   begin
   begin
     result:=
     result:=
       (inherited and
       (inherited and
-       not jvmimplicitpointertype(tparavarsym(symtableentry).vardef)) or
+       not jvmimplicitpointertype(tparavarsym(symtableentry).vardef) and
+       (tparavarsym(symtableentry).vardef.typ<>formaldef)) or
       is_copyout_addr_param_load;
       is_copyout_addr_param_load;
   end;
   end;
 
 

+ 123 - 0
compiler/jvmdef.pas

@@ -74,6 +74,11 @@ interface
     function jvmmangledbasename(sym: tsym; withsignature: boolean): TSymStr;
     function jvmmangledbasename(sym: tsym; withsignature: boolean): TSymStr;
     function jvmmangledbasename(sym: tsym; const usesymname: TSymStr; withsignature: boolean): TSymStr;
     function jvmmangledbasename(sym: tsym; const usesymname: TSymStr; withsignature: boolean): TSymStr;
 
 
+    { sometimes primitive types have to be boxed/unboxed via class types. This
+      routine returns the appropriate box type for the passed primitive type }
+    procedure jvmgetboxtype(def: tdef; out objdef, paradef: tdef);
+    function jvmgetunboxmethod(def: tdef): string;
+
 implementation
 implementation
 
 
   uses
   uses
@@ -503,6 +508,124 @@ implementation
       end;
       end;
 
 
 
 
+    procedure jvmgetboxtype(def: tdef; out objdef, paradef: tdef);
+      begin
+        case def.typ of
+          orddef:
+            begin
+              case torddef(def).ordtype of
+                pasbool8:
+                  begin
+                    objdef:=tobjectdef(search_system_type('JLBOOLEAN').typedef);
+                    paradef:=pasbool8type;
+                  end;
+                { wrap all integer types into a JLLONG, so that we don't get
+                  errors after returning a byte assigned to a long etc }
+                s8bit,
+                u8bit,
+                uchar,
+                bool8bit,
+                s16bit,
+                u16bit,
+                bool16bit,
+                pasbool16,
+                s32bit,
+                u32bit,
+                bool32bit,
+                pasbool32,
+                s64bit,
+                u64bit,
+                scurrency,
+                bool64bit,
+                pasbool64:
+                  begin
+                    objdef:=tobjectdef(search_system_type('JLLONG').typedef);
+                    paradef:=s64inttype;
+                  end;
+                uwidechar:
+                  begin
+                    objdef:=tobjectdef(search_system_type('JLCHARACTER').typedef);
+                    paradef:=cwidechartype;
+                  end;
+                else
+                  internalerror(2011052101);
+              end;
+            end;
+          floatdef:
+            begin
+              case tfloatdef(def).floattype of
+                s32real:
+                  begin
+                    objdef:=tobjectdef(search_system_type('JLFLOAT').typedef);
+                    paradef:=s32floattype;
+                  end;
+                s64real:
+                  begin
+                    objdef:=tobjectdef(search_system_type('JLDOUBLE').typedef);
+                    paradef:=s64floattype;
+                  end;
+                else
+                  internalerror(2011052102);
+              end;
+            end;
+          else
+            internalerror(2011052103);
+        end;
+      end;
+
+
+    function jvmgetunboxmethod(def: tdef): string;
+      begin
+        case def.typ of
+          orddef:
+            begin
+              case torddef(def).ordtype of
+                pasbool8:
+                  result:='BOOLEANVALUE';
+                s8bit,
+                u8bit,
+                uchar,
+                bool8bit:
+                  result:='BYTEVALUE';
+                s16bit,
+                u16bit,
+                bool16bit,
+                pasbool16:
+                  result:='SHORTVALUE';
+                s32bit,
+                u32bit,
+                bool32bit,
+                pasbool32:
+                  result:='INTVALUE';
+                s64bit,
+                u64bit,
+                scurrency,
+                bool64bit,
+                pasbool64:
+                  result:='LONGVALUE';
+                uwidechar:
+                  result:='CHARVALUE';
+                else
+                  internalerror(2011071702);
+              end;
+            end;
+          floatdef:
+            begin
+              case tfloatdef(def).floattype of
+                s32real:
+                  result:='FLOATVALUE';
+                s64real:
+                  result:='DOUBLEVALUE';
+                else
+                  internalerror(2011071703);
+              end;
+            end;
+          else
+            internalerror(2011071704);
+        end;
+      end;
+
+
     function jvmmangledbasename(sym: tsym; const usesymname: TSymStr; withsignature: boolean): TSymStr;
     function jvmmangledbasename(sym: tsym; const usesymname: TSymStr; withsignature: boolean): TSymStr;
       var
       var
         container: tsymtable;
         container: tsymtable;

+ 63 - 10
compiler/ncal.pas

@@ -178,6 +178,13 @@ interface
        private
        private
           fcontains_stack_tainting_call_cached,
           fcontains_stack_tainting_call_cached,
           ffollowed_by_stack_tainting_call_cached : boolean;
           ffollowed_by_stack_tainting_call_cached : boolean;
+       protected
+          { in case of copy-out parameters: initialization code, and the code to
+            copy back the parameter value after the call (including any required
+            finalization code }
+          fparainit,
+          fparacopyback: tnode;
+          procedure handleformalcopyoutpara(orgparadef: tdef);virtual;abstract;
        public
        public
           callparaflags : tcallparaflags;
           callparaflags : tcallparaflags;
           parasym       : tparavarsym;
           parasym       : tparavarsym;
@@ -187,6 +194,8 @@ interface
           destructor destroy;override;
           destructor destroy;override;
           constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
           constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
           procedure ppuwrite(ppufile:tcompilerppufile);override;
           procedure ppuwrite(ppufile:tcompilerppufile);override;
+          procedure buildderefimpl; override;
+          procedure derefimpl; override;
           function dogetcopy : tnode;override;
           function dogetcopy : tnode;override;
           procedure insertintolist(l : tnodelist);override;
           procedure insertintolist(l : tnodelist);override;
           function pass_typecheck : tnode;override;
           function pass_typecheck : tnode;override;
@@ -221,6 +230,7 @@ interface
             parameter whose evaluation involves a stack tainting parameter
             parameter whose evaluation involves a stack tainting parameter
             (result is only valid after order_parameters has been called) }
             (result is only valid after order_parameters has been called) }
           property followed_by_stack_tainting_call_cached: boolean read ffollowed_by_stack_tainting_call_cached;
           property followed_by_stack_tainting_call_cached: boolean read ffollowed_by_stack_tainting_call_cached;
+          property paracopyback: tnode read fparacopyback;
        end;
        end;
        tcallparanodeclass = class of tcallparanode;
        tcallparanodeclass = class of tcallparanode;
 
 
@@ -573,6 +583,8 @@ implementation
       begin
       begin
         inherited ppuload(t,ppufile);
         inherited ppuload(t,ppufile);
         ppufile.getsmallset(callparaflags);
         ppufile.getsmallset(callparaflags);
+        fparainit:=ppuloadnode(ppufile);
+        fparacopyback:=ppuloadnode(ppufile);
       end;
       end;
 
 
 
 
@@ -580,6 +592,28 @@ implementation
       begin
       begin
         inherited ppuwrite(ppufile);
         inherited ppuwrite(ppufile);
         ppufile.putsmallset(callparaflags);
         ppufile.putsmallset(callparaflags);
+        ppuwritenode(ppufile,fparainit);
+        ppuwritenode(ppufile,fparacopyback);
+      end;
+
+
+    procedure tcallparanode.buildderefimpl;
+      begin
+        inherited buildderefimpl;
+        if assigned(fparainit) then
+          fparainit.buildderefimpl;
+        if assigned(fparacopyback) then
+          fparacopyback.buildderefimpl;
+      end;
+
+
+    procedure tcallparanode.derefimpl;
+      begin
+        inherited derefimpl;
+        if assigned(fparainit) then
+          fparainit.derefimpl;
+        if assigned(fparacopyback) then
+          fparacopyback.derefimpl;
       end;
       end;
 
 
 
 
@@ -587,11 +621,19 @@ implementation
 
 
       var
       var
          n : tcallparanode;
          n : tcallparanode;
-
+         initcopy: tnode;
       begin
       begin
+         initcopy:=nil;
+         { must be done before calling inherited getcopy, because can create
+           tempcreatenodes for values used in left }
+         if assigned(fparainit) then
+           initcopy:=fparainit.getcopy;
          n:=tcallparanode(inherited dogetcopy);
          n:=tcallparanode(inherited dogetcopy);
          n.callparaflags:=callparaflags;
          n.callparaflags:=callparaflags;
          n.parasym:=parasym;
          n.parasym:=parasym;
+         n.fparainit:=initcopy;
+         if assigned(fparacopyback) then
+           n.fparacopyback:=fparacopyback.getcopy;
          result:=n;
          result:=n;
       end;
       end;
 
 
@@ -625,9 +667,13 @@ implementation
           tcallparanode(right).get_paratype;
           tcallparanode(right).get_paratype;
          old_array_constructor:=allow_array_constructor;
          old_array_constructor:=allow_array_constructor;
          allow_array_constructor:=true;
          allow_array_constructor:=true;
+         if assigned(fparainit) then
+          typecheckpass(fparainit);
          typecheckpass(left);
          typecheckpass(left);
          if assigned(third) then
          if assigned(third) then
            typecheckpass(third);
            typecheckpass(third);
+         if assigned(fparacopyback) then
+           typecheckpass(fparacopyback);
          allow_array_constructor:=old_array_constructor;
          allow_array_constructor:=old_array_constructor;
          if codegenerror then
          if codegenerror then
           resultdef:=generrordef
           resultdef:=generrordef
@@ -642,7 +688,11 @@ implementation
           tcallparanode(right).firstcallparan;
           tcallparanode(right).firstcallparan;
         if not assigned(left.resultdef) then
         if not assigned(left.resultdef) then
           get_paratype;
           get_paratype;
+        if assigned(fparainit) then
+          firstpass(fparainit);
         firstpass(left);
         firstpass(left);
+        if assigned(fparacopyback) then
+          firstpass(fparacopyback);
         if assigned(third) then
         if assigned(third) then
           firstpass(third);
           firstpass(third);
         expectloc:=left.expectloc;
         expectloc:=left.expectloc;
@@ -871,21 +921,22 @@ implementation
                          begin
                          begin
                            if not valid_for_formal_var(left,true) then
                            if not valid_for_formal_var(left,true) then
                             CGMessagePos(left.fileinfo,parser_e_illegal_parameter_list)
                             CGMessagePos(left.fileinfo,parser_e_illegal_parameter_list)
-                           else if (target_info.system in systems_managed_vm) and
-                              (left.resultdef.typ in [orddef,floatdef]) then
+                           else if (target_info.system in systems_managed_vm) then
                              begin
                              begin
-                               left:=cinlinenode.create(in_box_x,false,ccallparanode.create(left,nil));
-                               typecheckpass(left);
-{$ifdef nounsupported}
-                               { TODO: unbox afterwards }
-                               internalerror(2011042608);
-{$endif}
+                               olddef:=left.resultdef;
+                               handleformalcopyoutpara(left.resultdef);
                              end;
                              end;
                          end;
                          end;
                        vs_const :
                        vs_const :
                          begin
                          begin
                            if not valid_for_formal_const(left,true) then
                            if not valid_for_formal_const(left,true) then
-                            CGMessagePos(left.fileinfo,parser_e_illegal_parameter_list);
+                            CGMessagePos(left.fileinfo,parser_e_illegal_parameter_list)
+                           else if (target_info.system in systems_managed_vm) and
+                              (left.resultdef.typ in [orddef,floatdef]) then
+                             begin
+                               left:=cinlinenode.create(in_box_x,false,ccallparanode.create(left,nil));
+                               typecheckpass(left);
+                             end;
                          end;
                          end;
                      end;
                      end;
                    end
                    end
@@ -1006,6 +1057,8 @@ implementation
       begin
       begin
         docompare :=
         docompare :=
           inherited docompare(p) and
           inherited docompare(p) and
+          fparainit.isequal(tcallparanode(p).fparainit) and
+          fparacopyback.isequal(tcallparanode(p).fparacopyback) and
           (callparaflags = tcallparanode(p).callparaflags)
           (callparaflags = tcallparanode(p).callparaflags)
           ;
           ;
       end;
       end;

+ 22 - 0
compiler/ncgcal.pas

@@ -52,6 +52,7 @@ interface
 
 
           procedure handle_return_value;
           procedure handle_return_value;
           procedure release_unused_return_value;
           procedure release_unused_return_value;
+          procedure copy_back_paras;
           procedure release_para_temps;
           procedure release_para_temps;
           procedure pushparas;
           procedure pushparas;
           procedure freeparas;
           procedure freeparas;
@@ -181,6 +182,8 @@ implementation
              oflabel:=current_procinfo.CurrFalseLabel;
              oflabel:=current_procinfo.CurrFalseLabel;
              current_asmdata.getjumplabel(current_procinfo.CurrTrueLabel);
              current_asmdata.getjumplabel(current_procinfo.CurrTrueLabel);
              current_asmdata.getjumplabel(current_procinfo.CurrFalseLabel);
              current_asmdata.getjumplabel(current_procinfo.CurrFalseLabel);
+             if assigned(fparainit) then
+               secondpass(fparainit);
              secondpass(left);
              secondpass(left);
 
 
              maybechangeloadnodereg(current_asmdata.CurrAsmList,left,true);
              maybechangeloadnodereg(current_asmdata.CurrAsmList,left,true);
@@ -471,6 +474,22 @@ implementation
       end;
       end;
 
 
 
 
+    procedure tcgcallnode.copy_back_paras;
+      var
+        hp,
+        hp2 : tnode;
+        ppn : tcallparanode;
+      begin
+        ppn:=tcallparanode(left);
+        while assigned(ppn) do
+          begin
+             if assigned(ppn.paracopyback) then
+               secondpass(ppn.paracopyback);
+             ppn:=tcallparanode(ppn.right);
+          end;
+      end;
+
+
     procedure tcgcallnode.release_para_temps;
     procedure tcgcallnode.release_para_temps;
       var
       var
         hp,
         hp,
@@ -966,6 +985,9 @@ implementation
          if assigned(callcleanupblock) then
          if assigned(callcleanupblock) then
            secondpass(tnode(callcleanupblock));
            secondpass(tnode(callcleanupblock));
 
 
+         { copy back copy-out parameters if any }
+         copy_back_paras;
+
          { release temps and finalize unused return values, must be
          { release temps and finalize unused return values, must be
            after the callcleanupblock because that converts temps
            after the callcleanupblock because that converts temps
            from persistent to normal }
            from persistent to normal }

+ 3 - 0
compiler/ncgld.pas

@@ -809,6 +809,9 @@ implementation
 { TODO: HACK: unaligned test, maybe remove all unaligned locations (array of char) from the compiler}
 { TODO: HACK: unaligned test, maybe remove all unaligned locations (array of char) from the compiler}
                             { Use unaligned copy when the offset is not aligned }
                             { Use unaligned copy when the offset is not aligned }
                             len:=left.resultdef.size;
                             len:=left.resultdef.size;
+                            { can be 0 in case of formaldef on JVM target }
+                            if len=0 then
+                              len:=sizeof(pint);
 
 
                             { data smaller than an aint has less alignment requirements }
                             { data smaller than an aint has less alignment requirements }
                             alignmentrequirement:=min(len,sizeof(aint));
                             alignmentrequirement:=min(len,sizeof(aint));

+ 27 - 1
compiler/ninl.pas

@@ -74,8 +74,8 @@ interface
           function first_new: tnode; virtual;
           function first_new: tnode; virtual;
           function first_length: tnode; virtual;
           function first_length: tnode; virtual;
           function first_box: tnode; virtual; abstract;
           function first_box: tnode; virtual; abstract;
+          function first_unbox: tnode; virtual; abstract;
 
 
-          function handle_box: tnode; virtual;
         private
         private
           function handle_str: tnode;
           function handle_str: tnode;
           function handle_reset_rewrite_typed: tnode;
           function handle_reset_rewrite_typed: tnode;
@@ -85,6 +85,8 @@ interface
           function handle_val: tnode;
           function handle_val: tnode;
           function handle_setlength: tnode;
           function handle_setlength: tnode;
           function handle_copy: tnode;
           function handle_copy: tnode;
+          function handle_box: tnode;
+          function handle_unbox: tnode;
        end;
        end;
        tinlinenodeclass = class of tinlinenode;
        tinlinenodeclass = class of tinlinenode;
 
 
@@ -2903,6 +2905,10 @@ implementation
                 begin
                 begin
                   result:=handle_box;
                   result:=handle_box;
                 end;
                 end;
+              in_unbox_x_y:
+                begin
+                  result:=handle_unbox;
+                end;
               else
               else
                 internalerror(8);
                 internalerror(8);
             end;
             end;
@@ -3303,6 +3309,8 @@ implementation
            result:=first_new;
            result:=first_new;
          in_box_x:
          in_box_x:
            result:=first_box;
            result:=first_box;
+         in_unbox_x_y:
+           result:=first_unbox;
          else
          else
            internalerror(89);
            internalerror(89);
           end;
           end;
@@ -3597,9 +3605,27 @@ implementation
      function tinlinenode.handle_box: tnode;
      function tinlinenode.handle_box: tnode;
        begin
        begin
          result:=nil;
          result:=nil;
+         if not assigned(left) or
+            assigned(tcallparanode(left).right) then
+           CGMessage1(parser_e_wrong_parameter_size,'FpcInternalBox');
          resultdef:=class_tobject;
          resultdef:=class_tobject;
        end;
        end;
 
 
+
+     function tinlinenode.handle_unbox: tnode;
+       begin
+         result:=nil;
+         if not assigned(left) or
+            not assigned(tcallparanode(left).right) or
+            assigned(tcallparanode(tcallparanode(left).right).right) then
+           CGMessage1(parser_e_wrong_parameter_size,'FpcInternalUnBox');
+         if tcallparanode(left).left.nodetype<>typen then
+           internalerror(2011071701);
+         ttypenode(tcallparanode(left).left).allowed:=true;
+         resultdef:=tcallparanode(left).left.resultdef;
+       end;
+
+
      function tinlinenode.first_pack_unpack: tnode;
      function tinlinenode.first_pack_unpack: tnode;
        var
        var
          loopstatement    : tstatementnode;
          loopstatement    : tstatementnode;

+ 2 - 1
compiler/symdef.pas

@@ -4661,7 +4661,8 @@ implementation
                   does achieve regular call-by-reference semantics though;
                   does achieve regular call-by-reference semantics though;
                   formaldefs always have to be passed like that because their
                   formaldefs always have to be passed like that because their
                   contents can be replaced }
                   contents can be replaced }
-                if (vs.vardef.typ=formaldef) or
+                if ((vs.vardef.typ=formaldef) and
+                    (vs.varspez<>vs_const)) or
                    ((vs.varspez in [vs_var,vs_out,vs_constref]) and
                    ((vs.varspez in [vs_var,vs_out,vs_constref]) and
                     not jvmimplicitpointertype(vs.vardef)) then
                     not jvmimplicitpointertype(vs.vardef)) then
                   tmpresult:=tmpresult+'[';
                   tmpresult:=tmpresult+'[';

+ 2 - 0
rtl/inc/innr.inc

@@ -84,6 +84,8 @@ const
    fpc_in_sar_x             = 73;
    fpc_in_sar_x             = 73;
    fpc_in_bsf_x             = 74;
    fpc_in_bsf_x             = 74;
    fpc_in_bsr_x             = 75;
    fpc_in_bsr_x             = 75;
+   in_box_x                 = 76; { managed platforms: wrap in class instance }
+   in_unbox_x_y             = 77; { manage platforms: extract from class instance }
 
 
 { Internal constant functions }
 { Internal constant functions }
    fpc_in_const_sqr        = 100;
    fpc_in_const_sqr        = 100;