// $Id: depend.cpp,v 1.42 2004/04/07 13:08:20 ericb Exp $ // // This software is subject to the terms of the IBM Jikes Compiler // License Agreement available at the following URL: // http://ibm.com/developerworks/opensource/jikes. // Copyright (C) 1996, 2004 IBM Corporation and others. All Rights Reserved. // You must accept the terms of that agreement to use this software. // #include "depend.h" #include "control.h" #include "ast.h" #include "semantic.h" #include "option.h" #include "stream.h" #ifdef HAVE_JIKES_NAMESPACE namespace Jikes { // Open namespace Jikes block #endif // // Note that the types are ordered based on on the subtype relationship. We // reverse the order here because the desired order for processing is the // supertype relationship. // inline void TypeCycleChecker::ReverseTypeList() { for (int head = 0, tail = type_list.Length() - 1; head < tail; head++, tail--) { TypeSymbol* temp = type_list[head]; type_list[head] = type_list[tail]; type_list[tail] = temp; } } void TypeCycleChecker::PartialOrder(Tuple& semantic, int start) { type_list.Reset(); // // assert that the "index" of all types that should be checked is initially // set to OMEGA // for (unsigned i = start; i < semantic.Length(); i++) { Semantic* sem = semantic[i]; for (unsigned k = 0; k < sem -> compilation_unit -> NumTypeDeclarations(); k++) { AstDeclaredType* declared = sem -> compilation_unit -> TypeDeclaration(k); if (declared -> EmptyDeclarationCast()) continue; SemanticEnvironment* env = declared -> class_body -> semantic_environment; if (env) // type was successfully compiled thus far? { TypeSymbol* type = env -> Type(); if (type -> index == OMEGA) ProcessSubtypes(type); } } } ReverseTypeList(); } void TypeCycleChecker::PartialOrder(SymbolSet& types) { // // assert that the "index" of all types that should be checked is initially // set to OMEGA // for (TypeSymbol* type = (TypeSymbol*) types.FirstElement(); type; type = (TypeSymbol*) types.NextElement()) { if (type -> index == OMEGA) ProcessSubtypes(type); } ReverseTypeList(); } void TypeCycleChecker::ProcessSubtypes(TypeSymbol* type) { stack.Push(type); int indx = stack.Size(); type -> index = indx; type -> subtypes_closure = new SymbolSet; type -> subtypes_closure -> Union(*(type -> subtypes)); TypeSymbol* subtype; for (subtype = (TypeSymbol*) type -> subtypes -> FirstElement(); subtype; subtype = (TypeSymbol*) type -> subtypes -> NextElement()) { // // Only worry about top-level types. // if (subtype -> outermost_type != subtype) continue; if (subtype -> index == OMEGA) ProcessSubtypes(subtype); type -> index = Min(type -> index, subtype -> index); type -> subtypes_closure -> Union(*(subtype -> subtypes_closure)); } if (type -> index == indx) { TypeSymbol* scc_subtype; do { scc_subtype = stack.Top(); scc_subtype -> index = CYCLE_INFINITY; *(scc_subtype -> subtypes_closure) = *(type -> subtypes_closure); type_list.Next() = scc_subtype; stack.Pop(); } while (scc_subtype != type); } } ConstructorCycleChecker::ConstructorCycleChecker(AstClassBody* class_body) { for (unsigned k = 0; k < class_body -> NumConstructors(); k++) { AstConstructorDeclaration* constructor_declaration = class_body -> Constructor(k); if (constructor_declaration -> index == OMEGA) CheckConstructorCycles(constructor_declaration); } } void ConstructorCycleChecker::CheckConstructorCycles(AstConstructorDeclaration* constructor_declaration) { stack.Push(constructor_declaration); int indx = stack.Size(); constructor_declaration -> index = indx; AstConstructorDeclaration* called_constructor_declaration = NULL; AstMethodBody* constructor_block = constructor_declaration -> constructor_body; if (constructor_block -> explicit_constructor_opt) { AstThisCall* this_call = constructor_block -> explicit_constructor_opt -> ThisCallCast(); MethodSymbol* called_constructor = (MethodSymbol*) (this_call ? this_call -> symbol : NULL); if (called_constructor) { called_constructor_declaration = (AstConstructorDeclaration*) called_constructor -> declaration; if (called_constructor_declaration -> index == OMEGA) CheckConstructorCycles(called_constructor_declaration); constructor_declaration -> index = Min(constructor_declaration -> index, called_constructor_declaration -> index); } } if (constructor_declaration -> index == indx) { // // If the constructor_declaration is alone in its strongly connected // component (SCC), and it does not form a trivial cycle with itself, // pop it, mark it and return. // if (constructor_declaration == stack.Top() && constructor_declaration != called_constructor_declaration) { stack.Pop(); constructor_declaration -> index = CYCLE_INFINITY; } // // Otherwise, all elements in the stack up to (and including) // constructor_declaration form an SCC. Pop them off the stack, in // turn, mark them and issue the appropriate error message. // else { do { called_constructor_declaration = stack.Top(); stack.Pop(); called_constructor_declaration -> index = CYCLE_INFINITY; constructor_block = (AstMethodBody*) called_constructor_declaration -> constructor_body; AstMethodDeclarator* constructor_declarator = called_constructor_declaration -> constructor_declarator; Semantic* sem = called_constructor_declaration -> constructor_symbol -> containing_type -> semantic_environment -> sem; sem -> ReportSemError(SemanticError::CIRCULAR_THIS_CALL, constructor_block -> explicit_constructor_opt, sem -> lex_stream -> NameString(constructor_declarator -> identifier_token)); } while (called_constructor_declaration != constructor_declaration); } } } // // assert that the "index" of all types that should be checked is initially // set to OMEGA // void TypeDependenceChecker::PartialOrder() { for (FileSymbol* file_symbol = (FileSymbol*) file_set.FirstElement(); file_symbol; file_symbol = (FileSymbol*) file_set.NextElement()) { for (unsigned j = 0; j < file_symbol -> types.Length(); j++) { TypeSymbol* type = file_symbol -> types[j]; if (type -> incremental_index == OMEGA) ProcessType(type); } } for (unsigned k = 0; k < type_trash_bin.Length(); k++) { TypeSymbol* type = type_trash_bin[k]; if (type -> incremental_index == OMEGA) ProcessType(type); } } void TypeDependenceChecker::ProcessType(TypeSymbol* type) { stack.Push(type); int indx = stack.Size(); type -> incremental_index = indx; // if dependents is reflexive make it non-reflexive - saves time !!! type -> dependents -> RemoveElement(type); type -> dependents_closure = new SymbolSet; // compute reflexive transitive closure type -> dependents_closure -> AddElement(type); TypeSymbol* dependent; for (dependent = (TypeSymbol*) type -> dependents -> FirstElement(); dependent; dependent = (TypeSymbol*) type -> dependents -> NextElement()) { if (dependent -> incremental_index == OMEGA) ProcessType(dependent); type -> incremental_index = Min(type -> incremental_index, dependent -> incremental_index); type -> dependents_closure -> Union(*(dependent -> dependents_closure)); } if (type -> incremental_index == indx) { TypeSymbol* scc_dependent; do { scc_dependent = stack.Top(); scc_dependent -> incremental_index = CYCLE_INFINITY; *(scc_dependent -> dependents_closure) = *(type -> dependents_closure); type_list.Next() = scc_dependent; stack.Pop(); } while (scc_dependent != type); } } void TypeDependenceChecker::OutputMake(FILE* outfile, char* output_name, Tuple& file_list) { assert(outfile); for (unsigned i = 0; i < file_list.Length(); i++) { FileSymbol* file_symbol = file_list[i]; char* name = file_symbol -> FileName(); int length = file_symbol -> FileNameLength() - (file_symbol -> IsJava() ? FileSymbol::java_suffix_length : FileSymbol::class_suffix_length); char* class_name = new char[length + FileSymbol::class_suffix_length + 1]; char* java_name = new char[length + FileSymbol::java_suffix_length + 1]; strncpy(class_name, name, length); strcpy(&class_name[length], FileSymbol::class_suffix); strncpy(java_name, name, length); strcpy(&java_name[length], FileSymbol::java_suffix); fprintf(outfile, "%s : %s\n", output_name, java_name); if (i > 0) // Not the first file in the list { fprintf(outfile, "%s : %s\n", output_name, class_name); } delete [] class_name; delete [] java_name; } } void TypeDependenceChecker::OutputMake(FileSymbol* file_symbol) { // // // const char* name; char* buf = NULL; int length; if (control -> option.directory == NULL) { name = file_symbol -> FileName(); length = file_symbol -> FileNameLength() - (file_symbol -> IsJava() ? FileSymbol::java_suffix_length : FileSymbol::class_suffix_length); } else { name = file_symbol -> Utf8Name(); length = strlen(name); DirectorySymbol* dir_symbol = file_symbol -> OutputDirectory(); char* dir_name = dir_symbol -> DirectoryName(); int dir_length = strlen(dir_name); buf = new char[length + FileSymbol::class_suffix_length + dir_length + 2]; strcpy(buf, dir_name); #ifdef UNIX_FILE_SYSTEM buf[dir_length] = (char)U_SLASH; #elif defined(WIN32_FILE_SYSTEM) buf[dir_length] = (char)U_BACKSLASH; #endif strcpy(&buf[dir_length+1], name); name = buf; length = dir_length + 1 + length; } char* output_name = new char[length + FileSymbol::class_suffix_length + 1]; char* u_name = new char[length + strlen(StringConstant::U8S_DO_u) + 1]; strncpy(output_name, name, length); strncpy(u_name, name, length); strcpy(&output_name[length], FileSymbol::class_suffix); strcpy(&u_name[length], StringConstant::U8S_DO_u); // // // SymbolSet file_set; for (unsigned i = 0; i < file_symbol -> types.Length(); i++) { TypeSymbol* type = file_symbol -> types[i]; TypeSymbol* parent; for (parent = (TypeSymbol*) type -> parents_closure -> FirstElement(); parent; parent = (TypeSymbol*) type -> parents_closure -> NextElement()) { FileSymbol* symbol = parent -> file_symbol; if (symbol && (! symbol -> IsZip())) file_set.AddElement(symbol); } } file_set.RemoveElement(file_symbol); // // // Tuple file_list(file_set.Size()); file_list.Next() = file_symbol; for (FileSymbol* symbol = (FileSymbol*) file_set.FirstElement(); symbol; symbol = (FileSymbol*) file_set.NextElement()) file_list.Next() = symbol; FILE* outfile = SystemFopen(u_name, "w"); if (outfile == NULL) Coutput << "*** Cannot open output Makefile " << u_name << endl; else { OutputMake(outfile, output_name, file_list); fclose(outfile); } delete [] output_name; delete [] u_name; if (control -> option.directory) delete [] buf; } void TypeDependenceChecker::OutputDependences() { SymbolSet new_file_set; unsigned i; for (i = 0; i < type_list.Length(); i++) { TypeSymbol* type = type_list[i]; type -> parents_closure = new SymbolSet; FileSymbol* file_symbol = type -> file_symbol; if (file_symbol && (! file_symbol -> IsZip())) new_file_set.AddElement(file_symbol); } for (i = 0; i < type_list.Length(); i++) { TypeSymbol* parent = type_list[i]; TypeSymbol* dependent; for (dependent = (TypeSymbol*) parent -> dependents_closure -> FirstElement(); dependent; dependent = (TypeSymbol*) parent -> dependents_closure -> NextElement()) { dependent -> parents_closure -> AddElement(parent); } } for (FileSymbol* symbol = (FileSymbol*) new_file_set.FirstElement(); symbol; symbol = (FileSymbol*) new_file_set.NextElement()) { OutputMake(symbol); } for (i = 0; i < type_list.Length(); i++) { TypeSymbol* type = type_list[i]; delete type -> parents_closure; type -> parents_closure = NULL; } } void TopologicalSort::Process(TypeSymbol* type) { pending -> AddElement(type); TypeSymbol* super_type; for (super_type = (TypeSymbol*) type -> supertypes_closure -> FirstElement(); super_type; super_type = (TypeSymbol*) type -> supertypes_closure -> NextElement()) { if (type_collection.IsElement(super_type)) { if (! pending -> IsElement(super_type)) Process(super_type); } } type_list.Next() = type; } void TopologicalSort::Sort() { type_list.Reset(); for (TypeSymbol* type = (TypeSymbol*) type_collection.FirstElement(); type; type = (TypeSymbol*) type_collection.NextElement()) { if (! pending -> IsElement(type)) Process(type); } pending -> SetEmpty(); } TopologicalSort::TopologicalSort(SymbolSet& type_collection_, Tuple& type_list_) : type_collection(type_collection_) , type_list(type_list_) { pending = new SymbolSet(type_collection.Size()); } TopologicalSort::~TopologicalSort() { delete pending; } // // Depend on the base enclosing class. For example, with class A { class B{} }, // using the type A.B[] will add a dependence on A, because it is A.java that // must exist for the compiler to redefine B.class, and B.class that will be // used by the VM to define B[]. We cannot add dependences on the primitive // types, because there is no .java file that defines them. // void Semantic::AddDependence(TypeSymbol* base_type, TypeSymbol* parent_type, bool static_access) { assert(! base_type -> IsArray() && ! base_type -> Primitive()); if (parent_type -> IsArray()) { parent_type = parent_type -> base_type; } if (base_type -> Bad() || parent_type -> Bad() || parent_type == control.null_type || parent_type -> Primitive()) { return; } base_type = base_type -> outermost_type; parent_type = parent_type -> outermost_type; parent_type -> dependents -> AddElement(base_type); if (static_access) base_type -> static_parents -> AddElement(parent_type); else base_type -> parents -> AddElement(parent_type); // // It is not possible to import from the unnamed package, and without // imports, it is impossible to reference a class in the unnamed // package from a package. // assert(parent_type -> ContainingPackage() != control.UnnamedPackage() || base_type -> ContainingPackage() == control.UnnamedPackage()); } #ifdef HAVE_JIKES_NAMESPACE } // Close namespace Jikes block #endif