From ce4ccfc0aa652a0244d3a6815ae56abdf1507370 Mon Sep 17 00:00:00 2001
From: Mattias Gaertner <nc-gaertnma@netcologne.de>
Date: Mon, 22 Oct 2018 10:39:43 +0000
Subject: [PATCH] fcl-passrc: adapt pasuseanalyzer for pas2js

git-svn-id: trunk@40013 -
---
 packages/fcl-passrc/src/pastree.pp         |  17 +-
 packages/fcl-passrc/src/pasuseanalyzer.pas | 439 ++++++++++++++++-----
 2 files changed, 353 insertions(+), 103 deletions(-)

diff --git a/packages/fcl-passrc/src/pastree.pp b/packages/fcl-passrc/src/pastree.pp
index 26bdd3f465..a3de220b8d 100644
--- a/packages/fcl-passrc/src/pastree.pp
+++ b/packages/fcl-passrc/src/pastree.pp
@@ -135,6 +135,10 @@ type
     FParent: TPasElement;
     FHints : TPasMemberHints;
     FHintMessage : String;
+    {$ifdef pas2js}
+    FPasElementId: NativeInt;
+    class var FLastPasElementId: NativeInt;
+    {$endif}
     {$ifdef EnablePasTreeGlobalRefCount}
     class var FGlobalRefCount: int64;
     {$endif}
@@ -175,9 +179,12 @@ type
     property RefCount: LongWord read FRefCount;
     property Name: string read FName write FName;
     property Parent: TPasElement read FParent Write SetParent;
-    Property Hints : TPasMemberHints Read FHints Write FHints;
-    Property HintMessage : String Read FHintMessage Write FHintMessage;
-    Property DocComment : String Read FDocComment Write FDocComment;
+    property Hints : TPasMemberHints Read FHints Write FHints;
+    property HintMessage : String Read FHintMessage Write FHintMessage;
+    property DocComment : String Read FDocComment Write FDocComment;
+    {$ifdef pas2js}
+    property PasElementId: NativeInt read FPasElementId; // global unique id
+    {$endif}
     {$ifdef EnablePasTreeGlobalRefCount}
     class property GlobalRefCount: int64 read FGlobalRefCount write FGlobalRefCount;
     {$endif}
@@ -2308,6 +2315,10 @@ begin
   inherited Create;
   FName := AName;
   FParent := AParent;
+  {$ifdef pas2js}
+  inc(FLastPasElementId);
+  FPasElementId:=FLastPasElementId;
+  {$endif}
   {$ifdef EnablePasTreeGlobalRefCount}
   Inc(FGlobalRefCount);
   {$endif}
diff --git a/packages/fcl-passrc/src/pasuseanalyzer.pas b/packages/fcl-passrc/src/pasuseanalyzer.pas
index dee9a36098..308adde87f 100644
--- a/packages/fcl-passrc/src/pasuseanalyzer.pas
+++ b/packages/fcl-passrc/src/pasuseanalyzer.pas
@@ -39,12 +39,23 @@ Working:
 }
 unit PasUseAnalyzer;
 
-{$mode objfpc}{$H+}{$inline on}
+{$mode objfpc}{$H+}
+{$inline on}
+
+{$ifdef fpc}
+  {$define UsePChar}
+  {$define HasInt64}
+{$endif}
 
 interface
 
 uses
-  Classes, SysUtils, Types, AVL_Tree,
+  {$ifdef pas2js}
+  js,
+  {$else}
+  AVL_Tree,
+  {$endif}
+  Classes, SysUtils, Types,
   PasTree, PScanner, PasResolveEval, PasResolver;
 
 const
@@ -88,7 +99,7 @@ type
   private
     FRefCount: integer;
   public
-    Id: int64;
+    Id: TMaxPrecInt;
     MsgType: TMessageType;
     MsgNumber: integer;
     MsgText: string;
@@ -148,6 +159,43 @@ type
     property Overrides[Index: integer]: TPasElement read GetOverrides; default;
   end;
 
