#include "AliasInfos.h" #include "code-util.h" /* AA_NULLVALUE is no longer used everywhere. */ //////////////////////// UTILS ////////////////////// bool isNamedValue(int value) { return (value == AA_NULLVALUE || value == AA_EXTERNALVALUE || value == AA_THISVALUE || value == AA_UNUSEDVALUE); } /* A string representation of value. */ string valueToString(int value) { switch (value) { case AA_NULLVALUE: return nullString; case AA_EXTERNALVALUE: return extString; case AA_THISVALUE: return thisString; case AA_UNUSEDVALUE: return unusedString; default: fatal_error(""); return string(); } } void printBitset(Bitset *b, ostream &os) { os << "{ "; bool needComma = false; for (int i = 0; i < b->size(); i++) { if (b->test(i)) { if (!needComma) needComma = true; else os << ", "; if (isNamedValue(i)) os << valueToString(i); else os << i; } } os << " }"; } void purePrintBitset(Bitset *b, ostream &os) { os << "{ "; bool needComma = false; for (int i = 0; i < b->size(); i++) { if (b->test(i)) { if (!needComma) needComma = true; else os << ", "; os << i; } } os << " }"; } bool isConstructorCallNode(TreeNode *t) { return isThisConstructorCallNode(t) || isSuperConstructorCallNode(t); } /* An aliasable type? */ bool isAliasable(TypeNode *t) { // currently titaniumarraytypes are immutable and not references.. maybe bug? return t->isTitaniumArrayType() || ((t->isReference() || t->isArrayType() || t->isNullType()) && !t->isImmutable()); } bool equalDeclToBitsetMaps(DeclToBitsetMap *d1, DeclToBitsetMap *d2) { if (d1->size() != d2->size()) return false; // check that all of d1's fields are in d2, and then check their // equality if they are. notice we need not check the reverse because // the sizes are now known to be the same for (DeclToBitsetMap::const_iterator v = d1->begin(); v != d1->end(); v++) { Decl* decl = (*v).first; //Bitset *bs = (*v).second; if (!isInMap(decl, (*d2))) return false; if (!(*d1)[decl]->equal((*d2)[decl])) return false; } return true; } /* A copy of b, or NULL if b is NULL. */ Bitset *copyBitset(Bitset *b) { if (b == NULL) return NULL; else { Bitset *temp = new Bitset(b->size()); temp->un(b); return temp; } } /* A new Bitset which is the union of a and b. A NULL value for a or b is treated as the empty bitset. */ Bitset *newUnion(Bitset *a, Bitset *b) { if (a == NULL) return copyBitset(b); if (b == NULL) return copyBitset(a); Bitset *temp = copyBitset(a); temp->un(b); return temp; } /* Calls a->un(b) and returns if a has changed as a result. */ bool nonTrivialUnion(Bitset *a, Bitset *b) { Bitset *temp = copyBitset(a); a->un(b); return !(a->equal(temp)); } //////////////////////////////// ValueInfo /////////////////////////////// ValueInfo::ValueInfo(int i, int numValues, TypeNode *t) { index = i; size = numValues; valueType = t; arrayValues = new Bitset(numValues); // arrayValues->set(AA_NULLVALUE); unknownFieldValue = AA_EXTERNALVALUE; fieldToBitsetMap.clear(); } bool ValueInfo::equivalent(ValueInfo *vi) { return index == vi->index && size == vi->size && valueType == vi->valueType && // should be OK arrayValues->equal(vi->arrayValues) && equalDeclToBitsetMaps(&fieldToBitsetMap, &(vi->fieldToBitsetMap)); } ValueInfo *ValueInfo::newCopy() { ValueInfo *temp = new ValueInfo(index, size, valueType); temp->valueType = valueType; temp->arrayValues = copyBitset(arrayValues); temp->unknownFieldValue = unknownFieldValue; // a straight copy of my decls. for (DeclToBitsetMap::const_iterator v = fieldToBitsetMap.begin(); v != fieldToBitsetMap.end(); v++) { Decl* decl = (*v).first; Bitset *bs = (*v).second; temp->fieldToBitsetMap[decl] = copyBitset(bs); } return temp; } bool ValueInfo::merge(ValueInfo *vi) { // merge with their array values arrayValues->un(vi->arrayValues); // merge with their field decls. notice that since this is protective, // we must delete our own unless BOTH ours are present. for (DeclToBitsetMap::const_iterator v = fieldToBitsetMap.begin(); v != fieldToBitsetMap.end(); v++) { Decl* decl = (*v).first; Bitset *bs = (*v).second; if (!isInMap(decl, vi->fieldToBitsetMap)) { // we must erase if they don't have this fieldToBitsetMap.erase(decl); } else { fieldToBitsetMap[decl]->un(bs); } } assert(unknownFieldValue == vi->unknownFieldValue); return true; // not calculating the changed now } /* Print my array values and field values, and sub-values if they're interesting by comparing against defaults. */ void ValueInfo::println(int prefix, ostream &os) { if (isNamedValue(prefix)) os << valueToString(prefix); else os << prefix; os << "[???] == "; printBitset(arrayValues, os); os << endl; // print field infos if any.. for (DeclToBitsetMap::const_iterator v = fieldToBitsetMap.begin(); v != fieldToBitsetMap.end(); v++) { Decl* decl = (*v).first; Bitset *bs = (*v).second; if (isNamedValue(prefix)) os << valueToString(prefix); else os << prefix; os << "." << *(decl->name()) << " == "; printBitset(bs, os); os << endl; } } //////////////////////////////// AliasInfos /////////////////////////////// bool AliasInfos::merge(AliasInfos *ai) { assert(ai != NULL); // merge with their decls. for (DeclToBitsetMap::const_iterator v = ai->declToBitsetMap.begin(); v != ai->declToBitsetMap.end(); v++) { Decl* decl = (*v).first; Bitset *bs = (*v).second; if (!isInMap(decl, declToBitsetMap)) { declToBitsetMap[decl] = copyBitset(bs); } else { declToBitsetMap[decl]->un(bs); } } // deep copy over their values, *OR* merge mine with theirs if that's // the case. for (ValueToValueInfoMap::const_iterator v = ai->valueToValueInfoMap.begin(); v != ai->valueToValueInfoMap.end(); v++) { int value = (*v).first; ValueInfo *vi = (*v).second; if (!isInMap(value, valueToValueInfoMap)) { valueToValueInfoMap[value] = vi->newCopy(); } else { valueToValueInfoMap[value]->merge(vi); } } leaksSet->un(ai->leaksSet); return true; } TypeNode *getThisType(TreeNode *method) { assert(method->decl()->container()->isType()); return method->decl()->container()->asType(); } AliasInfos::AliasInfos(int _size, TreeNode *method) { size = _size; declToBitsetMap.clear(); valueToValueInfoMap.clear(); _myNullValueBitset = NULL; // null valueToValueInfoMap[AA_NULLVALUE] = new ValueInfo(AA_NULLVALUE, size, theNullType); valueToValueInfoMap[AA_NULLVALUE]->unknownFieldValue = AA_NULLVALUE; // an external array probably has elements that have external values valueToValueInfoMap[AA_EXTERNALVALUE] = new ValueInfo(AA_EXTERNALVALUE, size, theNullType); valueToValueInfoMap[AA_EXTERNALVALUE]->arrayValues->set(AA_EXTERNALVALUE); valueToValueInfoMap[AA_THISVALUE] = new ValueInfo(AA_THISVALUE, size, theNullType); valueToValueInfoMap[AA_THISVALUE]->arrayValues->set(AA_THISVALUE); if (isConstructorDeclNode(method)) valueToValueInfoMap[AA_THISVALUE]->unknownFieldValue = AA_EXTERNALVALUE; else valueToValueInfoMap[AA_THISVALUE]->unknownFieldValue = AA_THISVALUE; leaksSet = new Bitset(size); leaksSet->set(AA_EXTERNALVALUE); // leaksSet->set(AA_NULLVALUE); // leaksSet->set(AA_THISVALUE); } void AliasInfos::println(ostream &os) { for (DeclToBitsetMap::const_iterator v = declToBitsetMap.begin(); v != declToBitsetMap.end(); v++) { Decl* decl = (*v).first; Bitset *bs = (*v).second; os << *(decl->name()) << " == "; printBitset(bs, os); os << endl; } // print values' subvalues ValueToValueInfoMap::const_iterator v = valueToValueInfoMap.begin(); for (; v != valueToValueInfoMap.end(); v++) { int value = (*v).first; ValueInfo *vi = (*v).second; vi->println(value, os); } os << "Leaks set: "; printBitset(leaksSet, os); os << endl; // os << "???.??? == "; // printBitset(anyFieldValues, os); // os << endl; } bool AliasInfos::equivalent(AliasInfos *ai) { if (size != ai->size) return false; if (!equalDeclToBitsetMaps(&declToBitsetMap, &(ai->declToBitsetMap))) return false; // now check that our mappings are the same if (valueToValueInfoMap.size() != ai->valueToValueInfoMap.size()) return false; // sizes are same... ValueToValueInfoMap::const_iterator v = valueToValueInfoMap.begin(); for (; v != valueToValueInfoMap.end(); v++) { int value = (*v).first; ValueInfo *vi = (*v).second; if (!isInMap(value, ai->valueToValueInfoMap)) return false; if (!vi->equivalent(ai->valueToValueInfoMap[value])) return false; } if (!leaksSet->equal(ai->leaksSet)) return false; return true; } void AliasInfos::ruinFieldInfos(Bitset *incomingValues) { ValueToValueInfoMap::const_iterator v = valueToValueInfoMap.begin(); for (; v != valueToValueInfoMap.end(); v++) { ValueInfo *vi = (*v).second; vi->fieldToBitsetMap.clear(); // the entire purpose of the anyFieldValues field // anyFieldValues->un(incomingValues); // vi->anyFieldValues->un(incomingValues); } } bool AliasInfos::setupValueInfo(int index, TypeNode *t) { if (!isInMap(index, valueToValueInfoMap)) { valueToValueInfoMap[index] = new ValueInfo(index, size, t); return true; } return false; } void AliasInfos::printAliases(ostream &os) { for (DeclToBitsetMap::const_iterator v = declToBitsetMap.begin(); v != declToBitsetMap.end(); v++) { Decl* decl = (*v).first; Bitset *bs = (*v).second; for (DeclToBitsetMap::const_iterator v2 = declToBitsetMap.begin(); v2 != declToBitsetMap.end(); v2++) { Decl* decl2 = (*v2).first; Bitset *bs2 = (*v2).second; os << "(" << *(decl->name()) << ", " << *(decl2->name()) << ") = " << bs->disjoint(bs2) << ", "; } os << endl; } }