IMPLEMENTATION MODULE YaflDictionary;

FROM ArrayList IMPORT ArrayList;
FROM Conversions IMPORT IntConversions;
FROM Streams IMPORT StdOut;
IMPORT HashElement;
IMPORT HashSpace;
FROM List IMPORT List;
FROM Streams IMPORT OutputStream;
IMPORT SYSTEM;
IMPORT Space;
FROM YaflCfg IMPORT YaflCfg;
FROM YaflPredefined IMPORT PredefMethod, PredefItems;
IMPORT Stack;    
FROM YaflParser IMPORT NonTerminal;
FROM Streams IMPORT StdOut;

  CLASS UnaryReference;
    INHERITS HashElement; 
    
    VAR 
      TheModule : ARRAY OF CHAR;
      DeclPosition, 
      ImplPosition: INTEGER;
      
    CONST
      MaxLineLength = 4096;
      
    METHOD MakePosition (PosX, PosY: INTEGER): INTEGER;
      BEGIN
      RESULT := (PosY * MaxLineLength) + (PosX MOD MaxLineLength);
      END MakePosition;
      
    METHOD ExtractPosX (Position: INTEGER): INTEGER;
      POST
        NO_CHANGE;
      BEGIN           
      RESULT := Position MOD MaxLineLength;
      END ExtractPosX;
                     
    METHOD ExtractPosY (Position: INTEGER): INTEGER;
      POST
        NO_CHANGE;
      BEGIN           
      RESULT := Position / MaxLineLength;
      END ExtractPosY;
                     
    REDEFINE METHOD CREATE (Module : ARRAY OF CHAR);
      BEGIN      
      RenameUnary (Module);   
      DeclPosition := -1;
      ImplPosition := -1;
      SetState (NonTerminal.InitializedState);
      TheHash := -1;
      END CREATE;
      
    METHOD SetDeclPos (DeclX, DeclY : INTEGER);
      BEGIN
      DeclPosition := MakePosition (DeclX, DeclY);
      END SetDeclPos;
      
    METHOD SetImplPos (ImplX, ImplY : INTEGER);
      BEGIN
      ImplPosition := MakePosition (ImplX, ImplY);
      END SetImplPos;
              
    METHOD GetDeclX : INTEGER;
      BEGIN        
      RESULT := ExtractPosX(DeclPosition);
      END GetDeclX;
      
    METHOD GetDeclY : INTEGER;
      BEGIN        
      RESULT := ExtractPosY(DeclPosition);
      END GetDeclY;
                  
    METHOD GetImplX : INTEGER;
      BEGIN        
      RESULT := ExtractPosX(ImplPosition);
      END GetImplX;
      
    METHOD GetImplY : INTEGER;
      BEGIN        
      RESULT := ExtractPosY(ImplPosition);
      END GetImplY;           

    METHOD Public : BOOLEAN;
      BEGIN                
      RESULT := DeclPosition >= 0;
      END Public;

    VAR
      TheState : INTEGER;

    METHOD SetState (Value : INTEGER);
      BEGIN
      TheState := Value;
      END SetState;
      
    METHOD State : INTEGER;
      BEGIN     
      RESULT := TheState;
      END State;
      
    METHOD RenameUnary (Module : ARRAY OF CHAR);
      BEGIN 
      TheModule := Module;
      TheHash := -1;
      END RenameUnary;
      
    METHOD Module: ARRAY OF CHAR;
      BEGIN      
      RESULT := TheModule;
      END Module;         
      
    VAR
      TheHash: INTEGER;
      
    REDEFINE METHOD HashValue: INTEGER;
      BEGIN
      IF TheHash < 0 THEN
        TheHash := ComputeHashValue;
        ASSERT TheHash >= 0;
        END;        
      RESULT := TheHash;
      END HashValue;
      
    METHOD ClearHash;
      BEGIN         
      TheHash := -1;
      END ClearHash;

    METHOD ComputeHashValue : INTEGER;
      BEGIN
      RESULT := 9321;
      FOR i := 0 TO TheModule.SIZE - 1 DO
        RESULT := RESULT + (1 + (i * RESULT * SYSTEM.ORD(TheModule[i])));
        END;
      IF RESULT < 0 THEN
        RESULT := -RESULT;
        END;
      END ComputeHashValue;
      
    METHOD Image: ARRAY OF CHAR;
      BEGIN     
      RESULT := TheModule;
      END Image;

    METHOD Name : ARRAY OF CHAR;
      BEGIN    
      RESULT := TheModule;
      END Name;

    DEFERRED METHOD Clear;

    METHOD Zap;
      BEGIN
      DeclPosition := -1;
      ImplPosition := -1;
      TheModule := VOID;
      SetState (NonTerminal.InitializedState);
      TheHash := -1;
      END Zap;
      
  END UnaryReference;

---------------------------------------------

  CLASS BinaryReference;
    INHERITS UnaryReference;
    
    VAR
      TheClass : ARRAY OF CHAR;
    
    REDEFINE METHOD CREATE (Module, Class : ARRAY OF CHAR);
      BEGIN
      BASE (Module);
      TheClass := Class;
      END CREATE;

    METHOD RenameBinary (Module, Class : ARRAY OF CHAR);
      BEGIN
      RenameUnary (Module);
      TheClass := Class;
      END RenameBinary; 
    
    METHOD Class: ARRAY OF CHAR;
      BEGIN    
      RESULT := TheClass;
      END Class;
      
    REDEFINE METHOD ComputeHashValue : INTEGER;
      BEGIN
      RESULT := BASE;
      FOR i := 0 TO TheClass.SIZE - 1 DO
        RESULT := RESULT + (19 + (i * RESULT * SYSTEM.ORD(TheClass[i])));
        END;
      IF RESULT < 0 THEN
        RESULT := -RESULT;
        END;
      END ComputeHashValue;

    REDEFINE METHOD Image: ARRAY OF CHAR;
      BEGIN     
      RESULT := BASE + "." + TheClass;
      END Image;

    ---------------------------------------  
    VAR
      TheVisited,
      TheRemoved    : BOOLEAN;
        
    METHOD MarkVisited;
      BEGIN
      TheVisited := TRUE;
      END MarkVisited;
                      
    METHOD Visited: BOOLEAN;
      BEGIN
      RESULT := TheVisited;
      END Visited;
      
    REDEFINE METHOD Visit;
      BEGIN
      MarkVisited;
      END Visit; 
     
    REDEFINE METHOD Clear; 
      BEGIN
      TheVisited := FALSE;
      END Clear;
    
    ---------------------------------------  
    METHOD Useful: BOOLEAN;
      BEGIN
      RESULT := NOT Removed;
      END Useful;

    METHOD Remove; 
      BEGIN
      TheRemoved := TRUE;
      END Remove;        
      
    METHOD UnRemove;
      BEGIN
      TheRemoved := FALSE;
      END UnRemove;
      
    METHOD Removed: BOOLEAN;
      BEGIN
      RESULT := TheRemoved;
      END Removed;
        
    ----------------------------------------------    
    
    REDEFINE METHOD Name : ARRAY OF CHAR;
      BEGIN    
      RESULT := TheClass;
      END Name;
             
  END BinaryReference;

---------------------------------------------

  CLASS TernaryReference;
    INHERITS BinaryReference;
    VAR
      TheMethod : ARRAY OF CHAR;
    
    REDEFINE METHOD CREATE (Module, Class, Method: ARRAY OF CHAR);
      BEGIN
      BASE(Module, Class);
      TheMethod := Method;
      IF TheMethod <> VOID THEN  -- This is a true TernaryReference
        VOID := ClassRef;      -- Creates Class if necessary
                               -- Attach THIS to its class
        END;
      END CREATE;

    METHOD RenameTernary (Module, Class, Method : ARRAY OF CHAR);
      BEGIN
      RenameBinary (Module, Class);
      TheMethod := Method;
      END RenameTernary;

    METHOD Method: ARRAY OF CHAR;
      BEGIN
      RESULT := TheMethod;
      END Method;    
                 
    REDEFINE METHOD ComputeHashValue : INTEGER;
      BEGIN
      RESULT := BASE;
      FOR i := 0 TO TheMethod.SIZE - 1 DO
        RESULT := RESULT + (3 + ((i+1) * RESULT * SYSTEM.ORD(TheMethod[i])));
        END;
      IF RESULT < 0 THEN
        RESULT := -RESULT;
        END;
      END ComputeHashValue;

    -----------------------------------------
    VAR
      TheCall  : CallReference;
      TheEntry : EntryReference; 
      
    METHOD CallRef: CallReference;
      BEGIN       
      IF TheCall = VOID THEN
        TheCall := CallDictionary.FindCall (Module, Class, Method);
        ASSERT TheCall <> VOID;
        END;
      RESULT := TheCall;
      END CallRef;
               
    METHOD EntryRef: EntryReference;
      VAR
        Cl: ClassReference;
      BEGIN
      Cl := ClassRef;      
      WHILE (TheEntry = VOID) AND (Cl <> VOID) DO
        TheEntry :=  EntryDictionary.DoFind(Cl.Module, Cl.Class, Method);
        Cl := Cl.BaseClass;
        END;
      RESULT := TheEntry;
      END EntryRef;
    
    ----------------------------------------
    VAR 
      TheClassRef : ClassReference;
      
    METHOD ClassRef: ClassReference;
      BEGIN
      IF TheClassRef = VOID THEN
        TheClassRef := ClassDictionary.FindClass (Module, Class);
        END;
      RESULT := TheClassRef;
      END ClassRef;       
      
    REDEFINE METHOD Image: ARRAY OF CHAR;
      BEGIN     
      RESULT := BASE + '.' + TheMethod;
      END Image;
             
    REDEFINE METHOD Name : ARRAY OF CHAR;
      BEGIN     
      RESULT := TheMethod;
      END Name; 
      
    ---------------------------------------------
    REDEFINE METHOD Useful: BOOLEAN;
      BEGIN
      RESULT := BASE AND Visited;
      END Useful;

    ---------------------------------------------
    REDEFINE METHOD Dump (Output: OutputStream);
      VAR
        a: ARRAY OF CHAR;
      BEGIN               
      a := Image + "                                                                ";
      Output.WriteString (a.SLICE (0, 60));
      IF Removed THEN
        Output.WriteString ('Rem-');
       ELSE
        Output.WriteString ('----');
        END;
      IF Useful THEN
        Output.WriteString ('Use-');
       ELSE
        Output.WriteString ('----');
        END;
      IF Visited THEN
        Output.WriteString ('Vis-');
       ELSE
        Output.WriteString ('----');
        END;
      END Dump;
    
  END TernaryReference;