+  {$ifdef pas2js}
+  TPASItemToNameProc = function(Item: Pointer): String;
+  {$endif}
+
+  { TPasAnalyzerKeySet - set of items, each item has a key, no duplicate keys }
+
+  TPasAnalyzerKeySet = class
+  private
+    {$ifdef pas2js}
+    FItems: TJSObject;
+    FCount: integer;
+    FItemToName: TPASItemToNameProc;
+    FKeyToName: TPASItemToNameProc;
+    {$else}
+    FTree: TAVLTree; // tree of pointers, sorted for keys given by OnItemToKey, no duplicate keys
+    FCompareKeyWithData: TListSortCompare;
+    {$endif}
+  public
+    {$ifdef pas2js}
+    constructor Create(const OnItemToName, OnKeyToName: TPASItemToNameProc); reintroduce;
+    {$else}
+    constructor Create(const OnCompareMethod: TListSortCompare;
+      const OnCompareKeyWithData: TListSortCompare);
+    {$endif}
+    destructor Destroy; override;
+    procedure Clear;
+    procedure FreeItems;
+    procedure Add(Item: Pointer; CheckDuplicates: boolean = true);
+    procedure Remove(Item: Pointer);
+    function ContainsItem(Item: Pointer): boolean;
+    function ContainsKey(Key: Pointer): boolean;
+    function FindItem(Item: Pointer): Pointer;
+    function FindKey(Key: Pointer): Pointer;
+    function Count: integer;
+    function GetList: TFPList; // list of items
+  end;
+
   TPasAnalyzerOption = (
     paoOnlyExports, // default: use all class members accessible from outside (protected, but not private)
     paoImplReferences // collect references of top lvl proc implementations, initializationa dn finalization sections
@@ -175,29 +223,26 @@ type
 
   TPasAnalyzer = class
   private
-    FChecked: array[TPAUseMode] of TAVLTree; // tree of TElement
+    FChecked: array[TPAUseMode] of TPasAnalyzerKeySet; // tree of TElement
     FOnMessage: TPAMessageEvent;
     FOptions: TPasAnalyzerOptions;
-    FOverrideLists: TAVLTree; // tree of TPAOverrideList sorted for Element
+    FOverrideLists: TPasAnalyzerKeySet; // tree of TPAOverrideList sorted for Element
     FResolver: TPasResolver;
     FScopeModule: TPasModule;
-    FUsedElements: TAVLTree; // tree of TPAElement sorted for Element
+    FUsedElements: TPasAnalyzerKeySet; // tree of TPAElement sorted for Element
     procedure UseElType(El: TPasElement; aType: TPasType; Mode: TPAUseMode); inline;
     function AddOverride(OverriddenEl, OverrideEl: TPasElement): boolean;
-    function FindOverrideNode(El: TPasElement): TAVLTreeNode;
-    function FindOverrideList(El: TPasElement): TPAOverrideList;
     procedure SetOptions(AValue: TPasAnalyzerOptions);
     procedure UpdateAccess(IsWrite: Boolean; IsRead: Boolean; Usage: TPAElement);
     procedure OnUseScopeRef(Data, DeclScope: pointer);
   protected
-    procedure RaiseInconsistency(const Id: int64; Msg: string);
-    procedure RaiseNotSupported(const Id: int64; El: TPasElement; const Msg: string = '');
+    procedure RaiseInconsistency(const Id: TMaxPrecInt; Msg: string);
+    procedure RaiseNotSupported(const Id: TMaxPrecInt; El: TPasElement; const Msg: string = '');
     function FindTopImplScope(El: TPasElement): TPasScope;
     // mark used elements
     function Add(El: TPasElement; CheckDuplicate: boolean = true;
       aClass: TPAElementClass = nil): TPAElement;
-    function FindNode(El: TPasElement): TAVLTreeNode; inline;
-    function FindPAElement(El: TPasElement): TPAElement; inline;
+    function PAElementExists(El: TPasElement): boolean; inline;
     procedure CreateTree; virtual;
     function MarkElementAsUsed(El: TPasElement; aClass: TPAElementClass = nil): boolean; // true if new
     function ElementVisited(El: TPasElement; Mode: TPAUseMode): boolean;
@@ -238,7 +283,7 @@ type
     procedure AnalyzeModule(aModule: TPasModule);
     procedure AnalyzeWholeProgram(aStartModule: TPasProgram);
     procedure EmitModuleHints(aModule: TPasModule); virtual;
-    function FindElement(El: TPasElement): TPAElement;
+    function FindElement(El: TPasElement): TPAElement; inline;
     function FindUsedElement(El: TPasElement): TPAElement;
     // utility
     function IsUsed(El: TPasElement): boolean; // valid after calling Analyze*
@@ -247,8 +292,10 @@ type
     function IsExport(El: TPasElement): boolean;
     function IsIdentifier(El: TPasElement): boolean;
     function IsImplBlockEmpty(El: TPasImplBlock): boolean;
-    procedure EmitMessage(Id: int64; MsgType: TMessageType;
-      MsgNumber: integer; Fmt: String; const Args: array of const; PosEl: TPasElement);
+    procedure EmitMessage(Id: TMaxPrecInt; MsgType: TMessageType;
+      MsgNumber: integer; Fmt: String;
+      const Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif};
+      PosEl: TPasElement);
     procedure EmitMessage(Msg: TPAMessage);
     class function GetWarnIdentifierNumbers(Identifier: string;
       out MsgNumbers: TIntegerDynArray): boolean; virtual;
