/* static.cc: Main module for Java static semantics. */ #include #include "AST.h" #include "FieldDecl.h" #include "MethodDecl.h" #include "NameContext.h" #include "NamesQueue.h" #include "cfg.h" #include "code-point.h" #include "code-util.h" #include "compiler.h" #include "decls.h" #include "domain-decls.h" #include "errno.h" #include "errors.h" #include "is-main.h" #include "lower.h" #include "qual-infer/cqual/libcompat/regions.h" #include "qual-infer/local/options.h" #include "qual-infer/local/traverse.h" #include "qual-infer/sharing/options.h" #include "qual-infer/sharing/phase.h" #include "st-sglobal.h" #include "string-utils.h" #include "template.h" #include "templates/TemplatesQueue.h" #include "utils.h" #include "SearchPath.h" const string *TiString, *ObjectString, *UnknownString, *StringString, *StringBufferString, *JavaLangClassString, *ErrorString, *RuntimeExceptionString, *ClassCastExceptionString, *ThrowableString, *JavaArrayString, *RectDomainM1String, *RectDomainString, *DomainString, *tiDomainsString, #if 1 // !!! HACK miyamoto: to always instantiate domains *PointNString[3], *RectDomainNString[3], *RectDomainListNString[3], *RectDomainListIteratorNString[3], *DomainNString[3], #endif *TiArrayString, *TiArrayLString, *TiArrayM1String, *TemplateArgString, *PointString, *CloneableString, *TitaniumString, *InternalString, #if 1 // !!! HACK miyamoto: to always instantiate domains *DomainLibString, #endif *JavaString, *LangString, *ArityString, *CopyString, *RegionString, *SharedRegionString, *PrivateRegionString; Decl *unnamedPackage; ClassDecl *ObjectDecl, *StringDecl, *StringBufferDecl, *JavaLangClassDecl, *ErrorDecl, *RuntimeExceptionDecl, *ClassCastExceptionDecl, *ThrowableDecl, *JavaArrayDecl, *RectDomainM1Decl, *RectDomainDecl, *DomainDecl, *tiDomainsDecl, *PointDecl, #if 1 // !!! HACK miyamoto: to always instantiate domains *PointNDecl[3], *DomainNDecl[3], *RectDomainNDecl[3], *RectDomainListNDecl[3], *RectDomainListIteratorNDecl[3], #endif *TiArrayM1Decl, *TiArrayDecl, *TiArrayLDecl, *TemplateArgDecl, *CloneableDecl, *RegionDecl, *SharedRegionDecl, *PrivateRegionDecl, *NativeUtilsDecl; Decl *TiArityDecl; ClassDecl *UnknownClassDecl; Decl *UnknownPackageDecl, *UnknownFieldDecl, *UnknownMethodDecl; TypeNode *theArrayInitializerType; extern bool parse_only; static void importPackage(Environ &env, const string *s1, const string *s2) { NameNode outer(TreeNode::omitted, s1, NULL); NameNode name(&outer, s2, NULL); int errs0 = NumErrors(); resolveAName(&name, *(PackageDecl::System->environ()), NULL, Common::None, NULL, Decl::Package); if (errs0 == NumErrors()) foriter (type, name.decl()->environ()->allProperDecls(), EnvironIter) if (type->category() != Decl::Package) env.add(&*type); // conflicts appear on use only } static ClassDecl *requireClass(const Environ &env, const string *name) { Decl * const decl = env.lookup( name ); if (!decl) { cerr << "fatal error: could not find class or interface \"" << *name << "\" in bootstrap environment" << endl; if (DEBUG) { cerr << "bootstrap environment " << &env << " contains:\n"; env.print( cerr ); } exit(1); } if (!(decl->category() & (Decl::Class | Decl::Interface))) { cerr << "fatal error: " << decl->errorName() << " should be a class or interface" << endl; exit(1); } decl->drequire(); return static_cast< ClassDecl * >(decl); } /* Initialize Decls, types, etc, used internally */ void initTheSystem() { theArrayInitializerType = new ArrayInitializerTypeNode; TiString = intern ("Ti"); ObjectString = intern ("Object"); UnknownString = intern("tiUnknown"); StringString = intern ("String"); StringBufferString = intern ("StringBuffer"); JavaLangClassString = intern ("Class"); ErrorString = intern ("Error"); RuntimeExceptionString = intern ("RuntimeException"); ClassCastExceptionString = intern ("ClassCastException"); ThrowableString = intern ("Throwable"); CloneableString = intern ("Cloneable"); JavaArrayString = intern ("tiJArray"); DomainString = intern ("tiDomain"); RectDomainString = intern ("tiRectDomain"); RectDomainM1String = intern ("tiRectDomainM1"); PointString = intern ("tiPoint"); RegionString = intern("Region"); SharedRegionString = intern("SharedRegion"); PrivateRegionString = intern("PrivateRegion"); tiDomainsString = intern("tiDomains"); #if 1 // !!! HACK miyamoto: to always instantiate domains PointNString[0] = intern ("tiPoint1"); DomainNString[0] = intern ("tiDomain1"); RectDomainNString[0] = intern ("tiRectDomain1"); RectDomainListNString[0] = intern ("tiRectDomainList1"); RectDomainListIteratorNString[0] = intern ("tiRectDomainListIterator1"); PointNString[1] = intern ("tiPoint2"); DomainNString[1] = intern ("tiDomain2"); RectDomainNString[1] = intern ("tiRectDomain2"); RectDomainListNString[1] = intern ("tiRectDomainList2"); RectDomainListIteratorNString[1] = intern ("tiRectDomainListIterator2"); PointNString[2] = intern ("tiPoint3"); DomainNString[2] = intern ("tiDomain3"); RectDomainNString[2] = intern ("tiRectDomain3"); RectDomainListNString[2] = intern ("tiRectDomainList3"); RectDomainListIteratorNString[2] = intern ("tiRectDomainListIterator3"); #endif TiArrayString = intern("tiArray"); TiArrayLString = intern("tiArrayL"); TiArrayM1String = intern("tiArrayM1"); TemplateArgString = intern("tiTemplateArgument"); JavaString = intern ("java"); TitaniumString = intern ("ti"); InternalString = intern ("internal"); #if 1 // !!! HACK miyamoto: to always instantiate domains DomainLibString = intern ("domains"); #endif LangString = intern ("lang"); ArityString = intern ("arity"); CopyString = intern ("copy"); unnamedPackage = new PackageDecl(new string("")); Environ env; importPackage(env, JavaString, LangString); importPackage(env, TitaniumString, LangString); importPackage(env, TitaniumString, InternalString); importPackage(env, TitaniumString, DomainLibString); if (!parse_only) { ObjectDecl = requireClass( env, ObjectString ); UnknownClassDecl = requireClass( env, UnknownString ); StringDecl = requireClass( env, StringString ); StringBufferDecl = requireClass( env, StringBufferString ); JavaLangClassDecl = requireClass( env, JavaLangClassString ); ErrorDecl = requireClass( env, ErrorString ); RuntimeExceptionDecl = requireClass( env, RuntimeExceptionString ); ClassCastExceptionDecl = requireClass( env, ClassCastExceptionString ); ThrowableDecl = requireClass( env, ThrowableString ); CloneableDecl = requireClass( env, CloneableString ); JavaArrayDecl = requireClass( env, JavaArrayString ); RegionDecl = requireClass( env, RegionString ); SharedRegionDecl = requireClass( env, SharedRegionString ); PrivateRegionDecl = requireClass( env, PrivateRegionString ); #ifndef JAVA TiArrayDecl = requireClass( env, TiArrayString ); TiArrayLDecl = requireClass( env, TiArrayLString ); TiArrayM1Decl = requireClass( env, TiArrayM1String ); TemplateArgDecl = requireClass( env, TemplateArgString ); PointDecl = requireClass( env, PointString ); DomainDecl = requireClass( env, DomainString ); tiDomainsDecl = requireClass( env, tiDomainsString ); RectDomainDecl = requireClass( env, RectDomainString ); RectDomainM1Decl = requireClass( env, RectDomainM1String ); #endif #if 1 // !!! HACK miyamoto: to always instantiate domains for (int i = 0 ; i < 3; i++) { PointNDecl[i] = requireClass( env, PointNString[i] ); DomainNDecl[i] = requireClass( env, DomainNString[i] ); RectDomainNDecl[i] = requireClass( env, RectDomainNString[i] ); RectDomainListNDecl[i] = requireClass( env, RectDomainListNString[i] ); RectDomainListIteratorNDecl[i] = requireClass( env, RectDomainListIteratorNString[i] ); } #endif /* Instantiate java.lang.UNIXProcess and related stuff */ requireClass( env, intern( "UNIXProcess" ) ); requireClass( env, intern( "OutOfMemoryError" ) ); requireClass( env, TiString ); NativeUtilsDecl = requireClass( env, intern( "NativeUtils" ) ); PointUtilsDecl = requireClass( env, intern( "PointUtils" ) ); requireClass( env, intern( "ImplementsWorld" ) ); if (opt_local) requireClass( env, intern( "LocalInfer" ) ); if (opt_sharing) requireClass( env, intern( "SharingInfer" ) ); // string ti_lang_ti = new string("ti/lang/Ti.java"); // load(ti_lang_ti, ClassLib.fopen(ti_lang_ti, "r")); UnknownPackageDecl = new PackageDecl (NULL); UnknownPackageDecl->environ (new Environ); // Unkown field & method are public & static to avoid cascading errors UnknownFieldDecl = new FieldDecl (NULL, theIntType, UnknownClassDecl, (Common::Modifiers) (Common::Static | Common::Public), TreeNode::omitted); UnknownMethodDecl = new MethodDecl (NULL, new MethodTypeNode (NULL, theIntType, NULL), Decl::Method, UnknownClassDecl, (Common::Modifiers)(Common::Static | Common::Public), TreeNode::omitted); /* build environments for runtime stuff and find tiArity field */ buildEnvironments(); #ifndef JAVA TiArityDecl = TemplateArgDecl->environ()->lookup(ArityString); #endif } } llist *allFiles = NULL; static llist *recentFiles = NULL; static CompileUnitNode *loaded; /* The parser's interface to the rest of the compiler. The */ /* root of the synthesized abstract syntax tree is passed to */ /* this function. */ void compileAST (CompileUnitNode *root) { if (!parse_only) root->packageResolution(); loaded = root; } bool isTitanium(string fileName) { return hasSuffix(fileName, ".ti"); } void load(const string name, bool titaniumFile) { load(name.c_str(), titaniumFile); } void load(const char * const name, bool titaniumFile) { FILE * const file = ti_fopen(name, "r"); load(name, file, titaniumFile); if (file) ti_fclose(file); } void load(const string name, FILE *file, bool titaniumFile) { if (file) { bool newfile; if (file == stdin) newfile = true; else { static set loadedFiles; string *fullname = ti_fname(file); if (loadedFiles.count(*fullname)) newfile = false; else { newfile = true; loadedFiles.insert(*fullname); } } if (newfile) { loaded = NULL; compile_status(2,string("parsing: ") + name); parse(file, name, titaniumFile); if (loaded) { loaded->ident(new string(name)); loaded->loaded(); } } else { compile_status(2,string("skipping parse of duplicate file: ") + name); } } else Error() << "Couldn't open " << name << ':' << strerror(errno) << endl; } void CompileUnitNode::loaded() { push( allFiles, this ); push( recentFiles, this ); unresolvedNames.push_back( this ); unresolvedTemplates.push_back( this ); } void buildEnvironments() { foreach (f, llist, *recentFiles) (*f)->resolveClass(NULL, NULL, NULL); foreach (f, llist, *recentFiles) (*f)->resolveInheritance(); free_all(recentFiles); recentFiles = NULL; } void fixParents(llist *t) { int k = 0; foreach (f, llist, *t) k += (*f)->fixParent(); cout << "fixParents(): " << k << " fixed.\n"; } void fixParents(TreeNode *t) { int k = t->fixParent(); cout << "fixParents(): " << k << " fixed.\n"; } char *currentFilename; void staticSemantics() { buildEnvironments(); extern bool canbuildenv; extern bool allshouldbeloaded; canbuildenv = true; do { unresolvedNames.resolve(); foldConstants(); } while (unresolvedTemplates.resolve( false )); unresolvedTemplates.resolve( true ); unresolvedNames.resolve(); assert( unresolvedNames.empty() ); assert( unresolvedTemplates.empty() ); // catch bugs (no more loads after this point; see src-input.cc) allshouldbeloaded = true; // Handle files in the order they were loaded allFiles = dreverse(allFiles); verifyCircularity(); compile_status(1,"Type-checking..."); foreach (f, llist, *allFiles) { TreeNode *file = *f; if (DEBUG) cout << "static resolution of " << *file->ident() << "\n"; file->resolveField(NULL, NULL); file->resolveConcat(); compile_status(2,string("type-checking: ") + *file->ident()); file->typecheck(NULL); if (DEBUG_PHASE_ENABLED("typecheck", file->ident()->c_str())) { cout << "pseudoprint after typechecking: " << endl; file->pseudoprint(cout,0); cout << endl; cout << "AST dump after typechecking: " << endl; file->print(cout,0); cout << endl; } } if (NumErrors() == 0) { if (use_sglobal_inference) { compile_status(1,"Running sglobal inference..."); sglobalInference(); } compile_status(1,"Running single analysis..."); foreach (f, llist, *allFiles) singleAnalysis(*f); } /* fixParents(allFiles); */ if (NumErrors() == 0) { compile_status(1,"Rewriting..."); foreach (f, llist, *allFiles) { compile_status(2,string("rewriting: ") + *(*f)->ident()); (*f)->rewrite( 0 ); } } /* fixParents(allFiles); fixParents(allFiles); fixParents(allFiles); cout << "(The two lines above this one should be the same and should report 0 fixed\n if the AST has no shared subtrees.)\n"; */ // Invoke lowering and resolveRequires. if (NumErrors() == 0) { templateEnv.resolveTemplates(); foldInstantiations(); if (opt_local || opt_sharing) region_init(); if (opt_local) compile_status(1,"Running local inference..."); inferLocal(); if (opt_sharing) compile_status(1,"Running sharing inference..."); inferSharing(); compile_status(1,"Widening/lowering..."); foreach (f, llist, *allFiles) if ((*f)->selectedForCodeGen(false)) (*f)->lazyStaticSemantics(); } if (codeGen_main) { compile_status(1,"Looking for main()..."); foreach (f, llist, *allFiles) (*f)->lookForMain(); checkOnlyOneMain(); } } CompileUnitNode *CompileUnitNode::lazyStaticSemantics() { if (!ranLazyStaticSemantics) { compile_status(2,string("widening/lowering: ") + *ident()); collectCleanups(); widen(); if (DEBUG_PHASE_ENABLED("widened", ident()->c_str())) { cout << "AST dump after widening: " << endl; print(cout,0); cout << endl; } llist *t1 = NULL, *t2 = NULL; fixParent(); resetIFtemp(); *this = *dynamic_cast(lower(t1, t2)); *this = *dynamic_cast(collapseTrivialBlocks()); if (DEBUG_PHASE_ENABLED("lowered", ident()->c_str())) { cout << "AST dump after lowering: " << endl; print(cout,0); cout << endl; } fixParent(); checkAndFixAliasing(this); checkIF(true); resolveRequires(0); ranLazyStaticSemantics = true; } return this; } /* The decl method. */ ClassDecl *TemplateDeclNode::decl() const { return basis()->decl(); } ClassDecl* TypeNameNode::decl() const { Decl * const result = name()->decl(); assert( !result || result->category() & (Decl::Class | Decl::Interface) ); return static_cast< ClassDecl * >( result ); } TypeDecl *JavaArrayTypeNode::decl() const { return getJavaArrayDecl(this); } ClassDecl *PointTypeNode::decl() const { return getPointDecl(this); } ClassDecl *DomainTypeNode::decl() const { return getDomainDecl(this); } ClassDecl *RectDomainTypeNode::decl() const { return getRectDomainDecl(this); } ClassDecl *TitaniumArrayTypeNode::decl() const { return getTiArrayDecl(this); } Decl* ObjectNode::decl() const { return ObjectNode::name()->decl(); } ClassDecl* TypeDeclNode::decl() const { Decl * const result = simpName()->decl(); assert( result->category() & (Decl::Class | Decl::Interface) ); return static_cast< ClassDecl * >( result ); } Decl* FieldDeclNode::decl() const { return simpName()->decl(); } Decl* VarDeclNode::decl() const { return simpName()->decl(); } MethodDecl* MethodNode::decl() const { Decl * const result = simpName()->decl(); assert( result->category() == Decl::Method ); return static_cast< MethodDecl * >(result); } MethodDecl* ConstructorDeclNode::decl() const { Decl * const result = simpName()->decl(); assert( result->category() == Decl::Constructor ); return static_cast< MethodDecl * >(result); } Decl* ParameterNode::decl() const { return simpName()->decl(); } MemberDecl* FieldAccessNode::decl() const { return dynamic_cast< MemberDecl * >( simpName()->decl() ); } MethodDecl* MethodCallNode::decl() const { return dynamic_cast< MethodDecl * >( method()->decl() ); } MethodDecl* MethodCallAssignNode::decl() const { return dynamic_cast< MethodDecl * >( method()->decl() ); } TreeNode* NameNode::simpName() const { return const_cast ((const TreeNode*) this); }