---------------------------------------------

  CLASS CallReference;
    INHERITS TernaryReference;
    
    VAR
      TheCount : INTEGER;
      
    METHOD Increment; 
      BEGIN
      TheCount := TheCount + 1;
      END Increment;
      
    METHOD Count: INTEGER;
      BEGIN
      RESULT := TheCount;
      END Count;

    ------------------------------------------
    REDEFINE METHOD Insert;
      BEGIN
      -- Nobody's interseted in knowing all calls 
      -- available for a given class
      END Insert;
    ------------------------------------------
    VAR
      TheUpMethod: MethodReference;
      UpMethodSet: BOOLEAN;       
      
    METHOD PreviousCall: CallReference;  
      VAR
        BaseClass: ClassReference;
      BEGIN            
      ASSERT ClassRef <> EntryRef.ClassRef;
      BaseClass := ClassRef.BaseClass;
      ASSERT BaseClass <> VOID;
      RESULT := CallDictionary.FindCall (BaseClass.Module, 
                                          BaseClass.Class,
                                          Method);
      END PreviousCall;
      
    -- XXL
    METHOD UpCall: CallReference;
      VAR
        Cl : ClassReference;
      BEGIN
      ASSERT ClassRef <> VOID;
      Cl := ClassRef.BaseClass;
      RESULT := CallDictionary.FindCall (Cl.Module, Cl.Class, Method);
      END UpCall;
    -- END XXL  
      
      
    METHOD BaseCall: CallReference;  
      VAR
        Cl: ClassReference;
        MethRef: MethodReference;
      BEGIN            
      ASSERT ClassRef <> VOID;
      Cl := ClassRef.BaseClass;
      WHILE (Cl <> VOID) AND (RESULT = VOID) DO
        MethRef := MethodDictionary.FindMethod (Cl.Module,
                                                Cl.Class, 
                                                Method);
        IF MethRef <> VOID THEN
          RESULT := CallDictionary.FindCall (Cl.Module, Cl.Class, Method);
         ELSE
          Cl := Cl.BaseClass;                                        
          END;
        END;                                  
      END BaseCall;
      
	--------------------------------  
	-- UpMethod is the first method 
	-- matching this entry invocation  
	--------------------------------
    METHOD UpMethod: MethodReference;
      VAR
        ERef: EntryReference;
      BEGIN                        
      IF NOT UpMethodSet THEN 
        UpMethodSet := TRUE;
        TheUpMethod := MethodDictionary.DoFind (Module, Class, Method);
        IF TheUpMethod = VOID THEN
          ERef := EntryRef;
          IF (ERef <> VOID) AND (ClassRef <> ERef.ClassRef) THEN
            TheUpMethod := PreviousCall.UpMethod;
            END;
          END;
        END;
      RESULT := TheUpMethod;
      END UpMethod;
      
    ------------------------------------------
    REDEFINE METHOD Visit;
      VAR
        p: ClassReference; 
        MethRef : MethodReference;
      BEGIN            
      IF NOT Visited THEN
        VOID := UpMethod;
        BASE;
        IF EntryRef <> VOID THEN
          EntryRef.Visit;
          END;
           
        -- Which is the actual method called. 
        MethRef := UpMethod;
        IF MethRef <> VOID THEN
          MethodQueue.Push (MethRef);
          END;
          
        ClassRef.Visit;
          
        p := ClassRef.FirstDerived;
        WHILE p <> VOID DO
          CallDictionary.FindCall (p.Module, p.Class, Method).Visit;
          p := p.NextDerived;
          END;
        END;
      END Visit;
      
    REDEFINE METHOD Clear;
      BEGIN
      BASE;
      TheCount := 0;
      END Clear;
      
    ------------------------------------------   
    VAR
      TheSafeCall        : BOOLEAN;
      TheRiskyCall       : BOOLEAN;
      TheOptimizedMethod : MethodReference;
   
    METHOD AddPotentialMethod (MethRef : MethodReference);
      BEGIN
      ASSERT NOT SafeCall;
      TheSafeCall := TRUE;
      TheOptimizedMethod := MethRef;
      END AddPotentialMethod;
      
    METHOD AddPotentialDownMethod;
      BEGIN
      TheRiskyCall := TRUE;
      END AddPotentialDownMethod;
           
    METHOD OptimizedMethod : MethodReference; 
      BEGIN
      IF NOT RiskyCall THEN
        RESULT := TheOptimizedMethod;
        END;
      END OptimizedMethod;

    METHOD RiskyCall : BOOLEAN;
      POST
        NO_CHANGE;
      BEGIN              
      RESULT := TheRiskyCall;
      END RiskyCall;
      
    METHOD SafeCall : BOOLEAN;
      POST
        NO_CHANGE;
      BEGIN
      RESULT := TheSafeCall;
      END SafeCall;
      
    METHOD BadCall: BOOLEAN;
      BEGIN
      RESULT := NOT RiskyCall AND NOT SafeCall;
      END BadCall;
      
    METHOD IsMonomorphic: BOOLEAN;
      BEGIN
      RESULT := NOT RiskyCall AND SafeCall;
      END IsMonomorphic;
      
    METHOD IsPolymorphic: BOOLEAN;
      BEGIN
      RESULT := RiskyCall;
      END IsPolymorphic;

    METHOD Transitivable: BOOLEAN;
      BEGIN
      RESULT := (OptimizedMethod<>VOID) AND OptimizedMethod.TransferMethod;
      END Transitivable;
      
    -----------------------------------------
    VAR 
      TheDerivedMethods : ArrayList(MethodReference);
      
    METHOD DerivedMethods : ArrayList(MethodReference);
      VAR
        TheClass : ClassReference;
        TheMeth  : MethodReference;
        TheCall  : CallReference;
        TmpList  : List(MethodReference);
        BEGIN                                     
      IF TheDerivedMethods = VOID THEN
        TheDerivedMethods.CREATE; 
        TheClass := ClassRef.FirstDerived;
        WHILE TheClass <> VOID DO
          TheMeth := MethodDictionary.FindMethod (TheClass.Module,
                                                  TheClass.Class,
                                                  Method);
          IF TheMeth <> VOID THEN
            TheDerivedMethods.Append (TheMeth);
            END;
          TheCall := CallDictionary.FindCall (TheClass.Module, TheClass.Class,
                                              Method);
          ASSERT TheCall <> VOID;                                              
          FOR m IN TheCall.DerivedMethods DO
            TheDerivedMethods.Append(m);
            END;
          TheClass := TheClass.NextDerived;
          END;
        END;
      RESULT := TheDerivedMethods;
      END DerivedMethods;

    ------------------------------
    VAR
      TheAllocatingState : INTEGER;

    METHOD SetAllocatingState (Val : INTEGER);
      BEGIN                  
      TheAllocatingState := Val;
      END SetAllocatingState;
 
    METHOD AllocatingState : INTEGER;
      BEGIN
      RESULT := TheAllocatingState;
      END AllocatingState;

    METHOD CheckAllocatingState;
      VAR
        ExistsUnknown   : BOOLEAN;
        TheMeth: MethodReference;
      BEGIN
      TheMeth := UpMethod;
      IF TheMeth <> VOID THEN 
        TheMeth.CheckAllocatingState;
        IF TheMeth.AllocatingState <> DoesNotAllocate THEN 
          --State = Unknown OR State = Allocates
          TheAllocatingState := TheMeth.AllocatingState;
          ExistsUnknown := (TheMeth.AllocatingState = Unknown);
          END;
        END;

      FOR Meth IN DerivedMethods | 
            Meth <> VOID, Meth.AllocatingState <> DoesNotAllocate
             WHILE AllocatingState=Unknown DO
        TheAllocatingState := Meth.AllocatingState;
        ExistsUnknown := ExistsUnknown 
                             OR (Meth.AllocatingState = Unknown);
        END;
        
      IF (TheAllocatingState <> Allocates) AND NOT ExistsUnknown THEN 
        TheAllocatingState := DoesNotAllocate;
        END;                        
      END CheckAllocatingState;    
               
    ------------------------------
    VAR 
      TheGeneratedCount : INTEGER;
    
    METHOD AddGeneratedCall;
      BEGIN
      TheGeneratedCount := TheGeneratedCount + 1;
      END AddGeneratedCall;
      
    METHOD GeneratedCount: INTEGER;
      BEGIN              
      RESULT := TheGeneratedCount;
      END GeneratedCount;  
      
    ------------------------------
    
    REDEFINE METHOD Dump(Output: OutputStream);
      BEGIN    
      BASE (Output);
      IF BadCall THEN
        Output.WriteString ('Bad-');
       ELSE
        Output.WriteString ('----');
        END;
        
      CASE AllocatingState OF
        Allocates:
          Output.WriteString('Alloc ');
          END;
        DoesNotAllocate:
          Output.WriteString('NAlloc');
          END;
       ELSE      
        Output.WriteString('UAlloc');
        END;
        
      IF OptimizedMethod <> VOID THEN
        Output.WriteString (" Opt :" + OptimizedMethod.Image);
        END;
        
      IF UpMethod <> VOID THEN 
        Output.WriteString (" Up  :" + UpMethod.Image);
        END;
        
      Output.WriteLn; 
      IF DerivedMethods.Size > 0 THEN      
        Output.WriteString ("  ** Derived methods: ");
        FOR Meth IN DerivedMethods DO
          Output.WriteString (Meth.Image + " ");
          END;
         Output.WriteLn;
       END;
      
      END Dump;    
      
--    METHOD BaseCall: CallReference;
--      VAR
--        Cl: ClassReference;
--      BEGIN        
--      Cl := ClassRef.BaseClass;
--      IF Cl <> VOID THEN
--        RESULT := CallDictionary.FindCall (Cl.Module, Cl.Class, Method);
--        END;
--      END BaseCall;    
      
  END CallReference;