@@ -259,15 +306,43 @@ type
     property ScopeModule: TPasModule read FScopeModule write FScopeModule;
   end;
 
+{$ifdef pas2js}
+function PasElementToHashName(Item: Pointer): String;
+function PAElement_ElToHashName(Item: Pointer): String;
+function PAOverrideList_ElToHashName(Item: Pointer): String;
+{$else}
 function ComparePAElements(Identifier1, Identifier2: Pointer): integer;
 function CompareElementWithPAElement(El, Id: Pointer): integer;
 function ComparePAOverrideLists(List1, List2: Pointer): integer;
 function CompareElementWithPAOverrideList(El, List: Pointer): integer;
+{$endif}
 function GetElModName(El: TPasElement): string;
 function dbgs(a: TPAIdentifierAccess): string; overload;
 
 implementation
 
+{$ifdef pas2js}
+function PasElementToHashName(Item: Pointer): String;
+var
+  El: TPasElement absolute Item;
+begin
+  Result:=string(jsvalue(El.PasElementId));
+end;
+
+function PAElement_ElToHashName(Item: Pointer): String;
+var
+  El: TPAElement absolute Item;
+begin
+  Result:=string(jsvalue(El.Element.PasElementId));
+end;
+
+function PAOverrideList_ElToHashName(Item: Pointer): String;
+var
+  List: TPAOverrideList absolute Item;
+begin
+  Result:=string(jsvalue(List.Element.PasElementId));
+end;
+{$else}
 function ComparePointer(Data1, Data2: Pointer): integer;
 begin
   if Data1>Data2 then Result:=-1
@@ -304,6 +379,7 @@ var
 begin
   Result:=ComparePointer(El,OvList.Element);
 end;
+{$endif}
 
 function GetElModName(El: TPasElement): string;
 var
@@ -324,6 +400,190 @@ begin
   str(a,Result);
 end;
 
