#include "MethodStatics.h" //////////////////////////////// utils /////////////////////////////// MethodStatics *fullMethodStatics(TreeNode *md) { int size = AA_FIRSTVALUE + md->params()->arity(); Bitset *fullBS = new Bitset(size); for (int i = 1; i < AA_FIRSTVALUE; i++) fullBS->set(i); for (int i = AA_FIRSTVALUE; i < size; i++) if (isAliasable(md->params()->child(i - AA_FIRSTVALUE)->dtype())) fullBS->set(i); return new MethodStatics(md, fullBS, fullBS, fullBS); } MethodStatics *emptyMethodStatics(TreeNode *md) { int size = AA_FIRSTVALUE + md->params()->arity(); Bitset *emptyBS = new Bitset(size); return new MethodStatics(md, emptyBS, emptyBS, emptyBS); } /* Get statics info from what we know about library functions. I'm only hard-coding a few common ones for now. */ MethodStatics *lookupStatics(TreeNode *md) { // set up BS's int size = AA_FIRSTVALUE + md->params()->arity(); Bitset *emptyBS = new Bitset(size); Bitset *thisBS = new Bitset(size); thisBS->set(AA_THISVALUE); Decl *decl = md->decl(); if (*decl->container()->name() == "StringBuffer" && isInJavaLang(decl->container())) { if (*decl->name() == "append" || *decl->name() == "insert") return new MethodStatics(md, thisBS, emptyBS, thisBS); else if (*decl->name() == "StringBuffer") return new MethodStatics(md, thisBS, emptyBS, emptyBS); else if (*decl->name() == "toString") return new MethodStatics(md, emptyBS, emptyBS, emptyBS); } if (*decl->container()->name() == "Object" && isInJavaLang(decl->container())) { if (*decl->name() == "Object") return new MethodStatics(md, emptyBS, emptyBS, emptyBS); } if (*decl->container()->name() == "System" && isInJavaLang(decl->container())) { if (*decl->name() == "arraycopy") { Bitset *thirdArg = new Bitset(size); thirdArg->set(AA_FIRSTVALUE + 2); return new MethodStatics(md, emptyBS, emptyBS, thirdArg); } } if (*decl->container()->name() == "PrintStream" && isInJavaIO(decl->container())) { if (*decl->name() == "print" || *decl->name() == "println") { Bitset *ext = copyBitset(thisBS); ext->set(AA_EXTERNALVALUE); return new MethodStatics(md, ext, emptyBS, ext); } } return NULL; } // Returns true if all overriders of the MethodDecl *d are side-effect // free bool SEFOverriders(const Decl *d) { const MethodSet *overriders = d->overriders(); for (MethodSet::const_iterator method = overriders->begin(); method != overriders->end(); method++) { if (!(*method)->source()->isSideEffectFree()) return false; if (!SEFOverriders(*method)) return false; } return true; } // Returns true if all overriders of the MethodDecl *d are pure bool pureOverriders(const Decl *d) { const MethodSet *overriders = d->overriders(); for (MethodSet::const_iterator method = overriders->begin(); method != overriders->end(); method++) { if (!(*method)->source()->isPureFunction()) return false; if (!pureOverriders(*method)) return false; } return true; } void limitedMerge(int x, Bitset *a, Bitset *b) { if (a->size() == b->size()) a->un(b); else { for (int i = 0; i < x; i++) { if (b->test(i)) a->set(i); } } } static Bitset *makeSpecialValues(TreeNode *method, int size) { Bitset *specialValues = new Bitset(size); specialValues->set(AA_EXTERNALVALUE); specialValues->set(AA_THISVALUE); for (int i = 0; i < method->params()->arity(); i++) if (isAliasable(method->params()->child(i)->dtype())) specialValues->set(AA_FIRSTVALUE + i); return specialValues; } //////////////////////////////// MethodStatics /////////////////////////////// MethodStatics::MethodStatics(TreeNode *m, int _numValues, TreeNodeToIntMap &avm) { method = m; returnsValues = new Bitset(_numValues); modifiesValues = new Bitset(_numValues); leaksValues = new Bitset(_numValues); specialValues = makeSpecialValues(method, _numValues); ASTValueMap = avm; callBackList = NULL; _myThisValueBitset = NULL; _myNullValueBitset = NULL; _myExtValueBitset = NULL; status = 1; } MethodStatics::MethodStatics(TreeNode *m, Bitset *rv, Bitset *lv, Bitset *mv) { method = m; returnsValues = rv; leaksValues = lv; modifiesValues = mv; specialValues = NULL; callBackList = NULL; _myThisValueBitset = NULL; _myNullValueBitset = NULL; _myExtValueBitset = NULL; status = 2; } bool MethodStatics::equal(MethodStatics *ms) { assert(method == ms->method); return (returnsValues->equal(ms->returnsValues)) && (modifiesValues->equal(ms->modifiesValues)) && (leaksValues->equal(ms->leaksValues)); } MethodStatics* MethodStatics::emptyCopy() { MethodStatics *temp = new MethodStatics(); temp->method = method; temp->status = status; temp->returnsValues = copyBitset(returnsValues); temp->modifiesValues = copyBitset(modifiesValues); temp->leaksValues = copyBitset(leaksValues); temp->callBackList = NULL; return temp; } void MethodStatics::println(ostream &os) { os << "Modifies values: "; printBitset(modifiesValues, cout); cout << endl; os << "Leaks values: "; printBitset(leaksValues, cout); cout << endl; os << "Returns values: "; printBitset(returnsValues, cout); cout << endl; } void MethodStatics::merge(MethodStatics *ms) { int minSize = ms->method->params()->arity() + AA_FIRSTVALUE; limitedMerge(minSize, returnsValues, ms->returnsValues); limitedMerge(minSize, modifiesValues, ms->modifiesValues); limitedMerge(minSize, leaksValues, ms->leaksValues); } bool MethodStatics::isSideEffectFree() const { if (modifiesValues->test(AA_EXTERNALVALUE)) return false; if (!isConstructorDeclNode(method) && modifiesValues->test(AA_THISVALUE)) return false; for (int i = AA_FIRSTVALUE; i < AA_FIRSTVALUE + method->params()->arity(); i++) if (modifiesValues->test(i)) return false; return true; } Bitset *MethodStatics::newNullValueBitset() { return new Bitset(numValues()); } Bitset *MethodStatics::myNullValueBitset() { if (_myNullValueBitset == NULL) _myNullValueBitset = newNullValueBitset(); return _myNullValueBitset; } Bitset *MethodStatics::newThisValueBitset() { Bitset *thisValueBitset = new Bitset(numValues()); thisValueBitset->set(AA_THISVALUE); return thisValueBitset; } Bitset *MethodStatics::myThisValueBitset() { if (_myThisValueBitset == NULL) _myThisValueBitset = newThisValueBitset(); return _myThisValueBitset; } Bitset *MethodStatics::newExtValueBitset() { Bitset *extValueBitset = new Bitset(numValues()); extValueBitset->set(AA_EXTERNALVALUE); return extValueBitset; } Bitset *MethodStatics::myExtValueBitset() { if (_myExtValueBitset == NULL) _myExtValueBitset = newExtValueBitset(); return _myExtValueBitset; } ///////////////// other MethodStatics business ///////////////////////// MethodStatics *TreeNode::methodStatics() const { undefined("methodStatics"); return 0; } MethodStatics *MethodDeclNode::methodStatics() const { return _methodStatics; } MethodStatics *MethodSignatureNode::methodStatics() const { return _methodStatics; } MethodStatics *ConstructorDeclNode::methodStatics() const { return _methodStatics; } void TreeNode::setMethodStatics(MethodStatics *tm) { undefined("setMethodStatics"); } void MethodDeclNode::setMethodStatics(MethodStatics *tm) { _methodStatics = tm; } void MethodSignatureNode::setMethodStatics(MethodStatics *tm) { _methodStatics = tm; } void ConstructorDeclNode::setMethodStatics(MethodStatics *tm) { _methodStatics = tm; } ///////////////////////// ::isSideEffectFree and ::isPureFunction /////////// bool TreeNode::isPureFunction() const { undefined("isPureFunction"); return false; } bool MethodDeclNode::isPureFunction() const { // there is currently no analysis to tell if it's a pure function return isKnownPure(this); } bool MethodSignatureNode::isPureFunction() const { return true; } bool ConstructorDeclNode::isPureFunction() const { return isKnownPure(this); } bool MethodCallNode::isPureFunction() const { // This is very tricky here. Even if all overriders are pure, it doesn't // mean your "call" is pure! You might be calling different methods at // different times if your object is different. Thus remember to // consider the object an argument. return decl()->source()->isPureFunction() && pureOverriders(decl()); } bool AllocateNode::isPureFunction() const { return decl()->source()->isPureFunction(); } bool ThisConstructorCallNode::isPureFunction() const { return decl()->source()->isPureFunction(); } bool SuperConstructorCallNode::isPureFunction() const { return decl()->source()->isPureFunction(); } bool ConstructorDeclNode::isSideEffectFree() const { return isKnownSideEffectFree(this) || (methodStatics() != NULL && methodStatics()->isSideEffectFree()); } bool MethodDeclNode::isSideEffectFree() const { return isKnownSideEffectFree(this) || (methodStatics() != NULL && methodStatics()->isSideEffectFree()); } bool MethodSignatureNode::isSideEffectFree() const { // how silly. a method with no body cannot have side effects. (be // careful about its overriders though) return true; } bool TreeNode::isSideEffectFree() const { undefined("isSideEffectFree"); return false; } // Return true if the method being called and all its overriders are // side-effect free bool MethodCallNode::isSideEffectFree() const { return decl()->source()->isSideEffectFree() && SEFOverriders(decl()); } bool AllocateNode::isSideEffectFree() const { return decl()->source()->isSideEffectFree(); } bool ThisConstructorCallNode::isSideEffectFree() const { return decl()->source()->isSideEffectFree(); } bool SuperConstructorCallNode::isSideEffectFree() const { return decl()->source()->isSideEffectFree(); }