---------------------------------------------
  CLASS CloneCallReference;
    INHERITS CallReference;
    
    REDEFINE METHOD CREATE (Module, Class : ARRAY OF CHAR);
      BEGIN      
      BASE (Module, Class, PredefItems.Clone.Id.Data);
      END CREATE;                                      
        
    REDEFINE METHOD IsMonomorphic:BOOLEAN;
      BEGIN
      RESULT := SafeCall;
      END IsMonomorphic;
      
    REDEFINE METHOD IsPolymorphic: BOOLEAN;
      BEGIN             
      RESULT := NOT SafeCall;
      END IsPolymorphic;
      
    REDEFINE METHOD CheckAllocatingState;
      VAR
        TheMeth : MethodReference;
      BEGIN
      IF AllocatingState = CallReference.Unknown THEN
        TheMeth := UpMethod;
        IF TheMeth <> VOID THEN 
          TheMeth.SetAllocatingState (MethodReference.Allocates);
          END;
        SetAllocatingState (CallReference.Allocates);
        END;
      END CheckAllocatingState;

    REDEFINE METHOD Image : ARRAY OF CHAR;
      BEGIN
      RESULT := '(' + BASE + ')';
      END Image;
      
    END CloneCallReference;
    
---------------------------------------------
  CLASS CreateCallReference;
    INHERITS CallReference;
    
    REDEFINE METHOD CREATE (Module, Class: ARRAY OF CHAR);
      BEGIN
      BASE (Module, Class, PredefItems.Create.Id.Data);
      END CREATE;

    ---------------------------------------      
    VAR
      TheOptimizedMethod : MethodReference;
      
    REDEFINE METHOD IsMonomorphic: BOOLEAN;
      BEGIN
      RESULT := TRUE;
      END IsMonomorphic;
      
    REDEFINE METHOD IsPolymorphic: BOOLEAN;
      BEGIN
      RESULT := FALSE;
      END IsPolymorphic;
      
    REDEFINE METHOD BadCall: BOOLEAN;
      BEGIN
      RESULT := FALSE;
      END BadCall;
      
    REDEFINE METHOD OptimizedMethod: MethodReference;
      BEGIN               
      IF (TheOptimizedMethod = VOID) AND (EntryRef <> VOID) THEN
        TheOptimizedMethod := MethodDictionary.FindMethod (EntryRef.Module,
                                                           EntryRef.Class, 
                                                           EntryRef.Method);
        END;
      RESULT := TheOptimizedMethod;     
      END OptimizedMethod;
      
    REDEFINE METHOD AddPotentialMethod(MethRef : MethodReference);
      BEGIN
      END AddPotentialMethod;
                    
    REDEFINE METHOD AddPotentialDownMethod;
      BEGIN
      END AddPotentialDownMethod;
      
    REDEFINE METHOD RiskyCall : BOOLEAN;
      BEGIN
      RESULT := FALSE;
      END RiskyCall;
      
    REDEFINE METHOD SafeCall: BOOLEAN;
      BEGIN
      RESULT := TRUE;
      END SafeCall;
      
    REDEFINE METHOD Visit;
      BEGIN            
      IF NOT Visited THEN
        MarkVisited;
        IF EntryRef <> VOID THEN
          EntryRef.Visit;
          END;                   
        ClassRef.MarkCreated;
        END;
      END Visit;
      
    REDEFINE METHOD CheckAllocatingState;
      VAR
        TheMeth : MethodReference;
      BEGIN
      IF AllocatingState = CallReference.Unknown THEN
        TheMeth := UpMethod;
        IF TheMeth <> VOID THEN 
          TheMeth.SetAllocatingState (MethodReference.Allocates);
          END;
        SetAllocatingState (CallReference.Allocates);
        END;
      END CheckAllocatingState;

    REDEFINE METHOD Image : ARRAY OF CHAR;
      BEGIN
      RESULT := '(' + BASE + ')';
      END Image;
      
  END CreateCallReference;
---------------------------------------------
  CLASS CallReferenceList;
    INHERITS List(CallReference);
    
    REDEFINE METHOD ShouldSwap (One, Two: CallReference): BOOLEAN;
      BEGIN
      RESULT := One.HashValue > Two.HashValue;
      END ShouldSwap;
      
    METHOD Compress;
      BEGIN
      Sort;
      FOR i := Size - 1 TO 1 BY -1 DO
        IF Get(i) = Get(i-1) THEN
          Delete(i);
          END;
        END;
      END Compress;
      
  END CallReferenceList;
---------------------------------------------
  CLASS EntryReference;
    INHERITS TernaryReference;
    
    REDEFINE METHOD CREATE (Module, Class, Method : ARRAY OF CHAR);
      BEGIN
      BASE (Module, Class, Method);
      END CREATE;
  
    ------------------------------------------   
    VAR 
      TheNextEntry: EntryReference;

    REDEFINE METHOD Insert;
      VAR
        TheRef : EntryReference;
      BEGIN         
      DEBUG
        TheRef := ClassRef.FirstEntry;
        WHILE (TheRef <> VOID) AND (TheRef <> THIS) DO
          TheRef := TheRef.NextEntry;
          END; -- WHILE
        ASSERT TheRef <> THIS;
        END; -- DEBUG
      TheNextEntry := ClassRef.FirstEntry;
      ClassRef.SetFirstEntry (THIS);
      END Insert;
      
    METHOD NextEntry: EntryReference; -- Within the class...
      BEGIN                      
      RESULT := TheNextEntry;
      END NextEntry;         
                                  
    METHOD OptimizedMethod : MethodReference;
      BEGIN               
      RESULT := CallRef.OptimizedMethod;
      END OptimizedMethod;
                                     
    METHOD BadCall : BOOLEAN;
      BEGIN        
      RESULT := CallRef.BadCall;
      END BadCall;      
      
    METHOD IsMonomorphic: BOOLEAN; 
      BEGIN                  
      RESULT := CallRef.IsMonomorphic;
      END IsMonomorphic;
      
    METHOD IsPolymorphic: BOOLEAN;
      BEGIN
      RESULT := CallRef.IsPolymorphic;
      END IsPolymorphic;
      
    ----------------------------------------      
    METHOD GenerateAnchorId (Output : YaflGC);
      BEGIN
      Output.Anchor (Module, Class, Method);
      END GenerateAnchorId;               
      
    ----------------------------------------      
    REDEFINE METHOD Dump (Output: OutputStream);
      BEGIN
      BASE (Output); 
      IF IsPolymorphic THEN
        Output.WriteString ('Poly');
       ELSE
        Output.WriteString ('----');
        END;
      IF IsMonomorphic THEN
        Output.WriteString ('Mono');
       ELSE
        Output.WriteString ('----');
        END;
      IF OptimizedMethod <> VOID THEN
        Output.WriteString ("  Opt:" + OptimizedMethod.Image);
        END;
      Output.WriteLn;
      END Dump;
      
  END EntryReference;