+{ TPasAnalyzerKeySet }
+
+{$ifdef pas2js}
+constructor TPasAnalyzerKeySet.Create(const OnItemToName,
+  OnKeyToName: TPASItemToNameProc);
+begin
+  FItemToName:=OnItemToName;
+  FKeyToName:=OnKeyToName;
+  FItems:=TJSObject.new;
+end;
+{$else}
+constructor TPasAnalyzerKeySet.Create(const OnCompareMethod: TListSortCompare;
+  const OnCompareKeyWithData: TListSortCompare);
+begin
+  FTree:=TAVLTree.Create(OnCompareMethod);
+  FCompareKeyWithData:=OnCompareKeyWithData;
+end;
+{$endif}
+
+destructor TPasAnalyzerKeySet.Destroy;
+begin
+  {$ifdef pas2js}
+  FItems:=nil;
+  {$else}
+  FreeAndNil(FTree);
+  {$endif}
+  inherited Destroy;
+end;
+
+procedure TPasAnalyzerKeySet.Clear;
+begin
+  {$ifdef pas2js}
+  FItems:=TJSObject.new;
+  FCount:=0;
+  {$else}
+  FTree.Clear;
+  {$endif}
+end;
+
+procedure TPasAnalyzerKeySet.FreeItems;
+{$ifdef pas2js}
+var
+  List: TStringDynArray;
+  i: Integer;
+begin
+  List:=TJSObject.getOwnPropertyNames(FItems);
+  for i:=0 to length(List)-1 do
+    TObject(FItems[List[i]]).Destroy;
+  FItems:=TJSObject.new;
+  FCount:=0;
+end;
+{$else}
+begin
+  FTree.FreeAndClear;
+end;
+{$endif}
+
+procedure TPasAnalyzerKeySet.Add(Item: Pointer; CheckDuplicates: boolean);
+begin
+  if CheckDuplicates then
+    if ContainsItem(Item) then
+      raise Exception.Create('TPasAnalyzerSet.Add duplicate');
+  {$ifdef pas2js}
+  FItems[FItemToName(Item)]:=Item;
+  inc(FCount);
+  {$else}
+  FTree.Add(Item);
+  {$endif}
+end;
+
+procedure TPasAnalyzerKeySet.Remove(Item: Pointer);
+{$ifdef pas2js}
+var
+  aName: string;
+begin
+  aName:=FItemToName(Item);
+  if not FItems.hasOwnProperty(aName) then exit;
+  JSDelete(FItems,aName);
+  dec(FCount);
+end;
+{$else}
+begin
+  FTree.Remove(Item);
+end;
+{$endif}
+
+function TPasAnalyzerKeySet.ContainsItem(Item: Pointer): boolean;
+begin
+  {$ifdef pas2js}
+  Result:=FItems.hasOwnProperty(FItemToName(Item));
+  {$else}
+  Result:=FTree.Find(Item)<>nil;
+  {$endif}
+end;
+
+function TPasAnalyzerKeySet.ContainsKey(Key: Pointer): boolean;
+begin
+  {$ifdef pas2js}
+  Result:=FItems.hasOwnProperty(FKeyToName(Key));
+  {$else}
+  Result:=FTree.FindKey(Key,FCompareKeyWithData)<>nil;
+  {$endif}
+end;
+
+function TPasAnalyzerKeySet.FindItem(Item: Pointer): Pointer;
+{$ifdef pas2js}
+var
+  aName: string;
+begin
+  aName:=FItemToName(Item);
+  if not FItems.hasOwnProperty(aName) then
+    exit(nil)
+  else
+    Result:=Pointer(FItems[aName]);
+end;
+{$else}
+var
+  Node: TAVLTreeNode;
+begin
+  Node:=FTree.Find(Item);
+  if Node<>nil then
+    Result:=Node.Data
+  else
+    Result:=nil;
+end;
+{$endif}
+
+function TPasAnalyzerKeySet.FindKey(Key: Pointer): Pointer;
+{$ifdef pas2js}
+var
+  aName: string;
+begin
+  aName:=FKeyToName(Key);
+  if not FItems.hasOwnProperty(aName) then
+    exit(nil)
+  else
+    Result:=Pointer(FItems[aName]);
+end;
+{$else}
+var
+  Node: TAVLTreeNode;
+begin
+  Node:=FTree.FindKey(Key,FCompareKeyWithData);
+  if Node<>nil then
+    Result:=Node.Data
+  else
+    Result:=nil;
+end;
+{$endif}
+
+function TPasAnalyzerKeySet.Count: integer;
+begin
+  {$ifdef pas2js}
+  Result:=FCount;
+  {$else}
+  Result:=FTree.Count;
+  {$endif}
+end;
+
+function TPasAnalyzerKeySet.GetList: TFPList;
+{$ifdef pas2js}
+var
+  List: TStringDynArray;
+  i: Integer;
+begin
+  List:=TJSObject.getOwnPropertyNames(FItems);
+  Result:=TFPList.Create;
+  for i:=0 to length(List)-1 do
+    Result.Add(FItems[List[i]]);
+end;
+{$else}
+var
+  Node: TAVLTreeNode;
+begin
+  Result:=TFPList.Create;
+  Node:=FTree.FindLowest;
+  while Node<>nil do
+    begin
+    Result.Add(Node.Data);
+    Node:=FTree.FindSuccessor(Node);
+    end;
+end;
+{$endif}
+
 { TPAMessage }
 
 constructor TPAMessage.Create;
