#ifndef _CODE_DEFS_H_ #define _CODE_DEFS_H_ #include extern bool infer_nooverlap; // Set to true to use Titanium array no overlap inference class DefNode { public: int index; TreeNode *t; DefNode(TreeNode *tr, int i) : index(i), t(tr) {} }; // We need a canonical representation of a type that ignores // modifiers, because a def to a local single foo is treated the same as // a def to a foo. That is what xtype is. // also handles different TypeNode *'s that point to identical TypeNode's typedef string xtype; typedef map< Decl *, bool, less > map_decl_to_bool; typedef map< string, llist *, less > map_string_to_deflist; typedef map< Decl *, map_string_to_deflist, less > map_decl_field_to_deflist; typedef map< xtype, bool, less > map_type_to_bool; typedef map< xtype, map_string_to_deflist, less > map_type_field_to_deflist; typedef map< Decl *, llist *, less > map_decl_to_deflist; typedef map< xtype, llist *, less > map_type_to_deflist; typedef map< xtype, llist * > map_type_to_typelist; typedef map < TreeNode *, llist *, less > map_tnode_to_deflist; typedef map < xtype, llist* > map_type_to_fieldlist; class Defs { public: Defs() { unknownMethods = false; nextindex = 0; methodCalls = NULL; } int size() { return nextindex; }; // called from code-ud.cc to build def-use chains void merge(TreeNode *t, Bitset *defs, Bitset *kills); void reaching(TreeNode *t, Bitset *reaching); void connect(TreeNode *nameNode, Bitset *reaching); void addCallDefs(); // debugging dumps void print(ostream &os, int indent); void printVardefs(ostream &os, int indent); void printBitset(Bitset *bs, ostream &os, int indent); private: int nextindex; llist *getAllDefs(TreeNode *t); // type_field_to_deflist(fieldDecl) is a list of all nodes that modify // the given field decl map_decl_to_deflist _fieldDefs; #define fieldDefs(fieldDecl) \ _fieldDefs[fieldDecl] // varDefs(decl) is the list of DefNodes that are defs for the given var map_decl_to_deflist _varDefs; #define varDefs(decl) \ _varDefs[decl] // arrayDefs(type) is the list of DefNodes that are defs for A[p] // for some A of of the given type. map_type_to_deflist _arrayDefs; #define arrayDefs(type) \ _arrayDefs[type2xtype(type)] // callDefs(call) is the list of DefNodes that the given method call defines. map_tnode_to_deflist _callDefs; #define callDefs(call) \ _callDefs[call] // immutableIFields returns the list of instance (non-static) fields for any immutable type static llist* immutableIFields(TypeNode *t); // IIFDefs(objectdecl, fieldID) is the list of all nodes that modify // the given instance (non-static) field of the given immutable object // usually only happens in a constructor, but after inlining such defs could end up anywhere map_decl_field_to_deflist _IIFDefs; #define IIFDefs(objectdecl, fieldID) \ _IIFDefs[objectdecl][fieldID] // aliasableFields(fielddecl) is true for all aliasable fields that we ever reference (def or use) map_decl_to_bool _aliasableFields; #define aliasableFields(fielddecl) \ _aliasableFields[fielddecl] // aliasableArrays(type) is true for all array types whose elements we ever reference (def or use) map_type_to_bool _aliasableArrays; #define aliasableArrays(type) \ _aliasableArrays[type2xtype(type)] // typeAD(type) returns a list of all the ancestor and descendent types of given object type (not including given type) // NULL for none or non-object types static llist* typeAD(TypeNode *t); static llist* aliasableArrayTypes(TypeNode *t); friend void ArrayAccessNode::findMayMustReadWrite(bool r, bool w); // we may have assignments which involve the formal parameter "this", // but ThisNodes don't have an associated decl() we can use for indexing into our maps // so create a dummy decl that will serve as the map lookup handle for any ThisNode public: static Decl *fakeThisDecl; private: // helpers for def analysis on immutables: DOB 11/00 static inline bool isImmutableVar(TreeNode *t); static inline Decl *getImmutableVarDecl(TreeNode *t); static inline TypeNode *getImmutableVarType(TreeNode *t); static inline string getIIFANFieldID(TreeNode *iifan); static inline Decl *getIIFANObjectDecl(TreeNode *iifan); void reachingAnal(TreeNode *t, void (*deffn)(int), void (*killfn)(int)); //public: // this interface is too complicated and poorly documented to be public // use friend instead for the few external functions that need it void addVarDef(TreeNode *t, Decl *d); void addIIFDef(TreeNode *t, TreeNode *objectvar, const string& field); void addImmutableVarDef(TreeNode *t, TreeNode *immutableVar, bool deffields=true); void addTypeFieldDef(Decl* fieldDecl, TreeNode *assignment); void addArrayDef(TreeNode *assignment, TypeNode *t); void varAssignment(TreeNode *assignment); void assignment(TreeNode *t); void defAllAliasable(TreeNode *t); llist *methodCalls; bool unknownMethods; friend void VarDeclNode::findDefs(Defs *d); friend void ForEachPairNode::findDefs(Defs *d); friend void ParameterNode::findDefs(Defs *d); friend void AssignNode::findDefs(Defs *d); friend void MethodCallNode::findDefs(Defs *d); friend void FieldAccessNode::findDefs(Defs *d); friend void ArrayAccessNode::findDefs(Defs *d); //--------------------------------------------------------------------------- // storage reclamation // try to free memory as agressively as possible, because these things get REALLY big //--------------------------------------------------------------------------- private: static void free_DefNode_list(llist *deflist) { while (deflist) { delete deflist->front(); deflist = deflist->free(); } } #define DELETE_SIMPLE_MAP(maptype, mapname) do { \ for (maptype::const_iterator v = mapname.begin(); \ v != mapname.end(); v++) \ free_DefNode_list((*v).second); \ } while(0) #define DELETE_2D_MAP(primarymaptype, elementmaptype, primarymapname) do { \ for (primarymaptype::const_iterator pv = primarymapname.begin(); \ pv != primarymapname.end(); pv++) \ DELETE_SIMPLE_MAP(elementmaptype, (*pv).second); \ } while(0) public: ~Defs() { // free all the map data structures DELETE_SIMPLE_MAP(map_decl_to_deflist, _varDefs); DELETE_SIMPLE_MAP(map_type_to_deflist, _arrayDefs); DELETE_SIMPLE_MAP(map_decl_to_deflist, _fieldDefs); DELETE_2D_MAP(map_decl_field_to_deflist, map_string_to_deflist, _IIFDefs); // note: _immutableIFields should never be collected, they are static and shared by all instances of Defs // _callDefs gets collected below // cleanup other misscellaneous junk free_all(methodCalls); // the DefNodes referenced in _callDefs are all aliases of DefNodes pointed to by other maps // therefore, we just want to collect the linked lists and not the DefNodes attached to them for (map_tnode_to_deflist::const_iterator v = _callDefs.begin(); v != _callDefs.end(); v++) free_all((*v).second); } #undef DELETE_SIMPLE_MAP #undef DELETE_2D_MAP }; extern xtype type2xtype(TypeNode *t); static inline const string& decl2str(Decl *d) { return *d->name(); } static inline string xtype2str(xtype t) { return (string) t; } // #define type2str(t) ((t)->cType()) // #define field2str(f) (f) #endif