---------------------------------------------
  CLASS MethodReference;
    INHERITS TernaryReference;
    VAR
      TheEnclosing : MethodReference;
      
    METHOD Enclosing : MethodReference;
      BEGIN                
      RESULT := TheEnclosing;
      END Enclosing;
      
    METHOD SetEnclosing (MethRef : MethodReference);  
      BEGIN                  
      TheEnclosing := MethRef;
      END SetEnclosing;
      
    VAR
      ThePreviousRedefines : MethodReference;

    METHOD Redefines: MethodReference;
      VAR
        Base : ClassReference; 
      BEGIN
      IF (ThePreviousRedefines = VOID) THEN
        Base :=  ClassRef.BaseClass;
        WHILE (Base <> VOID) AND (ThePreviousRedefines = VOID) DO
          ThePreviousRedefines := MethodDictionary.FindMethod 
                                      (Base.Module, Base.Class, THIS.Method);
          Base := Base.BaseClass;                                     
          END;
        END;
      RESULT := ThePreviousRedefines; 
      END Redefines;

    VAR 
      TheNextMethod : MethodReference;

    REDEFINE METHOD Insert;
      VAR
        TheRef : MethodReference;
      BEGIN                      
      DEBUG
        TheRef := ClassRef.FirstMethod;
        WHILE (TheRef <> VOID) AND (TheRef <> THIS) DO
          TheRef := TheRef.NextMethod;
          END; -- WHILE
        ASSERT TheRef <> THIS;  
        END; -- DEBUG
      TheNextMethod := ClassRef.FirstMethod;
      ClassRef.SetFirstMethod (THIS);
      END Insert;
          
    METHOD NextMethod: MethodReference; -- Within the class...
      BEGIN
      RESULT := TheNextMethod;
      END NextMethod;
      
    ---------------------------------------------
    METHOD UsefulRootMethod : BOOLEAN;
      BEGIN
      RESULT := (EntryRef.Useful AND (EntryRef.ClassRef = ClassRef));
      END UsefulRootMethod;
      
    ---------------------------------------------
    METHOD MarkCallReferences;
      VAR
        CurCall : CallReference;
	    -- XXL
	    EntryCall: CallReference;
	    -- END XXL
        
      METHOD VisitDerivedClasses (RootCl: ClassReference);
        VAR
          Cl: ClassReference;
        BEGIN
        ASSERT RootCl <> VOID;
        Cl := RootCl.FirstDerived;
        WHILE Cl <> VOID DO
          IF MethodDictionary.DoFind(Cl.Module, Cl.Class, Method) = VOID THEN
            CallDictionary.FindCall (Cl.Module, Cl.Class, Method).
                               AddPotentialMethod (THIS);          
            VisitDerivedClasses(Cl);
            END;                           
          Cl := Cl.NextDerived;
          END;
        END VisitDerivedClasses;
        
      BEGIN                       
      CurCall := THIS.CallRef;
	  -- XXL 
	  ----------------------------------------
	  -- There is a method applicable on the entry.
	  -- The call is polymorphic iff the method is 
	  -- defined in a derived class from the entry class.
	  ----------------------------------------
	  EntryCall := CurCall.EntryRef.CallRef;
	  IF CurCall <> EntryCall THEN
	    EntryCall.AddPotentialDownMethod;
	    END;
	  -- END XXL
      WHILE (CurCall <> VOID) AND
            (CurCall.ClassRef <> CurCall.EntryRef.ClassRef) DO
        -- XXL    
        CurCall := CurCall.UpCall;
        -- END XXL
        IF CurCall <> VOID THEN
          CurCall.AddPotentialDownMethod;
          END;
        END;  
      THIS.CallRef.AddPotentialMethod (THIS);
      VisitDerivedClasses (ClassRef);
      END MarkCallReferences;
    
    ---------------------------------------------
    VAR
      TheSimpleAssignment,
      TheSimpleQuery,
      TheSimpleLiteral      : ARRAY OF CHAR;
      TheDoesNothing        : BOOLEAN;
      
      --------------------------
      -- The two following attributes are used for
      -- transitive consultation:
      --   * TheAttrib is the atribute on which the method is applied
      --   * TheCallRef is the call applied on that attribute
      --   * TheAssignToResult is set when it is a function
      --------------------------
      TheAttrib             : AttributeReference;
      TheCallRef            : CallReference;
      TheAssignToResult     : BOOLEAN;
      
    METHOD SetSimpleTransfer(AttribRef : AttributeReference; 
                             CallRef   : CallReference);
      BEGIN
      TheAttrib  := AttribRef;
      TheCallRef := CallRef;
      END SetSimpleTransfer;
                                 
    METHOD TransferPosition: INTEGER;
      BEGIN
      IF TransferMethod THEN
        IF CallApplied.Transitivable THEN
          RESULT := CallApplied.OptimizedMethod.TransferPosition + 1;
         ELSE
          RESULT := 1;
          END;
        END;
      END TransferPosition;
      
    METHOD SetAssignToResult;
      BEGIN
      TheAssignToResult := TRUE;
      END SetAssignToResult;
                       
    METHOD SetSimpleAssignment (Name : ARRAY OF CHAR);
      BEGIN                   
      TheSimpleAssignment := Name;
      END SetSimpleAssignment;
      
    METHOD SetSimpleQuery (Name : ARRAY OF CHAR);
      BEGIN
      TheSimpleQuery := Name;
      END SetSimpleQuery;

    METHOD SetSimpleLiteral (Value : ARRAY OF CHAR);
      BEGIN                
      TheSimpleLiteral := Value;
      END SetSimpleLiteral;
                       
    METHOD SetDoesNothing;
      BEGIN           
      TheDoesNothing := TRUE;
      END SetDoesNothing;

    METHOD SimpleAssignment: ARRAY OF CHAR;
      BEGIN
      RESULT := TheSimpleAssignment;
      END SimpleAssignment;
      
    METHOD SimpleQuery: ARRAY OF CHAR;
      BEGIN
      RESULT := TheSimpleQuery;
      END SimpleQuery;
      
    METHOD SimpleLiteral: ARRAY OF CHAR;
      BEGIN
      RESULT := TheSimpleLiteral;
      END SimpleLiteral;

    METHOD TransferMethod: BOOLEAN;
      BEGIN
      RESULT := CallApplied <> VOID;      
      END TransferMethod;
      
    METHOD CallApplied: CallReference;
      BEGIN
      RESULT := TheCallRef;
      END CallApplied;
      
    METHOD ConsultedAttribute: AttributeReference;
      BEGIN
      RESULT := TheAttrib;
      END ConsultedAttribute;      
      
    METHOD AssignToResult: BOOLEAN;
      BEGIN
      RESULT := TheAssignToResult;
      END AssignToResult;
      
    METHOD DoesNothing: BOOLEAN;
      BEGIN
      RESULT := TheDoesNothing;
      END DoesNothing;
      
    METHOD InLine : BOOLEAN;
      BEGIN
      RESULT := (SimpleAssignment <> VOID) OR 
                (SimpleQuery <> VOID) OR 
                (SimpleLiteral <> VOID) OR 
                DoesNothing;
      END InLine;

    ------------------------------------------
    VAR
      TheCyclomaticComplexity : INTEGER;
      
    METHOD SetCyclomaticComplexity (CyclomaticComplexity : INTEGER);
      BEGIN                             
      TheCyclomaticComplexity := CyclomaticComplexity;
      END SetCyclomaticComplexity;
    
    METHOD CyclomaticComplexity : INTEGER;
      BEGIN
      RESULT := TheCyclomaticComplexity;
      END CyclomaticComplexity;

    -----------------------------------------
    VAR
      TheCallBackFlag : BOOLEAN;
        
    METHOD SetCallBack;
      BEGIN
      TheCallBackFlag := TRUE;
      END SetCallBack;
      
    METHOD IsCallBack : BOOLEAN;
      BEGIN
      RESULT := TheCallBackFlag;
      END IsCallBack;
                             
    -----------------------------------------
    VAR
      ThePublishedFlag : BOOLEAN;
        
    METHOD SetPublished;
      BEGIN
      ThePublishedFlag := TRUE;
      END SetPublished;
      
    METHOD IsPublished : BOOLEAN;
      BEGIN
      RESULT := ThePublishedFlag;
      END IsPublished;
                             
    -----------------------------------------
    VAR 
      TheCallsBase : BOOLEAN;
      TheCalls     : ARRAY OF CallReference;
            
    METHOD SetCalls (Calls : ARRAY OF CallReference;
                     CallsBase: BOOLEAN);
      BEGIN
      TheCallsBase := CallsBase;
      TheCalls := Calls;
      END SetCalls;
      
    METHOD Calls : ARRAY OF CallReference;
      BEGIN
      RESULT := TheCalls;
      END Calls;

    METHOD AllCalls : ARRAY OF CallReference;
      VAR
        Temp: ARRAY OF CallReference;
        c: CallReference;
      BEGIN
      RESULT := Calls;
      IF TheCallsBase THEN
        c := CallRef.BaseCall;
        IF c <> VOID THEN
          Temp.CREATE (1);
          Temp[0] := c;
          RESULT := RESULT + Temp;
          END;
        END;
      END AllCalls;
      
    REDEFINE METHOD Visit;
      VAR
        c: CallReference;
      BEGIN
      IF YaflCfg.VerboseLevel > 0 THEN     
        StdOut.WriteLine ("Visiting method: " + Image);
        END;
      ASSERT Visited;
      FOR Call IN Calls | Call <> VOID DO
        Call.Visit;
        END;
      IF TheCallsBase THEN
        c := CallRef.BaseCall;
        IF c <> VOID THEN
          c.Visit;
          END;
        END;
      END Visit;

    -----------------------------------------
    VAR
      UsesValueStackFlag : BOOLEAN;
      TheAllocatingState : INTEGER;
      
    METHOD SetUsesValueStack (Val : BOOLEAN);
      BEGIN                 
      UsesValueStackFlag := Val;
      END SetUsesValueStack;
      
    METHOD UsesValueStack : BOOLEAN;
      BEGIN
      RESULT := UsesValueStackFlag;
      END UsesValueStack;
           
    METHOD SetAllocatingState (Val : INTEGER);
      BEGIN
      TheAllocatingState := Val;
      END SetAllocatingState;
      
    METHOD AllocatingState : INTEGER;
      BEGIN
      RESULT := TheAllocatingState;
      END AllocatingState;
            
    ----------------------------
    -- Check if this method might perform an allocation.
    -- RESULT = TRUE : This method might perform allocations
    -- RESULT = FALSE: THis method cannot perform any allocation 
    ----------------------------  
    METHOD CheckAllocatingState;
      VAR
        Tmp        : INTEGER;
                                  
      ----------------------------
      -- Checks if the BASE method performs allocations
      ----------------------------
      METHOD BaseState: INTEGER;
        VAR
          TheCall  : CallReference;
          TheClass : ClassReference;
          TheMeth  : MethodReference;
        BEGIN
        TheClass := ClassRef.BaseClass;
        IF TheClass <> VOID THEN 
          TheCall := CallDictionary.FindCall (TheClass.Module, 
                                              TheClass.Class,
                                              Method);
          ASSERT TheCall <> VOID;
          TheMeth := TheCall.UpMethod;                                              
          IF TheMeth <> VOID THEN
            RESULT := TheMeth.AllocatingState;
           ELSE
            RESULT := DoesNotAllocate;
            END;
         ELSE
          RESULT := DoesNotAllocate;
          END;
        END BaseState;
            
      BEGIN
      IF UsesValueStack OR (Method = PredefItems.Clone.Id.Data) THEN
        -- The CREATE case is already handled through CreateCallReference
        TheAllocatingState := Allocates;
       ELSE
        IF TheCallsBase THEN
          Tmp := BaseState;
          IF Tmp <> DoesNotAllocate THEN
            TheAllocatingState := Tmp;
            END;
          END;
        FOR Call IN Calls | Call <> VOID WHILE AllocatingState=Unknown DO 
          Tmp := Call.AllocatingState;
          IF Tmp <> DoesNotAllocate THEN
            TheAllocatingState := Tmp;
            END;
          END;

        IF AllocatingState = Unknown THEN
          TheAllocatingState := DoesNotAllocate;
          END;
        END;      
      END CheckAllocatingState;
    
    -----------------------------------------
    METHOD GenerateMethodRef (Output: YaflGC);    
      BEGIN
      Output.MethodStructRef(Module, Class, Method);
      END GenerateMethodRef;     
           
    -----------------------------------------
    REDEFINE METHOD Dump(Output: OutputStream);
      BEGIN              
      BASE (Output);
      IF UsesValueStackFlag THEN
        Output.WriteString('VSt-');
       ELSE
        Output.WriteString('----');
        END;

      CASE AllocatingState OF
        Allocates:
          Output.WriteString('Alloc-');
          END;
        DoesNotAllocate:
          Output.WriteString('NAlloc');
          END;
       ELSE      
        Output.WriteString('UAlloc');
        END;
        
      Output.WriteString (' Derived:');
      Output.WriteInt (CallRef.DerivedMethods.Size, 4);
      
      Output.WriteString (' Calls:');
      IF Calls = VOID THEN
        Output.WriteString ('   0');
       ELSE
        Output.WriteInt (Calls.SIZE, 4);
        END;
      IF TheCallsBase THEN
        Output.WriteString ('CallsBase');
       ELSE
        Output.WriteString ('---------');
        END;
      IF EntryRef <> VOID THEN
        Output.WriteString ('   Entry:'+ EntryRef.Module + '.' + 
                            EntryRef.Class + '.' + EntryRef.Method+' ');
        END;        
        
      IF TransferMethod THEN
        Output.WriteString(' *Trans* ');
        IF AssignToResult THEN
          Output.WriteString ('RESULT := ');
          END;
        IF (ConsultedAttribute<>VOID) THEN   
          Output.WriteString('(' + ConsultedAttribute.Image + ')->');
         ELSE
          Output.WriteString("(THIS)->");
          END;
        Output.WriteString(CallApplied.Image + " (");
        Output.WriteInt(TransferPosition, 2);
        Output.WriteString(")");
        END;
        
      Output.WriteLn;
      END Dump;
                               
    ---------------------------------------------
    VAR
      TheMonomorphable : BOOLEAN;
      
    METHOD Monomorphable: BOOLEAN;
      BEGIN
      RESULT := TheMonomorphable;
      END Monomorphable;
                                 
    METHOD SetMonomorphable;
      BEGIN
      TheMonomorphable := TRUE;
      END SetMonomorphable;
    
  END MethodReference;
