From 22926e4fc7a522d8985028922e6e3fd2bdcb46f8 Mon Sep 17 00:00:00 2001 From: mattias Date: Sat, 11 Jun 2022 00:21:07 +0200 Subject: [PATCH] pastojs: faster concat append array:=array+ --- packages/pastojs/src/fppas2js.pp | 56 +++++++++++++++++- packages/pastojs/tests/tcmodules.pas | 88 ++++++++++++++++++++++++++-- 2 files changed, 139 insertions(+), 5 deletions(-) diff --git a/packages/pastojs/src/fppas2js.pp b/packages/pastojs/src/fppas2js.pp index 9f37bb2af0e..5712bd53df1 100644 --- a/packages/pastojs/src/fppas2js.pp +++ b/packages/pastojs/src/fppas2js.pp @@ -2226,6 +2226,7 @@ TCreateRefPathData = record Function ConvertAssignStatement(El: TPasImplAssign; AContext: TConvertContext): TJSElement; virtual; Function ConvertDirectAssignArrayStatement(El: TPasImplAssign; AssignContext: TAssignContext): TJSElement; virtual; Function ConvertDirectAssignArrayConcat(El: TPasImplAssign; Params: TParamsExpr; AssignContext: TAssignContext): TJSElement; virtual; + Function ConvertDirectAssignArrayAdd(El: TPasImplAssign; Bin: TBinaryExpr; AssignContext: TAssignContext): TJSElement; virtual; Function ConvertRaiseStatement(El: TPasImplRaise; AContext: TConvertContext ): TJSElement; virtual; Function ConvertIfStatement(El: TPasImplIfElse; AContext: TConvertContext ): TJSElement; virtual; Function ConvertWhileStatement(El: TPasImplWhileDo; AContext: TConvertContext): TJSElement; virtual; @@ -23201,7 +23202,9 @@ function TPasToJSConverter.ConvertDirectAssignArrayStatement( end; end; - end; + end + else if (RightExpr.Kind=pekBinary) and (RightExpr.OpCode=eopAdd) then + Result:=ConvertDirectAssignArrayAdd(El,TBinaryExpr(RightExpr),AssignContext); end; function TPasToJSConverter.ConvertDirectAssignArrayConcat(El: TPasImplAssign; @@ -23272,6 +23275,57 @@ function TPasToJSConverter.ConvertDirectAssignArrayConcat(El: TPasImplAssign; end; end; +function TPasToJSConverter.ConvertDirectAssignArrayAdd(El: TPasImplAssign; + Bin: TBinaryExpr; AssignContext: TAssignContext): TJSElement; +var + BinLeft, BinRight: TPasExpr; + Ref: TResolvedReference; + Decl: TPasElement; + ParentContext: TConvertContext; + SubParams: TParamsExpr; + Call: TJSCallExpression; + i: Integer; + JS: TJSElement; +begin + Result:=nil; + BinLeft:=Bin.Left; + if not (BinLeft.CustomData is TResolvedReference) then + exit; + Ref:=TResolvedReference(BinLeft.CustomData); + Decl:=Ref.Declaration; + if not (El.Left.CustomData is TResolvedReference) then exit; + if (Decl<>TResolvedReference(El.Left.CustomData).Declaration) then + exit; + // A:=A+... + BinRight:=Bin.Right; + if BinRight.Kind=pekSet then + begin + // A:=A+[b,...] -> A=rtl.arrayPushN(A,b,...); + SubParams:=TParamsExpr(BinRight); + ParentContext:=AssignContext.Parent; + if length(SubParams.Params)=0 then + begin + // A:=Concat(A,[]) -> A; + Result:=ConvertExpression(BinLeft,ParentContext); + exit; + end; + try + Call:=CreateArrayConcat(AssignContext.LeftResolved.LoTypeEl as TPasArrayType, + El,ParentContext,true); + Call.AddArg(ConvertExpression(BinLeft,ParentContext)); + for i:=0 to length(SubParams.Params)-1 do + begin + JS:=CreateArrayEl(SubParams.Params[i],ParentContext); + Call.AddArg(JS); + end; + Result:=Call; + finally + if Result=nil then + Call.Free; + end; + end; +end; + function TPasToJSConverter.ConvertIfStatement(El: TPasImplIfElse; AContext: TConvertContext): TJSElement; Var diff --git a/packages/pastojs/tests/tcmodules.pas b/packages/pastojs/tests/tcmodules.pas index 6ced9f8811d..caf0c994823 100644 --- a/packages/pastojs/tests/tcmodules.pas +++ b/packages/pastojs/tests/tcmodules.pas @@ -501,6 +501,7 @@ TTestModule = class(TCustomTestModule) Procedure TestArray_Concat_Append_Var; Procedure TestArray_Copy; Procedure TestArray_InsertDelete; + Procedure TestArray_Add_Append; Procedure TestArray_DynArrayConstObjFPC; Procedure TestArray_DynArrayConstDelphi; Procedure TestArray_ArrayLitAsParam; @@ -11639,6 +11640,85 @@ ' TRec = record', ''])); end; +procedure TTestModule.TestArray_Add_Append; +begin + StartProgram(false); + Add([ + '{$modeswitch arrayoperators}', + 'type', + ' integer = longint;', + ' TFlag = (big,small);', + ' TFlags = set of TFlag;', + ' TRec = record', + ' i: integer;', + ' end;', + ' TArrInt = array of integer;', + ' TArrRec = array of TRec;', + ' TArrFlag = array of TFlag;', + ' TArrSet = array of TFlags;', + ' TArrJSValue = array of jsvalue;', + 'var', + ' ArrInt: tarrint;', + ' ArrRec: tarrrec;', + ' ArrFlag: tarrflag;', + ' ArrSet: tarrset;', + ' ArrJSValue: tarrjsvalue;', + ' r: TRec;', + ' f: TFlags;', + 'begin', + ' // append', + ' arrint:=arrint+[2];', + ' arrint:=arrint+[3,4];', + ' arrrec:=arrrec+[r];', + ' arrrec:=arrrec+[r,r];', + ' arrset:=arrset+[f];', + ' arrset:=arrset+[f,f];', + ' arrjsvalue:=arrjsvalue+[11];', + ' arrjsvalue:=arrjsvalue+[12,13];', + ' arrflag:=arrflag+[small];', + ' arrflag:=arrflag+[small,big];', + '']); + ConvertProgram; + CheckSource('TestArray_Add_Append', + LinesToStr([ // statements + 'this.TFlag = {', + ' "0": "big",', + ' big: 0,', + ' "1": "small",', + ' small: 1', + '};', + 'rtl.recNewT(this, "TRec", function () {', + ' this.i = 0;', + ' this.$eq = function (b) {', + ' return this.i === b.i;', + ' };', + ' this.$assign = function (s) {', + ' this.i = s.i;', + ' return this;', + ' };', + '});', + 'this.ArrInt = [];', + 'this.ArrRec = [];', + 'this.ArrFlag = [];', + 'this.ArrSet = [];', + 'this.ArrJSValue = [];', + 'this.r = this.TRec.$new();', + 'this.f = {};', + '']), + LinesToStr([ // $mod.$main + '$mod.ArrInt = rtl.arrayPushN($mod.ArrInt, 2);', + '$mod.ArrInt = rtl.arrayPushN($mod.ArrInt, 3, 4);', + '$mod.ArrRec = rtl.arrayPush($mod.TRec, $mod.ArrRec, $mod.TRec.$clone($mod.r));', + '$mod.ArrRec = rtl.arrayPush($mod.TRec, $mod.ArrRec, $mod.TRec.$clone($mod.r), $mod.TRec.$clone($mod.r));', + '$mod.ArrSet = rtl.arrayPush("refSet", $mod.ArrSet, rtl.refSet($mod.f));', + '$mod.ArrSet = rtl.arrayPush("refSet", $mod.ArrSet, rtl.refSet($mod.f), rtl.refSet($mod.f));', + '$mod.ArrJSValue = rtl.arrayPushN($mod.ArrJSValue, 11);', + '$mod.ArrJSValue = rtl.arrayPushN($mod.ArrJSValue, 12, 13);', + '$mod.ArrFlag = rtl.arrayPushN($mod.ArrFlag, $mod.TFlag.small);', + '$mod.ArrFlag = rtl.arrayPushN($mod.ArrFlag, $mod.TFlag.small, $mod.TFlag.big);', + ''])); +end; + procedure TTestModule.TestArray_DynArrayConstObjFPC; begin Parser.Options:=Parser.Options+[po_cassignments]; @@ -11688,9 +11768,9 @@ procedure TTestModule.TestArray_DynArrayConstObjFPC; '$mod.Ints = rtl.arrayConcatN([1], [2]);', '$mod.Ints = [2];', '$mod.Ints = rtl.arrayConcatN([], $mod.Ints);', - '$mod.Ints = rtl.arrayConcatN($mod.Ints, []);', + '$mod.Ints = $mod.Ints;', '$mod.Ints = rtl.arrayConcatN($mod.Ints, $mod.OneInt);', - '$mod.Ints = rtl.arrayConcatN($mod.Ints, [1, 1]);', + '$mod.Ints = rtl.arrayPushN($mod.Ints, 1, 1);', '$mod.Ints = rtl.arrayConcatN([$mod.i, $mod.i], $mod.Ints);', '$mod.Ints = rtl.arrayConcatN(rtl.arrayConcatN([1], [$mod.i]), [3]);', ''])); @@ -11872,7 +11952,7 @@ procedure TTestModule.TestArray_ArrayLitMultiDimAsParam; LinesToStr([ // $mod.$main '$mod.a = [[1]];', '$mod.a = [$mod.i];', - '$mod.a = rtl.arrayConcatN($mod.a, [$mod.i]);', + '$mod.a = rtl.arrayPushN($mod.a, $mod.i);', '$mod.a = rtl.arrayConcatN([$mod.i], $mod.a);', '$mod.a = [rtl.arrayConcatN([1], $mod.i)];', '$mod.a = [rtl.arrayConcatN([1], [2])];', @@ -11924,7 +12004,7 @@ procedure TTestModule.TestArray_ArrayLitStaticAsParam; LinesToStr([ // $mod.$main '$mod.a = [[1, 1]];', '$mod.a = [$mod.i.slice(0)];', - '$mod.a = rtl.arrayConcatN($mod.a, [$mod.i.slice(0)]);', + '$mod.a = rtl.arrayPushN($mod.a, $mod.i.slice(0));', '$mod.a = rtl.arrayConcatN([$mod.i.slice(0)], $mod.a);', '$mod.DoInt([[1, 1]]);', '$mod.DoInt([[1, 2], [3, 4]]);',