home *** CD-ROM | disk | FTP | other *** search
- // $Id: incrmnt.cpp,v 1.10 1999/08/26 15:34:08 shields Exp $
- //
- // This software is subject to the terms of the IBM Jikes Compiler
- // License Agreement available at the following URL:
- // http://www.ibm.com/research/jikes.
- // Copyright (C) 1996, 1998, International Business Machines Corporation
- // and others. All Rights Reserved.
- // You must accept the terms of that agreement to use this software.
- //
- #include "config.h"
- #include <sys/stat.h>
- #include <iostream.h>
- #include "control.h"
- #include "scanner.h"
- #include "parser.h"
- #include "semantic.h"
- #include "case.h"
- #include "set.h"
-
- void Control::RemoveTrashedTypes(SymbolSet &type_trash_set)
- {
- TypeSymbol *type;
-
- //
- // For each type T that is going to be trashed, and for each parent P of T that
- // is not itself being trashed, remove T from the set of dependents of P.
- // If T is a subtype of P it is also removed from the subtypes set.
- //
- for (type = (TypeSymbol *) type_trash_set.FirstElement(); type; type = (TypeSymbol *) type_trash_set.NextElement())
- {
- for (TypeSymbol *static_parent = (TypeSymbol *) type -> parents -> FirstElement();
- static_parent;
- static_parent = (TypeSymbol *) type -> parents -> NextElement())
- {
- if (! type_trash_set.IsElement(static_parent))
- {
- static_parent -> dependents -> RemoveElement(type);
- static_parent -> subtypes -> RemoveElement(type);
- }
- }
-
- for (TypeSymbol *parent = (TypeSymbol *) type -> parents -> FirstElement();
- parent;
- parent = (TypeSymbol *) type -> parents -> NextElement())
- {
- if (! type_trash_set.IsElement(parent))
- {
- parent -> dependents -> RemoveElement(type);
- parent -> subtypes -> RemoveElement(type);
- }
- }
- }
-
- //
- // We can now safely delete the type.
- //
- for (type = (TypeSymbol *) type_trash_set.FirstElement(); type; type = (TypeSymbol *) type_trash_set.NextElement())
- {
- PackageSymbol *package = type -> ContainingPackage();
-
- //
- // If a type that is about to be trashed was read in via a class file, remove the class file.
- // Note that invoking RemoveElement for a file that it does not contain has no ill effect.
- //
- FileSymbol *file_symbol = type -> file_symbol;
- if (file_symbol && type -> Identity() == file_symbol -> Identity())
- input_class_file_set.RemoveElement(file_symbol);
-
- //
- // If a type that is about to be trashed was contained in the unnamed_package,
- // remove it from the set "unnamed_package_types"
- //
- if (package == unnamed_package)
- unnamed_package_types.RemoveElement(type);
-
- //
- // Remove the type from its containing package.
- //
- package -> DeleteTypeSymbol(type);
- }
-
- return;
- }
-
-
- inline DirectoryEntry *Control::FindInputFile(FileSymbol *file_symbol)
- {
- int length = file_symbol -> Utf8NameLength() + FileSymbol::java_suffix_length;
-
- char *java_name = new char[length + 1]; // +1 for '\0'
- strcpy(java_name, file_symbol -> Utf8Name());
- strcat(java_name, FileSymbol::java_suffix);
-
- DirectoryEntry *java_entry = file_symbol -> directory_symbol -> FindEntry(java_name, length);
-
- delete [] java_name;
-
- return java_entry;
-
- }
-
-
- //
- // For each file whose associated source (".java") has changed, add it to the list to be recompiled...
- //
- void Control::FindMoreRecentInputFiles(SymbolSet &file_candidates)
- {
- for (FileSymbol *file_symbol = (FileSymbol *) file_candidates.FirstElement();
- file_symbol;
- file_symbol = (FileSymbol *) file_candidates.NextElement())
- {
- //
- // If the type is not zipped and it is not already contained in the recompilation set, then check it...
- //
- if ((! file_symbol -> IsZip()) &&
- (! recompilation_file_set.IsElement(file_symbol)) &&
- (! expired_file_set.IsElement(file_symbol)))
- {
- //
- // If there is no java source file or its time stamp is not newer than file_symbol then
- // reset file_symbol to NULL. Otherwise, reset file symbol to the newer file.
- //
- DirectoryEntry *java_entry = FindInputFile(file_symbol);
- if (! java_entry)
- {
- if (file_symbol -> IsJava()) // A source file that was compiled in the previous pass no longer exists.
- expired_file_set.AddElement(file_symbol);
- }
- else if (java_entry -> Mtime() > file_symbol -> mtime) // a newer file was found
- {
- file_symbol -> mtime = java_entry -> Mtime();
- recompilation_file_set.AddElement(file_symbol);
- }
- }
- }
-
- return;
- }
-
-
- void Control::RereadDirectory(DirectorySymbol *directory_symbol)
- {
- directory_symbol -> ResetDirectory();
-
- for (int i = 0; i < directory_symbol -> subdirectories.Length(); i++)
- RereadDirectory(directory_symbol -> subdirectories[i]);
-
- return;
- }
-
-
- void Control::RereadDirectories()
- {
- for (int i = (dot_classpath_index == 0 ? 0 : 1); i < classpath.Length(); i++)
- {
- PathSymbol *path_symbol = classpath[i];
- if (! path_symbol -> IsZip())
- RereadDirectory(path_symbol -> RootDirectory());
- }
-
- return;
- }
-
-
- void Control::ComputeRecompilationSet(TypeDependenceChecker &dependence_checker)
- {
- SymbolSet type_trash_set;
-
- //
- // Find out if any source files has been touched since the last compilation and
- // add all such files to recompilation_file_set.
- //
- FindMoreRecentInputFiles(dependence_checker.file_set);
-
- //
- // Before messing with the files, compute a list of all the types that have just been compiled.
- // We need to do this here as we will be "Resetting" and "reScanning" some files in the loop below,
- // which in effect removes the set of types to which they were associated in the previous compilation.
- //
- int length_estimate = input_java_file_set.Size(); // an estimate of the size of the problem
- Tuple<TypeSymbol *> input_types(length_estimate * 2);
- for (FileSymbol *file_symbol = (FileSymbol *) input_java_file_set.FirstElement();
- file_symbol;
- file_symbol = (FileSymbol *) input_java_file_set.NextElement())
- {
- for (int i = 0; i < file_symbol -> types.Length(); i++)
- input_types.Next() = file_symbol -> types[i];
- }
-
- //
- // Declare the closure set, and initialize it with the Union over the closure of the
- // types in the trash_bin. Essentially, we want to catch all "compiled" types in the
- // compilation that has a dependence on these bad types.
- //
- SymbolSet dependents_closure(length_estimate);
- for (int i = 0; i < type_trash_bin.Length(); i++)
- {
- TypeSymbol *type = type_trash_bin[i];
- if (! dependents_closure.IsElement(type))
- {
- if (type -> dependents_closure)
- dependents_closure.Union(*(type -> dependents_closure));
- else dependents_closure.AddElement(type);
- }
- }
-
- //
- // Compute the set of types from the recompilation set that needs to be recompiled
- // and update the recompilation file set.
- //
- SymbolSet new_set(length_estimate),
- file_seen(length_estimate);
- new_set = recompilation_file_set;
- new_set.Union(expired_file_set);
- file_seen = new_set;
-
- StoragePool *ast_pool = new StoragePool(64); // how much space do we need for a package declaration? estimate 64 tokens.
-
- //
- // As long as there is a new_set of files to process,...
- //
- do
- {
- //
- // For each file in new_set, compute the reflexive transitive closure of all types contained in that file.
- // Next, reset and rescan the file. If the scan was successful, iterate over the new list of types to see
- // if any of them had already been introduced in the previous compilation via a class file. If so, add all such
- // types to the dependents closure.
- //
- for (FileSymbol *file_symbol = (FileSymbol *) new_set.FirstElement();
- file_symbol;
- file_symbol = (FileSymbol *) new_set.NextElement())
- {
- for (int i = 0; i < file_symbol -> types.Length(); i++)
- {
- TypeSymbol *type = file_symbol -> types[i];
- if (! dependents_closure.IsElement(type))
- {
- if (type -> dependents_closure)
- dependents_closure.Union(*(type -> dependents_closure));
- else dependents_closure.AddElement(type);
- }
- }
-
- if (! expired_file_set.IsElement(file_symbol))
- {
- file_symbol -> Reset();
- file_symbol -> SetJava();
-
- scanner -> Scan(file_symbol);
-
- LexStream *lex_stream = file_symbol -> lex_stream;
- if (lex_stream) // did we have a successful scan!
- {
- AstPackageDeclaration *package_declaration = parser -> PackageHeaderParse(lex_stream, ast_pool);
- PackageSymbol *package = (package_declaration
- ? FindOrInsertPackage(lex_stream, package_declaration -> name) : unnamed_package);
- ast_pool -> Reset();
-
- //
- // If the file contained more than one type, only the main one would have
- // been deleted. We now delete the others if any...
- //
- for (int k = 0; k < lex_stream -> NumTypes(); k++)
- {
- LexStream::TokenIndex identifier_token = lex_stream -> Next(lex_stream -> Type(k));
- if (lex_stream -> Kind(identifier_token) == TK_Identifier)
- {
- NameSymbol *name_symbol = lex_stream -> NameSymbol(identifier_token);
- TypeSymbol *type = package -> FindTypeSymbol(name_symbol);
- if (type && (! dependents_closure.IsElement(type)))
- {
- if (type -> dependents_closure)
- dependents_closure.Union(*(type -> dependents_closure));
- else dependents_closure.AddElement(type);
- }
- }
- }
- }
- }
- }
-
- //
- // Iterate over the dependents_closure set. For each type T, add it to the trash pile.
- // If the file with which it is associated had not yet been processed, mark it as having
- // been "seen" and add it to the new_set to be considered later.
- // If the file had already been processed but not yet added to the recompilation set,
- // add it to the recompilation set, read it in and if it contains types other than the
- // the main one (that had previously been read in via class files) add those new types
- // to the trash pile.
- //
- new_set.SetEmpty();
- for (TypeSymbol *type = (TypeSymbol *) dependents_closure.FirstElement();
- type;
- type = (TypeSymbol *) dependents_closure.NextElement())
- {
- type_trash_set.AddElement(type);
-
- FileSymbol *file_symbol = type -> file_symbol;
- if (file_symbol && (! file_seen.IsElement(file_symbol)))
- {
- file_seen.AddElement(file_symbol);
- new_set.AddElement(file_symbol);
- file_symbol -> mtime = 0; // to force a reread of the file.
- }
- }
-
- //
- // Check that the files in new_set exist, and if so, add them to the recompilation_file_set.
- // Note that if they exist, they will be added because before a file is added to new_set
- // its time stamp is reset to 0. See loop above...
- //
- FindMoreRecentInputFiles(new_set);
-
- //
- // Empty out the dependents_closure set for the next round.
- //
- dependents_closure.SetEmpty();
- } while (! new_set.IsEmpty());
-
- delete ast_pool;
-
- //
- // Clean up the types that were compiled in the previous compilation pass.
- //
- for (int j = 0; j < input_types.Length(); j++)
- input_types[j] -> RemoveCompilationReferences();
-
- //
- // Reset the closure sets in all the types that were considered in the dependence checker.
- //
- Tuple<TypeSymbol *> &type_list = dependence_checker.TypeList();
- for (int k = 0; k < type_list.Length(); k++)
- {
- TypeSymbol *type = type_list[k];
-
- type -> index = CycleChecker::OMEGA;
- type -> unit_index = CycleChecker::OMEGA;
- type -> incremental_index = CycleChecker::OMEGA;
- delete type -> dependents_closure;
- type -> dependents_closure = NULL;
- }
-
- //
- // Remove all dependence edges that are no longer valid.
- //
- RemoveTrashedTypes(type_trash_set);
-
- return;
- }
-
-
- //
- // Check whether or not there are files to be rempiled.
- //
- bool Control::IncrementalRecompilation()
- {
- SymbolSet candidates(input_java_file_set.Size() + input_class_file_set.Size() + recompilation_file_set.Size());
- ArgumentExpander *new_arguments = NULL;
-
- if (! recompilation_file_set.IsEmpty())
- candidates = recompilation_file_set;
- else
- {
- fprintf(stderr, "\nIncremental Jikes: Press Enter to continue or [Q]uit + Enter to exit: ");
- fflush(stderr);
-
- Tuple<char> line;
- char ch;
- cin.get(ch);
- while(ch != U_ESCAPE && ch != U_LINE_FEED)
- {
- line.Next() = ch;
- cin.get(ch);
- }
- if (ch == U_ESCAPE)
- return false;
-
- new_arguments = new ArgumentExpander(line);
- char q[2] = {U_q, U_NU};
- if (new_arguments -> argc == 1 && (Case::StringEqual(new_arguments -> argv[0], U8S_quit) ||
- Case::StringSegmentEqual(new_arguments -> argv[0], q, 2)))
- {
- delete new_arguments;
- return false;
- }
-
- candidates = input_java_file_set;
- candidates.Union(input_class_file_set);
- }
-
- if ((! candidates.IsEmpty()) || (new_arguments && new_arguments -> argc > 0))
- {
- TypeDependenceChecker dependence_checker((Control *) this, candidates, type_trash_bin);
- dependence_checker.PartialOrder();
-
- //
- // Compute the initial set of files that need to be recompiled. Place them in recompilation_file_set.
- //
- RereadDirectories();
-
- if (new_arguments)
- ProcessNewInputFiles(recompilation_file_set, *new_arguments);
-
- ComputeRecompilationSet(dependence_checker);
- }
-
- //
- // Starting with the initial recompilation_file_set, complete the computation of the
- // set of files that need to be recompiled. (Add all new files to recompilation_file_set)
- // Also, complete the computation of type_trash_set, the set of files that should be
- // removed from the database as they will be recompiled.
- //
- fprintf(stderr, "%s", (recompilation_file_set.IsEmpty() && expired_file_set.IsEmpty() ? "\nnothing changed...\n" : "\nok...\n"));
- fflush(stderr);
-
- delete new_arguments;
-
- return true;
- }
-