---------------------------------------------
  CLASS ConstReference;
    INHERITS TernaryReference;
    VAR 
      TheNextConst : ConstReference;

    REDEFINE METHOD Insert;
      VAR
        TheRef : ConstReference;
      BEGIN
      DEBUG
        TheRef := ClassRef.FirstConst;
        WHILE (TheRef <> VOID) AND (TheRef <> THIS) DO
          TheRef := TheRef.NextConst;
          END; -- WHILE
        ASSERT TheRef <> THIS;
        END; -- DEBUG
      TheNextConst := ClassRef.FirstConst;
      ClassRef.SetFirstConst (THIS);
      END Insert;
      
    METHOD NextConst: ConstReference; -- Within the class...
      BEGIN
      RESULT := TheNextConst;
      END NextConst;
      
    END ConstReference;
  -------------------------------------    
  CLASS AttributeReference;   
    INHERITS TernaryReference;
    VAR 
      TheNextAttribute : AttributeReference;

    REDEFINE METHOD Insert;
      VAR
        TheRef : AttributeReference;
      BEGIN
      DEBUG
        TheRef := ClassRef.FirstAttribute;
        WHILE (TheRef <> VOID) AND (TheRef <> THIS) DO
          TheRef := TheRef.NextAttribute;
          END; -- WHILE
        ASSERT TheRef <> THIS;
        END; -- DEBUG
      TheNextAttribute := ClassRef.FirstAttribute;
      ClassRef.SetFirstAttribute (THIS);
      END Insert;
      
    METHOD NextAttribute: AttributeReference; -- Within the class...
      BEGIN
      RESULT := TheNextAttribute;
      END NextAttribute;
      
    END AttributeReference;
---------------------------------------------
  CLASS ClassReference;
    INHERITS BinaryReference;

    VAR
      TheFirstDerived, 
      TheNextDerived,    
      TheBaseClass        : ClassReference;
      TheProperCreations,
      TheDerivedCreations: INTEGER;
      
    REDEFINE METHOD CREATE (Module, Class : ARRAY OF CHAR);
      BEGIN
      BASE (Module, Class);
      IF Class <> VOID THEN
        VOID := ModuleRef;
        END;
      END CREATE;
                        
    VAR 
      TheModuleRef : ModuleReference;
      
    METHOD ModuleRef : ModuleReference;
      BEGIN
      IF TheModuleRef = VOID THEN
        TheModuleRef := ModuleDictionary.FindModule (Module);
        END; -- IF
      RESULT := TheModuleRef;   
      END ModuleRef;
      
    REDEFINE METHOD Insert;
      VAR
        TheRef : ClassReference;
      BEGIN                      
      DEBUG
        TheRef := ModuleRef.FirstClass;
        WHILE (TheRef <> VOID) AND (TheRef <> THIS) DO
          TheRef := TheRef.NextClass;
          END; -- WHILE
        ASSERT TheRef <> THIS;
        END; -- DEBUG
      TheNextClass := ModuleRef.FirstClass;
      ModuleRef.SetFirstClass (THIS);
      END Insert;   
      
    VAR
      TheNextClass : ClassReference;
         
    METHOD NextClass : ClassReference;
      BEGIN
      RESULT := TheNextClass;
      END NextClass;

    METHOD SetBaseClass (BaseClass : ClassReference);
      VAR 
        TheRef : ClassReference;
      BEGIN                  
      ASSERT BaseClass <> THIS;
      TheBaseClass := BaseClass;
      TheRef := BaseClass.FirstDerived;
      WHILE (TheRef <> VOID) AND (TheRef <> THIS) DO           
        TheRef := TheRef.NextDerived;
        END; -- WHILE                              
      IF TheRef = VOID THEN
        TheNextDerived := BaseClass.FirstDerived; 
        BaseClass.SetFirstDerived (THIS);
        END; -- IF
      END SetBaseClass;
      
    METHOD BaseClass: ClassReference;
      BEGIN
      RESULT := TheBaseClass;
      END BaseClass;      
      
    METHOD SetFirstDerived (DerivedClass : ClassReference);
     BEGIN         
     TheFirstDerived := DerivedClass;
     ASSERT DerivedClass.BaseClass = THIS;
     END SetFirstDerived; 
      
    METHOD FirstDerived: ClassReference;
      BEGIN
      RESULT := TheFirstDerived;
      END FirstDerived;
      
    METHOD NextDerived: ClassReference;
      BEGIN
      RESULT := TheNextDerived;           
      ASSERT (RESULT <> VOID) IMPLIES (RESULT.BaseClass = BaseClass);
      END NextDerived;

    ------------------------------------------
    VAR
      TheCyclomaticComplexity : INTEGER;
      
    METHOD SetCyclomaticComplexity (CyclomaticComplexity : INTEGER);
      BEGIN                             
      TheCyclomaticComplexity := CyclomaticComplexity;
      END SetCyclomaticComplexity;
    
    METHOD CyclomaticComplexity : INTEGER;
      BEGIN
      RESULT := TheCyclomaticComplexity;
      END CyclomaticComplexity;
            
    ------------------------------------------
    VAR                         
      TheFirstMethod      : MethodReference;
      
    METHOD SetFirstMethod (Method : MethodReference);
      BEGIN              
      TheFirstMethod := Method;
      END SetFirstMethod;
      
    METHOD FirstMethod: MethodReference;
      BEGIN           
      RESULT := TheFirstMethod;
      END FirstMethod;
    ------------------------------------------
    VAR                         
      TheFirstConst      : ConstReference;
                        
    METHOD SetFirstConst (Const : ConstReference);
      BEGIN              
      TheFirstConst := Const;
      END SetFirstConst;
      
    METHOD FirstConst: ConstReference;
      BEGIN           
      RESULT := TheFirstConst;
      END FirstConst;
    ------------------------------------------
    VAR                         
      TheFirstAttribute     : AttributeReference;
      
    METHOD SetFirstAttribute (Attribute : AttributeReference);
      BEGIN              
      TheFirstAttribute := Attribute;
      END SetFirstAttribute;
      
    METHOD FirstAttribute: AttributeReference;
      BEGIN           
      RESULT := TheFirstAttribute;
      END FirstAttribute;
    ------------------------------------------
    VAR                         
      TheFirstEntry      : EntryReference;
      
    METHOD SetFirstEntry (Entry : EntryReference);
      BEGIN              
      TheFirstEntry := Entry;
      END SetFirstEntry;
      
    METHOD FirstEntry: EntryReference;
      BEGIN           
      RESULT := TheFirstEntry;
      END FirstEntry;
      
    ------------------------------------------
    VAR 
      TheOnceFlag : BOOLEAN; 
     
    METHOD SetOnce (Val : BOOLEAN);
      BEGIN
      TheOnceFlag := Val;
      END SetOnce;
        
    METHOD IsOnce : BOOLEAN;
      BEGIN
      RESULT := TheOnceFlag;
      END IsOnce;  
           
    ------------------------------------------
    VAR
      TheKeepDual : BOOLEAN;
      
    METHOD DoKeepDual;
      BEGIN 
      IF NOT TheKeepDual THEN
        TheKeepDual := TRUE;
        IF BaseClass <> VOID THEN 
          BaseClass.DoKeepDual;
          END;
        END;
      END DoKeepDual;
      
    METHOD KeepDual : BOOLEAN;
      POST
        NO_CHANGE;
      BEGIN
      RESULT := TheKeepDual;
      END KeepDual;
      
    REDEFINE METHOD Visit;
      BEGIN
      BASE;
      IF BaseClass <> VOID THEN
        BaseClass.Visit;
        END;
      END Visit;               

    METHOD PropagateUseful;
      BEGIN
      IF (Useful) AND (BaseClass<>VOID) THEN
        UnRemove;
        BaseClass.PropagateUseful;        
        END;
      END PropagateUseful;
      
    ------------------------------------------
    VAR
      TheCreateMethod  : MethodReference;
      CreateSearched   : BOOLEAN;
      
    METHOD Create: MethodReference;
      BEGIN
      IF NOT CreateSearched THEN
        CreateSearched := TRUE;
        TheCreateMethod := MethodDictionary.FindMethod (Module, Class, 
                                                  PredefItems.Create.Id.Data);
        ASSERT FALSE;           -- CREATE in a base class???
        END;
      RESULT := TheCreateMethod;
      END Create;            
      
    ------------------------------------------
    METHOD VisitObliviousMethods;
      VAR
        MRef : MethodReference;
      BEGIN              
      --------------------------
      -- Clone & Kill methods are to be visited
      -- The CREATE method has also to be visited
      -- for ONCE classes.
      --------------------------
      ASSERT NOT Created;
      MRef := FirstMethod;
      WHILE MRef <> VOID DO
        IF (MRef.Method = PredefItems.Clone.Id.Data) OR
           (MRef.Method = PredefItems.Kill.Id.Data) OR
           (MRef.Method = PredefItems.Create.Id.Data) THEN
          -- No polymorphic call is performed on such method calls
          MRef.CallRef.Visit;
          MRef.EntryRef.Visit;
          MethodQueue.Push(MRef);
          MRef.CallRef.Increment;
          
         ELSIF (MRef.IsCallBack) OR (MRef.IsPublished) THEN 
          -- A polymorphic call could be required
          MRef.CallRef.Visit;
          END;
        MRef := MRef.NextMethod;
        END;
      END VisitObliviousMethods;
                     
    METHOD MarkCreated;
      VAR
        Cl: ClassReference;
      BEGIN 
      Visit;              
      IF NOT Created THEN
        VisitObliviousMethods;
        END;
      TheProperCreations := TheProperCreations + 1;      
      Cl := BaseClass;
      WHILE Cl <> VOID DO
        Cl.Visit;
        IF NOT Cl.Created THEN
          Cl.VisitObliviousMethods;
          END;
        Cl.TheDerivedCreations := Cl.TheDerivedCreations + 1;
        ASSERT Cl.Created;
        Cl := Cl.BaseClass;
        END;
      END MarkCreated;
                     
    METHOD Created : BOOLEAN;
      BEGIN
      RESULT := (TheProperCreations > 0) OR (TheDerivedCreations > 0);
      END Created;
            
    REDEFINE METHOD Clear;
      BEGIN      
      BASE;
      TheProperCreations := 0;
      TheDerivedCreations := 0;
      ASSERT NOT Created;
      END Clear;
     
    ------------------------------------------
    REDEFINE METHOD Useful : BOOLEAN;
      BEGIN
      RESULT := (Created OR KeepDual OR Visited) AND BASE;
      END Useful;
      
    METHOD BadCall : BOOLEAN;
      BEGIN
      RESULT := Visited AND NOT Created;
      END BadCall;

    ------------------------------------------
    METHOD GenerateCast (Output: YaflGC);
      BEGIN
      Output.LeftParent;
      Output.Class (Module, Class);
      Output.Star;
      Output.RightParent;
      END GenerateCast;
                
    ------------------------------------------
    REDEFINE METHOD Dump(Output: OutputStream);
      VAR
        a: ARRAY OF CHAR;
      BEGIN              
      a := Image + "                                                                        ";
      Output.WriteString (a.SLICE (0, 60));
      IF IsOnce THEN
        Output.WriteString ('Once-');
       ELSE
        Output.WriteString ('-----');
        END;
      IF Useful THEN
        Output.WriteString ('Use-');
       ELSE
        Output.WriteString ('----');
        END;
      IF Removed THEN
        Output.WriteString ('Rem-');
       ELSE
        Output.WriteString ('----');
        END;
      IF Visited THEN
        Output.WriteString ('Vis-');
       ELSE
        Output.WriteString ('----');
        END;
      IF Created THEN
        Output.WriteString ('Cre-');
       ELSE
        Output.WriteString ('----');
        END;    
      IF KeepDual THEN
        Output.WriteString ('Dual');
       ELSE
        Output.WriteString ('----');
        END;    
      IF BaseClass <> VOID THEN
        Output.WriteString (' Base: ' + BaseClass.Image);
        END;    
      Output.WriteLn;
      END Dump;      
      
  END ClassReference;
