#include "AST.h" #include "clone.h" TreeListNode *TreeListNode::clone() const { TreeListNode *copy = new TreeListNode; *copy = *this; copy->children = new TreeNode*[_arity]; memcpy(copy->children, children, _arity * sizeof(*children)); return copy; } //////////////////////////////////////////////////////////////////////// void TreeNode::deepCloneChildren( TreeNode © ) const { for (int sweep = arity(); sweep--; ) copy.child( sweep, child( sweep )->deepClone() ); } TreeListNode *TreeListNode::deepClone() const { TreeListNode * const copy = new TreeListNode; *copy = *this; copy->children = new TreeNode*[_arity]; deepCloneChildren( *copy ); return copy; } void TreeNode::deepCloneSpecial (TreeNode*) const { } //////////////////////////////////////////////////////////////////////// // below by Dan Bonachea #include "code-util.h" #include "AST.h" #include "llist.h" // the original deepClone() method neglects to fixup // several cross-tree references, // specifically: // GotoNode destination // BreakNode destination cleanups // ContinueNode destination cleanups // ReturnNode cleanups // MonitorUseNode fetcher // it also performs some cloning of decls as necessary for these nodes: // ForEachPairNode (LocalVarDecl) // VarDeclNode (LocalVarDecl) // ParameterNode (FormalParameterDecl) // the deepCloneWithCrossTreeFixup() function performs a deepClone(), // then does the necessary fixup on these nodes //------------------------------------------------------------------------------------ // helpers for jumps static bool isJumpNode(TreeNode *t) { return isGotoNode(t) || isBreakNode(t) || isContinueNode(t); } static TreeNode *getJumpDest(TreeNode *t) { if (isGotoNode(t)) return static_cast(t)->destination(); else if (isBreakNode(t)) return static_cast(t)->destination(); else if (isContinueNode(t)) return static_cast(t)->destination(); else fatal_error(""); return NULL; } static void setJumpDest(TreeNode *t, TreeNode *dest) { if (isGotoNode(t)) static_cast(t)->destination(dest); else if (isBreakNode(t)) static_cast(t)->destination(dest); else if (isContinueNode(t)) static_cast(t)->destination(dest); else fatal_error(""); } //------------------------------------------------------------------------------------ // helpers for cleanups static bool isCleanupsNode(TreeNode *t) { return isBreakNode(t) || isContinueNode(t) || isReturnNode(t); } llist* cloneList(llist* l) { if (!l) return NULL; return cons(l->front()->deepClone(), cloneList(l->tail())); } static void cloneCleanups(TreeNode *from, TreeNode *to) { if (isBreakNode(from)) { assert(isBreakNode(to)); static_cast(to)->cleanups(cloneList(static_cast(from)->cleanups())); } else if (isContinueNode(from)) { assert(isContinueNode(to)); static_cast(to)->cleanups(cloneList(static_cast(from)->cleanups())); } else if (isReturnNode(from)) { assert(isReturnNode(to)); static_cast(to)->cleanups(cloneList(static_cast(from)->cleanups())); } else fatal_error(""); } //------------------------------------------------------------------------------------ // helpers for checks static bool isLegalToClone(TreeNode *t) { // this is the current list of things for which we don't support semantically-correct cloning // high-level nodes that contain some non-child pointers // (we probably don't care to ever clone these anyhow) if (isTemplateDeclNode(t)) return false; // contains an Environ if (isTemplateInstanceDeclNode(t)) return false; // contains an Environ if (isCompileUnitNode(t)) return false; if (isMethodDeclNode(t)) return false; if (isMethodSignatureNode(t)) return false; if (isConstructorDeclNode(t)) return false; if (isReorderNode(t)) return false; if (isUpdatePointBeforeStmtNode(t)) return false; // these are legal unless their analysis data contains some information // (this could be relaxed if we figured out the right way to copy of reset the analysis results) if (isAllocateNode(t)) return (static_cast(t)->modifiesValues() == NULL); if (isMethodCallNode(t)) return (static_cast(t)->modifiesValues() == NULL); if (isForEachStmtNode(t)) { ForEachStmtNode* fe = static_cast(t); return (fe->invariants() == NULL && fe->defs() == NULL // && // fe->arrayAccesses == NULL && fe->SR == NULL ); } #if 0 if (isSRArrayAccessNode(t)) { TreeNode *sibptr = static_cast(t)->WRTloop(); return (sibptr->absent() || sibptr == NULL); } if (isOSRArrayAccessNode(t)) { TreeNode *sibptr = static_cast(t)->WRTloop(); return (sibptr->absent() || sibptr == NULL); } #endif return true; } bool isLegalToCloneDeep(TreeNode *t) { if (!isLegalToClone(t)) return false; foriter (p, t->allChildren(), TreeNode::ChildIter) if (!isLegalToCloneDeep(*p)) return false; return true; } //------------------------------------------------------------------------------------ // pre-pass that gathers necessary info and performs some checks static llist *jumpList = NULL; static map_tree_to_tree *labeledStmtsOldToNew = NULL; static llist *monitorUseNodeList = NULL; static map_tree_to_tree *monitorFetchersOldToNew = NULL; static map_tree_to_tree *corresponding = NULL; static llist *localNameNodeList = NULL; static map_decl_to_decl *localDeclsOldToNew = NULL; static void gatherCloningInfo(TreeNode *orig, TreeNode *copy, bool safety) { assert(!safety || isLegalToClone(orig)); // gather GotoNode info assert(labeledStmtsOldToNew != NULL); if (isJumpNode(copy)) { assert(isJumpNode(orig)); push(jumpList, copy); } if (isLabeledStmtNode(copy)) { assert(isLabeledStmtNode(orig)); (*labeledStmtsOldToNew)[orig] = copy; } // do cleanups if (isCleanupsNode(copy)) { assert(isCleanupsNode(orig)); cloneCleanups(orig, copy); } // gather MonitorUseNode info assert(monitorFetchersOldToNew != NULL); if (isMonitorUseNode(copy)) { assert(isMonitorUseNode(orig)); push(monitorUseNodeList, copy); } if (isMonitorFetchNode(copy)) { assert(isMonitorFetchNode(orig)); (*monitorFetchersOldToNew)[orig] = copy; } // gather local & formal decls info assert(localDeclsOldToNew != NULL); if (isNameNode(copy) && dynamic_cast(static_cast(copy)->decl())) { assert(isNameNode(orig) && dynamic_cast(static_cast(orig)->decl())); push(localNameNodeList, copy); } if (isNameNode(copy) && dynamic_cast(static_cast(copy)->decl())) { assert(isNameNode(orig) && dynamic_cast(static_cast(orig)->decl())); push(localNameNodeList, copy); } if (isNameNode(copy) && dynamic_cast(static_cast(copy)->decl())) { assert(isNameNode(orig) && dynamic_cast(static_cast(orig)->decl())); push(localNameNodeList, copy); } if (isVarDeclNode(copy)) { assert(isVarDeclNode(orig)); LocalVarDecl *oldDecl = dynamic_cast(static_cast(orig)->decl()); assert(oldDecl != NULL); // allocate a new decl node for this local and hook it up to the copy LocalVarDecl *newDecl = new LocalVarDecl(oldDecl->name(), oldDecl->type(), copy, oldDecl->assignable()); static_cast(copy)->simpName()->decl(newDecl); (*localDeclsOldToNew)[oldDecl] = newDecl; } if (isForEachPairNode(copy)) { assert(isForEachPairNode(orig)); LocalVarDecl *oldDecl = dynamic_cast(static_cast(orig)->simpName()->decl()); assert(oldDecl != NULL); // allocate a new decl node for this local and hook it up to the copy LocalVarDecl *newDecl = new LocalVarDecl(oldDecl->name(), oldDecl->type(), copy, oldDecl->assignable()); static_cast(copy)->simpName()->decl(newDecl); (*localDeclsOldToNew)[oldDecl] = newDecl; } if (isParameterNode(copy)) { // these occur as children of MethodDecls and CatchNodes assert(isParameterNode(orig)); FormalParameterDecl *oldDecl = dynamic_cast(static_cast(orig)->decl()); assert(oldDecl != NULL); // allocate a new decl node for this parameter and hook it up to the copy FormalParameterDecl *newDecl = new FormalParameterDecl(oldDecl->name(), oldDecl->type(), copy, oldDecl->assignable()); static_cast(copy)->simpName()->decl(newDecl); (*localDeclsOldToNew)[oldDecl] = newDecl; } if (isLabeledStmtNode(copy)) { // statements with actual user-provided labels have associated decls assert(isLabeledStmtNode(orig)); LabeledStmtNode *lsn = static_cast(orig); if (lsn->label() && !lsn->label()->absent()) { StmtLblDecl *oldDecl = dynamic_cast(static_cast(lsn)->label()->decl()); assert(oldDecl != NULL); // allocate a new decl node for this parameter and hook it up to the copy StmtLblDecl *newDecl = new StmtLblDecl(lsn->label()->ident(), copy); static_cast(copy)->label()->decl(newDecl); (*localDeclsOldToNew)[oldDecl] = newDecl; } } (*corresponding)[orig] = copy; assert(orig->arity() == copy->arity()); for (int sweep = copy->arity(); sweep--; ) gatherCloningInfo(orig->child(sweep), copy->child(sweep), safety); } TreeNode *foreachFixup(TreeNode *t, bool safety) { if (isSRArrayAccessNode(t) || isOSRArrayAccessNode(t)) { TreeNode *newloop = (*corresponding)[t->WRTloop()]; if (newloop != NULL) t->WRTloop(newloop); TreeNode *newarray = (*corresponding)[t->array()]; if (newarray != NULL) t->array(newarray); TreeNode *newindex = (*corresponding)[t->index()]; if (newindex != NULL) t->index(newindex); } for (int i = t->arity(); --i >= 0; ) t->child(i, foreachFixup(t->child(i), safety)); return t; } //------------------------------------------------------------------------------------ // the work-horse TreeNode *deepCloneWithCrossTreeFixup(TreeNode *orig, bool safety) { // do traversal TreeNode *copy = orig->deepClone(); // prepare to gather goto info assert(jumpList == NULL); assert(labeledStmtsOldToNew == NULL); labeledStmtsOldToNew = new map_tree_to_tree(); // prepare to gather monitor info assert(monitorUseNodeList == NULL); assert(monitorFetchersOldToNew == NULL); monitorFetchersOldToNew = new map_tree_to_tree(); // prepare to gather local decl info assert(localNameNodeList == NULL); assert(localDeclsOldToNew == NULL); localDeclsOldToNew = new map_decl_to_decl(); // prepare to gather correspondences assert(corresponding == NULL); corresponding = new map_tree_to_tree(); // gather info gatherCloningInfo(orig, copy, safety); // do the fixup while (jumpList) { TreeNode *j = jumpList->front(); jumpList = jumpList->free(); LabeledStmtNode *olddest = dynamic_cast(getJumpDest(j)); assert(olddest != NULL); LabeledStmtNode *newdest = dynamic_cast((*labeledStmtsOldToNew)[olddest]); if (newdest) setJumpDest(j, newdest); } while (monitorUseNodeList) { MonitorUseNode *s = static_cast(monitorUseNodeList->front()); monitorUseNodeList = monitorUseNodeList->free(); MonitorFetchNode *olddest = dynamic_cast(s->fetcher()); assert(olddest != NULL); MonitorFetchNode *newdest = dynamic_cast((*monitorFetchersOldToNew)[olddest]); if (newdest) s->fetcher(newdest); } while (localNameNodeList) { NameNode *s = static_cast(localNameNodeList->front()); localNameNodeList = localNameNodeList->free(); Decl *oldDecl = s->decl(); assert(oldDecl != NULL); Decl *newDecl = (*localDeclsOldToNew)[oldDecl]; if (newDecl) s->decl(newDecl); } copy = foreachFixup(copy, safety); // do cleanup assert(!jumpList); delete labeledStmtsOldToNew; labeledStmtsOldToNew = NULL; assert(!monitorUseNodeList); delete monitorFetchersOldToNew; monitorFetchersOldToNew = NULL; assert(!localNameNodeList); delete localDeclsOldToNew; localDeclsOldToNew = NULL; delete corresponding; corresponding = NULL; return copy; } ////////////////////////////////////////////////////////////////////////