package x10c.visit; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import polyglot.ast.ArrayAccess_c; import polyglot.ast.Assign; import polyglot.ast.Block; import polyglot.ast.Eval; import polyglot.ast.Expr; import polyglot.ast.Id; import polyglot.ast.IntLit; import polyglot.ast.Local; import polyglot.ast.LocalDecl; import polyglot.ast.Node; import polyglot.ast.NodeFactory; import polyglot.ast.Stmt; import polyglot.ast.Try; import polyglot.frontend.Job; import polyglot.types.Flags; import polyglot.types.LocalDef; import polyglot.types.LocalDef_c; import polyglot.types.LocalInstance; import polyglot.types.Name; import polyglot.types.SemanticException; import polyglot.types.Type; import polyglot.types.TypeSystem; import polyglot.types.Types; import polyglot.types.VarDef; import polyglot.types.VarInstance; import polyglot.util.Position; import polyglot.visit.ContextVisitor; import polyglot.visit.NodeVisitor; import x10.ast.Closure; import x10.ast.Closure_c; import x10.ast.X10Call; import x10.ast.X10Call_c; import x10.ast.X10CanonicalTypeNode; import x10.ast.X10Formal_c; import x10.ast.X10LocalAssign_c; import x10.ast.X10LocalDecl_c; import x10.ast.X10Local_c; import x10.extension.X10Ext_c; import x10.types.MethodInstance; import x10.types.X10ClassType; import x10.types.X10LocalDef; import x10.types.X10LocalDef_c; import x10.util.CollectionFactory; import x10c.ast.BackingArrayAccess; import x10c.ast.BackingArrayAccessAssign; import x10c.ast.BackingArrayNewArray; import x10c.ast.X10CNodeFactory_c; import x10c.types.BackingArrayType; import x10c.types.X10CTypeSystem_c; public class AsyncInitializer extends ContextVisitor { private final X10CTypeSystem_c xts; private final X10CNodeFactory_c xnf; // mapping corresponding box var id for init val private Map<VarDef, Id> initValToId = CollectionFactory.newHashMap(); private int nestLevel = 0; private int pcnt; public AsyncInitializer(Job job, TypeSystem ts, NodeFactory nf) { super(job, ts, nf); xts = (X10CTypeSystem_c) ts; xnf = (X10CNodeFactory_c) nf; } private boolean isFinishBlock(Try n) { return (collectAsyncVarsToBox(n) != null); } private boolean isAsyncBlock(X10Call n) { MethodInstance mi = (MethodInstance) n.methodInstance(); if (mi.container().isClass() && ((X10ClassType) mi.container().toClass()). fullName().toString().equals("x10.lang.Runtime")) { if (mi.signature().startsWith("runAsync")) return true; } return false; } @Override protected NodeVisitor enterCall(Node parent, Node n) throws SemanticException { if (n instanceof X10Call) { X10Call call = (X10Call)n; MethodInstance mi = (MethodInstance) call.methodInstance(); if (mi.container().isClass() && ((X10ClassType) mi.container().toClass()). fullName().toString().equals("x10.lang.Runtime")) { // adjust nest level counter of finish block if (mi.signature().startsWith("startFinish")) nestLevel++; else if (mi.signature().startsWith("stopFinish")) nestLevel--; } } if (n instanceof Try) { Set<LocalDef> asyncInitVal = collectAsyncVarsToBox((Try)n); if (asyncInitVal != null) { if (nestLevel == 1) { // outermost finish block -- initialize internal structure initValToId.clear(); pcnt = 0; } // register into the map (curr nest level, box var) registerInternalMap(((X10Ext_c)n.ext()).initVals); } } return super.enterCall(parent, n); } @Override protected Node leaveCall(Node parent, Node old, Node n, NodeVisitor v) throws SemanticException { if (!(n instanceof Try)) return n; // collect local vars accessed within async Set<LocalDef> asyncVar = collectLocalVarsToBox((Try)n); Set<LocalDef> asyncInitVal = collectAsyncVarsToBox((Try)n); if (asyncInitVal == null && asyncVar == null) return n; if (asyncVar != null) { // merge async init vals and async vars registerInternalMap(asyncVar); if (asyncInitVal == null) asyncInitVal = asyncVar; else asyncInitVal.addAll(asyncVar); } // box async init vals and async vars under the try-catch-finally block Try tcfBlock = replaceVariables((Try)n, asyncInitVal); if (nestLevel == 1) // after boxing all the nest levels tcfBlock = privatizeVariables(tcfBlock, asyncInitVal); List<Stmt> stmts = new ArrayList<Stmt>(); // declare boxed vars for (VarDef var : asyncInitVal) { stmts.add(genBoxDeclaration(var, n)); } stmts.add(tcfBlock); // store the boxed vars back into original final vars for (VarDef var : asyncInitVal) { stmts.add(genBackingStore(var, n)); } Block bb = xnf.Block(n.position(), stmts); return bb; } private Set<LocalDef> collectAsyncVarsToBox(Try n) { X10Ext_c ext = (X10Ext_c) n.ext(); if (ext.initVals == null) return null; Set<LocalDef> asyncInitVal = null; for (LocalDef initVal : ext.initVals) { if (((X10LocalDef) initVal).isAsyncInit()) { if (asyncInitVal == null) asyncInitVal = CollectionFactory.newHashSet(); asyncInitVal.add(initVal); } } return asyncInitVal ; } private Set<LocalDef> collectLocalVarsToBox(Try tcfBlock) { // one pass scan of async blocks within finish and collect accesses of vars declared outside final Set<LocalDef> asyncVar = CollectionFactory.newHashSet(); final List<LocalDef> localDeclList = new ArrayList<LocalDef>(); tcfBlock.visit(new NodeVisitor() { @Override public Node leave(Node parent, Node old, Node n, NodeVisitor v) { if (n instanceof X10Call_c) { X10Call call = (X10Call)n; if (isAsyncBlock(call)) { localDeclList.clear(); scanAsyncBlock(call, asyncVar, localDeclList); } } return n; }; }); return asyncVar.isEmpty() ? null : asyncVar; } private void scanAsyncBlock(final X10Call call, final Set<LocalDef> asyncVar, final List<LocalDef> localDeclList) { call.visit(new NodeVisitor() { @Override public Node override(Node parent, Node n) { if (n instanceof X10Call) { X10Call currCall = (X10Call)n; if (isAsyncBlock(currCall) && !currCall.equals(call)) // should not visit subtree of inner async block further (already done) return n; } if (n instanceof Try) { if (isFinishBlock((Try)n)) // should not visit subtree of inner finish block further (already done) return n; } if (n instanceof BackingArrayAccess) { BackingArrayAccess ba = (BackingArrayAccess) n; if (checkInitValList((Local)ba.array()) != null) { // should not visit backing array which is created by myself (already done) return n; } } if (n instanceof BackingArrayAccessAssign) { BackingArrayAccessAssign ba = (BackingArrayAccessAssign) n; if (checkInitValList((Local)((ArrayAccess_c)ba.left()).array()) != null) { // should not visit backing array which is created by myself (already done) // except that if a variable is referenced in the RHS, it may need to be added Expr right = ba.right(); if (right instanceof X10Local_c) { X10Local_c l = (X10Local_c)right; Flags flags = l.localInstance().flags(); if (flags == null || !flags.equals(Flags.FINAL)) { VarDef var = checkIfIncluded(l, asyncVar); if (var == null) { asyncVar.add(new LocalDef_c(ts, right.position(), flags, Types.ref(l.localInstance().type()), l.name().id()){}); } } } return n; } } return null; } @Override public Node leave(Node parent, Node old, Node n, NodeVisitor v) { if (n instanceof X10LocalDecl_c) { X10LocalDecl_c ld = (X10LocalDecl_c)n; if (ld.localDef().flags() == null || !ld.localDef().flags().equals(Flags.FINAL)) localDeclList.add(ld.localDef()); } if (n instanceof X10Formal_c) { X10Formal_c ld = (X10Formal_c)n; if (ld.localDef().flags() == null || !ld.localDef().flags().equals(Flags.FINAL)) localDeclList.add(ld.localDef()); } if (n instanceof X10Local_c) { X10Local_c l = (X10Local_c)n; Flags flags = l.localInstance().flags(); if (flags == null || !flags.equals(Flags.FINAL)) { // check if this is not locally declared var for (LocalDef localDefVar : localDeclList) { if (isLocalInstanceEquals(localDefVar.asInstance(), l.localInstance())) return n; } VarDef var = checkIfIncluded(l, asyncVar); if (var == null) asyncVar.add(new LocalDef_c(ts, n.position(), flags, Types.ref(l.localInstance().type()), l.localInstance().name()){}); } } return n; } }); } private boolean isLocalInstanceEquals(LocalInstance li1, LocalInstance li2) { return li1.name().equals(li2.name()) && li1.flags().equals(li2.flags()) && li1.type().typeEquals(li2.type(), context); } private Try replaceVariables(Try tcfBlock, final Set<LocalDef> asyncInitVal) { // box async init vals tcfBlock = (Try)tcfBlock.visit(new NodeVisitor() { private final Map<Name, X10LocalDef> nameToBoxDef = CollectionFactory.newHashMap(); private final List<LocalDef> localDeclList = new ArrayList<LocalDef>(); @Override public Node leave(Node parent, Node old, Node n, NodeVisitor v) { if (n instanceof X10LocalDecl_c) { X10LocalDecl_c ld = (X10LocalDecl_c)n; if (ld.localDef().flags() == null || !ld.localDef().flags().equals(Flags.FINAL)) localDeclList.add(ld.localDef()); return n; } if (n instanceof X10LocalAssign_c) { X10LocalAssign_c la = (X10LocalAssign_c) n; Type type = Types.baseType(la.type()); Expr left = la.left(); if (!(left instanceof Local)) { return n; } Local local = (Local)left; VarDef initVal = checkIfIncluded(local, asyncInitVal); if (initVal == null) return n; // initialization to boxed variable Id id = getBoxId(initVal); BackingArrayType arrayType = xts.createBackingArray(n.position(), Types.ref(type)); LocalDef ldef = getBoxLocalDef(n, arrayType, initVal, id); IntLit idx0 = (IntLit) xnf.IntLit(n.position(), IntLit.INT, 0).type(xts.Int()); for (LocalDef localDefVar : localDeclList) { if (isLocalInstanceEquals(localDefVar.asInstance(), local.localInstance())) return n; } return xnf.BackingArrayAccessAssign(n.position(), xnf.Local(n.position(), id).localInstance(ldef.asInstance()).type(arrayType), idx0, la.operator(), la.right()).type(type); } if (n instanceof X10Local_c) { if ((parent instanceof X10LocalAssign_c) && n.equals(((X10LocalAssign_c)parent).left())) // should be processed in the above return n; X10Local_c local = (X10Local_c) n; VarDef initVal = checkIfIncluded(local, asyncInitVal); if (initVal == null) return n; Type type = Types.baseType(local.type()); Id id = getBoxId(initVal); BackingArrayType arrayType = xts.createBackingArray(n.position(), Types.ref(type)); LocalDef ldef = getBoxLocalDef(n, arrayType, initVal, id); IntLit idx0 = (IntLit) xnf.IntLit(n.position(), IntLit.INT, 0).type(xts.Int()); for (LocalDef localDefVar : localDeclList) { if (isLocalInstanceEquals(localDefVar.asInstance(), local.localInstance())) return n; } return xnf.BackingArrayAccess(n.position(), xnf.Local(n.position(), id).localInstance(ldef.asInstance()).type(arrayType), idx0, type); } if (n instanceof Closure) { Closure closure = (Closure) n; List<VarInstance<? extends VarDef>> newCaps = new ArrayList<VarInstance<? extends VarDef>>(); List<VarInstance<? extends VarDef>> caps = closure.closureDef().capturedEnvironment(); for (VarInstance<? extends VarDef> vi : caps) { if (nameToBoxDef.containsKey(vi.def().name())) { newCaps.add(nameToBoxDef.get(vi.def().name()).asInstance()); } else { newCaps.add(vi); } } closure.closureDef().setCapturedEnvironment(newCaps); localDeclList.clear(); } return n; } private X10LocalDef getBoxLocalDef(Node n, Type type, VarDef initVal, Id id) { X10LocalDef ldef; if (nameToBoxDef.containsKey(initVal.name())) { ldef = nameToBoxDef.get(initVal.name()); } else { ldef = xts.localDef(n.position(), xts.Final(), Types.ref(type), id.id()); nameToBoxDef.put(initVal.name(), ldef); } return ldef; } }); // tcfBlock.dump(System.err); return tcfBlock; } private Try privatizeVariables(Try tcfBlock, final Set<LocalDef> asyncInitVal) { // setup internal structures final List<PVarInfo> privatizedVarList = new ArrayList<PVarInfo>(); pcnt = 0; // tcfBlock.dump(System.err); Block newTryBlock = (Block)tcfBlock.tryBlock().visit(new NodeVisitor() { @Override public Node leave(Node parent, Node old, Node n, NodeVisitor v) { if (n instanceof X10Call_c) { X10Call call = (X10Call)n; if (isAsyncBlock(call)) { privatizedVarList.clear(); pcnt++; collectInfo(call, privatizedVarList); return doPrivatization(call, privatizedVarList); } } return n; }; }); // newTryBlock.dump(System.err); tcfBlock = xnf.Try(tcfBlock.position(), newTryBlock, tcfBlock.catchBlocks(), tcfBlock.finallyBlock()); return tcfBlock; } private void collectInfo(final X10Call call, final List<PVarInfo> privatizedVarList) { call.visit(new NodeVisitor() { @Override public Node override(Node parent, Node n) { if (n instanceof X10Call) { X10Call currCall = (X10Call)n; if (isAsyncBlock(currCall) && !currCall.equals(call)) // should not visit subtree of inner async block further (already done) return n; } if (n instanceof Try) { if (isFinishBlock((Try)n)) // should not visit subtree of inner finish block further (already done) return n; } return null; } @Override public Node leave(Node parent, Node old, Node n, NodeVisitor v) { if (n instanceof BackingArrayAccessAssign) { BackingArrayAccessAssign ba = (BackingArrayAccessAssign)n; VarDef initVal = checkInitValList((Local)((ArrayAccess_c)ba.left()).array()); if (initVal != null) { registerPrivatizedList(privatizedVarList, initVal, true); } } if (n instanceof BackingArrayAccess) { BackingArrayAccess ba = (BackingArrayAccess)n; VarDef initVal = checkInitValList((Local)ba.array()); if (initVal != null) { // check left hand side if (parent instanceof X10LocalAssign_c) { Expr left = ((X10LocalAssign_c)parent).left(); if (left instanceof Local && initVal.name().equals(((Local)left).name().id())) { // this is a backing store just generated in the above return n; } } registerPrivatizedList(privatizedVarList, initVal, false); } } return n; }; }); // dumpPrivatizedList(privatizedVarList); } private void registerPrivatizedList(List<PVarInfo> privatizedVarList, VarDef initVal, boolean isAssign) { for (PVarInfo valInfo : privatizedVarList) { if (valInfo.initVal.equals(initVal)) { // found the match if (!isAssign) valInfo.refCount++; else valInfo.isAssign = true; return; } } privatizedVarList.add(new PVarInfo(initVal, isAssign)); } private boolean checkPrivatizeCriteria(PVarInfo pvarInfo) { if (pvarInfo.initVal.flags().equals(Flags.FINAL)) // local val return pvarInfo.refCount > 0; // local var: reference only case // (currently cannot find location to write back updated private var) return !pvarInfo.isAssign && pvarInfo.refCount > 0; } private X10Call doPrivatization(final X10Call call, final List<PVarInfo> privatizedVarList) { if (privatizedVarList.isEmpty()) // nothing to do for this runAsync return call; X10Call newCall = (X10Call)call.visit(new NodeVisitor() { @Override public Node override(Node parent, Node n) { if (n instanceof X10Call) { X10Call currCall = (X10Call)n; if (isAsyncBlock(currCall) && !currCall.equals(call)) // should not visit subtree of inner async block further (already done) return n; } if (n instanceof Try) { if (isFinishBlock((Try)n)) // should not visit subtree of inner finish block further (already done) return n; } return null; } @Override public Node leave(Node parent, Node old, Node n, NodeVisitor v) { if (n instanceof Closure_c) { // private var declaration at each closure entry List<Stmt> stmts = new ArrayList<Stmt>(); // for (VarDef initVal : asyncInitVal) { for (PVarInfo pvarInfo : privatizedVarList) { if (checkPrivatizeCriteria(pvarInfo)) // privatize only if reference exists stmts.add(genPrivateVarDeclaration(pvarInfo, n)); } if (stmts.isEmpty()) return n; Closure_c c = (Closure_c) n; stmts.add(c.body()); Block newBody = xnf.Block(n.position(), stmts); return (Closure_c)c.body(newBody); } if (n instanceof Eval) { Eval e = (Eval) n; if (e.expr() instanceof BackingArrayAccessAssign) { BackingArrayAccessAssign ba = (BackingArrayAccessAssign)(e.expr()); VarDef initVal = checkInitValList((Local)((ArrayAccess_c)ba.left()).array()); PVarInfo pvarInfo = checkPrivatizeVarList(initVal, privatizedVarList); if (pvarInfo == null) return n; if (pvarInfo.initVal.flags().equals(Flags.FINAL)) { // local val case: add assignment to private var List<Stmt> stmts = new ArrayList<Stmt>(); stmts.add(e); stmts.add(genPrivateVarAssign(pvarInfo, n)); return xnf.StmtSeq(n.position(), stmts); } else { // local var case: replace with private var Id id = getPrivateId(pvarInfo, n); Type type = ts.createLocalInstance(n.position(), Types.ref((LocalDef_c)initVal)).type(); // left-hand side (private var) LocalDef ldef = xts.localDef(n.position(), xts.NoFlags(), Types.ref(type), id.id()); Local left = (Local) xnf.Local(n.position(), id).localInstance(ldef.asInstance()).type(type); // creation of assignment node Expr expr = xnf.LocalAssign(n.position(), left, Assign.ASSIGN, ba.right()).type(type); return xnf.Eval(n.position(), expr); } } if (e.expr() instanceof X10Call) { X10Call call = (X10Call)(e.expr()); MethodInstance mi = (MethodInstance) call.methodInstance(); if (mi.container().isClass() && ((X10ClassType) mi.container().toClass()). fullName().toString().equals("x10.lang.Runtime")) { if (mi.signature().startsWith("stopFinish")) { // in case of nested finish where boxed vars may be updated List<Stmt> stmts = new ArrayList<Stmt>(); for (PVarInfo pvarInfo : privatizedVarList) { if (checkPrivatizeCriteria(pvarInfo) && !pvarInfo.isAssign) // add assignment to private var stmts.add(genPrivateVarAssign(pvarInfo, n)); } if (stmts.isEmpty()) return n; stmts.add(0, e); return xnf.StmtSeq(n.position(), stmts); } } } } if (n instanceof BackingArrayAccess) { BackingArrayAccess ba = (BackingArrayAccess)n; VarDef initVal = checkInitValList((Local)ba.array()); PVarInfo pvarInfo = checkPrivatizeVarList(initVal, privatizedVarList); if (pvarInfo == null) return n; // replace with private var Id id = getPrivateId(pvarInfo, n); Type type = ts.createLocalInstance(n.position(), Types.ref((LocalDef_c)initVal)).type(); LocalDef ldef = xts.localDef(n.position(), xts.Final(), Types.ref(type), id.id()); return xnf.Local(n.position(), xnf.Id(n.position(), id.id())).localInstance(ldef.asInstance()).type(type); } return n; }; }); // newCall.dump(System.err); return newCall; } private void registerInternalMap(Set<LocalDef> asyncInitVal) { List<LocalDef> removeList = new ArrayList<LocalDef>(); for (LocalDef initVal : asyncInitVal) { if (initVal instanceof X10LocalDef && !((X10LocalDef)initVal).isAsyncInit()) continue; Id id = initValToId.get(initVal); if (id == null) { // register id = xnf.Id(Position.COMPILER_GENERATED, Name.makeFresh("$"+initVal.name())); initValToId.put(initVal, id); } else { // already registered in the outer finish removeList.add(initVal); } } for (LocalDef initVal : removeList) { asyncInitVal.remove(initVal); } } private Id getBoxId(VarDef initVal) { Id id = initValToId.get(initVal); assert(id != null); return id; } private Id getPrivateId(PVarInfo pvarInfo, Node n) { // create an unique new name (not shadowed) if (pvarInfo.pvarId == null) { Id boxId = initValToId.get(pvarInfo.initVal); pvarInfo.pvarId = xnf.Id(n.position(), Name.make("p"+pcnt+boxId.toString())); } return pvarInfo.pvarId; } private PVarInfo checkPrivatizeVarList(VarDef initVal, List<PVarInfo> list) { for (PVarInfo pvarInfo : list) { if (initVal.equals(pvarInfo.initVal) && checkPrivatizeCriteria(pvarInfo)) return pvarInfo; } return null; } private VarDef checkInitValList(Local lv) { String name = lv.toString(); for (Map.Entry<VarDef,Id> entry : initValToId.entrySet()) { Id id = entry.getValue(); if (id.toString().equals(name)) return entry.getKey(); } return null; } private VarDef checkIfIncluded(Local lv, Set<LocalDef> asyncInitVal) { Name name1 = lv.name().id(); Flags flags1 = lv.localInstance().flags(); Type t1 = lv.localInstance().type(); for (VarDef var : asyncInitVal) { Name name2 = ((LocalDef_c)var).name(); Flags flags2 = ((LocalDef_c)var).flags(); Type t2 = ts.createLocalInstance(lv.position(), Types.ref((LocalDef_c)var)).type(); if (name1.toString().equals(name2.toString()) && t1.typeEquals(t2, context)) return var; } return null; } private Type createArrayType(Type t) { return xts.createBackingArray(t.position(), Types.ref(t)); } private Stmt genBoxDeclaration(VarDef initVal, Node n) { Type type = ts.createLocalInstance(n.position(), Types.ref((LocalDef_c)initVal)).type(); Type arrayType = createArrayType(type); X10CanonicalTypeNode tnArray = xnf.X10CanonicalTypeNode(n.position(), arrayType); // right-hand side (array creation) List<Expr> dims = new ArrayList<Expr>(); dims.add(xnf.IntLit(n.position(), IntLit.INT, 1).type(xts.Int())); BackingArrayNewArray ba = xnf.BackingArrayNewArray(n.position(), tnArray, dims, 0, arrayType); // creation of declaration node Id id = getBoxId(initVal); LocalDef ldef = xts.localDef(n.position(), xts.Final(), Types.ref(arrayType), id.id()); LocalDecl ld = xnf.LocalDecl(n.position(), xnf.FlagsNode(n.position(), Flags.FINAL), tnArray, id, ba) .localDef(ldef); if (initVal.flags().equals(Flags.FINAL)) // local val case return ld; // local var case: set value from original var to boxed var ldef = xts.localDef(n.position(), xts.NoFlags(), Types.ref(type), id.id()); Name name = ((LocalDef_c)initVal).name(); Local right = (Local) xnf.Local(n.position(), xnf.Id(n.position(), name)).localInstance(ldef.asInstance()).type(type); IntLit idx0 = (IntLit) xnf.IntLit(n.position(), IntLit.INT, 0).type(xts.Int()); Expr baa = xnf.BackingArrayAccessAssign(n.position(), xnf.Local(n.position(), id).localInstance(ldef.asInstance()).type(arrayType), idx0, Assign.ASSIGN, right).type(type); // returning a pair of statements List<Stmt> stmts = new ArrayList<Stmt>(); stmts.add(ld); stmts.add(xnf.Eval(n.position(), baa)); return xnf.StmtSeq(n.position(), stmts); } private Stmt genBackingStore(VarDef initVal, Node n) { Name name = ((LocalDef_c)initVal).name(); Type type = ts.createLocalInstance(n.position(), Types.ref((LocalDef_c)initVal)).type(); // right-hand side (boxed var) Id id = getBoxId(initVal); LocalDef rdef = xts.localDef(n.position(), xts.Final(), Types.ref(type), id.id()); IntLit idx0 = (IntLit) xnf.IntLit(n.position(), IntLit.INT, 0).type(xts.Int()); BackingArrayAccess right = xnf.BackingArrayAccess(n.position(), xnf.Local(n.position(), id).localInstance(rdef.asInstance()).type(type), idx0, type); // left-hand side (original final var) LocalDef ldef = xts.localDef(n.position(), xts.Final(), Types.ref(type), name); Local left = (Local) xnf.Local(n.position(), xnf.Id(n.position(), name)).localInstance(ldef.asInstance()).type(type); // creation of assignment node Expr expr = xnf.LocalAssign(n.position(), left, Assign.ASSIGN, right).type(type); Stmt stmt = xnf.Eval(n.position(), expr); // stmt.dump(System.err); return stmt; } private Stmt genPrivateVarDeclaration(PVarInfo pvarInfo, Node n) { // Name name = ((LocalDef_c)initVal).name(); VarDef initVal = pvarInfo.initVal; boolean isAssign = pvarInfo.isAssign; Type type = ts.createLocalInstance(n.position(), Types.ref((LocalDef_c)initVal)).type(); // creation of declaration node (private final var) Id id = getPrivateId(pvarInfo, n); LocalDef ldef = xts.localDef(n.position(), xts.Final(), Types.ref(type), id.id()); LocalDecl ld; if (isAssign && initVal.flags().equals(Flags.FINAL)) { // no initial value ld = xnf.LocalDecl(n.position(), xnf.FlagsNode(n.position(), Flags.FINAL), xnf.X10CanonicalTypeNode(n.position(), type), xnf.Id(n.position(), id.id())) .localDef(ldef); } else { // local var or reference only val: set initial value from boxed var BackingArrayAccess right = getBoxReference(initVal, type, n); // privatized var for local var (not val) should be non-final ld = xnf.LocalDecl(n.position(), xnf.FlagsNode(n.position(), Flags.NONE), xnf.X10CanonicalTypeNode(n.position(), type), xnf.Id(n.position(), id.id()), right) .localDef(ldef); } // ld.dump(System.err); return ld; } private Stmt genPrivateVarAssign(PVarInfo pvarInfo, Node n) { VarDef initVal = pvarInfo.initVal; Type type = ts.createLocalInstance(n.position(), Types.ref((LocalDef_c)initVal)).type(); // get right-hand side (boxed var) BackingArrayAccess right = getBoxReference(initVal, type, n); // left-hand side (private var) Id id = getPrivateId(pvarInfo, n); LocalDef ldef = xts.localDef(n.position(), xts.NoFlags(), Types.ref(type), id.id()); Local left = (Local) xnf.Local(n.position(), xnf.Id(n.position(), id.id())).localInstance(ldef.asInstance()).type(type); // creation of assignment node Expr expr = xnf.LocalAssign(n.position(), left, Assign.ASSIGN, right).type(type); Stmt stmt = xnf.Eval(n.position(), expr); // stmt.dump(System.err); return stmt; } private BackingArrayAccess getBoxReference(VarDef initVal, Type type, Node n) { Id id = getBoxId(initVal); LocalDef rdef = xts.localDef(n.position(), xts.NoFlags(), Types.ref(type), id.id()); IntLit idx0 = (IntLit) xnf.IntLit(n.position(), IntLit.INT, 0).type(xts.Int()); BackingArrayAccess baa = xnf.BackingArrayAccess(n.position(), xnf.Local(n.position(), id).localInstance(rdef.asInstance()), idx0, type); return baa; } private void dumpPrivatizedList(List<PVarInfo> privatizedVarList) { System.out.println("-------------------"); for (PVarInfo elem : privatizedVarList) { System.out.println(elem.toString()); } } static class PVarInfo { VarDef initVal; // corresponding asyncInitVal or asyncVar Id pvarId; // unique id for each runAsync int refCount; boolean isAssign; PVarInfo(VarDef initVal, boolean isAssign) { this.initVal = initVal; this.isAssign = isAssign; this.refCount = isAssign ? 0 : 1; } public String toString() { return initVal.toString()+" refCount:"+refCount+" isAssign:"+isAssign; } } }