home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 20 / AACD20.BIN / AACD / Programming / Jikes / Source / src / incrmnt.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-02-24  |  15.3 KB  |  425 lines

  1. // $Id: incrmnt.cpp,v 1.23 2001/01/10 16:49:45 mdejong Exp $
  2. //
  3. // This software is subject to the terms of the IBM Jikes Compiler
  4. // License Agreement available at the following URL:
  5. // http://www.ibm.com/research/jikes.
  6. // Copyright (C) 1996, 1998, International Business Machines Corporation
  7. // and others.  All Rights Reserved.
  8. // You must accept the terms of that agreement to use this software.
  9. //
  10. #include "platform.h"
  11. #include "control.h"
  12. #include "scanner.h"
  13. #include "parser.h"
  14. #include "semantic.h"
  15. #include "case.h"
  16. #include "set.h"
  17.  
  18. #ifdef    HAVE_JIKES_NAMESPACE
  19. namespace Jikes {    // Open namespace Jikes block
  20. #endif
  21.  
  22. void Control::RemoveTrashedTypes(SymbolSet &type_trash_set)
  23. {
  24.     TypeSymbol *type;
  25.  
  26.     //
  27.     // For each type T that is going to be trashed, and for each parent P of T that
  28.     // is not itself being trashed, remove T from the set of dependents of P.
  29.     // If T is a subtype of P it is also removed from the subtypes set.
  30.     //
  31.     for (type = (TypeSymbol *) type_trash_set.FirstElement(); type; type = (TypeSymbol *) type_trash_set.NextElement())
  32.     {
  33.         for (TypeSymbol *static_parent = (TypeSymbol *) type -> static_parents -> FirstElement();
  34.                          static_parent;
  35.                          static_parent = (TypeSymbol *) type -> static_parents -> NextElement())
  36.         {
  37.             if (! type_trash_set.IsElement(static_parent))
  38.             {
  39.                 static_parent -> dependents -> RemoveElement(type);
  40.                 static_parent -> subtypes -> RemoveElement(type);
  41.             }
  42.         }
  43.  
  44.         for (TypeSymbol *parent = (TypeSymbol *) type -> parents -> FirstElement();
  45.                          parent;
  46.                          parent = (TypeSymbol *) type -> parents -> NextElement())
  47.         {
  48.             if (! type_trash_set.IsElement(parent))
  49.             {
  50.                 parent -> dependents -> RemoveElement(type);
  51.                 parent -> subtypes -> RemoveElement(type);
  52.             }
  53.         }
  54.     }
  55.  
  56.     //
  57.     // We can now safely delete the type.
  58.     //
  59.     for (type = (TypeSymbol *) type_trash_set.FirstElement(); type; type = (TypeSymbol *) type_trash_set.NextElement())
  60.     {
  61.         PackageSymbol *package = type -> ContainingPackage();
  62.  
  63.         //
  64.         // If a type that is about to be trashed was read in via a class file, remove the class file.
  65.         // Note that invoking RemoveElement for a file that it does not contain has no ill effect.
  66.         //
  67.         FileSymbol *file_symbol = type -> file_symbol;
  68.         if (file_symbol && type -> Identity() == file_symbol -> Identity())
  69.             input_class_file_set.RemoveElement(file_symbol);
  70.  
  71.         //
  72.         // If a type that is about to be trashed was contained in the unnamed_package,
  73.         // remove it from the set "unnamed_package_types"
  74.         //
  75.         if (package == unnamed_package)
  76.             unnamed_package_types.RemoveElement(type);
  77.  
  78.         //
  79.         // Remove the type from its containing package.
  80.         //
  81.         package -> DeleteTypeSymbol(type);
  82.     }
  83.  
  84.     return;
  85. }
  86.  
  87.  
  88. inline DirectoryEntry *Control::FindInputFile(FileSymbol *file_symbol)
  89. {
  90.     int length = file_symbol -> Utf8NameLength() + FileSymbol::java_suffix_length;
  91.  
  92.     char *java_name = new char[length + 1]; // +1 for '\0'
  93.     strcpy(java_name, file_symbol -> Utf8Name());
  94.     strcat(java_name, FileSymbol::java_suffix);
  95.  
  96.     DirectoryEntry *java_entry = file_symbol -> directory_symbol -> FindEntry(java_name, length);
  97.  
  98.     delete [] java_name;
  99.  
  100.     return java_entry;
  101.  
  102. }
  103.  
  104.  
  105. //
  106. // For each file whose associated source (".java") has changed, add it to the list to be recompiled...
  107. //
  108. void Control::FindMoreRecentInputFiles(SymbolSet &file_candidates)
  109. {
  110.     for (FileSymbol *file_symbol = (FileSymbol *) file_candidates.FirstElement();
  111.                      file_symbol;
  112.                      file_symbol = (FileSymbol *) file_candidates.NextElement())
  113.     {
  114.         //
  115.         // If the type is not zipped and it is not already contained in the recompilation set, then check it...
  116.         //
  117.         if ((! file_symbol -> IsZip()) &&
  118.             (! recompilation_file_set.IsElement(file_symbol)) &&
  119.             (! expired_file_set.IsElement(file_symbol)))
  120.         {
  121.             //
  122.             // If there is no java source file or its time stamp is not newer than file_symbol then
  123.             // reset file_symbol to NULL. Otherwise, reset file symbol to the newer file.
  124.             //
  125.             DirectoryEntry *java_entry = FindInputFile(file_symbol);
  126.             if (! java_entry)
  127.             {
  128.                 if (file_symbol -> IsJava()) // A source file that was compiled in the previous pass no longer exists.
  129.                     expired_file_set.AddElement(file_symbol);
  130.             }
  131.             else if (java_entry -> Mtime() > file_symbol -> mtime) // a newer file was found
  132.             {
  133.                  file_symbol -> mtime = java_entry -> Mtime();
  134.                  recompilation_file_set.AddElement(file_symbol);
  135.             }
  136.         }
  137.     }
  138.  
  139.     return;
  140. }
  141.  
  142.  
  143. void Control::RereadDirectory(DirectorySymbol *directory_symbol)
  144. {
  145.     directory_symbol -> ResetDirectory();
  146.  
  147.     for (int i = 0; i < directory_symbol -> subdirectories.Length(); i++)
  148.         RereadDirectory(directory_symbol -> subdirectories[i]);
  149.  
  150.     return;
  151. }
  152.  
  153.  
  154. void Control::RereadDirectories()
  155. {
  156.     for (int i = (dot_classpath_index == 0 ? 0 : 1); i < classpath.Length(); i++)
  157.     {
  158.         PathSymbol *path_symbol = classpath[i];
  159.         if (! path_symbol -> IsZip())
  160.             RereadDirectory(path_symbol -> RootDirectory());
  161.     }
  162.  
  163.     return;
  164. }
  165.  
  166.  
  167. void Control::ComputeRecompilationSet(TypeDependenceChecker &dependence_checker)
  168. {
  169.     SymbolSet type_trash_set;
  170.  
  171.     //
  172.     // Find out if any source files has been touched since the last compilation and
  173.     // add all such files to recompilation_file_set.
  174.     //
  175.     FindMoreRecentInputFiles(dependence_checker.file_set);
  176.  
  177.     //
  178.     // Before messing with the files, compute a list of all the types that have just been compiled.
  179.     // We need to do this here as we will be "Resetting" and "reScanning" some files in the loop below,
  180.     // which in effect removes the set of types to which they were associated in the previous compilation.
  181.     //
  182.     int length_estimate = input_java_file_set.Size(); // an estimate of the size of the problem
  183.     Tuple<TypeSymbol *> input_types(length_estimate * 2);
  184.     for (FileSymbol *file_symbol = (FileSymbol *) input_java_file_set.FirstElement();
  185.                      file_symbol;
  186.                      file_symbol = (FileSymbol *) input_java_file_set.NextElement())
  187.     {
  188.         for (int i = 0; i < file_symbol -> types.Length(); i++)
  189.             input_types.Next() = file_symbol -> types[i];
  190.     }
  191.  
  192.     //
  193.     // Declare the closure set, and initialize it with the Union over the closure of the
  194.     // types in the trash_bin. Essentially, we want to catch all "compiled" types in the
  195.     // compilation that has a dependence on these bad types.
  196.     //
  197.     SymbolSet dependents_closure(length_estimate);
  198.     for (int i = 0; i < type_trash_bin.Length(); i++)
  199.     {
  200.         TypeSymbol *type = type_trash_bin[i];
  201.         if (! dependents_closure.IsElement(type))
  202.         {
  203.             if (type -> dependents_closure)
  204.                  dependents_closure.Union(*(type -> dependents_closure));
  205.             else dependents_closure.AddElement(type);
  206.         }
  207.     }
  208.  
  209.     //
  210.     // Compute the set of types from the recompilation set that needs to be recompiled
  211.     // and update the recompilation file set.
  212.     //
  213.     SymbolSet new_set(length_estimate),
  214.               file_seen(length_estimate);
  215.     new_set = recompilation_file_set;
  216.     new_set.Union(expired_file_set);
  217.     file_seen = new_set;
  218.  
  219.     StoragePool *ast_pool = new StoragePool(64); // how much space do we need for a package declaration? estimate 64 tokens.
  220.  
  221.     //
  222.     // As long as there is a new_set of files to process,...
  223.     //
  224.     do
  225.     {
  226.         //
  227.         // For each file in new_set, compute the reflexive transitive closure of all types contained in that file.
  228.         // Next, reset and rescan the file. If the scan was successful, iterate over the new list of types to see
  229.         // if any of them had already been introduced in the previous compilation via a class file. If so, add all such
  230.         // types to the dependents closure.
  231.         //
  232.         for (FileSymbol *file_symbol = (FileSymbol *) new_set.FirstElement();
  233.                          file_symbol;
  234.                          file_symbol = (FileSymbol *) new_set.NextElement())
  235.         {
  236.             for (int i = 0; i < file_symbol -> types.Length(); i++)
  237.             {
  238.                 TypeSymbol *type = file_symbol -> types[i];
  239.                 if (! dependents_closure.IsElement(type))
  240.                 {
  241.                     if (type -> dependents_closure)
  242.                          dependents_closure.Union(*(type -> dependents_closure));
  243.                     else dependents_closure.AddElement(type);
  244.                 }
  245.             }
  246.  
  247.             if (! expired_file_set.IsElement(file_symbol))
  248.             {
  249.                 file_symbol -> Reset();
  250.                 file_symbol -> SetJava();
  251.  
  252.                 scanner -> Scan(file_symbol);
  253.  
  254.                 LexStream *lex_stream = file_symbol -> lex_stream;
  255.                 if (lex_stream) // did we have a successful scan!
  256.                 {
  257.                     AstPackageDeclaration *package_declaration = parser -> PackageHeaderParse(lex_stream, ast_pool);
  258.                     PackageSymbol *package = (package_declaration
  259.                                                   ? FindOrInsertPackage(lex_stream, package_declaration -> name) : unnamed_package);
  260.                     ast_pool -> Reset();
  261.  
  262.                     //
  263.                     // If the file contained more than one type, only the main one would have
  264.                     // been deleted. We now delete the others if any...
  265.                     //
  266.                     for (int k = 0; k < lex_stream -> NumTypes(); k++)
  267.                     {
  268.                         LexStream::TokenIndex identifier_token = lex_stream -> Next(lex_stream -> Type(k));
  269.                         if (lex_stream -> Kind(identifier_token) == TK_Identifier)
  270.                         {
  271.                             NameSymbol *name_symbol = lex_stream -> NameSymbol(identifier_token);
  272.                             TypeSymbol *type = package -> FindTypeSymbol(name_symbol);
  273.                             if (type && (! dependents_closure.IsElement(type)))
  274.                             {
  275.                                 if (type -> dependents_closure)
  276.                                      dependents_closure.Union(*(type -> dependents_closure));
  277.                                 else dependents_closure.AddElement(type);
  278.                             }
  279.                         }
  280.                     }
  281.                 }
  282.             }
  283.         }
  284.  
  285.         //
  286.         // Iterate over the dependents_closure set. For each type T, add it to the trash pile.
  287.         // If the file with which it is associated had not yet been processed, mark it as having
  288.         // been "seen" and add it to the new_set to be considered later.
  289.         // If the file had already been processed but not yet added to the recompilation set,
  290.         // add it to the recompilation set, read it in and if it contains types other than the
  291.         // the main one (that had previously been read in via class files) add those new types
  292.         // to the trash pile.
  293.         //
  294.         new_set.SetEmpty();
  295.         for (TypeSymbol *type = (TypeSymbol *) dependents_closure.FirstElement();
  296.                          type;
  297.                          type = (TypeSymbol *) dependents_closure.NextElement())
  298.         {
  299.             type_trash_set.AddElement(type);
  300.  
  301.             FileSymbol *file_symbol = type -> file_symbol;
  302.             if (file_symbol && (! file_seen.IsElement(file_symbol)))
  303.             {
  304.                 file_seen.AddElement(file_symbol);
  305.                 new_set.AddElement(file_symbol);
  306.                 file_symbol -> mtime = 0; // to force a reread of the file.
  307.             }
  308.         }
  309.  
  310.         //
  311.         // Check that the files in new_set exist, and if so, add them to the recompilation_file_set.
  312.         // Note that if they exist, they will be added because before a file is added to new_set
  313.         // its time stamp is reset to 0. See loop above...
  314.         //
  315.         FindMoreRecentInputFiles(new_set);
  316.  
  317.         //
  318.         // Empty out the dependents_closure set for the next round.
  319.         //
  320.         dependents_closure.SetEmpty();
  321.     } while (! new_set.IsEmpty());
  322.  
  323.     delete ast_pool;
  324.  
  325.     //
  326.     // Clean up the types that were compiled in the previous compilation pass.
  327.     //
  328.     for (int j = 0; j < input_types.Length(); j++)
  329.         input_types[j] -> RemoveCompilationReferences();
  330.  
  331.     //
  332.     // Reset the closure sets in all the types that were considered in the dependence checker.
  333.     //
  334.     Tuple<TypeSymbol *> &type_list = dependence_checker.TypeList();
  335.     for (int k = 0; k < type_list.Length(); k++)
  336.     {
  337.         TypeSymbol *type = type_list[k];
  338.  
  339.         type -> index = CycleChecker::OMEGA;
  340.         type -> unit_index = CycleChecker::OMEGA;
  341.         type -> incremental_index = CycleChecker::OMEGA;
  342.         delete type -> dependents_closure;
  343.         type -> dependents_closure = NULL;
  344.     }
  345.  
  346.     //
  347.     // Remove all dependence edges that are no longer valid.
  348.     //
  349.     RemoveTrashedTypes(type_trash_set);
  350.  
  351.     return;
  352. }
  353.  
  354.  
  355. //
  356. // Check whether or not there are files to be recompiled.
  357. //
  358. bool Control::IncrementalRecompilation()
  359. {
  360.     //
  361.     // Empty out the type lookup table so that it does not continue
  362.     // to point to a type that is deleted here.
  363.     //
  364.     type_table.SetEmpty();
  365.  
  366.     SymbolSet candidates(input_java_file_set.Size() + input_class_file_set.Size() + recompilation_file_set.Size());
  367.  
  368.     if (! recompilation_file_set.IsEmpty())
  369.         candidates = recompilation_file_set;
  370.     else
  371.     {
  372.     // FIXME: This actually uses cerr for output, can't pass cout as argument because
  373.     // of the wacky #define of cout in platform.h.
  374.     Ostream out;
  375.     // FIXME: Why does this not work?
  376.     //out << endl;
  377.     out << "\nIncremental: Enter to continue or q + Enter to quit: ";
  378.     out.flush();
  379.  
  380.         char ch;
  381.         // See if the user types Q or presses enter/escape or sends an EOF
  382.         while (1) {
  383.             cin.get(ch);
  384.             if (cin.eof() || (ch == U_q) || (ch == U_Q)) {
  385.                 return false;
  386.             }
  387.             if ((ch == U_ESCAPE) || (ch == U_LINE_FEED)) {
  388.                 break;
  389.             }
  390.         }
  391.  
  392.         candidates = input_java_file_set;
  393.         candidates.Union(input_class_file_set);
  394.     }
  395.  
  396.     if (!candidates.IsEmpty())
  397.     {
  398.         TypeDependenceChecker dependence_checker((Control *) this, candidates, type_trash_bin);
  399.         dependence_checker.PartialOrder();
  400.  
  401.         //
  402.         // Compute the initial set of files that need to be recompiled. Place them in recompilation_file_set.
  403.         //
  404.         RereadDirectories();
  405.  
  406.         ComputeRecompilationSet(dependence_checker);
  407.     }
  408.  
  409.     //
  410.     // Starting with the initial recompilation_file_set, complete the computation of the
  411.     // set of files that need to be recompiled. (Add all new files to recompilation_file_set)
  412.     // Also, complete the computation of type_trash_set, the set of files that should be
  413.     // removed from the database as they will be recompiled.
  414.     //
  415.     fprintf(stderr, "%s", (recompilation_file_set.IsEmpty() && expired_file_set.IsEmpty() ? "\nnothing changed...\n" : "\nok...\n"));
  416.     fflush(stderr);
  417.  
  418.     return true;
  419. }
  420.  
  421. #ifdef    HAVE_JIKES_NAMESPACE
  422. }            // Close namespace Jikes block
  423. #endif
  424.  
  425.