#include "code-util.h" #include "code-ipanal.h" #include "cfg.h" #include "MethodSet.h" bool aaDebugOn = false; // turn on by -dumpphase aa bool aaSuperDebugOn = false; // turn on by -dumpphase aaSuper static llist *sortedMethodList; // main(...) goes LAST // Globals used during setup of each method to use the // TraverseBblocks(...) procedures.. yuck static TreeNodeToIntMap tempMap; static int nextMethodValue; static llist *addList; void processMethods(TreeNode *t, void action(TreeNode *t)) { const int childCount = t->arity(); if (isMethodDeclNode(t) || isConstructorDeclNode(t)) { action(t); } else { for (int sweep = 0; sweep < childCount; sweep++) { if (!t->child(sweep)->isStatementNode()) { processMethods(t->child(sweep), action); } } } } void setupBblocksMethod(TreeNode *t); void setupBblocks() { foreach (f, llist, *allFiles) if ((*f)->selectedForCodeGen(false)) processMethods(*f, setupBblocksMethod); } // also sets up method statics void topSortMethods() { sortedMethodList = NULL; foreach (f, llist, *allFiles) if ((*f)->selectedForCodeGen(false)) processMethods(*f, setupMethodStatics); sortedMethodList = dreverse(sortedMethodList); } void printSEF(TreeNode *t) { cout << *t->simpName()->ident() << " in "; t->decl()->container()->print(cout); if (t->methodStatics() == NULL) cout << "has no methodStatics"; else cout << " is sideEffectFree? " << t->isSideEffectFree(); cout << ". listlook: " << isKnownSideEffectFree(t); cout << endl; } void IPAnal() { DEBUG_PHASE("aa", currentFilename, aaDebugOn = true); DEBUG_PHASE("aaSuper", currentFilename, aaSuperDebugOn = true); topSortMethods(); while (sortedMethodList != NULL) { TreeNode *next = sortedMethodList->front(); sortedMethodList = sortedMethodList->free(); // alias analysis analyzeMethodWakeup(next); /* other stuff can go here */ } if (DEBUG_PHASE_ENABLED("sef", currentFilename)) foreach (f, llist, *allFiles) if ((*f)->selectedForCodeGen(false)) processMethods(*f, printSEF); } /* Returns the 'real' object after CastNode's or IBroadcastNodes. In the new IF, there are not many possibilities. See comments in lower.cc. */ TreeNode *getRealExpr(TreeNode *rightSide) { // casts should only go 1-deep if (isCastNode(rightSide) || isIBroadcastNode(rightSide)) return rightSide->child(0); return rightSide; } llist *getDeclAndOverriders(TreeNode *md) { llist *temp = cons(md); MethodSet *overriders = md->decl()->overriders(); for (MethodSet::const_iterator method = overriders->begin(); method != overriders->end(); method++) { temp = extend(temp, getDeclAndOverriders((*method)->source())); } return temp; } /* Set up the call graph and assign numbers to each allocate node, and keep track of what numbers we assigned. We give regular methodcallnode's a number too because it MIGHT allocate something and it gets one only for consistency. */ void setupValuesBblock(Bblock *b) { ListIterator cfgIt = b->cfgIter(); for (; !cfgIt.isDone(); cfgIt.next()) { CfgNode *cfg = *cfgIt; TreeNode *t = cfg->astNode(); if (isAllocateNode(t) || isAllocateArrayNode(t) || isStringLitNode(t)|| isArrayInitNode(t) || (isMethodCallNode(t) && isAliasable(t->type()))) { tempMap[getRealExpr(t)] = nextMethodValue; nextMethodValue++; } if (isAllocateNode(t) || isConstructorCallNode(t) || isMethodCallNode(t)) addList = extend(getDeclAndOverriders(t->decl()->source()), addList); } } bool isInList(TreeNode *t, llist *l) { while (l != NULL) { if (l->front() == t) return true; else l = l->tail(); } return false; } /* Code is elsewhere if it's a native method. */ bool codeIsElsewhere(TreeNode *t) { return (t->flags() & Common::Native) != 0; } /* Method with omitted body. Abstract methods and hidden constructors. */ bool emptyMethod(TreeNode *t) { return isMethodSignatureNode(t) || t->body() == TreeNode::omitted; } void clearAbstractValues(Bblock *b) { ListIterator cfgIt = b->cfgIter(); for (; !cfgIt.isDone(); cfgIt.next()) { TreeNode *t = (*cfgIt)->astNode(); if (isExprNode(t)) { delete t->getAbstractValues(); t->setAbstractValues(NULL); } } } void nullifyAA(TreeNode *m) { delete m->methodStatics(); m->setMethodStatics(NULL); if (m->getBblockRoot() != NULL) TraverseBblocks(m->getBblockRoot(), clearAbstractValues); } void unsetupAA() { foreach (f, llist, *allFiles) if ((*f)->selectedForCodeGen(false)) processMethods(*f, nullifyAA); } void setupMethodStatics(TreeNode *t) { if (t->methodStatics() != NULL) return; if (t->getBblockRoot() == NULL) { if (!codeIsElsewhere(t) && emptyMethod(t)) t->setMethodStatics(emptyMethodStatics(t)); return; } // set up AST --> values mapping. save room for parameters nextMethodValue = AA_FIRSTVALUE + t->params()->arity(); tempMap.clear(); addList = NULL; TraverseBblocks(t->getBblockRoot(), setupValuesBblock); MethodStatics *ms = new MethodStatics(t, nextMethodValue, tempMap); t->setMethodStatics(ms); llist *copyAddList = dreverse(addList); while (copyAddList != NULL) { setupMethodStatics(copyAddList->front()); copyAddList = copyAddList->free(); } if (!isInList(t, sortedMethodList)) sortedMethodList = cons(t, sortedMethodList); } // analyze and then requeue anyone waiting on this method. void analyzeMethodWakeup(TreeNode *t) { analyzeMethod(t); // if it's not pending anything, it's done if (t->methodStatics()->status != 3) t->methodStatics()->status = 2; // re-queue waiters if (t->methodStatics()->callBackList != NULL) { llist *workList = copylist(t->methodStatics()->callBackList); while (workList != NULL) { TreeNode *next = workList->front()->waiter; MethodStatics *nextMS = workList->front()->ms; workList = workList->free(); if (!nextMS->equal(t->methodStatics())) { if (!isInList(next, sortedMethodList)) { if (aaDebugOn) cout << "Requeing: " << *next->decl()->name() << endl; sortedMethodList = cons(next, sortedMethodList); } } } } }