---------------------------------------------
  CLASS ModuleReference;
    INHERITS UnaryReference;
                     
    REDEFINE METHOD Dump (Output : OutputStream);
      BEGIN    
      Output.WriteLine (Image);
      END Dump;                      
                                    
    -------------------------------------------                          
    VAR
      TheWorld : ARRAY OF CHAR;
      
    METHOD SetWorld (World : ARRAY OF CHAR);
      BEGIN        
      TheWorld := World;
      END SetWorld;     
      
    METHOD World : ARRAY OF CHAR;
      BEGIN     
      RESULT := TheWorld;
      END World;  

    -------------------------------------------                          
    VAR
      TheFirstClass : ClassReference;
        
    METHOD SetFirstClass (Class : ClassReference);
      BEGIN                   
      TheFirstClass := Class;
      END SetFirstClass;
      
    METHOD FirstClass: ClassReference;
      BEGIN
      RESULT := TheFirstClass;
      END FirstClass;
      
  END ModuleReference;
---------------------------------------------
  CLASS UnaryDictionary (Element IN UnaryReference);
    INHERITS ArrayList(Element);
    
    VAR
      Storage     : HashSpace(Element);

    REDEFINE METHOD CREATE;
      BEGIN      
      BASE;
      Storage.CREATE (128);
      Zap;
      END CREATE;
                      
    METHOD Store (El: Element): BOOLEAN;
      VAR
        i: INTEGER;
      BEGIN                         
      i := Storage.AllocatedSize;
      IF i - Storage.Stored < i / 3 THEN
        Storage.Resize (i + i / 2);
        END;
      RESULT := Storage.Store(El); 
      IF RESULT THEN
        Append (El);
        END;
      END Store;
                         
    METHOD Collisions : INTEGER;
      BEGIN
      RESULT := Storage.Collisions;
      END Collisions;

    METHOD TheoreticalCollisions: REAL;
      VAR
         k, n: INTEGER;  
        
      METHOD Q(k, p: INTEGER): REAL;
        BEGIN
        IF (k >= 0) AND (p >= 0) THEN 
          IF k = 0 THEN
            IF p = 0 THEN
              RESULT := 1.0;
             ELSE
              RESULT := 0.0;
              END;
           ELSE 
            RESULT := (Q(k-1, p)*SYSTEM.FLOAT(n-k)+ Q(k-1, p-1))/
                            SYSTEM.FLOAT(n-k+1);
            END;
          END;
        END Q;
                
      BEGIN 
      k := Size;
      n := Storage.AllocatedSize;
      FOR i := 0 TO k DO
        RESULT := RESULT + SYSTEM.FLOAT(i) * Q(k, i);
        END; 
      END TheoreticalCollisions;
      
    METHOD LargestBucket : INTEGER;
      BEGIN
      RESULT := Storage.LargestBucket;
      END LargestBucket;
                                      
    METHOD Find (i : INTEGER): Element;
      BEGIN
      RESULT := Storage.Find (i);
      END Find;
                
    METHOD Next : Element; 
      BEGIN
      RESULT := Storage.Next;
      END Next;
      
    METHOD Clear;
      BEGIN
      FOR x IN THIS DO
        x.Clear;
        END;
      END Clear;
     
    METHOD Zap;
      CONST
        InitialSize = 128;
      BEGIN   
      Purge;
      Storage.CREATE (InitialSize);
      END Zap;  
      
    ----------------------------------------
    METHOD ToString(i : INTEGER): ARRAY OF CHAR;
      BEGIN
      RESULT := IntConversions.IntToString (i, 4);
      END ToString;

    METHOD Dump(FName : ARRAY OF CHAR);
      VAR
        Output: OutputStream;
      BEGIN                             
      Output.CREATE;
      Output.Create (FName, Output.WriteAccess);
      FOR x IN THIS DO
        x.Dump(Output);
        END;
      Output.Close;
      END Dump;

    METHOD Stats (Output : OutputStream);
      BEGIN     
      Output.WriteLine ("Cardinality            :" + ToString(Size));
      Output.WriteLine ("Collisions             :" + ToString(Collisions));
      Output.WriteLine ("Bucket                 :" + ToString(LargestBucket));
      END Stats;
      
  END UnaryDictionary;
---------------------------------------------
  CLASS BinaryDictionary (Element IN BinaryReference);
    INHERITS UnaryDictionary(Element);
      
    METHOD RemoveUseless;
      BEGIN        
      FOR x IN THIS | NOT x.Useful DO
        x.Remove;
        END;
      END RemoveUseless;
    ----------------------------------------
    METHOD UsefulCount: INTEGER;
      BEGIN        
      FOR x IN THIS | x.Useful DO
        RESULT := RESULT + 1;
        END;
      END UsefulCount;
      
    REDEFINE METHOD Stats (Output : OutputStream);
      BEGIN
      BASE (Output);
      Output.WriteLine ("Useful                 : "+ToString(UsefulCount));
      END Stats;
      
    END BinaryDictionary;
---------------------------------------------
  CLASS TernaryDictionary (Element IN TernaryReference);
    INHERITS BinaryDictionary(Element);

    VAR 
      TheSearchElement : TernaryReference;
    
    REDEFINE METHOD CREATE;
      BEGIN
      TheSearchElement.CREATE (VOID, VOID, VOID);
      BASE;
      END CREATE;
    
    METHOD DoFind (Module, Class, Meth: ARRAY OF CHAR): Element;
      VAR
        Index : INTEGER;
        Found : BOOLEAN;
      BEGIN
      ASSERT Space.StoreString (Meth) = Meth;
      ASSERT Space.StoreString (Class) = Class;
      ASSERT Space.StoreString (Module) = Module;
      TheSearchElement.RenameTernary (Module, Class, Meth);
      Index := TheSearchElement.HashValue;
      RESULT := Find(Index);      
      WHILE NOT Found AND (RESULT <> VOID) DO
        Found := (RESULT.Method = Meth) AND (RESULT.Class = Class) AND
                 (RESULT.Module = Module);
        IF NOT Found THEN 
          RESULT := Next;
          END;
        END; 
      END DoFind;                           
      
    ----------------------------------------
    METHOD FillStructure;
      BEGIN
      FOR x IN THIS DO
        VOID := x.ClassRef;
        END;
      END FillStructure;
      
  END TernaryDictionary;
---------------------------------------------
  ONCE CLASS AttributeDictionary;        
    INHERITS TernaryDictionary(AttributeReference);
    
    REDEFINE METHOD CREATE;
      BEGIN
      BASE;
      END CREATE;
  
    METHOD FindAttribute (Module, Class, Attr: ARRAY OF CHAR)
                                             : AttributeReference;
      BEGIN  
      RESULT := DoFind (Module, Class, Attr);
      IF RESULT = VOID THEN
        RESULT.CREATE (Module, Class, Attr);
        RESULT.Insert;
        IF NOT Store (RESULT) THEN
          ASSERT FALSE;
          END; -- IF
        END; -- IF 
      ASSERT RESULT <> VOID;    
      END FindAttribute;
             
    REDEFINE METHOD Stats (Output: OutputStream);
      BEGIN                                     
      Output.WriteLn;
      Output.WriteLine ("Attribute dictionary:");
      Output.WriteLine ("---------------------");
      BASE (Output);
      END Stats;
    
  END AttributeDictionary;  