@@ -342,7 +602,11 @@ begin
     raise Exception.Create('');
   dec(FRefCount);
   if FRefCount=0 then
+    {$ifdef pas2js}
+    Destroy;
+    {$else}
     Free;
+    {$endif}
 end;
 
 { TPAOverrideList }
@@ -417,21 +681,9 @@ end;
 { TPasAnalyzer }
 
 // inline
-function TPasAnalyzer.FindNode(El: TPasElement): TAVLTreeNode;
+function TPasAnalyzer.PAElementExists(El: TPasElement): boolean;
 begin
-  Result:=FUsedElements.FindKey(El,@CompareElementWithPAElement);
-end;
-
-// inline
-function TPasAnalyzer.FindPAElement(El: TPasElement): TPAElement;
-var
-  Node: TAVLTreeNode;
-begin
-  Node:=FindNode(El);
-  if Node=nil then
-    Result:=nil
-  else
-    Result:=TPAElement(Node.Data);
+  Result:=FUsedElements.ContainsKey(El);
 end;
 
 // inline
@@ -443,33 +695,22 @@ begin
   UseType(aType,Mode);
 end;
 
+// inline
+function TPasAnalyzer.FindElement(El: TPasElement): TPAElement;
+begin
+  Result:=TPAElement(FUsedElements.FindKey(El));
+end;
+
 procedure TPasAnalyzer.SetOptions(AValue: TPasAnalyzerOptions);
 begin
   if FOptions=AValue then Exit;
   FOptions:=AValue;
 end;
 
-function TPasAnalyzer.FindOverrideNode(El: TPasElement): TAVLTreeNode;
-begin
-  Result:=FOverrideLists.FindKey(El,@CompareElementWithPAOverrideList);
-end;
-
-function TPasAnalyzer.FindOverrideList(El: TPasElement): TPAOverrideList;
-var
-  Node: TAVLTreeNode;
-begin
-  Node:=FindOverrideNode(El);
-  if Node=nil then
-    Result:=nil
-  else
-    Result:=TPAOverrideList(Node.Data);
-end;
-
 function TPasAnalyzer.AddOverride(OverriddenEl, OverrideEl: TPasElement): boolean;
 // OverrideEl overrides OverriddenEl
 // returns true if new override
 var
-  Node: TAVLTreeNode;
   Item: TPAOverrideList;
   OverriddenPAEl: TPAElement;
   TypeEl: TPasType;
@@ -477,16 +718,15 @@ begin
   {$IFDEF VerbosePasAnalyzer}
   writeln('TPasAnalyzer.AddOverride OverriddenEl=',GetElModName(OverriddenEl),' OverrideEl=',GetElModName(OverrideEl));
   {$ENDIF}
-  Node:=FindOverrideNode(OverriddenEl);
-  if Node=nil then
+  Item:=TPAOverrideList(FOverrideLists.FindKey(OverriddenEl));
+  if Item=nil then
     begin
     Item:=TPAOverrideList.Create;
     Item.Element:=OverriddenEl;
-    FOverrideLists.Add(Item);
+    FOverrideLists.Add(Item,false);
     end
   else
     begin
-    Item:=TPAOverrideList(Node.Data);
     if Item.IndexOf(OverrideEl)>=0 then
       exit(false);
     end;
@@ -494,7 +734,7 @@ begin
   Item.Add(OverrideEl);
   Result:=true;
 
