View Issue Details

IDProjectCategoryView StatusLast Update
0033194pas2jstranspilerpublic2018-03-08 23:44
ReporterwarleyalexAssigned ToMattias Gaertner 
PrioritynormalSeverityminorReproducibilityalways
Status resolvedResolutionfixed 
Product VersionProduct Build0.9.5 
Target Version1.0.0Fixed in Version1.0.0 
Summary0033194: Passing Static Array in parameter issue
Description----------------------------------------------------
type
  TJyArray = array [0..15] of byte;

Procedure Init(const X : TJyArray);
var
  I: byte;
begin
  for I := Low(X) to High(X) do
    WriteLn('Integer at index ', I, ' is ', X[I]);
end;

var
  JyArray : TJyArray;

begin
  JyArray[8] := 8;
  JyArray[7] := 7;
  JyArray[6] := 6;
  JyArray[5] := 5;
  Init(JyArray);
(*
  Integer at index 0 is 0
  Integer at index 1 is 0
  Integer at index 2 is 0
  Integer at index 3 is 0
  Integer at index 4 is 0
  Integer at index 5 is 5
  Integer at index 6 is 6
  Integer at index 7 is 7
  Integer at index 8 is 8
  Integer at index 9 is 0
  Integer at index 10 is 0
  Integer at index 11 is 0
  Integer at index 12 is 0
  Integer at index 13 is 0
  Integer at index 14 is 0
  Integer at index 15 is 0
*)
---------------------------
This is working as expected!
----------------------------------------------------
Steps To ReproduceI think we have a minor issue, when passing static arrays in parameter the following situation:
---------------------------------
type
   TFixedSizeArray = array [0..9] of Integer;
   TDynamicArray = array of Integer;

procedure SomeProc(fixed : TFixedSizeArray; dynamico : TDynamicArray);
begin
  fixed[0] := fixed[0] + 1;
  SetLength(dynamico, 20);
  dynamico[0] := fixed[0] + dynamico[0];
end;


var f : TFixedSizeArray;
    d : TDynamicArray;

begin
  f[0] := 100;
  SetLength(d, 10);
  d[0] := 50;

  SomeProc(f, d);

  WriteLn(IntToStr( f[0]) );
  // pas2js returns 101 ---> the expected value would be 100

  WriteLn(IntToStr( d[0]) ); //151 --> correct
---------------------------------

Note that f[0] should be unchanged after call SomeProc method!
f is a TFixedSizeArray.



Additional Informationpas2js emitt: -----------> $mod.SomeProc($mod.f,$mod.d);
I think the correct is: --> $mod.SomeProc($mod.f.slice(0),$mod.d);
TagsNo tags attached.
Fixed in Revision
Attached Files

Relationships

related to 0033387 resolvedMattias Gaertner TJSArray._of doesn't like negative values (inline array) 

Activities

Mattias Gaertner

2018-02-18 15:05

developer   ~0106429

It is a bigger issue. Assigning a static array should copy too.

And a slice(0) is not always sufficient.
A static array of static array or of record needs a recursive copy.

Serge Anvarov

2018-02-18 17:05

reporter   ~0106433

I do not know how in pas2js, but in fpc dynamico[0] should remain equal to 50, because another local array was allocated inside the procedure.

Mattias Gaertner

2018-02-18 17:34

developer   ~0106436

In FPC dynamic arrays are reference counted and SetLength checks the ref count, and when >1 it clones the dynarray. In pas2js the dynarray is not ref counted, so it can't do that. It does not clone.

jamie philbrook

2018-02-18 17:57

reporter   ~0106440

Maybe there is misunderstanding in description here or we don't think the same?

What I find and it seems to be correct in my line of thinking is this..

A dynamic array given to a procedure as NON "Var" type will give the pointer
to the array onto the stack. Code within the procedure is looking at the given
array via the pointer on the stack, which means any changes made in this procedure will effect the contents of the array that was given, when the
call was made.. In other words, its the same as using "Var" or Referenced .

 Now, make a call to the SetLength, no matter the size, even if its the same as the original, will make a NEW local array and copy the original contents over to it, in other words, clone it, that much I understand. And thus any changes
inside this procedure will not effect the original via the pointer on the stack, in fact, it simply replaces the pointer on the stack with this new one but not before it copies (clones) it..

 As for static Arrays, they are simply copied to the stack unless a "VAR" referenced to it made, then it simply passes a pointer to the array.

 Did I get this correct? if so, I don't see any problems on the FPC side.

Mattias Gaertner

2018-02-18 18:23

developer   ~0106442

@jamie: You are almost correct.
SetLength does not always create a new array.
For example try the following:

var c: array of integer;
begin
  SetLength(c,2);
  writeln(HexStr(ptruint(Pointer(c)),8));
  SetLength(c,2);
  writeln(HexStr(ptruint(Pointer(c)),8));
  SetLength(c,3);
  writeln(HexStr(ptruint(Pointer(c)),8));
  SetLength(c,2);
  writeln(HexStr(ptruint(Pointer(c)),8));
  SetLength(c,3);
  writeln(HexStr(ptruint(Pointer(c)),8));
end;

Here is an example:
03D9A050
03D9A050
03D92050
03D92050
03D92050

As you can see, that the array is only reallocated if the underlying memory does not fit.

This is quite a speed difference. Because pas2js can't do this optimization, there was an idea to add some flag to choose between slow and FPC compatible, or fast and JS compatible behavior of SetLength.

Mattias Gaertner

2018-02-18 23:07

developer   ~0106457

38287

Issue History

Date Modified Username Field Change
2018-02-18 13:34 warleyalex New Issue
2018-02-18 15:05 Mattias Gaertner Note Added: 0106429
2018-02-18 15:05 Mattias Gaertner Assigned To => Mattias Gaertner
2018-02-18 15:05 Mattias Gaertner Status new => assigned
2018-02-18 17:05 Serge Anvarov Note Added: 0106433
2018-02-18 17:34 Mattias Gaertner Note Added: 0106436
2018-02-18 17:57 jamie philbrook Note Added: 0106440
2018-02-18 18:23 Mattias Gaertner Note Added: 0106442
2018-02-18 23:07 Mattias Gaertner Note Added: 0106457
2018-02-18 23:07 Mattias Gaertner Status assigned => resolved
2018-02-18 23:07 Mattias Gaertner Fixed in Version => 1.0.0
2018-02-18 23:07 Mattias Gaertner Resolution open => fixed
2018-02-18 23:07 Mattias Gaertner Target Version => 1.0.0
2018-03-08 23:44 Mattias Gaertner Relationship added related to 0033387