---------------------------------------------
  ONCE CLASS ConstDictionary;
    INHERITS TernaryDictionary(ConstReference);
    
    REDEFINE METHOD CREATE;
      BEGIN
      BASE;
      END CREATE;
  
    METHOD FindConst (Module, Class, Const: ARRAY OF CHAR): ConstReference;
      BEGIN  
      RESULT := DoFind (Module, Class, Const);
      IF RESULT = VOID THEN
        RESULT.CREATE (Module, Class, Const);
        RESULT.Insert;         
        IF NOT Store (RESULT) THEN
          ASSERT FALSE;
          END; -- IF 
        END; -- IF                      
      ASSERT RESULT <> VOID;    
      END FindConst;
             
    REDEFINE METHOD Stats (Output: OutputStream);
      BEGIN                                     
      Output.WriteLn;
      Output.WriteLine ("Const dictionary:");
      Output.WriteLine ("-----------------");
      BASE (Output);
      END Stats;
    
  END ConstDictionary;  
---------------------------------------------
  ONCE CLASS CallDictionary;
    INHERITS TernaryDictionary(CallReference);
    
    REDEFINE METHOD CREATE;
      BEGIN
      BASE;
      END CREATE;
  
    METHOD FindCall (Module, Class, Meth: ARRAY OF CHAR): CallReference;
      VAR
        Found: BOOLEAN;
        CreateRef : CreateCallReference;
        CloneRef  : CloneCallReference;
      BEGIN  
      RESULT := DoFind (Module, Class, Meth);
      IF RESULT = VOID THEN
        IF Meth = PredefItems.Create.Id.Data THEN
          CreateRef.CREATE (Module, Class);
          RESULT := CreateRef;
         ELSIF Meth = PredefItems.Clone.Id.Data THEN
          CloneRef.CREATE (Module, Class);
          RESULT := CloneRef;
         ELSE
          RESULT.CREATE (Module, Class, Meth);
          END;
        Found := Store(RESULT);
        ASSERT Found;
        ASSERT RESULT = DoFind (Module, Class, Meth);
        END;
      END FindCall;
             
    METHOD IncrementCall (Module, Class , Method : ARRAY OF CHAR);
      BEGIN 
      FindCall(Module, Class, Method).Increment;
      END IncrementCall;
      
    METHOD Calls : INTEGER;
      BEGIN
      FOR x IN THIS DO
        RESULT := RESULT + x.Count;
        END;
      END Calls;

    METHOD OptCalls : INTEGER;
      BEGIN
      FOR x IN THIS | x.IsMonomorphic DO
        RESULT := RESULT + x.Count;
        END;
      END OptCalls;
              
    METHOD AllocatingCount : INTEGER;
      BEGIN
      FOR x IN THIS | NOT x.Removed DO
        IF (x.AllocatingState = CallReference.Allocates) THEN
          RESULT := RESULT + 1;
          END;
        END;
      END AllocatingCount;
      
    METHOD FindAllocating;
      VAR
        Pass        : INTEGER;
        ExistsUnknown : BOOLEAN;
      BEGIN
      StdOut.WriteLine ("Finding Allocating Calls");
      ExistsUnknown := TRUE;
      WHILE ExistsUnknown DO
        ExistsUnknown := FALSE;
        Pass := Pass + 1;
        FOR x IN THIS | x.AllocatingState = CallReference.Unknown DO
          x.CheckAllocatingState;
          ExistsUnknown := ExistsUnknown OR 
                               (x.AllocatingState = CallReference.Unknown);
          END;
        StdOut.WriteLine ("Pass " + ToString (Pass) + "  AllocatingCalls " +
                          ToString(AllocatingCount) + "/" +
                          ToString(EffectiveCardinality));
        END;
      END FindAllocating;

    METHOD TransitivableCount : INTEGER;
      BEGIN
      FOR x IN THIS | x.Transitivable DO
        RESULT := RESULT + 1;
        END;
      END TransitivableCount;
      
    METHOD InitMonomorphableFlag;
      BEGIN
      FOR x IN THIS | NOT x.Removed DO
        IF (x.OptimizedMethod <> VOID) THEN
          x.OptimizedMethod.SetMonomorphable;
          END;
        END;
      END InitMonomorphableFlag;            
      
    --------------------------------------
    -- Statistics
    --------------------------------------
    METHOD EffectiveCardinality: INTEGER;
      BEGIN
      FOR x IN THIS | NOT x.Removed DO
        RESULT := RESULT + 1;
        END;
      END EffectiveCardinality;
      
    METHOD MonomorphicCalls: INTEGER;
      BEGIN                
      FOR x IN THIS | NOT (x.Removed) AND x.IsMonomorphic DO
        RESULT := RESULT + 1;
        END;
      END MonomorphicCalls;
      
    METHOD PolymorphicCalls: INTEGER;
      BEGIN                
      FOR x IN THIS | NOT (x.Removed) AND x.IsPolymorphic DO
        RESULT := RESULT + 1;
        END;
      END PolymorphicCalls;
      
    METHOD BadCalls: INTEGER;
      BEGIN
      FOR x IN THIS | NOT (x.Removed) AND x.BadCall DO
        RESULT := RESULT + 1;
        END;
      END BadCalls;      
      
    METHOD InLineCalls: INTEGER;
      VAR
        OptMeth : MethodReference;
      BEGIN
      FOR x IN THIS | NOT x.Removed DO
        OptMeth := x.OptimizedMethod;
        IF (OptMeth <> VOID) AND OptMeth.InLine THEN
          RESULT := RESULT + 1;
          END;
        END;
      END InLineCalls;
      
    METHOD NoGarbage: INTEGER;
      BEGIN
      FOR x IN THIS | NOT x.Removed DO
        IF (x.AllocatingState = CallReference.DoesNotAllocate) THEN
          RESULT := RESULT + 1;
          END;
        END;
      END NoGarbage;

    METHOD CallsGenerated:INTEGER;
      BEGIN
      FOR x IN THIS DO
        RESULT := RESULT + x.GeneratedCount;
        END;
      END CallsGenerated;
    
    METHOD MonomorphicCallsGen: INTEGER;
      BEGIN                
      FOR x IN THIS | NOT x.Removed DO
        IF (x.IsMonomorphic) THEN
          RESULT := RESULT + x.GeneratedCount;
          END;
        END;
      END MonomorphicCallsGen;
      
    METHOD PolymorphicCallsGen: INTEGER;
      BEGIN                
      FOR x IN THIS | NOT x.Removed DO
        IF (x.IsPolymorphic) THEN
          RESULT := RESULT + x.GeneratedCount;
          END;
        END;
      END PolymorphicCallsGen;
      
    METHOD BadCallsGen: INTEGER;
      BEGIN                
      FOR x IN THIS | NOT x.Removed DO
        IF (x.BadCall) THEN
          RESULT := RESULT + x.GeneratedCount;
          END;
        END;
      END BadCallsGen;
    
    METHOD InLineCallsGen: INTEGER;
      VAR
        OptMeth : MethodReference;
      BEGIN
      FOR x IN THIS | NOT x.Removed DO
        OptMeth := x.OptimizedMethod;
        IF (OptMeth <> VOID) AND OptMeth.InLine THEN
          RESULT := RESULT + x.GeneratedCount;
          END;
        END;
      END InLineCallsGen;
      
    METHOD NoGarbageGen: INTEGER;
      BEGIN
      FOR x IN THIS | NOT x.Removed DO
        IF (x.AllocatingState = CallReference.DoesNotAllocate) THEN
          RESULT := RESULT + x.GeneratedCount;
          END;
        END;
      END NoGarbageGen;           
      
    REDEFINE METHOD Stats (Output: OutputStream);
      BEGIN                                     
      Output.WriteLn;
      Output.WriteLine ("Calls dictionnary:");
      Output.WriteLine ("------------------");
      BASE (Output);
      Output.WriteLn;
      Output.WriteLine ("Allocating count       : " + ToString(AllocatingCount));
      Output.WriteLine ("Effective cardinality  : " + ToString(EffectiveCardinality));
      Output.WriteLine ("  -> Monomorphic       : " + ToString(MonomorphicCalls));
      Output.WriteLine ("  -> Polymorphic       : " + ToString(PolymorphicCalls));
      Output.WriteLine ("  -> Bad               : " + ToString(BadCalls));
      Output.WriteLine ("  -> InLinable         : " + ToString(InLineCalls));
      Output.WriteLine ("  -> No garbage        : " + ToString(NoGarbage));
      Output.WriteLine ("  -> Transitivable     : " + ToString(TransitivableCount));
      Output.WriteLine ("Calls generated        : " + ToString(CallsGenerated));
      Output.WriteLine ("  -> Monomorphic       : " + ToString(MonomorphicCallsGen));
      Output.WriteLine ("  -> Polymorphic       : " + ToString(PolymorphicCallsGen));
      Output.WriteLine ("  -> Bad               : " + ToString(BadCallsGen));
      Output.WriteLine ("  -> InLinable         : " + ToString(InLineCallsGen));
      Output.WriteLine ("  -> No garbage        : " + ToString(NoGarbageGen));
      END Stats;
         
  END CallDictionary;  
---------------------------------------------
  ONCE CLASS EntryDictionary;
    INHERITS TernaryDictionary(EntryReference);
  
    REDEFINE METHOD CREATE;
      BEGIN
      BASE;
      END CREATE;
  
    METHOD FindEntry (Module, Class, Meth: ARRAY OF CHAR): EntryReference;
      BEGIN  
      RESULT := DoFind (Module, Class, Meth);
      END FindEntry;
      
    METHOD AddEntry (Module, Class, Meth: ARRAY OF CHAR): EntryReference;
      VAR
        Found: BOOLEAN;
      BEGIN
      ASSERT DoFind (Module, Class, Meth) = VOID;
      RESULT.CREATE (Module, Class, Meth);
      Found := Store(RESULT);
      ASSERT Found;
      ASSERT DoFind (Module, Class, Meth) = RESULT;
      END AddEntry;
                   
    METHOD MonoCount : INTEGER;
      BEGIN
      FOR x IN THIS | NOT x.Removed DO
        IF (x.IsMonomorphic) THEN
          RESULT := RESULT + 1;
          END;
        END;
      END MonoCount;
      
    REDEFINE METHOD Stats (Output: OutputStream);
      BEGIN
      Output.WriteLn;
      Output.WriteLine ("Entries dictionnary:");
      Output.WriteLine ("--------------------");
      BASE (Output);
      Output.WriteLn;
      Output.WriteLine ("Useful Entries         : " + ToString (UsefulCount));
      Output.WriteLine ("Monomorphic Entries    : " + ToString (MonoCount));
      END Stats;
      
  END EntryDictionary; 