-  OverriddenPAEl:=FindPAElement(OverriddenEl);
+  OverriddenPAEl:=FindElement(OverriddenEl);
   if OverriddenPAEl<>nil then
     begin
     // OverriddenEl was already used -> use OverrideEl
@@ -567,7 +807,7 @@ begin
     end;
 end;
 
-procedure TPasAnalyzer.RaiseInconsistency(const Id: int64; Msg: string);
+procedure TPasAnalyzer.RaiseInconsistency(const Id: TMaxPrecInt; Msg: string);
 begin
   {$IFDEF VerbosePasAnalyzer}
   writeln('TPasAnalyzer.RaiseInconsistency ['+IntToStr(Id)+']: '+Msg);
@@ -575,7 +815,7 @@ begin
   raise EPasAnalyzer.Create('['+IntToStr(Id)+']: '+Msg);
 end;
 
-procedure TPasAnalyzer.RaiseNotSupported(const Id: int64; El: TPasElement;
+procedure TPasAnalyzer.RaiseNotSupported(const Id: TMaxPrecInt; El: TPasElement;
   const Msg: string);
 var
   s: String;
@@ -626,9 +866,9 @@ begin
   if El=nil then
     RaiseInconsistency(20170308093407,'');
   {$IFDEF VerbosePasAnalyzer}
-  writeln('TPasAnalyzer.Add ',GetElModName(El),' New=',FindNode(El)=nil);
+  writeln('TPasAnalyzer.Add ',GetElModName(El),' New=',not PAElementExists(El));
   {$ENDIF}
-  if CheckDuplicate and (FindNode(El)<>nil) then
+  if CheckDuplicate and PAElementExists(El) then
     RaiseInconsistency(20170304201318,'');
   if aClass=nil then
     aClass:=TPAElement;
@@ -636,13 +876,18 @@ begin
   Result.Element:=El;
   FUsedElements.Add(Result);
   {$IFDEF VerbosePasAnalyzer}
-  //writeln('TPasAnalyzer.Add END ',GetElModName(El),' Success=',FindNode(El)<>nil,' ',ptruint(pointer(El)));
+  //writeln('TPasAnalyzer.Add END ',GetElModName(El),' Success=',PAElementExists(El),' ',ptruint(pointer(El)));
   {$ENDIF}
 end;
 
 procedure TPasAnalyzer.CreateTree;
 begin
-  FUsedElements:=TAVLTree.Create(@ComparePAElements);
+  FUsedElements:=TPasAnalyzerKeySet.Create(
+    {$ifdef pas2js}
+    @PAElement_ElToHashName,@PasElementToHashName
+    {$else}
+    @ComparePAElements,@CompareElementWithPAElement
+    {$endif});
 end;
 
 function TPasAnalyzer.MarkElementAsUsed(El: TPasElement; aClass: TPAElementClass
@@ -650,7 +895,7 @@ function TPasAnalyzer.MarkElementAsUsed(El: TPasElement; aClass: TPAElementClass
 
   function MarkModule(CurModule: TPasModule): boolean;
   begin
-    if FindNode(CurModule)<>nil then
+    if PAElementExists(CurModule) then
       exit(false);
     {$IFDEF VerbosePasAnalyzer}
     writeln('TPasAnalyzer.MarkElement.MarkModule mark "',GetElModName(CurModule),'"');
@@ -686,7 +931,7 @@ begin
     end;
 
   // mark element
-  if FindNode(El)<>nil then exit(false);
+  if PAElementExists(El) then exit(false);
   Add(El,false,aClass);
   Result:=true;
 
@@ -705,9 +950,9 @@ function TPasAnalyzer.ElementVisited(El: TPasElement; Mode: TPAUseMode
 begin
   if El=nil then
     exit(true);
-  if FChecked[Mode].Find(El)<>nil then exit(true);
+  if FChecked[Mode].ContainsItem(El) then exit(true);
   Result:=false;
-  FChecked[Mode].Add(El);
+  FChecked[Mode].Add(El,false);
 end;
 
 procedure TPasAnalyzer.MarkImplScopeRef(El, RefEl: TPasElement;
@@ -900,7 +1145,7 @@ procedure TPasAnalyzer.UseModule(aModule: TPasModule; Mode: TPAUseMode);
     UseScopeReferences(Scope.References);
     if (Scope.References=nil) and IsImplBlockEmpty(ImplBlock) then exit;
     // this module has an initialization section -> mark module
-    if FindNode(aModule)=nil then
+    if not PAElementExists(aModule) then
       Add(aModule);
     UseImplBlock(ImplBlock,true);
   end;
@@ -936,7 +1181,7 @@ begin
 
   if Mode=paumElement then
     // e.g. a reference: unitname.identifier
-    if FindNode(aModule)=nil then
+    if not PAElementExists(aModule) then
       Add(aModule);
 end;
 
@@ -979,7 +1224,7 @@ begin
         if IsImplBlockEmpty(UsedModule.InitializationSection)
             and IsImplBlockEmpty(UsedModule.FinalizationSection) then
           continue;
-        if FindNode(UsedModule)=nil then
+        if not PAElementExists(UsedModule) then
           Add(UsedModule);
         UseImplBlock(UsedModule.InitializationSection,true);
         UseImplBlock(UsedModule.FinalizationSection,true);
@@ -1427,7 +1672,7 @@ procedure TPasAnalyzer.UseProcedure(Proc: TPasProcedure);
     i: Integer;
     OverrideProc: TPasProcedure;
   begin
-    OverrideList:=FindOverrideList(CurProc);
+    OverrideList:=TPAOverrideList(FOverrideLists.FindKey(CurProc));
     if OverrideList=nil then exit;
     // Note: while traversing the OverrideList it may grow
     i:=0;
@@ -1637,7 +1882,7 @@ procedure TPasAnalyzer.UseClassType(El: TPasClassType; Mode: TPAUseMode);
     i: Integer;
     Prop: TPasProperty;
   begin
-    OverrideList:=FindOverrideList(El);
+    OverrideList:=TPAOverrideList(FOverrideLists.FindKey(El));
     if OverrideList=nil then exit;
     // Note: while traversing the OverrideList it may grow
     i:=0;
@@ -2099,7 +2344,7 @@ begin
       begin
       UsedModule:=TPasModule(Use.Module);
       if CompareText(UsedModule.Name,'system')=0 then continue;
-      if FindNode(UsedModule)=nil then
+      if not PAElementExists(UsedModule) then
         EmitMessage(20170311191725,mtHint,nPAUnitNotUsed,sPAUnitNotUsed,
           [UsedModule.Name,aModule.Name],Use.Expr);
       end;
@@ -2128,7 +2373,7 @@ begin
       EmitProcedureHints(TPasProcedure(Decl))
     else
       begin
-      Usage:=FindPAElement(Decl);
+      Usage:=FindElement(Decl);
       if Usage=nil then
         begin
         // declaration was never used
@@ -2149,7 +2394,7 @@ begin
   {$IFDEF VerbosePasAnalyzer}
   writeln('TPasAnalyzer.EmitTypeHints ',GetElModName(El));
   {$ENDIF}
-  Usage:=FindPAElement(El);
+  Usage:=FindElement(El);
   if Usage=nil then
     begin
     // the whole type was never used
@@ -2191,7 +2436,7 @@ begin
   {$IFDEF VerbosePasAnalyzer}
   writeln('TPasAnalyzer.EmitVariableHints ',GetElModName(El));
   {$ENDIF}
-  Usage:=FindPAElement(El);
+  Usage:=FindElement(El);
   if Usage=nil then
     begin
     // not used
@@ -2251,7 +2496,7 @@ begin
     ImplProc:=El
   else
     ImplProc:=ProcScope.ImplProc;
-  if FindNode(DeclProc)=nil then
+  if not PAElementExists(DeclProc) then
     begin
     // procedure never used
     if ProcScope.DeclarationProc=nil then
@@ -2282,7 +2527,7 @@ begin
     for i:=0 to Args.Count-1 do
       begin
       Arg:=TPasArgument(Args[i]);
-      Usage:=FindPAElement(Arg);
+      Usage:=FindElement(Arg);
       if (Usage=nil) or (Usage.Access=paiaNone) then
         begin
         // parameter was never used
@@ -2308,7 +2553,7 @@ begin
       PosEl:=TPasFunction(El).FuncType.ResultEl;
       if (ProcScope.ImplProc<>nil) and (TPasFunction(ProcScope.ImplProc).FuncType.ResultEl<>nil) then
         PosEl:=TPasFunction(ProcScope.ImplProc).FuncType.ResultEl;
-      Usage:=FindPAElement(TPasFunction(El).FuncType.ResultEl);
+      Usage:=FindElement(TPasFunction(El).FuncType.ResultEl);
       if (Usage=nil) or (Usage.Access in [paiaNone,paiaRead]) then
         // result was never used
         EmitMessage(20170313214038,mtHint,nPAFunctionResultDoesNotSeemToBeSet,
@@ -2334,8 +2579,20 @@ var
 begin
   CreateTree;
   for m in TPAUseMode do
-    FChecked[m]:=TAVLTree.Create;
-  FOverrideLists:=TAVLTree.Create(@ComparePAOverrideLists);
+    FChecked[m]:=TPasAnalyzerKeySet.Create(
+      {$ifdef pas2js}
+      @PasElementToHashName
+      {$else}
+      @ComparePointer
+      {$endif}
+      ,nil
+      );
+  FOverrideLists:=TPasAnalyzerKeySet.Create(
+    {$ifdef pas2js}
+    @PAOverrideList_ElToHashName,@PasElementToHashName
+    {$else}
+    @ComparePAOverrideLists,@CompareElementWithPAOverrideList
+    {$endif});
 end;
 
 destructor TPasAnalyzer.Destroy;
@@ -2354,8 +2611,8 @@ procedure TPasAnalyzer.Clear;
 var
   m: TPAUseMode;
 begin
-  FOverrideLists.FreeAndClear;
-  FUsedElements.FreeAndClear;
+  FOverrideLists.FreeItems;
+  FUsedElements.FreeItems;
   for m in TPAUseMode do
     FChecked[m].Clear;
 end;
@@ -2418,17 +2675,6 @@ begin
   //EmitBlockHints(aModule.FinalizationSection);
 end;
 
-function TPasAnalyzer.FindElement(El: TPasElement): TPAElement;
-var
-  Node: TAVLTreeNode;
-begin
-  Node:=FindNode(El);
-  if Node=nil then
-    Result:=nil
-  else
-    Result:=TPAElement(Node.Data);
-end;
-
 function TPasAnalyzer.FindUsedElement(El: TPasElement): TPAElement;
 var
   ProcScope: TPasProcedureScope;
@@ -2450,7 +2696,7 @@ end;
 
 function TPasAnalyzer.IsTypeInfoUsed(El: TPasElement): boolean;
 begin
-  Result:=FChecked[paumTypeInfo].Find(El)<>nil;
+  Result:=FChecked[paumTypeInfo].ContainsItem(El);
 end;
 
 function TPasAnalyzer.IsModuleInternal(El: TPasElement): boolean;
@@ -2497,8 +2743,9 @@ begin
   Result:=false;
 end;
 
-procedure TPasAnalyzer.EmitMessage(Id: int64; MsgType: TMessageType;
-  MsgNumber: integer; Fmt: String; const Args: array of const;
+procedure TPasAnalyzer.EmitMessage(Id: TMaxPrecInt; MsgType: TMessageType;
+  MsgNumber: integer; Fmt: String;
+  const Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif};
   PosEl: TPasElement);
 var
   Msg: TPAMessage;
@@ -2617,16 +2864,8 @@ begin
 end;
 
 function TPasAnalyzer.GetUsedElements: TFPList;
-var
-  Node: TAVLTreeNode;
 begin
-  Result:=TFPList.Create;
-  Node:=FUsedElements.FindLowest;
-  while Node<>nil do
-    begin
-    Result.Add(Node.Data);
-    Node:=FUsedElements.FindSuccessor(Node);
-    end;
+  Result:=FUsedElements.GetList;
 end;
 
 end.