---------------------------------------------
  ONCE CLASS MethodDictionary;
    INHERITS TernaryDictionary(MethodReference);
  
    REDEFINE METHOD CREATE;
      BEGIN
      BASE;
      END CREATE;
  
    METHOD FindMethod (Module, Class, Meth: ARRAY OF CHAR): MethodReference;
      BEGIN  
      RESULT := DoFind (Module, Class, Meth);
      END FindMethod;
      
    METHOD AppendMethod (Meth: MethodDeclaration);
      VAR
        MethRef: MethodReference;
        Entry : EntryReference;
        OtherMeth: MethodDeclaration;
      BEGIN     
      --------------------------
      -- First, make sure I am not trying to enter a predefined
      -- method.
      --------------------------  
      DEBUG          
        WHAT Meth OF
          IN PredefMethod:  
            ASSERT FALSE;
            END;
         ELSE
          -- Don't abort...
          END;
        END;
      --------------------------
      -- Then, make sure that the method has not been entered already
      --------------------------  
      IF DoFind (Meth.Class.Module.Id.Data, Meth.Class.Id.Data,
                                                  Meth.Id.Data) = VOID THEN
        IF Meth.Redefine AND Meth.IsTagged THEN
          IF NOT Meth.IsCreate THEN
            OtherMeth := Meth.Redefined (Original := TRUE);
            IF OtherMeth <> VOID THEN
              WHAT OtherMeth OF
                IN PredefMethod:
                  END;
               ELSE
                AppendMethod (OtherMeth);
                Entry := EntryDictionary.FindEntry 
                                           (OtherMeth.Class.Module.Id.Data, 
                                            OtherMeth.Class.Id.Data, 
                                            OtherMeth.Id.Data);
                ASSERT Entry <> VOID;
                END;
              END;                                       
            END;
          END;
        IF Entry = VOID THEN
          Entry := EntryDictionary.FindEntry (Meth.Class.Module.Id.Data, 
                                              Meth.Class.Id.Data, 
                                              Meth.Id.Data);
          IF Entry = VOID THEN
            Entry := EntryDictionary.AddEntry (Meth.Class.Module.Id.Data, 
                                               Meth.Class.Id.Data, 
                                               Meth.Id.Data);                
            END;
          END;                                      
        IF NOT Meth.Deferred THEN                          
          MethRef.CREATE (Meth.Class.Module.Id.Data, 
                          Meth.Class.Id.Data,
                          Meth.Id.Data);
          MethRef.Insert;
          IF NOT Store (MethRef) THEN
            ASSERT FALSE;
            END; -- IF
          END; -- IF
        ASSERT Entry <> VOID;
        END;
      END AppendMethod;

    METHOD InlinableMethodsCount : INTEGER;
      BEGIN
      FOR x IN THIS | x.InLine DO
        RESULT := RESULT + 1;
        END;
      END InlinableMethodsCount;  
      
    METHOD CallsCount: INTEGER;
      BEGIN
      FOR x IN THIS | NOT(x.Removed) AND (x.Calls <> VOID) DO
        RESULT := RESULT + x.Calls.SIZE;
        END;
      END CallsCount;
      
    METHOD MarkCallReferences;
      BEGIN 
      FOR x IN THIS DO
        x.MarkCallReferences;
        END;
      END MarkCallReferences;                                          
              
    METHOD AllocatingCount : INTEGER;
      BEGIN
      FOR x IN THIS | x.AllocatingState = MethodReference.Allocates DO
        RESULT := RESULT + 1;
        END;
      END AllocatingCount;
      
    METHOD InLineCount : INTEGER;
      BEGIN
      FOR x IN THIS | x.InLine DO
        RESULT := RESULT + 1;
        END;
      END InLineCount;
           
    METHOD AverageChainSize: REAL;
      VAR
        Sum, Count        : INTEGER;
      BEGIN      
      FOR x IN THIS | x.TransferMethod DO
        Count := Count + 1;
        Sum := Sum + x.TransferPosition;
        END;
      RESULT := SYSTEM.FLOAT(Sum)/SYSTEM.FLOAT(Count);
      END AverageChainSize; 

    REDEFINE METHOD Stats (Output: OutputStream);
      BEGIN
      Output.WriteLn;
      Output.WriteLine ("Methods dictionnary:");
      Output.WriteLine ("--------------------");
      BASE (Output);
      Output.WriteLn;
      Output.WriteLine ("Useful Methods         : " + ToString (UsefulCount));
      Output.WriteLine ("Inlinable Methods      : " + ToString (InLineCount));
      Output.WriteLine ("Calls in methods       : " + ToString (CallsCount));
      Output.WriteLine ("Allocating Methods     : " + ToString (AllocatingCount));
      Output.WriteString ("Average Chain Size     : ");
      Output.WriteReal (AverageChainSize,7,3);
      Output.WriteLn;
      END Stats;
      
  END MethodDictionary;        
---------------------------------------------
  ONCE CLASS ClassDictionary;
    INHERITS BinaryDictionary (ClassReference);
    
    VAR
      TheSearchElement: ClassReference;
    
    REDEFINE METHOD CREATE;
      BEGIN      
      BASE;
      TheSearchElement.CREATE (VOID, VOID);
      END CREATE;
  
    METHOD DoFind (Module, Class: ARRAY OF CHAR): ClassReference;
        VAR
        Index: INTEGER;
        Found: BOOLEAN;
     BEGIN
      ASSERT Space.StoreString (Class) = Class;
      ASSERT Space.StoreString (Module) = Module;
      TheSearchElement.RenameBinary (Module, Class);
      Index := TheSearchElement.HashValue;
      RESULT := Find(Index);
      WHILE NOT Found AND (RESULT <> VOID) DO
        Found := (RESULT.Class = Class) AND (RESULT.Module = Module);
        IF NOT Found THEN 
          RESULT := Next;
          END;
        END;
      END DoFind;  
      
    METHOD FindClass (Module, Class: ARRAY OF CHAR): ClassReference;
      BEGIN 
      RESULT := DoFind (Module, Class);
      IF RESULT = VOID THEN
        RESULT.CREATE (Module, Class);
        RESULT.Insert;
        IF NOT Store (RESULT) THEN
          ASSERT FALSE;
          END; -- IF
        END; -- IF
      ASSERT RESULT <> VOID;    
      END FindClass;  
      
    METHOD VisitOnceClasses;
      BEGIN                        
      FOR x IN THIS | x.IsOnce DO
        x.MarkCreated;
        END;
      END VisitOnceClasses;
      
    METHOD PropagateUseful;
      BEGIN
      FOR x IN THIS DO
        x.PropagateUseful;
        END;
      END PropagateUseful;

    REDEFINE METHOD Stats (Output : OutputStream);
      BEGIN    
      Output.WriteLn;
      Output.WriteLine ("Classes dictionnary:");
      Output.WriteLine ("--------------------");
      BASE (Output);
      Output.WriteLn;
      END Stats;
      
  END ClassDictionary; 
----------------------------------------------------------
  ONCE CLASS ModuleDictionary;
    INHERITS UnaryDictionary(ModuleReference);
                       
    VAR
      TheSearchElement: ModuleReference;
    
    REDEFINE METHOD CREATE;
      BEGIN      
      BASE;
      TheSearchElement.CREATE (VOID);
      END CREATE;
  
    METHOD DoFind (Module : ARRAY OF CHAR): ModuleReference;
      VAR
        Index: INTEGER;
        Found: BOOLEAN;
      BEGIN
      ASSERT Space.StoreString (Module) <> VOID;
      TheSearchElement.RenameUnary (Module);
      Index := TheSearchElement.HashValue;
      RESULT := Find(Index);      
      WHILE NOT Found AND (RESULT <> VOID) DO
        Found := (RESULT.Module = Module);
        IF NOT Found THEN 
          RESULT := Next;
          END;
        END;
      END DoFind;  
           
    METHOD FindModule (Module : ARRAY OF CHAR) : ModuleReference;
      BEGIN 
      RESULT := DoFind (Module);
      IF RESULT = VOID THEN
        RESULT.CREATE (Module);
        IF NOT Store (RESULT) THEN
          ASSERT Store (RESULT);
          END; -- IF
        END; -- IF
      END FindModule;  
      
    REDEFINE METHOD Stats (Output : OutputStream);
      BEGIN    
      Output.WriteLn;
      Output.WriteLine ("Modules dictionnary:");
      Output.WriteLine ("--------------------");
      BASE (Output);
      Output.WriteLn;
      END Stats;         
    
  END ModuleDictionary;
----------------------------------------------------------
  ONCE CLASS MethodQueue;
    
    VAR
      MethStack: Stack(MethodReference);
    
    REDEFINE METHOD CREATE;
      BEGIN
      BASE;
      MethStack.CREATE;
      END CREATE;
      
    -----------------------------------
    -- Test if Elt is in Visited, and, if not, 
    -- adds Elt in ToVisit & Visited
    -----------------------------------
    METHOD Push(El : MethodReference);
      BEGIN
      IF NOT El.Visited THEN
        El.MarkVisited;
        MethStack.Push(El);
        END;                                  
      END Push;
    
    METHOD VisitTop;   
      VAR
        Top: MethodReference;
      BEGIN  
      IF MethStack.Depth > 0 THEN
        Top := MethStack.Pop;
        Top.Visit;
        END;
      END VisitTop;
      
    METHOD Size: INTEGER;
      BEGIN    
      RESULT := MethStack.Depth;
      END Size;
      
  END MethodQueue;
----------------------------------------------------------
    
END YaflDictionary;
